Is there such functionality in GCC/C++. For example
#ifdef __linux__
//linux code goes here
#elif _WIN32
// windows code goes here
#else
#endif
For ex. force compile for linux
gcc/g++ my_prog.c -di __linux__ -o ./my_prog
This is just for one case, but you get the idea. Is there flexibility to fully control the macro compilation process to override default with command line parameters? Including with custom directives
The GCC commandline option -DFOO[=value]
has
the same effect as placing #define FOO [val]
on an imaginary source line before the real first line of every
source file compiled by the command. The option -UFOO
has the same effect as placing
#undef FOO
on an imaginary line. If there are N such options on the commandline then it as if there are N imaginary lines.
However the C Standard - C17 here, but likewise any other edition - states:
7.1.3 Reserved identifiers ... All identifiers that begin with an underscore and either an uppercase letter or another under- score are always reserved for any use, except those identifiers which are lexically identical to keywords ... If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined.
So it is UB for you to define, e.g. __linux__
or _WIN32
, and the likeliest (and kindest) UB that
your compiler will exihibit if you try to is simply to ignore your definitions that
conflict with its reserved ones.
Such reserved macro names are pre-defined by your compiler. E.g. this compiler:
$ gcc --version | head -n1
gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
$ echo | gcc -dM -E - | grep linux; echo Done
#define __linux 1
#define __gnu_linux__ 1
#define linux 1
#define __linux__ 1
Done
$ echo | gcc -dM -E - | grep x86; echo Done
#define __x86_64 1
#define __x86_64__ 1
Done
was built to target x86_64 GNU/Linux and not built to target Windows:
$ echo | gcc -dM -E - | grep _WIN32; echo Done
Done
Whereas this cross-compiler:
$ echo | x86_64-w64-mingw32-gcc-win32 -dM -E - | grep linux ; echo Done
Done
$ echo | x86_64-w64-mingw32-gcc-win32 -dM -E - | grep _WIN32; echo Done
#define __WIN32__ 1
#define _WIN32 1
#define __WIN32 1
Done
$ echo | x86_64-w64-mingw32-gcc-win32 -dM -E - | grep x86 ; echo Done
#define __x86_64 1
#define __x86_64__ 1
Done
was built to target x86_64 Windows. And this one:
$ echo | aarch64-linux-gnu-gcc -dM -E - | grep linux ; echo Done
#define __linux 1
#define __gnu_linux__ 1
#define linux 1
#define __linux__ 1
Done
$ echo | aarch64-linux-gnu-gcc -dM -E - | grep x86 ; echo Done
Done
echo | aarch64-linux-gnu-gcc -dM -E - | grep ARM_ARCH ; echo Done
#define __ARM_ARCH_PROFILE 65
#define __ARM_ARCH 8
#define __ARM_ARCH_8A 1
#define __ARM_ARCH_ISA_A64 1
Done
was built to target ARM 64 GNU/Linux.
These pre-defined macros are not defaults that you can override. They report immutable features of the compiler that programmers can query with the like of:
#ifdef __linux__
...
#endif
In other words it is not the case that any GCC compiler can be made act as any desired cross-compiler by feeding it the right macro definitions.
A few pre-defined macros are mandated by the Standard. See 6.10.8 Predefined macro names in the same document. The rest (including all 3.7.3 System-specific Predefined Macros like the ones mentioned) are chosen and defined by the compiler implementer, so there is no over-arching regulation of what they are, how they are defined, or what they mean.