Win32 Clang c++98 vs c++11

Started by
16 comments, last by Finalspace 6 years, 3 months ago

I am having trouble getting clang into a C++/98 mode, can someone help me with that?

 

1.) No uint32_t in c++/98


// Are this the correct includes for uint32_t and size_t ?
#include <stdint.h> // uint64_t, uint32_t, uint8_t, int16_t, etc.
#include <stdlib.h> // size_t
#include <limits.h> // UINT32_MAX

/*
..\final_platform_layer.hpp:1646:11: error: unknown type name 'uint32_t'; did you mean 'int32_t'?
                fpl_api uint32_t ReadFileBlock32(const FileHandle &fileHandle, const uint32_t sizeToRead, void *targetBuffer, const uint32_t maxTargetBufferSize);
*/


2.) Macro is expanded always - even though __cplusplus should not be greater than 199711...

 


#if (__cplusplus >= 201103L) || (_MSC_VER >= 1900)
	//! Null pointer (nullptr)
#	define fpl_null nullptr
	//! Constant (constexpr)
#	define fpl_constant constexpr
#else
	//! Null pointer (0)
#	define fpl_null 0
	//! Constant (static const)
#	define fpl_constant static const
#endif
  
/*
In file included from FPL_Console\main.cpp:13:
..\final_platform_layer.hpp:1623:4: error: unknown type name 'constexpr'
                        fpl_constant uint32_t MAX_FILEENTRY_PATH_LENGTH = 1024;
*/

 

I am compiling like this (Win32): 


set BUILD_DIR=bin\FPL_Console\x64-Debug
set IGNORED_WARNINGS=-Wno-missing-field-initializers -Wno-sign-conversion -Wno-cast-qual -Wno-unused-parameter -Wno-format-nonliteral -Wno-old-style-cast -Wno-header-hygiene
rmdir /s /q %BUILD_DIR%
mkdir %BUILD_DIR%
clang -g -Weverything %IGNORED_WARNINGS% -DFPL_DEBUG -std=c++98 -O0 -I..\ -lkernel32.lib -o%BUILD_DIR%\FPL_Console.exe FPL_Console\main.cpp > error.txt 2>&1

 

Advertisement
2 hours ago, Finalspace said:

1.) No uint32_t in c++/98

The standard int-types in stdint.h are an C++11 feature. If you want to use them for C++98, you have to define them yourself.

2 hours ago, Finalspace said:

2.) Macro is expanded always - even though __cplusplus should not be greater than 199711...

What is the value of __cplusplus? You should be able to view/output it to see whats going wrong. Even so, it seems that clang rather uses a check for each indivdual feature instead (https://stackoverflow.com/questions/7139323/what-macro-does-clang-define-to-announce-c11-mode-if-any).

<stdint.h> is a C99 header.  I don't know what vendor's C standard library you;re using, but if it's the native Microsoft Windows one it doesn't support C99 yet.

Clang uses a non-conformant method of indicating support for various features instead of the standards-sanctioned ways, which means you're going to need to use libc++ for the standard library because other vendor's standard C++ libraries are conformant.  There was some discussion in the standards committee about whether to do something like clang does, but it was rejected outright as non-scalable.

Is there any reason you can't just switch from an ancient primordial version of the language to an old out-of-date one?  The differences between C++98 and C++11 are subtle and obscure for he most part, if you avoid the newer features (and do you really care that std::list::length() is guaranteed O(1) instead of having its complexity order implementation-defined?) You should be able to just compile C++98 code in C++11 mode without problem.

Stephen M. Webb
Professional Free Software Developer

16 hours ago, Bregma said:

<stdint.h> is a C99 header.  I don't know what vendor's C standard library you;re using, but if it's the native Microsoft Windows one it doesn't support C99 yet.

Clang uses a non-conformant method of indicating support for various features instead of the standards-sanctioned ways, which means you're going to need to use libc++ for the standard library because other vendor's standard C++ libraries are conformant.  There was some discussion in the standards committee about whether to do something like clang does, but it was rejected outright as non-scalable.

Is there any reason you can't just switch from an ancient primordial version of the language to an old out-of-date one?  The differences between C++98 and C++11 are subtle and obscure for he most part, if you avoid the newer features (and do you really care that std::list::length() is guaranteed O(1) instead of having its complexity order implementation-defined?) You should be able to just compile C++98 code in C++11 mode without problem.

Well i have written a platform abstraction library and i want this to be as portable as possible, so its based on C++/98 - but i want to optionally want to support C++/11 features like constexpr, nullptr and the standard types.

So the only thing i want right know is to reliably detect if i am compiling with C++/11 or not - on common platforms (Win32, Linux, Unix) and compilers (MSVC, G++, CLANG, Intel, MingW).

But thanks for that infos!

Seems like this is the way to go:


//
// C++ feature detection
//
#if (__cplusplus >= 201103L) || (defined(FPL_COMPILER_MSVC) && _MSC_VER >= 1900)
#	define FPL_CPP_2011
#endif

#if !defined(cxx_constexpr)
#	define cxx_constexpr 2235
#endif
#if !defined(cxx_nullptr)
#	define cxx_nullptr 2431
#endif

#if !defined(__has_feature)
#	if defined(FPL_CPP_2011)
#		define __has_feature(x) (((x == cxx_constexpr) || (x == cxx_nullptr)) ? 1 : 0)
#	else
#		define __has_feature(x) 0
#	endif
#endif

#define FPL_CPP_CONSTEXPR __has_feature(cxx_constexpr)
#define FPL_CPP_NULLPTR __has_feature(cxx_nullptr)

 

4 hours ago, Finalspace said:

So the only thing i want right know is to reliably detect if i am compiling with C++/11 or not - on common platforms (Win32, Linux, Unix) and compilers (MSVC, G++, CLANG, Intel, MingW).

 

You need to go even deeper.  You need every single practical combination of OS, compiler, standard library, and possibly thread model and exception model.  If you're using clang on a Linux OS, for example, are you using libstdc++, libc++, or one of the more obscure third-party libraries?  If you're using mingw on a Linux OS to cross-compile for Win32 to run on Win64, do you choose the posix thread model or the win32 thread model?  It's a crazy crazy world out there and I can tell you from experience there are bizarre toolchain combinations that will never work 100% despite your manager a technical expert insisting they're the way things have to be done.

If you really want to make your stuff portable across platforms, look at how boost does it.  It's OK to leverage the work of others, and best of luck to you it can be a fun challenge.

Stephen M. Webb
Professional Free Software Developer

4 hours ago, Bregma said:

You need to go even deeper.  You need every single practical combination of OS, compiler, standard library, and possibly thread model and exception model.  If you're using clang on a Linux OS, for example, are you using libstdc++, libc++, or one of the more obscure third-party libraries?  If you're using mingw on a Linux OS to cross-compile for Win32 to run on Win64, do you choose the posix thread model or the win32 thread model?  It's a crazy crazy world out there and I can tell you from experience there are bizarre toolchain combinations that will never work 100% despite your manager a technical expert insisting they're the way things have to be done.

If you really want to make your stuff portable across platforms, look at how boost does it.  It's OK to leverage the work of others, and best of luck to you it can be a fun challenge.

I dont intent to use any libraries whatsoever in the library itself - except for very raw operating system libraries, like kernel32.dll in win32 and libld.so in linux. Also if possible i would eliminate the need of the c++ runtime as well. Therefore thirdparty libraries are out of question!

But i know that you cannot get it work on every platform/architecture - i just want to work it for common combinations like MSVC/Win32 or Clang/Win32 or Clang/Posix or G++/Posix in x86 and x86_64.

I still cannot get it to compile with clang, even after i cleaned up all c++/98 incompatible stuff and now get the following error:


In file included from FPL_Console\main.cpp:13:
In file included from ..\final_platform_layer.hpp:2966:
In file included from C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\um\Windows.h:168:
In file included from C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\shared\windef.h:24:
In file included from C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\shared\minwindef.h:182:
C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\um\winnt.h:11483:1: error: unknown type name 'constexpr'
DEFINE_ENUM_FLAG_OPERATORS(JOB_OBJECT_NET_RATE_CONTROL_FLAGS)

C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\um\winnt.h:11483:1: error: expected ';' after top level declarator
C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\um\winnt.h:2288:38: note: expanded from macro 'DEFINE_ENUM_FLAG_OPERATORS'
inline _ENUM_FLAG_CONSTEXPR ENUMTYPE operator | (ENUMTYPE a, ENUMTYPE b) throw() { return ENUMTYPE(((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)a) | ((_ENUM_FLAG_SIZED_INTEGER<ENUMTYPE>::type)b)); } \

The line 2966 in my library is just the include of the windows.h -.-

I have no idea why clang in combination with the windows header wants to use constexpr...

 

Here are the clang input:


clang -g -Weverything %IGNORED_WARNINGS% -DFPL_DEBUG -std=c++98 -O0 -I..\ -lkernel32.lib -o%BUILD_DIR%\FPL_Console.exe FPL_Console\main.cpp > error.txt 2>&1

 

If you want to try it yourself:

- Clone https://github.com/f1nalspace/final_game_tech

- Go into demos folder

- Call "clang_x64_debug.bat"

- Look into the errors.txt

 

Does LLVM/clang not support c++/98?

1 hour ago, Finalspace said:

The line 2966 in my library is just the include of the windows.h -.-

I have no idea why clang in combination with the windows header wants to use constexpr...

Inspect windows.h and try to see why it tries to use constexpr.

You will probably need to define some macros that you'll discover while inspecting windows.h

 

Also:

></pre>
<table>				typedef unsigned char fpl_u8;					</table>
<table>				typedef unsigned short fpl_u16;					</table>
<table>				typedef unsigned int fpl_u32;					</table>
<table>				typedef unsigned long long fpl_u64;					</table>
<table>				typedef signed char fpl_s8;					</table>
<table>				typedef signed short fpl_s16;					</table>
<table>				typedef signed int fpl_s32;					</table>
<p>	typedef signed long long fpl_s64;</p><p>

 

This is not guaranteed to be what you think about them. Most of the time, yes, but sometimes no. You'll have to rely on other things (compiler pre-defined macros, standard headers max values for each types...).

9 hours ago, _Silence_ said:

Inspect windows.h and try to see why it tries to use constexpr.

You will probably need to define some macros that you'll discover while inspecting windows.h

Good idea, i will look into that. No idea why i didnt thought this solution myself...

9 hours ago, _Silence_ said:

Also:

 



></pre>
<table>				typedef unsigned char fpl_u8;					</table>
<table>				typedef unsigned short fpl_u16;					</table>
<table>				typedef unsigned int fpl_u32;					</table>
<table>				typedef unsigned long long fpl_u64;					</table>
<table>				typedef signed char fpl_s8;					</table>
<table>				typedef signed short fpl_s16;					</table>
<table>				typedef signed int fpl_s32;					</table>
<p>	typedef signed long long fpl_s64;</p><p>

This is not guaranteed to be what you think about them. Most of the time, yes, but sometimes no. You'll have to rely on other things (compiler pre-defined macros, standard headers max values for each types...).

I know, but there are no "default" types in C++/98, so i have no choice to define them myself.

But really the only problem i see are unsigned int64 aka long long and the dilemma about long vs int. Maybe short can be defined in a weird way, but i wouldn´t expect that "int" is less than 32-bit or "char" more than 8-bit. Unfortunatly i dont have platforms which are defined other than that and right know, i support x86 and x86_64. But i will ask a friend which works all day on dozens of different platforms.

This topic is closed to new replies.

Advertisement