'CMake have a target depend on a generated file in a subdirectory

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?



Solution 1:[1]

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).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1