c++cmakec++20std-source-location

How can I pass CMake's CMAKE_SOURCE_DIR to C++ source files?


In my C++ program I use std::source_location for log output. The printed path is currently absolute. The project is built with CMake. I want to shorten the std::source_location path according to the CMake variable CMAKE_SOURCE_DIR.

How can I access CMAKE_SOURCE_DIR within my C++ code?

I tried:

add_compile_definitions("-DSOURCE_ROOT=\"${CMAKE_SOURCE_DIR}\"")

But got:

error: macro names must be identifiers

I have CMake 3.22.1 installed, and cmake_minimum_required(VERSION 3.19) in my CMakeLists.txt. I tested with GCC on Ubuntu, but I have an unsubstantiated hunch that I'll observe the same on MSVC and clang on Windows as well.


Solution

  • The general approach you're taking with add_compile_definitions works. One part of why it's not working is that you're prefixing with -D manually, which CMake will add for you (you don't need to include it). Another part is that you don't need to add the quotes around the definition value. CMake will add quotes automatically around the value if it needs them (Ex. if it contains spaces). So you can just do add_compile_definitions("SOURCE_ROOT=${CMAKE_SOURCE_DIR}") (or use target_compile_definitions if appropriate).

    Note from the add_compile_definition docs:

    New in version 3.26: Any leading -D on an item will be removed.

    which is why I couldn't reproduce your issue (I originally had 3.26 installed at the time of this writing)

    There are also other ways to do what you're looking for. You can use CMake to generate a header containing the macro definition, which I suppose could have the benefit that for installations, if someone wants to use the installation and the macro needs to be available in the installed headers, then that wouldn't rely on any CMake-specific mechanism. To do that, you can use the configure_file command. This is actually part of the very first step of the CMake tutorial. Create an input file with include guards and #define VAR ${CMAKE_SOURCE_DIR} (or whatever variable you want), and then configure that file. Conventionally, generated files get put somewhere in the CMAKE_CURRENT_BINARY_DIR (or some other binary directory like PROJECT_BINARY_DIR or CMAKE_BINARY_DIR). Then add the appropriate include directory using add_include_directory or include_directories or target_include_directories.

    Note that there are other related variables to CMAKE_SOURCE_DIR that you might actually be interested in using instead based on your actual needs: PROJECT_SOURCE_DIR, CMAKE_CURRENT_SOURCE_DIR, CMAKE_CURRENT_LIST_DIR.

    If you want to debug these things, you can use the non-standard (but supported in GCC, Clang, and MSVC) #pragma message ... pragma to print the macro definition, or if your generator supports it, a compile_commands.json file.