I need to get a specific path of where something is installed, and then use that path to tell a program where to search at runtime. This is working as expected on Windows, but on Linux (specifically Ubuntu running in WSL2), something odd is happening.
In my CMake I run the following:
find_package(PROJ CONFIG REQUIRED)
find_path(PROJ_DATA_DIR
NAMES proj.db
PATHS "${PROJ_DIR}"
NO_DEFAULT_PATH
REQUIRED
)
add_compile_definitions(MY_PROJ_DIR=${PROJ_DATA_DIR})
message(${PROJ_DATA_DIR})
This prints out:
/mnt/c/Users/cgnam/Source/Repos/vira/out/build/ubuntu/vcpkg_installed/x64-linux/share/proj
which is the path I am expecting it to be. In my c++ code however, when I inspect the value of the defined macro using:
#define STRINGIFY2(X) #X
#define STRINGIFY(X) STRINGIFY2(X)
...
std::cout << STRINGIFY(MY_PROJ_DIR);
it prints out:
/mnt/c/Users/cgnam/Source/Repos/vira/out/build/ubuntu/vcpkg_installed/x64-1/share/proj
This is nearly entirely correct, except the x64-linux
has been replaced by x64-1
.
This exact code works completely as expected when being built on Windows, so I am at a loss for why it is doing this when being built on Ubuntu. Its especially odd to me that linux
is being replaced by the integer 1, but this also feels intentional as if I am missing something.
By default, for both GCC and Clang under Linux, linux
is a predefined macro:
$ cpp -dM /dev/null | grep linux
#define __linux 1
#define __gnu_linux__ 1
#define linux 1
#define __linux__ 1
So, for example
#include <iostream>
#define MY_PROJ_DIR /mnt/c/Users/cgnam/Source/Repos/vira/out/build/ubuntu/vcpkg_installed/x64-linux/share/proj
#define STRINGIFY2(X) #X
#define STRINGIFY(X) STRINGIFY2(X)
int main()
{
std::cout << STRINGIFY(MY_PROJ_DIR);
}
prints
/mnt/c/Users/cgnam/Source/Repos/vira/out/build/ubuntu/vcpkg_installed/x64-1/share/proj
The "linux" part of the path is replaced with "1", as that is the value of the linux
macro.
If you instead do add_compile_definitions(MY_PROJ_DIR="${PROJ_DATA_DIR}")
, then your macro will be defined as if by
#define MY_PROJ_DIR "/mnt/c/Users/cgnam/Source/Repos/vira/out/build/ubuntu/vcpkg_installed/x64-linux/share/proj"
As that is a string, the preprocessor won't perform macro replacement.
You also won't need the STRINGIFY
macro and can just use MY_PROJ_DIR
directly.
NOTE: some compiler flags will suppress the linux
flag. According to gcc's documentation:
When the -ansi option, or any -std option that requests strict conformance, is given to the compiler, all the system-specific predefined macros outside the reserved namespace are suppressed. The parallel macros, inside the reserved namespace, remain defined.
For instance:
$ cpp -std=c99 -dM /dev/null | grep linux
#define __linux 1
#define __gnu_linux__ 1
#define __linux__ 1