Friday, October 29, 2021

[SOLVED] Modern CMake: is there a way to build external projects using a CMakePresets.json?

Issue

Disclaimer: I'm rather new to C++ development and handling bigger projects, so this might be a wrong approach or tool, so I am very open to different ideas.

I want to be able to provide a sort of package that is a collection of prebuilt libraries / binaries for different platforms, to be used with our other software.

I need to be able to add or remove targets independently without breaking anything. (as in, adding a new library should be as simple as creating a new directory libname and configuring a CMakePresets.json inside)

Ideally, my thoughts were:

  • create a repository with build instructions for each dependency
  • have a CI/CD pipeline building all the different versions we need (linux x64, linux ARM, windows)
  • provide a platform to download specific versions

So, what I had in mind was something like this:

├── A
│   └── CMakePresets.txt
├── B
│   └── CMakePresets.txt
├── C
│   └── CMakePresets.txt
└── CMakeLists.txt (or something like a python script)

A B and C being my dependencies and the way I want to build them, by using a script in the root directory.

I have spent a bit of time trying to figure out a way of doing this cleanly and cross platform but no avail. I thought of using a CMakeLists.txt because of the FetchContent / ExternalProject_Add commands but haven't really found a way to pass variables that is not tedious.

This is very frustrating because this seems like something that should be relatively common but I feel like i'm missing something...

Perhaps I should be using something like a Python script for some of the tasks (for example cloning the sources, copying the presets in the new directories and build from there) but I really liked the idea of doing everything with CMake, considering it handles a lot of the things I want (cloning a specific git tag etc)

Thank you


Solution

You have just described the goal and approach of Conan. It interfaces well with CMake, and uses your "build recipe" approach. You, and Conan, recognize that C++ packages are inherently different from, say, Python or Javascript, in that they have endless variations due to compiler version, libc version, build configuration, etc. The solution is to provide the build instructions, and cache the built result at multiple layers: local machine, private server, public server.

The result is that you specify the packages with the versions you want. The package will just be downloaded if any match the configuration you have specified, else it will be built and cached. With the right CI setup, you can upload the result to your internal server so that most of the time, the necessary packages are all pre-built.

Last time I tried it, I struggled with a few things like transitive dependencies, and you might find yourself maintaining your own internal branches of the build recipes for all the packages you need, so that you can control those transitive dependencies.



Answered By - Peter