如何 add_custom_command() 用于 CMake 构建过程本身?
How to add_custom_command() for the CMake build process itself?
有什么方法可以做等同于 add_custom_command(运行 某个文件更改时的外部脚本),但是对于在 CMake 脚本执行期间应该是 运行 的东西本身? (即,用于生成依赖图。)
我们将源代码文件分成多个子库,并且有配置文件列出了哪个源文件与哪个库。 (这些配置文件的格式由我们使用的另一个工具固定。)目前,我们 运行 一个自定义的外部脚本,它解析这些配置文件并写入新文件,然后由 CMake 构建过程加载这些文件以提供要传递给 add_library() 的文件名列表。这意味着每次源文件是 added/removed 时,我们需要记住重新 运行 预构建命令,然后再 运行ning CMake,然后重新启动构建命令.
我知道 CMake 可以识别它需要重新 运行 本身,所以我希望我们可以让 CMake 1) 识别配置文件已更改 2) 重新运行 配置文件解析器 3) 加载新文件列表 4) 使用新文件列表重新生成依赖树 5) 最后启动包含新文件的实际 build/compilation 进程。 ...所有这些都来自标准构建命令,无需手动 运行 外部配置文件解析器或手动重新 运行 CMake 命令,并且在配置文件未更改时无需执行不必要的操作。
在搜索中,我确实找到了 this question,其中建议使用 configure_file(),但这并没有解决如何调用外部配置文件解析器脚本的问题。
将我的评论变成答案
configure_file()
is the right choice to retrigger the configuration process. And execute_process()
用于配置步骤中的 运行 命令。
这是您描述中步骤的抽象 CMake 片段:
function(my_add_library_from_cfg _target _cfg_file)
# Retrigger configuration process each time config file changes
get_filename_component(_cfg_name "${_cfg_file}" NAME)
configure_file("${_cfg_file}" "${_cfg_name}.tmp")
# Generating sources and file list
execute_process(
COMMAND ${CMAKE_COMMAND} -E echo "#define FOO"
OUTPUT_FILE foo.c
)
execute_process(
COMMAND ${CMAKE_COMMAND} -E echo "foo.c"
OUTPUT_FILE files.lst
)
# Reading file list and add library
file(STRINGS "${CMAKE_CURRENT_BINARY_DIR}/files.lst" _sources_lst)
add_library(${_target} ${_sources_lst} "${_cfg_file}")
endfunction(my_add_library_from_cfg)
configure_file()
将在每次给定的 .cfg
文件更改时重新触发 CMake
- 如果你在
execute_process()
中实际使用.cfg
文件作为命令行参数,你应该使用当前二进制目录 中生成的.tmp
版本
execute_process()
可以做很多事情
- 我用它回显
stdout
并将输出写入文件
- 默认
WORKING_DIRECTORY
这里是当前二进制目录
file()
读取源文件列表
- 完整路径,换行分隔
- 我特意把生成的文件写到了二进制输出目录
- 它使干净的构建更容易,只需删除整个二进制输出目录
- 并且 CMake 对此有内置支持;它将首先在当前源中搜索没有绝对路径的源文件,然后在当前二进制目录中搜索
- 而且我没有使用
GENERATED
源文件 属性
- 因为仅当源代码是由先前的构建步骤生成时才需要
- 当源文件列表中的文件实际上丢失时,CMake 本身将不再识别
有什么方法可以做等同于 add_custom_command(运行 某个文件更改时的外部脚本),但是对于在 CMake 脚本执行期间应该是 运行 的东西本身? (即,用于生成依赖图。)
我们将源代码文件分成多个子库,并且有配置文件列出了哪个源文件与哪个库。 (这些配置文件的格式由我们使用的另一个工具固定。)目前,我们 运行 一个自定义的外部脚本,它解析这些配置文件并写入新文件,然后由 CMake 构建过程加载这些文件以提供要传递给 add_library() 的文件名列表。这意味着每次源文件是 added/removed 时,我们需要记住重新 运行 预构建命令,然后再 运行ning CMake,然后重新启动构建命令.
我知道 CMake 可以识别它需要重新 运行 本身,所以我希望我们可以让 CMake 1) 识别配置文件已更改 2) 重新运行 配置文件解析器 3) 加载新文件列表 4) 使用新文件列表重新生成依赖树 5) 最后启动包含新文件的实际 build/compilation 进程。 ...所有这些都来自标准构建命令,无需手动 运行 外部配置文件解析器或手动重新 运行 CMake 命令,并且在配置文件未更改时无需执行不必要的操作。
在搜索中,我确实找到了 this question,其中建议使用 configure_file(),但这并没有解决如何调用外部配置文件解析器脚本的问题。
将我的评论变成答案
configure_file()
is the right choice to retrigger the configuration process. And execute_process()
用于配置步骤中的 运行 命令。
这是您描述中步骤的抽象 CMake 片段:
function(my_add_library_from_cfg _target _cfg_file)
# Retrigger configuration process each time config file changes
get_filename_component(_cfg_name "${_cfg_file}" NAME)
configure_file("${_cfg_file}" "${_cfg_name}.tmp")
# Generating sources and file list
execute_process(
COMMAND ${CMAKE_COMMAND} -E echo "#define FOO"
OUTPUT_FILE foo.c
)
execute_process(
COMMAND ${CMAKE_COMMAND} -E echo "foo.c"
OUTPUT_FILE files.lst
)
# Reading file list and add library
file(STRINGS "${CMAKE_CURRENT_BINARY_DIR}/files.lst" _sources_lst)
add_library(${_target} ${_sources_lst} "${_cfg_file}")
endfunction(my_add_library_from_cfg)
configure_file()
将在每次给定的.cfg
文件更改时重新触发 CMake- 如果你在
execute_process()
中实际使用.cfg
文件作为命令行参数,你应该使用当前二进制目录 中生成的
.tmp
版本- 如果你在
execute_process()
可以做很多事情- 我用它回显
stdout
并将输出写入文件 - 默认
WORKING_DIRECTORY
这里是当前二进制目录
- 我用它回显
file()
读取源文件列表- 完整路径,换行分隔
- 我特意把生成的文件写到了二进制输出目录
- 它使干净的构建更容易,只需删除整个二进制输出目录
- 并且 CMake 对此有内置支持;它将首先在当前源中搜索没有绝对路径的源文件,然后在当前二进制目录中搜索
- 而且我没有使用
GENERATED
源文件 属性- 因为仅当源代码是由先前的构建步骤生成时才需要
- 当源文件列表中的文件实际上丢失时,CMake 本身将不再识别