Issue
I have two folders, each containing some targets. One is a child folder of another. But I don't think it really matters for my problem. It applies to any two folders. Anyways, here's my dependencies:
- folder2/target1 -> folder1/target1
- folder1/target2 -> folder2/target1
From the targets point of view, these are completely normal dependencies. However, I don't know how to express this in CMake, since I can't add_subdirectory()
each other in both folders, which would create a cyclic reference.
This is what I have:
folder1/CMakeLists.txt:
...
add_subdirectory(folder2)
...
folder2/CMakeLists.txt:
...
add_subdirectory(../ folder1)
...
And I'm using VS code with CMake extension. In fact, CMake doesn't seem to be able to detect the cyclic reference and keeps running forever and using up the RAM and eventually crashing VS code.
I'm converting an existing codebase from Bazel to CMake. And it's not possible, at least not practical, to change the folder structures. In Bazel, you don't need to add another folder in their BUILD file. You can simply specify a fully qualified target name.
What's the best way to achieve something similar in CMake? Thanks.
Solution
It seems you have some misconceptions about how CMake works or is to be used. Maybe these come from your experience with Bazel (though I cannot tell).
The idea is that CMake traverses your project once, starting from the project's root and descending into subdirectories. It picks up targets (libraries, executables and custom ones) as it goes, orders them as appropriate and generates a build system.
Entering a parent directory using add_subdirectory()
is unusual but not an error in itself. It is not needed in your case. Adding a subdirectory more than once is certainly wrong.
Whenever CMake visits a CMakeLists.txt
by add_subdirectory()
, it creates a new directory scope. Making CMake do so recursively will eventually exhaust the available memory as we've seen.
The following two CMakeList.txt
s cover the case you describe:
In folder1/CMakeLists.txt
:
add_library(f1t1 foo.cpp)
add_executable(f1t2 main.cpp)
target_link_libraries(f1t2 f2t1)
add_subdirectory(folder2)
In folder1/folder2/CMakeLists.txt
:
add_library(f2t1 bar.cpp)
target_link_libraries(f2t1 f1t1)
Note that target names have to be unique, that's why I shortened and disambiguated them to f1t1
etc.
Also refer to the documentation of target_link_libraries
. In this case, the linked <item>
in the documentation is a target name defined in the same project. That means you can link f2t1
in folder1 even though it has not yet been added.
Should you not provide a target f2t1
, CMake will assume it's a plain library name and have the linker look it up. CMake will still work but it will eventually result in a linker error.
I left out header files as they are not needed for this simplistic example. In a real-world scenario, you would have header files and would want to make them accessible e.g. by calling target_include_directories()
.
Answered By - Friedrich Answer Checked By - Clifford M. (WPSolving Volunteer)