26

我正在将 makefile 项目迁移到 CMake。第一次编写 makefile 的人已经完成了一个模块,用于在包含文件中写入某些值。

有一个包含 config_in.h 的主 config.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_aconfig_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"
)

但这并不是每次都执行,我不知道如何将其设置为单个目标。

任何帮助表示赞赏。感谢您阅读所有这些内容。对不起,长篇大论:)

更新

这里提供的解决方案是解决方案道路上的一大进步。问题是不允许递归定义。我举个例子:

在 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
4

4 回答 4

52

您可以通过避免创建虚拟目标和删除配置文件来简化事情。相反,如果您在调用 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()

默认情况下,如果您只运行 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

然后在您的 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()

于 2013-03-04T23:07:18.653 回答
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)

这告诉 cmake 添加宏的预处理器定义WITH_FEATURE_AWITH_FEATURE_B(具有适当的值),就像您在 *pp 文件中定义它们一样。然后你可以告诉 make 编译哪个版本:

make versionA
make versionB
于 2017-02-01T21:57:46.207 回答
4

听起来您想介绍您的选项之间的关系。如果您将步骤分开,这将更容易。首先解决关系,然后在结果上设置 C 定义。请记住 WITH_FEATURE_A 是一个 cmake 变量,而 USE_FEATURE_A 是 C 预处理器定义集,带有 ADD_DEFINITIONS:

# 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()
于 2013-03-05T16:36:58.860 回答
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

参考:

于 2021-04-06T21:17:17.370 回答