Writing the Configuration

Last update: 05 Jul 2023 [History] [Edit]

The Project Configuration

As mentioned before, when one calls cmake, it looks for a file called CMakeLists.txt, which should describe the build of an entire project. For an “ATLAS project” the project configuration normally looks like (with some extraneous segments removed)

Note this may differ from the CMakeLists.txt you added to your project but the general idea and code is the same. The file you have is slightly more sophisticated with environmental variables etc.

# Set the minimum required CMake version:
cmake_minimum_required( VERSION 3.7 FATAL_ERROR )

project(UserAnalysis)
...

# Pick up a local version of the AtlasCMake code if it exists:
find_package( AtlasCMake QUIET )

# Find the project that we depend on:
find_package( AnalysisBase )

# Set up CTest:
atlas_ctest_setup()

# Set up a work directory project:
atlas_project( WorkDir 21.2.189
   USE AnalysisBase 21.2.189
    )

# Set up the runtime environment setup script(s):
lcg_generate_env( SH_FILE ${CMAKE_BINARY_DIR}/${ATLAS_PLATFORM}/env_setup.sh )
install( FILES ${CMAKE_BINARY_DIR}/${ATLAS_PLATFORM}/env_setup.sh
   DESTINATION . )

# Set up CPack:
atlas_cpack_setup()

Let’s step through the file statement-by-statement.

  • Every project configuration must begin with a cmake_minimum_required call. Even if you’re not particularly interested which version of CMake is used to build your code. The ATLAS CMake code requires CMake 3.7 at the minimum to work correctly. But note that asetup at the time of writing provides CMake 3.14.3 by default.
  • The next step should always be to look for the base project that you want to build against. In this example the configuration requires some version of AnalysisBase-21.2.X (or any newer version) to be found. Note that if you want to only allow building your code against one very specific version of the base project, you can do that like:
find_package( AnalysisBase )
  • Next, in order to set up both unit testing, and some other internal properties correctly, you have to use the atlas_ctest_setup function.
  • Now we come to the “main” function of the project configuration, atlas_project. This function call is responsible for doing most of the heavy lifting in setting up your work directory project’s build. It has a fairly long list of optional arguments, but on first order you just use it with:
atlas_project( <name of this project> <version of this project> 
   USE <name of base project> <version of base project> 
    )
# Set up a work directory project:
atlas_project( WorkDir 21.2.189
   USE AnalysisBase 21.2.189
    )
  • In order to set up a functional runtime environment for the project, we use the lcg_generate_env helper function. It can be used to generate a shell script that can set up an environment allowing all the “externals” needed by the project to be used successfully. Since the lcg_generate_env function call only generates the setup_env.sh file for the “build directory”, we also need to use the built-in install function to install this script together with our project. All in all you don’t need to worry about these calls too much if you’re not interested in the details of our build system.
  • The final tweaks to the project are made with the atlas_cpack_setup function call. This call sets up CPack to be able to possibly build an RPM (linux only), TGZ or possibly DMG (macOS only) file from our project. Note that amongst other things PanDA uses this feature of our build system to package up user projects for grid running, so you should not forget about adding this call to your project’s configuration if you’ll ever want to run your code on the grid.

The Package Configuration

Again this may differ to what you have in your package CMakeLists.txt but the general outline should be the same

# The name of the package:
atlas_subdir (MyAnalysis)

# Add the shared library:
atlas_add_library (MyAnalysisLib
  MyAnalysis/*.h Root/*.cxx
  PUBLIC_HEADERS MyAnalysis
  LINK_LIBRARIES AnaAlgorithmLib xAODMuon SystematicsHandlesLib)

if (XAOD_STANDALONE)
 # Add the dictionary (for AnalysisBase only):
 atlas_add_dictionary (MyAnalysisDict
  MyAnalysis/MyAnalysisDict.h
  MyAnalysis/selection.xml
  LINK_LIBRARIES MyAnalysisLib)
endif ()

if (NOT XAOD_STANDALONE)
  # Add a component library for AthAnalysis only:
  atlas_add_component (MyAnalysis
    src/components/*.cxx
    LINK_LIBRARIES MyAnalysisLib)
endif ()

# Install files from the package:
atlas_install_python_modules( python/*.py ) 
atlas_install_joboptions( share/*_jobOptions.py )
atlas_install_scripts( share/*_eljob.py )
  • All your packages must always start with using atlas_subdir(...) to declare the name of the package.
  • You use atlas_add_library, atlas_add_executable, atlas_add_root_dictionary and atlas_add_dictionary to generate/build all the code in your package. There are more functions available than this (see SoftwareDevelopmentWorkBookCMakeInAtlas), but these are the ones used most often in analysis packages.

  • The if statements using XAOD_STANDALONE that use atlas_add_dictionary and atlas_add_component, these are in place to separate adding a dictionary or a component library depending on if you are using AthAnalysis or AnalysisBase

  • Finally you declare which files from your package should be “installed”. Into a location that makes them visible during runtime. Find the full list of installation functions under here.