cmake 生成 header 导致双重构建

cmake generated header causes double build

一个非常简单的场景 - 我需要生成 header,包含它,如果生成的 header 在 cmake 构建时更新,所有依赖的 cpp 单元也必须重建。

一个简化的例子:

add_custom_command(
    OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/test.h
    COMMAND ...
    DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/test.in"

add_custom_target(test_target DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/test.h)

add_executable(test_exe
    ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
)
add_dependencies(test_exe test_target)

main.cpp 就是:

#include "test.h"

int main()
{
    return 0;
}

当我进行完全重建时,一切正常。但是当我更改 test.in 时, 运行 只是 cmake.exe --build . --target all 仅重新生成 test.h,但 main.cpp 不会重新编译。但是当我再次 运行 cmake.exe --build . --target all 时(第二次),main.cpp 被重新编译并且 test_exe 被重新链接。

我做错了什么?

P.S。如果我明确使用 OBJECT_DEPENDS,没有问题,重建工作正常,但文档说它不再需要 - https://cmake.org/cmake/help/v3.20/prop_sf/OBJECT_DEPENDS.html

更新: 我使用 Windows 10、CMake 3.19.2 和 Ninja 1.10.2

解法: 在你的项目目录中使用构建目录,那么就没有问题了。但是如果构建目录在我们项目目录之外,那就有问题了。

张贴为能够显示完整示例的答案

CMakeLists.txt

cmake_minimum_required(VERSION 3.15)

project(example)

add_custom_command(
    OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/test.h
    COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/test.in" ${CMAKE_CURRENT_SOURCE_DIR}/test.h
    DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/test.in")

add_custom_target(test_target DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/test.h)

add_executable(test_exe
    ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
)
add_dependencies(test_exe test_target)

main.cpp

#include "stdio.h"
#include "test.h"

int main()
{
    printf("The value is %d\n", FOO);
    return 0;
}

test.in

#define FOO 4

这适用于 windows CMake 3.19.2 和 Ninja 1.10.2,可以在初始构建后更改 test.in 中的 FOO 定义并查看生成的可执行文件重建并看到它的值发生了变化。

用于测试的命令

$ cmake -B build -G Ninja
-- The C compiler identification is Clang 11.0.0 with GNU-like command-line
-- The CXX compiler identification is Clang 11.0.0 with GNU-like command-line
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files/LLVM/bin/clang.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files/LLVM/bin/clang++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done                            
-- Build files have been written to: <some_path>
                                                      
$ cmake --build build                                 
[3/3] Linking CXX executable test_exe.exe             
                                                         
$ ./build/test_exe.exe                                
The value is 4                                        
                                                          
$ echo "#define FOO 3" > test.in                      
                                                      
$ cmake --build build                                 
[3/3] Linking CXX executable test_exe.exe             
                                                          
$ ./build/test_exe.exe                                
The value is 3