C++ cmake生成的头导致双重生成

C++ cmake生成的头导致双重生成,c++,cmake,ninja,C++,Cmake,Ninja,一个非常简单的场景-我需要生成标题,包括它,如果生成的标题在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 ${C

一个非常简单的场景-我需要生成标题,包括它,如果生成的标题在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
只是:

#包括“test.h”
int main()
{
返回0;
}
当我进行全面重建时,一切都很顺利。但是当我更改
test.in
时,只运行
cmake.exe--build--仅重新生成
test.h
,但不重新编译
main.cpp
。但是当我运行
cmake.exe时——build--再次(第二次)瞄准所有对象,重新编译
main.cpp
,并重新链接
test_exe

我错了什么

另外,如果我明确使用
OBJECT\u dependens
,则没有问题,重建工作正常,但文档称不再需要它-

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

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

作为答案发布,以便能够显示完整的示例

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
这适用于装有CMake 3.19.2和Ninja 1.10.2的windows,用户可以在
test中更改
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    
$cmake-B build-G忍者
--C编译器标识是使用类似GNU的命令行的Clang 11.0.0
--CXX编译器标识为Clang 11.0.0,使用类似GNU的命令行
--检测C编译器ABI信息
--检测C编译器ABI信息-完成
--检查C编译器是否工作:C:/Program Files/LLVM/bin/clang.exe-已跳过
--检测C编译特性
--检测C编译特性-完成
--检测CXX编译器ABI信息
--检测CXX编译器ABI信息-完成
--检查CXX编译器是否工作:C:/Program Files/LLVM/bin/clang++.exe-已跳过
--检测CXX编译特性
--检测CXX编译功能-完成
--配置完成
--生成完成
--生成文件已写入:
$cmake——构建
[3/3]链接CXX可执行文件test_exe.exe
$./build/test_exe.exe
值为4
$echo“#定义FOO 3”>test.in
$cmake——构建
[3/3]链接CXX可执行文件test_exe.exe
$./build/test_exe.exe
值为3

不相关,但您可以直接在
添加可执行文件
命令中添加目标,您不需要
添加依赖项
。我预见到了有关使用
添加自定义目标
添加依赖项
的响应,因此决定使用它们。我尝试了所有可能的变体(没有显式依赖项,使用它们,使用静态库)。唯一有效的变体是设置
OBJECT\u dependence
,但在我看来,它已经过时且不实用。
add\u dependencies
只提供目标之间的顺序。要使可执行文件依赖于自定义命令生成的头文件,请将该头文件添加到
add_executable
调用中:
add_executable(test_exe${CMAKE_CURRENT_SOURCE_DIR}/main.cpp${CMAKE_CURRENT_SOURCE_DIR}/test.h)
@Tsyvarev
test.h
包含在
main.cpp>中。但我试过了,它不起作用。可能需要使用什么样的CMake版本、平台和生成器。将
COMMAND${CMAKE\u COMMAND}-E copy“${CMAKE\u CURRENT\u SOURCE\u DIR}/test.in”${CMAKE\u CURRENT\u SOURCE\u DIR}/test.h
CMAKE\u minimum\u required
project
一起添加到示例中,将在我的windows机器上重新编译main.cpp。CMake版本3.18.2使用msbuild和Ninja。您是否碰巧整合了多个CMakeLists.txt文件以最小化问题?似乎我找到了原因。如果我从控制台调用
cmake-B build-G Ninja
,一切都会按照预期工作,与您的示例完全相同,但是如果我从QtCreator生成它,行为会有所不同——正如我在问题中描述的那样。我会挖进去的。非常感谢。哇!如果在项目目录外使用build目录,即
cmake-B..\build-G Ninja
,则存在问题,但如果在项目内使用build目录,则没有问题。这是一种记录在案的行为吗?这非常奇怪。>如果在项目目录之外使用build目录,即
cmake-B..\build-G Ninja
,那么问题就出在这里,我无法重现:(它似乎在项目目录内部或外部处理相同的增量。