0

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.

starball
  • 20,030
  • 7
  • 43
  • 238
Benjamin Buch
  • 4,752
  • 7
  • 28
  • 51
  • I'm not an expert in cmake, but I guess you have your syntax wrong. See [here](https://stackoverflow.com/q/9017573/509868). It looks like cmake doesn't need any quotes, escaping or `-D`. – anatolyg Apr 19 '23 at 20:40
  • IME it's fine to have `-D`, inner quotes might cause the problem though – Osyotr Apr 19 '23 at 20:46
  • cannot reproduce. what compiler and version of it are you using (I'm guessing MSVC?)? What CMake version do you have installed, and what version specified in your `cmake_minimum_required`? What if you just remove the `-D`? [docs](https://cmake.org/cmake/help/latest/command/add_compile_definitions.html): "_New in version 3.26: Any leading -D on an item will be removed._" – starball Apr 19 '23 at 21:18

2 Answers2

3

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.

starball
  • 20,030
  • 7
  • 43
  • 238
1

The simple way would be to:

add_compile_definitions("SOURCE_ROOT=${CMAKE_SOURCE_DIR}")

And then you would do:

#define STRING(x) #x
#define XSTRING(x) STRING(x)
std::cout << XSTRING(SOURCE_ROOT) << '\n';
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • 1
    `CMAKE_SOURCE_DIR` corresponds to the top level CMakeLists.txt. It's better to use `CMAKE_CURRENT_SOURCE_DIR` in most situations. – jpr42 Apr 19 '23 at 23:41
  • @jpr42 it depends completely on what the asker wants no? And I'm not sure if they even specified. All they specified is that they _want_ to use `CMAKE_SOURCE_DIR`. – starball Apr 20 '23 at 07:37
  • 1
    I want to use `CMAKE_SOURCE_DIR`. All paths should be relative to the global source root. – Benjamin Buch Apr 20 '23 at 07:49