如何 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 本身将不再识别