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
JavaScriptadd_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
.