C语言 CMake 条件预处理器在代码上定义

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15201064/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 05:33:40  来源:igfitidea点击:

CMake conditional preprocessor define on code

ccmakepreprocessor

提问by andyinno

I'm migrating a makefile project to CMake. The person who wrote the makefile the first time had done a module for writing certain values in an include file.

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

There's a main config.h file that includes a config_in.h. The config.h file contains something like this:

有一个包含 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

In the makefile there's a fake target like with_feature_athat writes in config_in.h

在 makefile 中有一个像with_feature_aconfig_in.h 中写的假目标

#define USE_FEATURE_A 1

In this way someone can type

这样有人可以输入

make with_feature_a
make

to get the right build.

以获得正确的构建。

I want to replicate something like this using this codebase but using CMake. I tried a couple of approaches suggested on the net, but I didn't get it to work.

我想使用此代码库但使用 CMake 复制类似的内容。我尝试了网上建议的几种方法,但我没有让它起作用。

set_target_properties(with_feature_a PROPERTIES COMPILE_DEFINITIONS 
    "WITH_FEATURE_A=1"
)

This isn't working because if I run

这不起作用,因为如果我跑

make with_feature_a

I don't see with_feature_ain the preprocessor command line.

with_feature_a在预处理器命令行中没有看到。

The second attempt I made is to write a file directly with the content set to whatever I want, but I didn't understand how to connect the file()command to my target.

我所做的第二次尝试是直接将内容设置为我想要的任何内容写入文件,但我不明白如何将file()命令连接到我的目标。

I placed this in my CMakeLists.txt

我把它放在我的 CMakeLists.txt

file(WRITE 
local/config_in.h 
    "#define WITH_FEATURE_A 1"
)

but this isn't executed everytime and I don't know how to set it to a single target.

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

Any help is appreciated. Thank you for reading all this stuff. Sorry for the long story :)

任何帮助表示赞赏。感谢您阅读所有这些内容。对不起,故事太长了:)

UPDATE

更新

The solution provided hereis a big enhacement on the road to solution. The problem is that is don't allow recursive definitions. I show an example:

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

in CMakeLists.txt I placed:

在 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()

in this case if I execute cmake with -DWITH_FEATURE_A=1 I'd love to see in the output:

在这种情况下,如果我使用 -DWITH_FEATURE_A=1 执行 cmake,我很想在输出中看到:

WITH_FEATURE_A
WITH_FEATURE_B
WITH_FEATURE_D

actually this code print just

实际上这个代码只是打印

WITH_FEATURE_A

回答by Fraser

You can simplify things by avoiding creating the dummy targets and removing the config file. Instead, if you pass the requirements via the command line when you invoke CMake (or via the CMake GUI), you can run make only once.

您可以通过避免创建虚拟目标和删除配置文件来简化事情。相反,如果您在调用 CMake(或通过 CMake GUI)时通过命令行传递要求,则您只能运行一次 make。

For example, you could add the following to your CMakeLists.txt:

例如,您可以将以下内容添加到 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()

By default, if you just run CMake, it will set the CMake variable WITH_FEATURE_Ato ONwhich consequently adds USE_FEATURE_Aas a preprocessor definition to the build. USE_FEATURE_Bis undefined in the code.

默认情况下,如果你只是运行CMake的,它会设置CMake的变量WITH_FEATURE_AON这因此增加了USE_FEATURE_A预处理器定义来构建。 USE_FEATURE_B在代码中未定义。

This would be equivalent to doing #define USE_FEATURE_Ain your code.

这相当于#define USE_FEATURE_A在你的代码中做。



If you really need the equivalent of

如果你真的需要相当于

#define USE_FEATURE_A 1
#define USE_FEATURE_B 0

then in your CMakeLists.txt you can do:

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



To change these defaults from the command line, simply do (e.g.):

要从命令行更改这些默认值,只需执行(例如):

cmake . -DWITH_FEATURE_A=OFF -DWITH_FEATURE_B=ON
make

Once a variable has been set via the command line this way, it is cached and will remain unchanged until either it is overwritten with a different value on the command line, or you delete the CMakeCache.txt file in your build root.

以这种方式通过命令行设置变量后,它会被缓存并保持不变,直到它在命令行上被不同的值覆盖,或者您删除构建根目录中的 CMakeCache.txt 文件。



Response to update:

响应更新:

As @Peter noted, you appear to be mixing up CMake variables (the WITH_FEATURE...ones) and the preprocessor definitions (the USE_FEATURE...ones). You can as suggested resolve all the dependencies between options first, then set the resulting preprocessor definitions, or in this case where the flow is quite straightforward, just do it all in one go:

正如@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()



回答by Peter

It sounds like you want to introduce relationships between your options. This will be easier if you separate the steps. First resolve the relationships, then set the C defines on the results. Remember that WITH_FEATURE_A is a cmake variable, and USE_FEATURE_A is C preprocessor define set with ADD_DEFINITIONS:

听起来您想介绍选项之间的关系。如果您将步骤分开,这会更容易。首先解决关系,然后在结果上设置 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()

回答by bartgol

I stumbled on this question and I figured I shared another option: TARGET_COMPILE_DEFINITIONS. You could have two targets in your CMakeLists.txt file, one per configuration, and have something like this

我偶然发现了这个问题,我想我分享了另一个选择: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)

This is tells cmake to add the preprocessors definitions of macros WITH_FEATURE_Aand WITH_FEATURE_B(with the proper value), just like if you defined them in your *pp files. Then you can tell make which version to compile:

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

make versionA
make versionB