CMake条件预处理器定义代码

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_AON这因此增加了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)



bar*_*gol 6

我偶然发现了这个问题,我想我分享了另一个选择: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_AWITH_FEATURE_B(具有适当的值),就像您在 *pp 文件中定义它们一样。然后你可以告诉 make 编译哪个版本:

make versionA
make versionB
Run Code Online (Sandbox Code Playgroud)