英文:
file generated by add_custom_command cannot be found within add_subdirectory
问题
我正在使用CMake和FlatBuffers生成API。但是在CMake顶层目录生成API后,在子目录需要使用的包含文件无法找到。
错误信息显示:
CMake Error at app/CMakeLists.txt:2 (add_executable):
Cannot find source file:
/home/xxx/build.test/incl/testapi_generated.h
Tried extensions .c .C .c++ .cc .cpp .cxx .cu .m .M .mm .h .hh .h++ .hm
.hpp .hxx .in .txx
testapi_generated.h
找不到,因为它没有被生成。但它应该被生成,因为 flatbuffers_generate_headers
函数为所需的 .h
文件设置了 add_custom_command
。
当我将可执行文件的构建移到主CMake文件,取代如下代码的末尾:
add_executable(testapp app/src/test.cpp)
target_link_libraries(testapp incl)
#add_subdirectory(app)
'.h' 文件就会生成,简单的应用程序也能够正常构建。在这一点上启用子目录也将导致可执行文件正常工作。执行 make clean
后再次构建将再次失败。
我做错了什么?不可能首先在子目录中使用由 add_custom_command
创建的文件吗?
你可以查看完整项目的代码库:https://github.com/CedricSchmeits/file-generation-issue
(请注意,这是对问题的简短总结,只包括翻译部分。)
英文:
I'm in the process of generating an api using flatbuffers within cmake. Now when on top level of the cmake directory tree the api is generated, the include files that should be generated are not found when they are needed in the branches.
./CMakeLists.txt
set(INTERFACE_FBS ${CMAKE_CURRENT_SOURCE_DIR}/fbs/testapi.fbs)
flatbuffers_generate_headers(TARGET incl
SCHEMAS ${INTERFACE_FBS}
FLAGS --scoped-enums --cpp-std c++17)
target_link_libraries(incl INTERFACE flatbuffers::flatbuffers)
set_directory_properties(PROPERTIES ADDITIONAL_CLEAN_FILES incl)
#add_executable(testapp app/src/test.cpp)
#target_link_libraries(testapp incl)
add_subdirectory(app)
./app/CMakeLists.txt
add_executable(app src/test.cpp)
target_link_libraries(app incl)
Running the system like this results in the following error:
CMake Error at app/CMakeLists.txt:2 (add_executable):
Cannot find source file:
/home/xxx/build.test/incl/testapi_generated.h
Tried extensions .c .C .c++ .cc .cpp .cxx .cu .m .M .mm .h .hh .h++ .hm
.hpp .hxx .in .txx
The testapi_generated.h
can't be found as it's not generated. But it should be generated as the function flatbuffers_generate_headers
sets an add_custom_command
for the wanted .h
file.
When I move the building of the executable to the main cmake file, so replacing the bottom of:
./CMakeLists.txt
add_executable(testapp app/src/test.cpp)
target_link_libraries(testapp incl)
#add_subdirectory(app)
the '.h' file is generated and the simple application builds without problems. Also enabling the subdirectory at that point will result in a working executable. Performing a make clean
and the building will fail again.
What am I doing wrong? Is it not possible to first use files created by an add_custom_command
in a subdirectory?
I've put the whole project into a repository:
https://github.com/CedricSchmeits/file-generation-issue
答案1
得分: 1
如Milan Š.已经提到的,问题是由作用域引起的。在flatbuffers_generate_headers
内,文件是通过add_custom_command
生成的,这是生成文件的正确方式。在add_custom_command
的描述中,已经提到了这一点: 同一目录(CMakeLists.txt文件)
这定义了一个命令来生成指定的OUTPUT文件。在同一目录(CMakeLists.txt文件)中创建的一个目标,将任何自定义命令的输出文件作为源文件,都将在构建时使用命令生成文件的规则。
解决方案进一步提到:
相反,使用
add_custom_target()
命令来驱动该命令,并使其他目标依赖于该目标。
这意味着实现另一个目标,该目标依赖于flatbuffers_generate_headers
创建的所有自定义命令,将解决问题。然后,在另一个目录中,该目标还应该依赖于接口库和附加目标。使用add_dependencies
这在Flatbuffers的拉取请求中得到了解决: 将GENERATE_<TARGET>添加到flatbuffers_generate_headers,它被添加到版本v23.3.3中。
flatbuffers_generate_headers
现在不仅生成INTERFACE库${TARGET}
,还生成一个名为:GENERATE_${TARGET}
的新目标。这意味着只需要在子目录中进行一些更改。
./app/CMakeLists.txt
add_executable(app src/test.cpp)
target_link_libraries(app incl)
add_dependencies(app GENERATE_incl)
还要确保您使用的CMake版本至少是3.20,因为在该版本中解决了一些关于GENERATE文件标志的问题。
./CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
英文:
As Milan Š. already stated the problem is caused by scoping. Within flatbuffers_generate_headers
the files are generated by add_custom_command
which is the correct way of generating files. Within the desciption of add_custom_command
this is already addressed with: same directory (CMakeLists.txt file)
> This defines a command to generate specified OUTPUT file(s). A target created in the same directory (CMakeLists.txt file) that specifies any output of the custom command as a source file is given a rule to generate the file using the command at build time.
Further on the solution is stated:
> Instead, use the add_custom_target() command to drive the command and make the other targets depend on that one.
This means that implementing another target which is depended on all the custom commands created by flatbuffers_generate_headers
would solve the problem. Then within another directory the target there should also be made depended not only of the interface library but also of the additional target. using add_dependencies
This is solved in the pull request for flatbuffers: Added GENERATE_<TARGET> to flatbuffers_generate_headers which is added to release v23.3.3.
The flatbuffers_generate_headers
now not only generates the INTERFACE library ${TARGET}
but also a new target named: GENERATE_${TARGET}
. Which results that only within the sub directory a change needs to be done.
./app/CMakeLists.txt
add_executable(app src/test.cpp)
target_link_libraries(app incl)
add_dependencies(app GENERATE_incl)
Also make sure that you are using at least version 3.20 from cmake as within that version some issues with GENERATE files flags are solved.
./CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
答案2
得分: 0
这是一个作用域问题。flatbuffers_generate_headers
的编写方式阻止了子目录按正确顺序调用子命令。对此,除了"硬编码子目录"之外,没有其他办法,而我不建议这样做。
我的意思是,这本质上等同于将其复制粘贴到根目录的 CMakeLists.txt
中,但以更隐蔽的方式,即:
通过直接包含子目录的 CMakeLists.txt
文件:
include(app/CMakeLists.txt)
然而,沿着这个方向可能会导致其他问题,因为add_subdirectory
的主要好处在于它为 CMakeLists.txt
创建的作用域。
因此,我要重申一下:我不建议上述方法,而是建议将相应的代码移动到适当的CMakeLists.txt
中。
英文:
TL;DR: It's a scope issue, and the "solution" outlined in this answer is not really a solution but a hack which I don't recommend.
This is a scope issue. The way flatbuffers_generate_headers
is written prevents the subdirectory to invoke the correct (sub)commands in order. There is nothing you can do about this, other than "hardcoding the subdirectory in" - which I don't recommend.
What I mean by that is essentially the equivalent of copy pasting it into the root CMakeLists.txt
, but in a more hidden way, i.e.
By directly including the subdirectories CMakeLists.txt
file:
include(app/CMakeLists.txt)
However down the line this may lead to other issues because the main benefit of add_subdirectory
is the scope it creates for the CMakeLists.txt
.
Hence I will repeat myself: I do not recommend the above and instead recommend moving either code respectively into the appropriate CMakeLists.txt
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论