我一直在尝试获得简单的用例,即让 cmake 使用脚本生成一些文件,然后从这些生成的文件中构建一个可执行文件。在花了几个小时阅读文档和各种堆栈溢出答案之后,似乎一切都应该如此安排,但 cmake 拒绝配置项目。
这个想法是通过以下步骤完成事情:
- 在配置期间,会使用正确的路径生成generate_files.sh
- 在构建期间,首先构建目标
gen
,然后构建目标test
步骤 1 已正确执行,但步骤 2 未正确执行。 Cmake 提示找不到目标 test
的源文件,尽管它应该先构建 gen
然后再找到源代码。
我做错了什么?
目录结构:
.
├── build
├── CMakeLists.txt
├── config
│ └── generate_files.sh.in
├── extern
│ ├── CMakeLists.txt
│ └── gen
├── scripts
└── src
├── CMakeLists.txt
└── main.cpp
顶级 CMakeLists:
cmake_minimum_required(VERSION 3.13)
project(test VERSION 0.1.0.0)
add_subdirectory(src)
add_subdirectory(extern)
configure_file("${CMAKE_SOURCE_DIR}/config/generate_files.sh.in" "${CMAKE_SOURCE_DIR}/scripts/generate_files.sh")
src/CMakeLists:
add_executable(test main.cpp)
外部/CMakeLists:
set(generated_sources
${CMAKE_CURRENT_SOURCE_DIR}/gen/generated.h
${CMAKE_CURRENT_SOURCE_DIR}/gen/generated_1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/gen/generated_2.cpp
)
set(generated_directories
${CMAKE_CURRENT_SOURCE_DIR}/gen)
add_custom_command(
OUTPUT ${generated_sources}
COMMAND "${CMAKE_SOURCE_DIR}/scripts/generate_files.sh"
)
add_custom_target(gen
DEPENDS ${generated_sources}
)
add_dependencies(test gen)
target_sources(test
PRIVATE
${generated_sources}
)
target_include_directories(test
PRIVATE
${generated_directories}
)
config/generate_files.sh.in:
#! /bin/bash
echo " const int get_trouble_code();
const int get_higher_trouble_code();" > ${CMAKE_SOURCE_DIR}/extern/gen/generated.h
echo " #include \"generated.h\"
const int get_trouble_code(){return 1;}" > ${CMAKE_SOURCE_DIR}/extern/gen/generated_1.cpp
echo " #include \"generated.h\"
const int get_higher_trouble_code(){return 1+1;}" > ${CMAKE_SOURCE_DIR}/extern/gen/generated_2.cpp
src/main.cpp:
#include "generated.h"
int main()
{
get_trouble_code();
get_higher_trouble_code();
return 0;
}
编辑:我找到了一种让它发挥作用的方法,但现在我更困惑了。将生成的文件添加为库而不是自定义目标似乎可以解决问题。对 extern/CMakeLists 的以下更改有效,但有人可以解释原因吗? :
set(generated_sources
${CMAKE_CURRENT_SOURCE_DIR}/gen/generated.h
${CMAKE_CURRENT_SOURCE_DIR}/gen/generated_1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/gen/generated_2.cpp
)
set(generated_directories
${CMAKE_CURRENT_SOURCE_DIR}/gen)
add_custom_command(
OUTPUT ${generated_sources}
COMMAND "${CMAKE_SOURCE_DIR}/scripts/generate_files.sh"
)
#comment out this stuff
#add_custom_target(gen
# DEPENDS ${generated_sources}
# )
#
#add_dependencies(test gen)
#
#target_sources(test
# PRIVATE
# ${generated_sources}
#)
#add as library instead
add_library(gen ${generated_sources})
target_link_libraries(test PRIVATE gen)
target_include_directories(test
PRIVATE
${generated_directories}
)
最佳答案
CMake complains that the source files for target
test
aren't found ...
这是因为源文件不存在,其GENERATED属性未设置。
通常,add_custom_command
为其 OUTPUT 中列出的所有文件设置 GENERATED 属性。但在 CMake 3.20 之前,该属性位于目录本地:
add_custom_command
是从extern/CMakeLists.txt
调用的,但是- target
test
在创建目标的顶级CMakeLists.txt
中评估其源。 (无论在哪里调用target_sources
)。
在 CMake 3.20 中,GENERATED 属性变为全局(要使用此功能,您的项目应该具有相应的 cmake_minimum_required
)。
如果无法更新 CMake,那么您可以在顶级 CMakeLists.txt
中手动设置 GENERATED 属性。 (这会损害您的 CMakeLists.txt
的局部性。因此最好更新 CMake。)
从技术上讲,您会触发 that bugreport 中发布的问题.
关于c++ - cmake add_dependency、add_custom_command 和 add_custom_target 不能一起工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75502630/