如何将CMake的CMAKE_SOURCE_DIR传递给C++源文件?

huangapple go评论69阅读模式
英文:

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

问题

在我的C++程序中,我使用std::source_location进行日志输出。目前打印的路径是绝对路径。该项目使用CMake构建。我想根据CMake变量CMAKE_SOURCE_DIR缩短std::source_location的路径。

如何在我的C++代码中访问CMAKE_SOURCE_DIR

我尝试过:

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

但是出现了错误:

error: macro names must be identifiers

我安装了CMake 3.22.1,并在我的CMakeLists.txt中使用了cmake_minimum_required(VERSION 3.19)。我在Ubuntu上使用GCC进行了测试,但我有一种不成熟的预感,我在Windows上使用MSVC和clang时也会遇到相同的问题。

英文:

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.

答案1

得分: 3

通用的 add_compile_definitions 方法是有效的。其中一个原因是你手动添加了 -D 前缀,而 CMake 会为你添加(你不需要包含它)。另一个原因是你不需要在定义值周围添加引号。如果需要的话,CMake 会自动在值周围添加引号(例如,如果它包含空格)。所以你可以简单地执行 add_compile_definitions("SOURCE_ROOT=${CMAKE_SOURCE_DIR}")(或者在合适的情况下使用 target_compile_definitions)。

来自 add_compile_definition 文档 的注释:

> 3.26 版本新增: 任何前导的 -D 都将被移除。

这就是为什么我无法重现你的问题的原因(在我撰写这篇文章时,我最初安装的是 3.26 版本)。

还有其他方法可以实现你想要的效果。你可以使用 CMake 生成包含宏定义的头文件,这样做的好处是如果有人想要使用安装版本并且宏需要在已安装的头文件中可用,那就不依赖于任何特定于 CMake 的机制。要做到这一点,你可以使用 configure_file 命令。实际上,这是 CMake 教程的第一步 的一部分。创建一个带有包含保护和 #define VAR ${CMAKE_SOURCE_DIR}(或者你想要的任何变量)的输入文件,然后配置该文件。通常,生成的文件会被放在 CMAKE_CURRENT_BINARY_DIR 中(或者是其他二进制目录,比如 PROJECT_BINARY_DIRCMAKE_BINARY_DIR)。然后使用 add_include_directoryinclude_directoriestarget_include_directories 添加适当的包含目录。

请注意,还有其他与 CMAKE_SOURCE_DIR 相关的变量,根据你的实际需求,你可能会更感兴趣使用它们:PROJECT_SOURCE_DIRCMAKE_CURRENT_SOURCE_DIRCMAKE_CURRENT_LIST_DIR

如果你想调试这些东西,你可以使用非标准的(但在 GCC、Clang 和 MSVC 中受支持的)#pragma message ... 指示来打印宏定义,或者如果你的生成器支持的话,可以使用 compile_commands.json 文件

英文:

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.

答案2

得分: 1

简单的方法是:

    add_compile_definitions("SOURCE_ROOT=${CMAKE_SOURCE_DIR}")

然后你会:

    #define STRING(x) #x
    #define XSTRING(x) STRING(x)
    std::cout << XSTRING(SOURCE_ROOT) << '\n';
英文:

The simple way would be to:

add_compile_definitions(&quot;SOURCE_ROOT=${CMAKE_SOURCE_DIR}&quot;)

And then you would do:

#define STRING(x) #x
#define XSTRING(x) STRING(x)
std::cout &lt;&lt; XSTRING(SOURCE_ROOT) &lt;&lt; &#39;\n&#39;;

huangapple
  • 本文由 发表于 2023年4月20日 04:23:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76058544.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定