This results in 'gen.cpp': No such file or directory during the build of the target.
It seems like the generated file isnt registered properly.
However, if I set the target_sources to PUBLIC, it does work, but that is not behavior we want (its a source file being compiled into a library, and we dont want dependent targets to also do that).
Also, if we instead declare the library in the top-level CMakeLists.txt and comment it out in the platform sub-directory, it also works.
Source file properties are a bit strange in their interactions with directories. What happens if you set a minimum CMake version via cmake_minimum_required() to 3.20 (to get CMP0118)?
Ninja has issues with path equivalence as it does string comparisons. You’ll need to use / everywhere; something is using \ as a separator. You can use file(TO_CMAKE_PATH) to do this transformation as needed.
The __ comes from the transform of .. in any relative path to a source file.
So, I think I’ve managed to narrow it down a bit. So far it seems that any GENERATED file via a custom command wont be registered properly if the target is not declared in the same CMakeLists.txt. I ran into the same issues in another spot…
The only workaround I have managed to do is to immediately declare a new interface library, and then link that library to the target…
If I were to move the gd_platform target into that directory, then the icon would be registered via target_sources, but then the other generated files would no longer work.
Yes that’s the reason. When you are creating a file as an output of an add_custom_command(), a target defined in the same directory scope must depend on that output file. It is not enough for a target in a different directory to depend on it, that’s not supported. The add_custom_command() docs state the following, which probably should be stated in reverse instead to highlight this constraint:
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.
Policy CMP0118 only covers whether the GENERATED property is visible to a different directory scope. The actual dependencies are separate from that.
Then is the ideal solution to this to use an interface library like I have above? The only downside I seem to find is that it pollutes my target list in CLion and other IDE’s
Personally I wouldn’t use that directory structure to begin with. I recommend defining the target at the higher level, then only add sources to it from that level or below. It’s a bit strange to be adding a source from a level above where the target is defined.
I don’t disagree, and flipping the where it was declared wasn’t an issue. But add_custom_command only seems to work for targets declared in the current directory, not sub directories either. So even in a top-down approach we still need intermediate INTERFACE targets it seems.
If I move the target declaration up to platform in this case, then the generated code in platform works. However, generated files in platform/windows/ now need an interface target to work. And vice versa.
Sorry, I was a bit short on time when making that last reply. You do need some kind of target defined in the same scope as the one you have your add_custom_command() for generating the file. Typically, I see projects create a custom target using something like:
There are other ways of achieving the same thing, using something other than a custom target, but the above would be more like the canonical pattern projects typically use. You can’t get away from adding a target in your scenario, so may as well make it a simple custom target rather than trying to get fancy with something else.
I also encountered this bug, similar directory structure, with “file(GENERATE ...)” instead of “add_custom_command(...)”, and cmake version 3.23.2. Fortunately I found this defect report.
As you mentioned it worked if you put everything in the top-level “CMakeLists.txt”, so I replaced “add_subdirectory(subdir)” in the top-level “CMakeLists.txt” with “include(subdir/CMakeLists.txt)”, which also worked around the bug.
Well, more specifically, it’s that some of these things are mediated by directory properties. Without add_subdirectory, a new set of properties isn’t created.