add_custom_command生成的文件在add_subdirectory中找不到。

huangapple go评论60阅读模式
英文:

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

huangapple
  • 本文由 发表于 2023年2月23日 23:19:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/75546798.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定