首页 > 解决方案 > CMake:使用 Ninja 构建时如何处理 add_custom_command 子构建

问题描述

我正在使用 CMake 构建一个 C++ 项目(在 Linux 上)。该项目由许多子项目组成,每个子项目都可以调用一个函数来创建一个有用的link_date.c源文件,其中包含链接发生时的时间戳。我使用它作为一种可靠地将构建时间嵌入到二进制文件中的方法,而不管自上次构建以来发生了哪些源更改。

这个函数是这样声明的:

function(add_link_date TARGET)
    file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/link_date.c.in "
    const char *link_date() { return(\"@LINK_DATE@\"); }
    ")
    file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/link_date.cmake "
    EXECUTE_PROCESS(
        COMMAND date
        OUTPUT_VARIABLE LINK_DATE
        OUTPUT_STRIP_TRAILING_WHITESPACE
    )
    CONFIGURE_FILE(\${SRC} \${DST} @ONLY)
    ")
    add_custom_command(
        OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/link_date.c
        COMMAND ${CMAKE_COMMAND} -DSRC=link_date.c.in -DDST=link_date.c
        -P link_date.cmake
        DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/link_date.c.in)
    add_library(link_date-${TARGET} STATIC EXCLUDE_FROM_ALL link_date.c)
    target_link_libraries(${TARGET} link_date-${TARGET})
    add_custom_command(
        TARGET ${TARGET}
        PRE_LINK
        COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/link_date.c.in
        COMMAND ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR} --target link_date-${TARGET})
endfunction()

该函数为调用它的每个目标创建一个link_date.c.in模板,然后使用该模板link_date.c为该目标创建。然后将其添加到特定于目标的库中,然后将其与目标可执行文件链接。finaladd_custom_command用于确保每次 CMake 即将链接目标可执行文件时都重建 link_date 库。我从这里得到了这个的原始代码。

关键是它总是将构建时间戳注入到可执行文件中,无论是谁构建它——开发人员、CI 管道等。它与 Makefiles 生成器配合得非常好,我已经使用它超过 12 个月了,没有任何问题.

最近我一直在考虑更新我们的构建以使用 Ninja,因为它在我的大多数管道中都明显更快,但是在这个项目中它遇到了一个问题,特别是最后COMMAND一个add_custom_command(PRE_LINK) 语句的最后一个,它运行子构建。这有cding 到调用的子项目的 build 子目录的效果add_link_date,但是因为 CMake 只build.ninja在 build 目录的顶部生成了一个 Ninja 文件,所以 childcmake --build失败了,因为build.ninja这个子项目目录中没有。

有没有办法修改这个过程以与忍者一起工作?

我知道并不是每个 CMake 项目都可以从 Makefiles 迁移到 Ninja,但是这是我在这个特定项目中遇到的唯一真正的障碍,所以很高兴找到一个解决方法。

标签: cmakebuildmigrationninjacmake-custom-command

解决方案


推荐阅读