configure_file 中的生成器表达式

The*_*ing 2 cmake

我们正在移植一些相当旧的代码,当然我们现在想使用生成器表达式。byconfigure_file生成的 .pc 文件现在包含-I$<INSTALL_INTERFACE:include>. 关于如何解决我发现的生成器表达式的唯一提示是使用

file(GENERATE 
Run Code Online (Sandbox Code Playgroud)

当然,这是在配置步骤期间执行的,因此上述表达式被解析为空字符串。

编辑:这是一个示例 CMakeLists.txt:

cmake_minimum_required(VERSION 3.11)
project(test CXX)

add_library(foo SHARED main.cpp)

target_include_directories(foo PUBLIC $<INSTALL_INTERFACE:include>)

# now later buried deep in some functions

get_property( _include_dirs TARGET foo PROPERTY INCLUDE_DIRECTORIES )

configure_file(config.in config.out @ONLY)
# content of config.out is "include = -I$<INSTALL_INTERFACE:include>"

file(GENERATE OUTPUT config.out2 INPUT ${CMAKE_CURRENT_BINARY_DIR}/config.out)
# content of config.out2 is "include = -I"
# most likely because the INSTALL_INTERFACE isn't used when the file is generated
Run Code Online (Sandbox Code Playgroud)

配置文件:

include = @_include_dirs@
Run Code Online (Sandbox Code Playgroud)

而 main.cpp 只是空的。

小智 6

正如 CMake 文档所述,文件 (GENERATE ...)命令可以使用由生成器计算的生成器表达式。

生成文件

您可以让 CMake 直接使用自定义代码生成文件,而无需使用configure_file命令。

单配置生成器

对于像Makefiles这样的单配置生成器,您可以使用:

file (GENERATE
    OUTPUT "config.out" 
    CONTENT "include = -I$<INSTALL_INTERFACE:include>"
)
Run Code Online (Sandbox Code Playgroud)

由于我的 CMake 代码必须同时使用多配置和单配置生成器,因此我没有专门测试代码。

单配置和多配置生成器

一般来说,对于所有生成器,可以使用以下签名:

file (GENERATE
    OUTPUT "config_$<CONFIG>.out" 
    CONTENT "include = -I$<INSTALL_INTERFACE:include>"
)
Run Code Online (Sandbox Code Playgroud)

由于与Visual Studio等多配置生成器相关的命令的性质,这将在您的构建文件夹中为此变量CMAKE_CONFIGURATION_TYPES 中指定的每个构建类型生成多个文件:

  • config_Debug.out
  • config_Release.out
  • config_RelWithDebInfo.out
  • ...
  • config_<BUILD_TYPE>.out

如果您没有指定唯一的文件名并且 CMake 尝试生成文件,它将停止执行并显示错误。

使用生成的文件

要使用以前生成的文件,它取决于您的需要。首先,文件将在配置阶段之后存在。

单配置生成器

要在具有常量名称(例如 config.out)的单配置生成器场景中使用生成的文件,应该不需要额外的工作。

单配置和多配置生成器

对于多配置生成器,它略有不同。因为您必须使用生成器表达式在构建时访问适当的文件。如果你有一个支持生成器表达式的 CMake 指令,那么你可以只使用 filename config_$<CONFIG>.out

但是,如果您需要将文件命名为完全相同的文件,而不管构建类型(如 config.out)如何,那就有点棘手了。

首先,您必须config.out通过使用add_custom_command并指定OUTPUT参数来告诉 CMake 应该有一个名为 like 的文件:

add_custom_command (
    COMMAND ${CMAKE_COMMAND} "-E" "copy_if_different" "config_$<CONFIG>.out" "config.out"
    VERBATIM
    PRE_BUILD
    DEPENDS  "config_$<CONFIG>.out"
    OUTPUT   "config.out"
    COMMENT  "creating config.out file ({event: PRE_BUILD}, {filename: config.out})"
)
Run Code Online (Sandbox Code Playgroud)

CMake 将在内部创建一个文件依赖项,每次引用文件名时config.out,它将确保执行add_custom_command

但这并不适用于所有情况,因为它取决于应该使用该文件的进一步说明。

根据您使用的命令,您现在可以将文件指定config.out为某些命令的输入(如 target_sources,...),CMake 将在文件依赖级别上检测它必须确保config.out.

如果要生成在文件依赖项级别未引用的文件(如 versioninfo.txt),则必须确保每次构建目标通过目标依赖项执行时,CMake 都会执行add_custom_command

add_custom_target ("generate_config_out" DEPENDS "config.out")
add_dependencies ("MY_LIBRARY_TARGET" "generate_config_out")
Run Code Online (Sandbox Code Playgroud)

每次 CMake 构建MY_LIBRARY_TARGET目标时,它都会先构建generate_config_out目标,而目标又取决于config.outCMake 将在文件依赖级别上处理的目标。