I have a CMake project using the Ninja generator and GNU Arm Embedded Toolchain, with libraries in Git submodules. I’d like to be able to add the libraries using add_subdirectory() or similar, with its scoping features, without needing a CMakeLists.txt in the subdirs. This would allow me to use the repos unmodified from upstream (since they don’t have CMakeLists.txt files), and maintain my own CMakeLists.txt files in the main project.
To date, I’ve been using add_subdirectory() with forks of the library repos, with CMakeLists.txt added in each. Existing project structure is like this:
Another option would be to build your own directory hierarchy just for the CMakeLists.txt files, and set up a mechanism to refer to the upstream dirs. Something like this:
Then, inside the CMakeLists under mycmake, call the function at the top and then just use ${UPSTREAM_CURRENT_SOURCE_DIR} to refer to paths within the corresponding upstream project.
It turns out I have more custom modifications than I realized in the libraries, so I’m now leaning toward injecting the CMakeLists.txt files along with them. However, suppose for a moment that I don’t do that.
As I initially described, on the surface, it seems like I’d want to be able to add_subdirectory() and pass in a CMakeLists.txt from outside, to save me the trouble of the type of workaround you suggested. (i.e. A possible CMake feature request.) Maybe that wouldn’t work recursively, though?
You can use FetchContent to pull down the project from a URL, apply patches (which can add a whole new CMakeLists.txt as well as make changes to existing source files) and then build the code as part of your project.
Another option may be to use vcpkg which provides similar abilities to download source code, apply patches and add a CMake based build where one doesn’t already exist. Then you can leverage additional capabilities from vcpkg like binary caching and so-on. However, I’m uncertain how vcpkg works with cross-compiling since it hijacks the CMAKE_TOOLCHAIN_FILE mechanism to inject dependencies at the time the project function is called.
The FetchContent route would seem to be the smallest change from where you are currently.
Thanks for the info. I don’t think these suggestions fit well with my existing workflow, though. Please correct me if I’m wrong.
I don’t want CMake to interfere with or replace the fetching or content management of Git / git submodule. And I want “clean” builds, with the source fully captured in git commits.
A full package manager would be a replacement for git submodules, right?
I don’t want CMake to interfere with or replace the fetching or content management of Git / git submodule. And I want “clean” builds, with the source fully captured in git commits.
It’s a different workflow, but you can still do this with FetchContent. I suppose it depends on how actively you are modifying the dependency. If it’s a routine thing, then FetchContent is probably not the best fit, but your own parallel directory structure so that add_subdirectory works as expected, but the sources are pulled from the submodule instead of being in the same directory as the CMakeLists.txt file.
A full package manager would be a replacement for git submodules, right?
Again, it depends on how often you’re modifying the dependencies. Generally speaking both the FetchContent approach and the vcpkg approach assume relatively stable dependencies. Both give you the ability to apply patches and/or add your own CMakeLists.txt for the dependencies.
With FetchContent, the targets are more directly included in your build (e.g. in a Visual Studio solution they appear as targets in the IDE), whereas with vcpkg the coupling is looser and while you can step through the source in the debugger, the dependencies won’t appear as targets in your VS solution.
I just thought I’d toss out these two alternatives as other options for you to consider.
That’s not really the case for this project. The submodules do require occasional modification–sometimes merely as a one-off for testing (not committed).
When I need to use libraries that don’t support CMake, I usually make a small wrapper repo that contains the CMakeLists.txt, and that wrapper repo is what the main project includes via FetchContent