3

I have a scenario that I think is very similar to this one: CMake add_custom_command/_target in different directories for cross-compilation, however the solution for that issue isn't working for me.

In subdir/CMakeLists.txt I have:

add_custom_command(OUTPUT foo.h foo.cpp COMMAND ... DEPENDS foo.xml)
add_custom_target(generate_foo DEPENDS foo.h foo.cpp)

and then CMakeLists.txt:

add_executable(MyTarget
               subdir/foo.h
               subdir/foo.cpp
               ${OTHER_SOURCES})
add_dependencies(MyTarget generate_foo)
add_subdirectory(subdir)

This fails with "Cannot find source file: subdir/foo.h". The documentation for add_dependencies suggests that it will ensure that generate_foo builds before MyTarget, but if that's the case it looks like it's at least trying to access all source files before either target builds. Am I doing something wrong here? How can I compile source files that are generated by a custom target/command in a subdirectory?

Ben
  • 389
  • 3
  • 8
  • Hmm, `add_dependencies()` with a target created **after** that. Is this ever configured? Try to swap `add_dependencies` and `add_subdirectory` calls. Also, when you have *generated* source files, add them to the executable using **absolute** path: `${CMAKE_CURRENT_BINARY_DIR}/subdir/foo.h`. – Tsyvarev Oct 17 '17 at 20:51
  • @Tsyvarev Thanks for the suggestion, I have since updated my CMakeLists.txt to use an absolute path, ${CMAKE_CURRENT_LIST_DIR}/subdir/foo.h rather than CMAKE_CURRENT_BINARY_DIR. However, this didn't seem to have any effect. For the other suggestion, it is the style of the repository I'm working in to have all add_subdirectory calls at the bottom of every CMakeLists.txt. I tested and verified that moving it to the top makes no difference. – Ben Oct 18 '17 at 19:36
  • 2
    Ok. As the last resort - try to set [GENERATED](https://cmake.org/cmake/help/v3.9/prop_sf/GENERATED.html) property for files which are created in other directory: `set_source_files_properties( PROPERTIES GENERATED TRUE)`. I agree that this looks ugly, but CMake actually cannot track *file* dependencies between different `CMakeLists.txt`; only *target* dependencies are tracked globally. – Tsyvarev Oct 18 '17 at 19:51

1 Answers1

0

The problem is that the GENERATED file property (that CMake uses to determine if it needs to check that a file exists at configure time) is not visible outside the directory in which the file is generated. The problem goes away in CMake 3.20. This is explained here.

I usually solve this problem by compiling generated source files into a static or object library in the subdirectory, then linking to that, since targets are globally visible. You can also explicitly set the GENERATED property on the generated files in the scope you wish to use them, but this hack breaks the encapsulation gained by using a subdirectory.

It's also worth noting that you can do away with the custom target and the call to add_dependencies because the generated files are already dependencies of the executable (this has always has been the case AFAIK).

jezza
  • 331
  • 2
  • 13