When writing a CMakeLists.txt file, I have always called target_link_libraries() with a list of targets that I am generating in other directories, then I call add_subdirectory() to add the files that create the targets. AI is telling me that I need to call add_subdirectory() before target_link_libraries() so that the target is defined before the call to target_link_libraries() references it. I have never had an issue with target names resolving. What is the correct way to handle this?
AI does not know all, and sometime it hallucinate!
There are more ways to do it:
One is:
add_executable(your_target ...)
add_library(foo)
# ...
add_library(bar)
add_subdirectory(path/to/foo) # to use target_source(foo ...)
# ...
add_subdirectory(path/to/bar) # to use target_source(bar ...)
target_link_libraries(your_target PUBLIC foo bar ...)
I agree. It does hallucinate often. I just want to know if this is a hallucination, or it is something that I didn’t know but should have known.
Things are changing over the time. i.e.
CMake 3.12 and earlier prohibited target_link_libraries() from operating on a target defined in a different directory. If a subdirectory needed to make the target link to something, it couldn’t do so from within that subdirectory. …
from Professional CMake
Focusing on the original question, consider the following call:
target_link_libraries(Algo PRIVATE SpecialSauce)
CMake will immediately issue an error if Algo isn’t a defined target. It is perfectly happy for SpecialSauce to not be defined yet, the only criteria is that it must eventually be defined somewhere before the end of the entire CMake configure execution. For example, the following is safe and supported:
add_executable(App ...)
target_link_libraries(App PRIVATE Algo) # Algo doesn't exist yet, but App does
add_library(Algo STATIC ...)
I generally recommend that projects define things before they are referenced, but that isn’t a requirement for target_link_libraries() except for its first argument, as explained above. The reason I recommend that is occasionally projects try to do things that assume all referenced entities exist. I’m being deliberately vague about that, but I’ve seen it done a few times and sometimes by very commonly used projects. Now, projects shouldn’t generally do things like that, but occasionally they need to do something for which there’s no other workaround and the project is willing to accept the limitations of such logic.
I think in large codebases (tens to hundreds of libraries, with tens of applications being build up by using some of those libraries), having this order always in place might be hard, many libraries in different folders. Say libraries A, B, C, D, and let’s assume they can be anywhere in the source tree, relative to one another, but when starting at the top level, the end result of several add_subdirectory does however ensure, they would have been added in the order , A, B,C, D. Great, we met the requirement. And suddenly the implementation of B changes, in that way it uses ‘D’. Now what , restructure the source tree, move things around to make it work ? While feasible maybe not so much wanted.
Do note, that (if I recall correctly) with aliases this freedom is not there, and Foo::foo has to be known by the time somebody uses it as a dependency in target_link_libraries !
Can you give a more fleshed out example of that? I’m not aware of any restriction specific to ALIAS targets like what you describe, but maybe I’m misunderstanding what you’re saying.
It seems this works now, I do remember years ago it did not work, since I ran into this problem, but as said those were tests and conclusions somewhere in the 2019-2020 time frame. Never re-tried it, so very happy to be stand corrected and know this is no longer a problem ![]()