My project has this simplified directory structure:
+-src
| +-CMakeLists.txt
+-example
| +-CMakeLists.txt
+-_builds
| +-win
| | +-src
| | +-example
| +-linux
| | +-src
| | +-example
+-CMakeLists.txt
In example/CMakeLists.txt
I compile the shaders with a platform-dependent compiler into the appropriate _builds/*/example
directory, then I pass the path to the C++ code like this:
target_compile_definitions(vulkan_tutorial PRIVATE EXAMPLE_BIN_DIR=${CMAKE_CURRENT_BINARY_DIR})
In C++ I do this:
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define GET_EXAMPLE_BIN_DIR() TOSTRING(MYLIB_EXAMPLE_BIN_DIR)
std::cout << GET_EXAMPLE_BIN_DIR() << std::endl;
On Windows this works as I expect, and it prints D:/Dev/mylib/_builds/win/example
.
However, on Ubuntu virtual machine it prints
/mnt/hgfs/dev/mylib/_builds/1/example
. So the linux word is replaced with a 1. Why is that? How to solve it?
I named my project mylib
only for this question. Its real name is different, just in case it matters. It is simple, and contains only a few core ASCII characters, underscore letters only.
I checked the binary directory structure whether it contains a folder named 1. It doesn't. It contains what is listed above. I searched for similar CMake variables but did not find any solution. I also realized that in case of a syntax error CMake shows the whole command. Abusing this, I checked my CMake build command, and found that it looks good. It contains this:
-DEXAMPLE_BIN_DIR=/mnt/hgfs/dev/mylib/_builds/linux/example
The whole command line looks like this (I did not simplify this one, not to hide any possible errors):
/bin/x86_64-linux-gnu-g++-9 -DMYLIB_ASSERT_TO_CERR -DMYLIB_ENABLE_EXCEPTIONS -DMYLIB_EXAMPLE_BIN_DIR=/mnt/hgfs/dev/mylib/_builds/linux/example -DMYLIB_LINKED_WITH_VULKAN -DMYLIB_LOGLEVEL=3 -DMYLIB_PRINT_CONFIG -I/mnt/hgfs/dev/mylib/include -I/mnt/hgfs/dev/mylib/third_party/glad2/include -I/mnt/hgfs/dev/mylib/_builds/linux/_deps/glfw-src/include -I/mnt/hgfs/dev/mylib/_builds/linux/_deps/glm-src -g -std=gnu++17 -MD -MT example/CMakeFiles/vulkan_tutorial.dir/vulkan.cpp.o -MF example/CMakeFiles/vulkan_tutorial.dir/vulkan.cpp.o.d -o example/CMakeFiles/vulkan_tutorial.dir/vulkan.cpp.o -c /mnt/hgfs/dev/mylib/example/vulkan.cpp
linux
is defined to 1
, the tokens in MYLIB_EXAMPLE_BIN_DIR
get expanded before they are stringified. If you want a macro to be a string just pass it to the compiler as a string to start with, you can then skip the stringify and are guaranteed not to get any weird expansions:
-DMYLIB_EXAMPLE_BIN_DIR=\"/mnt/hgfs/dev/mylib/_builds/linux/example\"
#include <iostream>
#define GET_EXAMPLE_BIN_DIR() MYLIB_EXAMPLE_BIN_DIR
int main()
{
std::cout << GET_EXAMPLE_BIN_DIR() << std::endl;
}
https://godbolt.org/z/ev4aq4eMx To do this in cmake:
target_compile_definitions(vulkan_tutorial PRIVATE MYLIB_EXAMPLE_BIN_DIR="${CMAKE_CURRENT_BINARY_DIR}")