and*_*nno 21 c preprocessor cmake
我正在将一个makefile项目迁移到CMake.第一次编写makefile的人已经完成了一个用于在include文件中写入某些值的模块.
有一个主config.h文件,其中包含config_in.h.config.h文件包含以下内容:
#ifndef USE_FEATURE_A
#define USE_FEATURE_A 0
#endif
#ifndef USE_FEATURE_B
#define USE_FEATURE_B 0
#endif
Run Code Online (Sandbox Code Playgroud)
在makefile中有一个伪目标,就像with_feature_a在config_in.h中写的那样
#define USE_FEATURE_A 1
Run Code Online (Sandbox Code Playgroud)
通过这种方式,有人可以打字
make with_feature_a
make
Run Code Online (Sandbox Code Playgroud)
获得正确的构建.
我想使用这个代码库但使用CMake复制这样的东西.我在网上尝试了几种方法,但我没有让它发挥作用.
set_target_properties(with_feature_a PROPERTIES COMPILE_DEFINITIONS
"WITH_FEATURE_A=1"
)
Run Code Online (Sandbox Code Playgroud)
这不起作用,因为如果我跑
make with_feature_a
Run Code Online (Sandbox Code Playgroud)
我没有with_feature_a在预处理器命令行中看到.
我做的第二次尝试是直接用内容集写一个文件到我想要的东西,但我不明白如何将file()命令连接到我的目标.
我把它放在我的CMakeLists.txt中
file(WRITE
local/config_in.h
"#define WITH_FEATURE_A 1"
)
Run Code Online (Sandbox Code Playgroud)
但这并不是每次都执行,我不知道如何将它设置为单个目标.
任何帮助表示赞赏.感谢您阅读所有这些内容.对不起长话:)
UPDATE
这里提供的解决方案是解决问题之路上的一大亮点.问题是不允许递归定义.我举了一个例子:
在CMakeLists.txt我放置:
if (WITH_FEATURE_A)
MESSAGE(STATUS "WITH_FEATURE_A")
add_definitions(-DUSE_FEATURE_A=1)
add_definitions(-DWITH_FEABURE_B=1)
endif()
if (WITH_FEABURE_B)
MESSAGE(STATUS "WITH_FEATURE_B")
add_definitions(-DUSE_FEATURE_D=1)
endif()
if (WITH_FEABURE_C)
MESSAGE(STATUS "WITH_FEATURE_C")
add_definitions(-DUSE_FEATURE_D=1)
endif()
if (WITH_FEABURE_D)
MESSAGE(STATUS "WITH_FEATURE_D")
endif()
Run Code Online (Sandbox Code Playgroud)
在这种情况下,如果我用-DWITH_FEATURE_A = 1执行cmake,我很乐意在输出中看到:
WITH_FEATURE_A
WITH_FEATURE_B
WITH_FEATURE_D
Run Code Online (Sandbox Code Playgroud)
实际上这段代码打印出来
WITH_FEATURE_A
Run Code Online (Sandbox Code Playgroud)
Fra*_*ser 38
您可以通过避免创建虚拟目标并删除配置文件来简化操作.相反,如果在调用CMake(或通过CMake GUI)时通过命令行传递需求,则只能运行一次make.
例如,您可以将以下内容添加到CMakeLists.txt:
option(WITH_FEATURE_A "Option description" ON)
option(WITH_FEATURE_B "Option description" OFF)
if(WITH_FEATURE_A)
add_definitions(-DUSE_FEATURE_A)
endif()
if(WITH_FEATURE_B)
add_definitions(-DUSE_FEATURE_B)
endif()
Run Code Online (Sandbox Code Playgroud)
默认情况下,如果你只是运行CMake的,它会设置CMake的变量WITH_FEATURE_A来ON这因此增加了USE_FEATURE_A预处理器定义来构建. USE_FEATURE_B在代码中未定义.
这相当于#define USE_FEATURE_A在您的代码中执行.
如果你真的需要相当于
#define USE_FEATURE_A 1
#define USE_FEATURE_B 0
Run Code Online (Sandbox Code Playgroud)
然后在你的CMakeLists.txt中你可以做到:
option(WITH_FEATURE_A "Option description" ON)
option(WITH_FEATURE_B "Option description" OFF)
if(WITH_FEATURE_A)
add_definitions(-DUSE_FEATURE_A=1)
else()
add_definitions(-DUSE_FEATURE_A=0)
endif()
if(WITH_FEATURE_B)
add_definitions(-DUSE_FEATURE_B=1)
else()
add_definitions(-DUSE_FEATURE_B=0)
endif()
Run Code Online (Sandbox Code Playgroud)
要从命令行更改这些默认值,只需执行(例如):
cmake . -DWITH_FEATURE_A=OFF -DWITH_FEATURE_B=ON
make
Run Code Online (Sandbox Code Playgroud)
一旦通过命令行以这种方式设置了变量,它就会被缓存并保持不变,直到在命令行上用不同的值覆盖它,或者删除构建根目录中的CMakeCache.txt文件.
正如@Peter所指出的那样,你似乎混淆了CMake变量(WITH_FEATURE...那些)和预处理器定义(USE_FEATURE...那些).您可以按照建议首先解析选项之间的所有依赖关系,然后设置生成的预处理程序定义,或者在这种情况下,流程非常简单,只需一次完成即可:
if(WITH_FEATURE_A)
message(STATUS "WITH_FEATURE_A")
add_definitions(-DUSE_FEATURE_A=1)
set(WITH_FEATURE_B ON)
endif()
if(WITH_FEATURE_B)
message(STATUS "WITH_FEATURE_B")
add_definitions(-DUSE_FEATURE_B=1)
set(WITH_FEATURE_D ON)
endif()
if(WITH_FEATURE_C)
message(STATUS "WITH_FEATURE_C")
add_definitions(-DUSE_FEATURE_C=1)
set(WITH_FEATURE_D ON)
endif()
if(WITH_FEATURE_D)
message(STATUS "WITH_FEATURE_D")
add_definitions(-DUSE_FEATURE_D=1)
endif()
Run Code Online (Sandbox Code Playgroud)
我偶然发现了这个问题,我想我分享了另一个选择:TARGET_COMPILE_DEFINITIONS. 你可以在你的 CMakeLists.txt 文件中有两个目标,每个配置一个,并且有这样的东西
ADD_EXECUTABLE (versionA, ...)
TARGET_COMPILE_DEFINITIONS (versionA, PUBLIC -DWITH_FEATURE_A=1 -DWITH_FEATURE_B=0)
ADD_EXECUTABLE (versionB, ...)
TARGET_COMPILE_DEFINITIONS (versionB, PUBLIC -DWITH_FEATURE_A=0 -DWITH_FEATURE_B=1)
Run Code Online (Sandbox Code Playgroud)
这告诉 cmake 添加宏的预处理器定义WITH_FEATURE_A和WITH_FEATURE_B(具有适当的值),就像您在 *pp 文件中定义它们一样。然后你可以告诉 make 编译哪个版本:
make versionA
make versionB
Run Code Online (Sandbox Code Playgroud)