Skip to content

Using CMake with Athena

Introduction

ATLAS uses CMake for building all of its offline/trigger/analysis software since 2018. CMake is a very generic framework for setting up the build of practically any software.

This current tutorial is not meant as a generic introduction into CMake, but rather as a cook-book for using CMake in ATLAS projects, most importantly in Athena.

For a lower-level introduction into the basics of CMake, consider going through the following materials:

Basics

Anatomy of an ATLAS Package

ATLAS's software is split into and organized as a list of "packages". A "package" is practically just a subdirectory in the directory structure of the atlas/athena repository, for example: AthExHelloWorld

By convention, packages have the following layout:

  • One CMakeLists.txt file sits at the root of the sub-directory. This is the description to the build system of what to do with the package.
  • Public headers (for "the" shared library of the package) in the package are put into a sub-directory with the same name as that of the package. There could technically be further sub-directories inside of that directory, but it's not conventional to have them.
  • Private headers and source files are put into a sub-directory called src/.
  • If the package builds a "component library", the source file needed for building that component library, is called src/components/<PkgName>_entries.cxx.
  • Python code included in the package is put into a sub-directory called python/.
  • Scripts are usually put into a sub-directory called share/.
  • Unit tests, compiled or otherwise, are put into a sub-directory called test/.
  • For compiled executables there is no real convention. Putting their sources into a dedicated sub-directory would be a good choice.

Generally, there is no strict requirement for a package to be laid out in one specific way. The CMakeLists.txt configuration of the package can technically pick up source files / scripts / etc. from any place inside of the package's directory. In most cases, if you are not sure how to do a particular thing, it's worth having a look at how other packages would have done it.

AtlasCMake / AtlasLCG

In order to make it easier to set up the build of thousands of packages consistently, we provide a layer of ATLAS specific CMake code that packages should use to do "standard" things. The code for this is in atlasexternals/Build/AtlasCMake and atlasexternals/Build/AtlasLCG. You can find the reference documentation for the code of AtlasCMake here

In this tutorial we will use the functions documented on that page, without duplicating the documentation of the functions in this page.

Building a Project

So far we only talked about packages. But one never tells CMake to build a package by pointing at the package's directory. One must always rather build a project.

When working with the atlas/athena repository, this is practically always the Projects/WorkDir project that you should be using.

While CMake has many command line options, in the majority of the cases when working on ATLAS code, what you need to do is to create an empty "build directory" (the convention is to make a directory called build/ beside the athena/ directory), and from inside of it execute: * in case of a partial checkout simply:

cmake ../athena/Projects/WorkDir/
make
  • in case of a partial build, after setting up a package_filters.txt file (more on it later), with:
cmake -DATLAS_PACKAGE_FILTER_FILE=../package_filters.txt ../athena/Projects/WorkDir/
make

Exercises

The first 3 exercises use an external repository on GitHub. Have a look here.

You will need to first of all clone it locally, simply with:

git clone https://github.com/krasznaa/atlas-cmake-tutorial.git

For these first 3 exercises, you should in all cases just use the latest Athena nightly. I.e.

setupATLAS
asetup Athena,main,latest

Add a (Reflex) dictionary to a package

Please see Exercise1 for a description of the exercise.

Add compiled and scripted unit tests to a package

Please see Exercise2 for a description of the exercise.

Introduce a new LCG external dependency for a package

Please see Exercise3 for a description of the exercise.

Work with updated externals

One of the most advanced things to do on top of a nightly build is to make use of a new version of an external project. This includes trying out new versions of Gaudi, Geant4, GeoModel or Acts. This is something that only a small number of developers do regularly, so this is mostly about making you aware of this possibility.

You have already seen in Exercise 3 how to pick up a new external from an LCG release. Apart from picking up software from LCG releases, and picking up some libraries from the system (from /usr), Athena receives a number of its externals from AthenaExternals. While for some updates in these externals it is unavoidable to perform a full build of Athena by hand, some updates are possible by "only" re-building a finite number of packages on top of a nightly, "in the correct way".

The method is the following: * You first need to build the new/different version of the external project. This can be done in a lot of different ways... In this exercise we will make use of AthenaExternals itself to perform this build. * Set up the desired Athena nightly, then set up the build of WorkDir with a command like:

CMAKE_PREFIX_PATH=/local/directory/with/external/install cmake -DATLAS_PACKAGE_FILTER_FILE=../package_filters.txt ../athena/Projects/WorkDir/

The build should in principle work find like this, as long as you select an appropriate list of packages to build. This list depends on the external that you're testing like this. But to test the modified binaries in action, one needs to be even more verbose. Since the environment setup script generated by CMake (setup.sh) has a good chance of not generating a functional runtime environment for using the updated external. Requiring you, after sourcing the setup.sh script of your build directory, to manually add appropriate directories to the $LD_LIBRARY_PATH, $PYTHONPATH, etc. environment variables in your shell.

The exercise from here on out shows how to build GeoModel "just so", and then build the DetectorDescription/GeoModel/GeoModelUtilities package against that local version of GeoModel.

  • You will first need an up-to-date version of athena. Feel free to re-use the clone of your fork that you would've used on a previous day.
  • Build GeoModel with the help of this local athena clone. To do that, you can use the Projects/Athena/build_externals.sh script like the following:
setupATLAS
asetup none,gcc13,cmakesetup --cmakeversion=3.29.5
./athena/Projects/Athena/build_externals.sh -t RelWithDebInfo -b $PWD/geomodel_build -c -x -DATLAS_GEOMODEL_SOURCE="GIT_REPOSITORY;https://gitlab.cern.ch/GeoModelDev/GeoModel.git;GIT_TAG;6.8.0" -k Package_GeoModel 
  • Now set up a package_filters.txt file with the following contents:
+ DetectorDescription/GeoModel/GeoModelUtilities
- .*
  • After all of this, you can perform the build of the package in a new/separate terminal with:
setupATLAS
asetup Athena,main,latest
CMAKE_PREFIX_PATH=$PWD/geomodel_build/install/AthenaExternals/25.0.25/InstallArea/x86_64-el9-gcc13-opt:$CMAKE_PREFIX_PATH cmake -DATLAS_PACKAGE_FILTER_FILE=$PWD/package_filters.txt -S athena/Projects/WorkDir/ -B athena_build
VERBOSE=1 cmake --build ./athena_build/ 

Pay attention to the compilation and linking commands coming up in the latest command. Which should all point to your local GeoModel installation.