我正在将一个makefile项目迁移到CMake。第一次编写makefile的人已经完成了一个模块,用于在包含文件中写入某些值。
有一个主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
在makefile中有一个伪目标,如with_feature_a
,在config_in.h中写入
#define USE_FEATURE_A 1
通过这种方式,有人可以输入
make with_feature_a
make
获得正确的构建。
我想使用这个代码库但使用CMake来复制这样的东西。我在网上尝试了几种方法,但我没有让它发挥作用。
set_target_properties(with_feature_a PROPERTIES COMPILE_DEFINITIONS
"WITH_FEATURE_A=1"
)
这不起作用,因为如果我运行
make with_feature_a
我在预处理器命令行中看不到with_feature_a
。
我做的第二次尝试是直接用内容集写一个文件到我想要的东西,但我不明白如何将file()
命令连接到我的目标。
我把它放在我的CMakeLists.txt
中file(WRITE
local/config_in.h
"#define WITH_FEATURE_A 1"
)
但这并不是每次都执行,我不知道如何将其设置为单个目标。
感谢任何帮助。感谢您阅读所有这些内容。抱歉长篇故事:)
更新
提供的解决方案here是解决问题之路上的一大亮点。问题是不允许递归定义。我举了一个例子:
在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()
在这种情况下,如果我用-DWITH_FEATURE_A = 1执行cmake,我很乐意在输出中看到:
WITH_FEATURE_A
WITH_FEATURE_B
WITH_FEATURE_D
实际上这段代码打印只是
WITH_FEATURE_A
答案 0 :(得分:36)
您可以通过避免创建虚拟目标并删除配置文件来简化操作。相反,如果在调用CMake(或通过CMake GUI)时通过命令行传递需求,则只能运行一次。
例如,您可以将以下内容添加到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()
默认情况下,如果您只运行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
然后在你的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()
要从命令行更改这些默认值,只需执行(例如):
cmake . -DWITH_FEATURE_A=OFF -DWITH_FEATURE_B=ON
make
一旦通过命令行以这种方式设置了变量,它就会被缓存并保持不变,直到它被命令行上的不同值覆盖,或者删除构建根目录中的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()
答案 1 :(得分:4)
听起来你想介绍你的选择之间的关系。如果您分开步骤,这将更容易。首先解决关系,然后在结果上设置C定义。请记住,WITH_FEATURE_A是一个cmake变量,而USE_FEATURE_A是使用ADD_DEFINITIONS的C预处理器定义集:
# Specify the inter-feature dependencies
if (WITH_FEATURE_A)
# A requires B because <somereason>
set(WITH_FEATURE_B ON)
endif()
if (WITH_FEATURE_B)
set(WITH_FEATURE_D ON)
endif()
if (WITH_FEATURE_C)
set(WITH_FEATURE_D ON)
endif()
# Now generate the C defines for passing the options to the compiler
if (WITH_FEATURE_A)
MESSAGE(STATUS "WITH_FEATURE_A")
add_definitions(-DUSE_FEATURE_A=1)
endif()
if (WITH_FEATURE_B)
MESSAGE(STATUS "WITH_FEATURE_B")
add_definitions(-DUSE_FEATURE_B=1)
endif()
if (WITH_FEATURE_C)
MESSAGE(STATUS "WITH_FEATURE_C")
add_definitions(-DUSE_FEATURE_C=1)
endif()
if (WITH_FEATURE_D)
MESSAGE(STATUS "WITH_FEATURE_D")
add_definitions(-DUSE_FEATURE_D=1)
endif()
答案 2 :(得分:3)
我偶然发现了这个问题,我想我分享了另一个选项: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)
这告诉cmake添加宏WITH_FEATURE_A
和WITH_FEATURE_B
的预处理器定义(具有正确的值),就像在* pp文件中定义它们一样。然后你可以告诉make编译哪个版本:
make versionA
make versionB
答案 3 :(得分:0)
configure_file
可用于此目的。例如,在 CMakeLists.txt
中:
if(WITH_FEATURE_A)
set(USE_FEATURE_A 1)
# Feature A should enable feature B
set(WITH_FEATURE_B ON)
endif()
if(WITH_FEATURE_B)
set(USE_FEATURE_B 1)
# Feature B should enable feature D
set(WITH_FEATURE_D ON)
endif()
if(WITH_FEATURE_C)
set(USE_FEATURE_C 1)
# Feature C should enable feature D, too
set(WITH_FEATURE_D ON)
endif()
if(WITH_FEATURE_D)
set(USE_FEATURE_D 1)
endif()
configure_file(config.h.in config.h)
在 config.h.in
中,您可以将 CMake 变量转换为定义:
#cmakedefine USE_FEATURE_A 1
#cmakedefine USE_FEATURE_B 1
#cmakedefine USE_FEATURE_C 1
/* You can use the values of the cmake variables too, using @<var>@. Ex: */
#cmakedefine USE_FEATURE_D @USE_FEATURE_D@
运行 cmake -DWITH_FEATURE_A=1
时,生成的 config.h 将是:
#define USE_FEATURE_A 1
#define USE_FEATURE_B 1
/* #undef USE_FEATURE_C */
/* You can use the values of the cmake variables too, using @<var>@: */
#define USE_FEATURE_D 1
参考文献: