I load a path name with cmake
add_definitions(-DMY_PATH =${CMAKE_INSTALL_FULL_DATADIR}/path)
and want to use as a string in my C++ program to load some data. For this the stringification operator # is really handy – I use the macro provided in this answer which is the same as here. Now when I have “linux” or “unix” in my path, this goes horribly wrong (at least with gcc), as these names are simply replaced by “1”:
#include <stdio.h> #define xstr(a) str(a) #define str(a) #a #ifndef MY_PATH #define MY_PATH /path/x86-unix/linux/path #endif int main() { char my_path_str[] = xstr(MY_PATH); printf("my path is %s", my_path_str); return 0; }
Can anyone give a hint why is this happening and how I can prevent it? There is a similar question here, but there is no suitable answer to use it with cmake.
Advertisement
Answer
why is this happening
Macros unix
and linux
are legacy defined to 1 on UNIX platforms.
Part of the program /path/x86-unix/linux/pat
consists of tokens unix
and linux
, so as part of macro expansion in xstr
these macros are substituted for 1
.
how I can prevent it?
#undef
linux
and unix
macros. Or disable gnu extensions, for example, use c11 standard. With GCC compiler on Linux:
$ gcc -E -dM - </dev/null | grep linux #define __linux 1 #define __gnu_linux__ 1 #define linux 1 // here it is #define __linux__ 1 $ gcc -std=c11 -E -dM - </dev/null | grep linux #define __linux 1 #define __gnu_linux__ 1 #define __linux__ 1 // now there's no #define linux
how I can prevent it?
I load a path name with cmake and want to use as a string in my C++ program
Adapting example from Example
section from CMake documentation of configure_file, create a file named my_path.h.in
with content:
#cmakedefine MY_PATH "@MY_PATH@"
Add the following to your cmake configuration:
set(MY_PATH "/path/x86-unix/linux/path") # Generate the file configure_file(my_path.h.in ${CMAKE_CURRENT_BINARY_DIR}/generated/my_path.h ESCAPE_QUOTES @ONLY ) # add the path to your target target_include_directories(your_target PUBLIC_or_PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/generated )
And use #include <my_path.h>
in your program to get MY_PATH
definitions.
I see no reason to use a macro – maybe it would be better to do static const char MY_PATH[] = "@MY_PATH@";
instead.
I load a path name with cmake
add_definitions(-DMY_PATH =${CMAKE_INSTALL_FULL_DATADIR}/path)
Do not use add_definitions
. Prefer target_compile_definitions
instead. See CMake add_definitions documentations.
As a crude workaround, you can add quotes, assuming the shell and compiler will properly parse them:
target_compile_definitions(your_target PRIVATE MY_PATH="${CMAKE_INSTALL_FULL_DATADIR}/path" )
(Note that quotes in the above are preserved literally and passed to the compiler (or build system). CMake quoting does not work like shell quoting. In CMake language, to quote a word, quotes "
have to be exactly the first and last characters of the word. If one of them is in the middle, they are interpreted literally)
However, I think using configure_file
would be preferred, because of ESCAPE_QUOTES
.