![]() |
Project
|
The driving force is to abandon the whole bucket system that proved itself a great way to hide genuine dependency issues we're having in our build system.
To do so the main idea is to migrate our CMake usage to latest practices recommended by the CMake community.
Details can be found in many online locations in blog post, video, or book form, but the core concept is to base everything on targets and forego as much as possible the usage of variables and/or directory specific functions.
Also, since our CMakeLists.txt that were first written a few years back, more third-party libraries have embraced the new CMake ways of working and as such provide reasonably good XXXConfig.cmake files that are used when using find_package(XXX). We should use them instead of cooking complicated FindXXX.cmake as much as we can.
Targets are normally created with CMake-provided functions like add_library, add_executable and characterized with functions like target_include_directories, target_link_libraries, etc...
We pondered for a long time whether we should simply stick to those native functions for our builds. But that would mean quite a bit of repetitive pieces of code in all our CMakeLists.txt. Plus it would make enforcing some conventions harder. So we decided (like in the previous incarnation of our build system) to use our own functions instead.
Compared to the previous system though, we tried :
All our CMake functions are defined in the cmake directory. Each file there defines one function. The filename is UpperCamelCase while the function name is snake_case (CMake function names are case insensitive but the modern convention is to have them all lower case). So for instance o2_add_executable is defined in cmake/O2AddExecutable.cmake. Each function is documented in its corresponding .cmake file.
The main defined functions are currently :
All the o2_ functions above take as first (unnamed) parameter the basename of a target. In order to prepare for the packaging step, the actual target name is not the same as this basename. The target naming scheme is handled by the o2_name_target function. But in most cases the developpers do not need to know this final name, just that their target should be referenced as basename when they are used as first parameter of the o2_xxx functions or as O2::basename when used as dependencies.
The idea is to go in steps.
In this step the idea is to limit ourselves to change only CMakeLists.txt and *.cmake files and not the source code (unless absolutely necessary). The top CMakeLists.txt was rewritten from scratch and is composed of different parts :
For the developper there is one major visible usage change : testing (still using ctest of course) can now be done from the build tree itself, i.e. without installation.
The main changes with respect to the current/previous situation are highlighted below.
CMake 3.13 is still the minimum version required. 3.14 would be interesting but is not critical. Note that when out CMake 3.15 will bring some generator expressions features that we might want to take advantage of (e.g. REMOVE_DUPLICATES) and so might justify bumping the CMake version we use at that moment.
Here we have some basic sanity checks (forbid in-source builds for instance), perform some feature checks on the CXX compiler, set the default for our build options, set the output directories and RPATH settings. Note the BUILD_SIMULATION option : currently used "only" to fetch more dependencies, but might imagine to actually group all the simulation-dependent parts of O2 into an optional component ? Not for now, but maybe a thing to consider for the future ?
Compared to previous usage, a stage area was added in the build tree, where (most of) the build artifacts are created. That's where you'll find the bin, lib, share directories instead of directly under the build topdir.
Third-party dependencies are found in dependencies/CMakeLists.txt. find_package calls are of the CONFIG variety unless there's a compelling reason to use the MODULE version. In particular :
FairRoot::XXX targets even if those are not (yet) created by FairRoot itself. That file will disappear when FairRoot completes its own CMake migration.ms_gsl target corresponding to the header only libraryRapidJSON::RapidJSON target corresponding to the header only libraryAs an aside, in order to ease the development of this new CMake system, a o2_find_dependencies_from_alibuild function that "detects" the third-party dependencies from an AliBuild installation zone was developped. That might come in handy for other people too (e.g. those using IDEs like CLion ?)
That part is the meat of the CMakeLists.txt and is just the inclusion of the relevant subdirectories, but with a catch : order matters ! Some dependency cycles that had been hidden with the bucket system now shows up ...
Lastly some setup for testing is done in tests subdirectory. That part is still a bit WIP, but that's the location of the shell scripts that are used.
The way it was developped : first make a regular install of O2@dev using aliBuild. Then switch to cmake-migration-step-1 branch. Create a build directory somewhere, and run cmake there :
Use ninja to build, cmake . to force rerunning cmake. Rince and repeat. Do it on Mac(10.14) and on CentOS7.
The tests for this step (the failing test is only failing on CentOS7 in Debug configuration) :
In the build directory, if you do :
Then after the cmake configure stage (if using CMake >= 3.14) you'll get a list of JSON files describing the targets in the reply subdir :
This step is trying to get the GPU targets back in business. There are three versionsto consider: HIP, OpenCL and CUDA (for TPC and ITS).
In the GPUTracking all the AliRoot-specific references has been removed. They will need to be put back there if needed.
This step was tested on a CentOS7 server with OpenCL, HIP and CUDA dev. kits installed.
This step also brings a temporary O2RecipeAdapter cmake include to be able to test this without having to modify (too much at least) the existing o2 recipe and CI.
In order to have the O2Suite building fine, step 3 is now the addition of the creation of a proper O2Config.cmake file, so that consumer packages (like QualityControl) can use our targets.
The proper generation of the O2Config.cmake (step 3) file has been done in anticipation for its usage by QualityControl.
The macro testing (step 4) is working, but only within the correct environment (i.e. within an alibuild build). The running of ctest without a prior environment will have to be deferred for later on, as it's not a completely trivial task (and is a departure from the current practice anyway)
[ ] Remaining to be done : generation of O2ConfigVersion.cmake file.