Difference: GaudiCMake315Configuration (1 vs. 7)

Revision 72019-08-21 - ThomasCluzel

Line: 1 to 1
 
META TOPICPARENT name="TWiki.WebPreferences"
This documentation is the updated version of https://twiki.cern.ch/twiki/bin/view/LHCb/GaudiCMakeConfiguration and is based on CMake 3.15.
Line: 429 to 429
  add_subdirectory(Gaudi) add_subdirectory(LHCb)
Changed:
<
<
# add_subdirectory() ... all the other project of the stack
>
>
# add_subdirectory() ... all the other projects of the stack
 EOF %ENDCODE%

Revision 62019-08-21 - ThomasCluzel

Line: 1 to 1
 
META TOPICPARENT name="TWiki.WebPreferences"
This documentation is the updated version of https://twiki.cern.ch/twiki/bin/view/LHCb/GaudiCMakeConfiguration and is based on CMake 3.15.
Line: 417 to 417
  %CODE{"sh"}% mkdir workspace ; cd workspace
Changed:
<
<
git clone # of all the projects of the desired stack
>
>
git clone project_url # of all the projects of the desired stack
 cat < CMakeLists.txt cmake_minimum_required(VERSION 3.15)
Line: 425 to 425
  LANGUAGES CXX DESCRIPTION "LHCb full stack")
Added:
>
>
enable_testing()
 add_subdirectory(Gaudi) add_subdirectory(LHCb)
Changed:
<
<
# add_subdirectory ... all the other project of the stack
>
>
# add_subdirectory() ... all the other project of the stack
 EOF %ENDCODE%
Line: 442 to 444
 Pro tip: do not document to much GaudiObjDesc so that people begrudge to use GaudiObjDesc.
Deleted:
<
<
-- ThomasCluzel - 2019-08-20
 \ No newline at end of file
Added:
>
>
-- ThomasCluzel - 2019-08-21
 \ No newline at end of file

Revision 52019-08-20 - ThomasCluzel

Line: 1 to 1
 
META TOPICPARENT name="TWiki.WebPreferences"
This documentation is the updated version of https://twiki.cern.ch/twiki/bin/view/LHCb/GaudiCMakeConfiguration and is based on CMake 3.15.
Line: 312 to 312
 %ENDCODE%
Added:
>
>
Help Why is the explicit list of sources mandatory? Even tough CMake is able to use glob patterns with file(GLOB...), those glob patterns are expanded at configure time and their results hardcoded in makefile or build.ninja or whichever file used by IDEs. This means that if a new file that matches the pattern is added, there is no way for the build system (make, ninja...) to notice it. The first solution is to reconfigure the project each time a new file is added to update the hardcoded list of sources. (This can be done either by rerunning the configuration command or by touching a CMakeLists.txt.) The other solution would be to forward the glob pattern to the build system. CMake offers a way to do so: file(GLOB ... CONFIGURE_DEPENDS) but for the time being, only Makefiles generators and Ninja are supported, meaning that people using IDEs would still have to reconfigure the project themselves.
 

Adding a new sub-project to the project

If a new sub-project is added to a project, its directory must be added to the list of sub-projects in the top-level CMakeLists.txt
Line: 426 to 442
 Pro tip: do not document to much GaudiObjDesc so that people begrudge to use GaudiObjDesc.
Changed:
<
<
-- ThomasCluzel - 2019-08-19
>
>
-- ThomasCluzel - 2019-08-20
 \ No newline at end of file

Revision 42019-08-19 - ThomasCluzel

Line: 1 to 1
 
META TOPICPARENT name="TWiki.WebPreferences"
This documentation is the updated version of https://twiki.cern.ch/twiki/bin/view/LHCb/GaudiCMakeConfiguration and is based on CMake 3.15.
Line: 86 to 86
 

CMake Configuration of a Gaudi-based Project

Several steps must be performed to build a Gaudi based project:
Changed:
<
<
  • Set up the environment (if not already set up)
>
>
  • Set up the build environment (if not already set up)
 
  • Configure the project with CMake (generate Makefile or build.ninja)
  • Compile the source files and link the binaries
  • Test the previously build binaries (optional but recommended)
Changed:
<
<

Set up the environment

To set up the environment, some environment variables need to be set.
>
>

Set up the build environment

To set up the build environment, some environment variables need to be set.
 
  • BINARY_TAG: the variable that describe the platform
  • CMAKE_PREFIX_PATH: is a path-like variable that must contain the list the list of path to:
Line: 115 to 115
 %ENDCODE%
Added:
>
>
It is also possible to list the call to export in a shell script to be able to source it later on.
 

With a view

%CODE{"sh"}%
Line: 124 to 126
 %ENDCODE%
Added:
>
>
Warning, important Sourcing a view is not the same as sourcing a shell script that uses export. A view is a directory of symbolic links and a setup.sh script.
 

With a toolchain

%CODE{"sh"}%
Line: 199 to 204
 %ENDCODE%
Added:
>
>
The wrapper uses a toolchain if a file called toolchain.cmake exists in the current directory. It might be useful to have a shell function to easily switch from one toolchain to another.
<!-- SyntaxHighlightingPlugin -->
function switch_platform
{
    export BINARY_TAG=$1
    rm -f toolchain.cmake
    ln -s /cvmfs/.../toolchains/$1.cmake toolchain.cmake # !!! Use the right path on CVMFS
}
<!-- end SyntaxHighlightingPlugin -->

Use the software

In order to use the previously built software, it is mandatory to use the runtime environment (it may differ from the build environment). The runtime environment is generated by the configuration at configure time in the build tree in a script called run.

<!-- SyntaxHighlightingPlugin -->
cd build.$BINARY_TAG
# ./run <program> <args...>
./run listcomponents -h
./run gaudirun.py
<!-- end SyntaxHighlightingPlugin -->
 

Modify the configuration

At the top level directory of a project and in every sub-project (package)
Line: 341 to 375
 

Gaudi CMake functions to help the configuration

All the gaudi_*() functions are defined by Gaudi. Their content and documentation can be found
Changed:
<
<
here.
>
>
here in GaudiToolbox.cmake.
  List of defined functions:
  • gaudi_add_library()
Deleted:
<
<
<!-- SyntaxHighlightingPlugin -->
gaudi_add_library(lib_name
                  SOURCES file.cpp file2.cpp...
                  [LINK PUBLIC <lib>... PRIVATE <lib>... INTERFACE <lib>...])

This function builds a shared library with the given parameters.
It also provides the alias ${PROJECT_NAME}::${lib_name}
and configure the installation of the library and its public headers.
/!\ Public headers must be under "${CMAKE_CURRENT_SOURCE_DIR}/include"
    (e.g. ${CMAKE_CURRENT_SOURCE_DIR}/include/GaudiAlg/file.hpp)

lib_name
    the name of the target to build

SOURCES file1.cpp file2.cpp...
    the list of file to compile

LINK PUBLIC <lib>... PRIVATE <lib>... INTERFACE <lib>...
    <lib> can be Package::Lib, MyTarget, SomeLib
    with the same syntax as target_link_libraries()
<!-- end SyntaxHighlightingPlugin -->
 
  • gaudi_add_header_only_library()
Deleted:
<
<
<!-- SyntaxHighlightingPlugin -->
gaudi_add_header_only_library(lib_name
                              [LINK <lib>... ])

This function registers a header only library (a library that only have
header files (.h or .hpp)).
This function does not produce any object files at build time but
it create an interface target that one can link against at configure time.
It also provides the alias ${PROJECT_NAME}::${lib_name}
and configure the installation of the public headers.
/!\ Public headers must be under "${CMAKE_CURRENT_SOURCE_DIR}/include"
    (e.g. ${CMAKE_CURRENT_SOURCE_DIR}/include/GaudiHive/file.hpp)

lib_name
    the name of the target to build

LINK <lib>...
    <lib> can be Package::Lib, MyTarget, SomeLib
    with the same syntax as target_link_libraries() (INTERFACE is implied)
<!-- end SyntaxHighlightingPlugin -->
 
  • gaudi_add_module()
Deleted:
<
<
<!-- SyntaxHighlightingPlugin -->
gaudi_add_module(plugin_name
                 SOURCES file.cpp file2.cpp...
                 [LINK <lib>...]
                 [GENCONF_OPTIONS --opt1=val1 --opt2=val2...])

This function builds a plugin library with the given parameters.
It generates .components files with listcomponents and .confdb
and python modules with genconf.
It also configure the installation.

plugin_name
    the name of the target to build (not possible to link against)

SOURCES file1.cpp file2.cpp...
    the list of file to compile

LINK <lib>...
    <lib> can be Package::Lib, MyTarget, SomeLib
    with the same syntax as target_link_libraries() (PRIVATE is implied)

GENCONF_OPTIONS --opt1=val1 --opt2=val2...
    a list of additional arguments to pass to genconf
    e.g. --user-module=package.module --load-library=library
<!-- end SyntaxHighlightingPlugin -->
 
  • gaudi_add_python_module()
Deleted:
<
<
<!-- SyntaxHighlightingPlugin -->
gaudi_add_python_module(module_name
                        SOURCES file.cpp file2.cpp...
                        [LINK <lib>...]
                        [PACKAGE <path>])

This function builds a compiled python module from the sources
and install it.

SOURCES file1.cpp file2.cpp...
    the list of file to compile

LINK <lib>...
    <lib> can be Package::Lib, MyTarget, SomeLib
    with the same syntax as target_link_libraries() (PRIVATE is implied)
    LINK Python::Module is implied

PACKAGE <path>
    The path to the python package the compiled module should be part of
    and installed with.
    Default value: ${CMAKE_CURRENT_SOURCE_DIR}/python/${package_name}
        ${package_name} is the name of the subdirectory we are in
<!-- end SyntaxHighlightingPlugin -->
 
  • gaudi_add_executable()
Deleted:
<
<
<!-- SyntaxHighlightingPlugin -->
gaudi_add_executable(exe_name
                     SOURCES file.cpp file2.cpp...
                     [LINK <lib>...]
                     [TEST])

This function builds an executable with the given parameters.
It also configure its installation.

exe_name
    the name of the target to build

SOURCES file1.cpp file2.cpp...
    the list of file to compile

LINK <lib>...
    <lib> can be Package::Lib, MyTarget, SomeLib
    with the same syntax as target_link_libraries() (PRIVATE is implied)

TEST
    This option specify that the executable must be added to the test set
    to be run by ctest.
<!-- end SyntaxHighlightingPlugin -->
 
  • gaudi_add_tests()
Deleted:
<
<
<!-- SyntaxHighlightingPlugin -->
gaudi_add_tests(QMTest|nosetests|pytest [test_directory])

This function adds unit tests of a given test framework to the project.
Test names will be inferred from the directory name and files names.

QMTest
    Adds QMTest tests.
    Default test_directory is ${CMAKE_CURRENT_SOURCE_DIR}/tests/qmtest
    /!\ Each time a new .qmt file is added, reconfiguring the project with cmake is mandatory

nosetests
    Adds nosetests tests.
    Default test_directory is ${CMAKE_CURRENT_SOURCE_DIR}/tests/nose
    An imported target called nosetests must exist with a valid imported location.

pytest
    Adds pytest tests.
    Default test_directory is ${CMAKE_CURRENT_SOURCE_DIR}/tests/pytest
    An imported target called pytest must exist with a valid imported location.

test_directory
    The directory containing the test files.
    Providing a value for this argument overrides the default one.
    Do not put a "/" at the end.
<!-- end SyntaxHighlightingPlugin -->
 
  • gaudi_add_dictionary()
Deleted:
<
<
<!-- SyntaxHighlightingPlugin -->
gaudi_add_dictionary(dictionary
                     HEADERFILES header1.h header2.h...
                     SELECTION select.xml
                     [OPTIONS opt1 opt2...]
                     [LINK <lib>...])

This function generates the sources of a ROOT reflex dictionary. (build
target: ${dictionary}-gen)
Then it builds the dictionary as a plugin. (build target: ${dictionary})
Finally it installs the compiled dictionary and the _rdict.pcm files alongside
the other plugins of the project.
Futhermore, all the .rootmap files generated are merged in
${PROJECT_NAME}.rootmap and this file is installed with the shared
libraries of the project.

dictionary
    The name of the target to compile the dictionary.
    By convention, call it <GaudiSubDir>Dict

HEADERFILES header1.h header2.h...
    One or more C++ headers

SELECTION select.xml
    The selection file, XML

OPTIONS opt1 opt2...
    options to pass verbatim to genreflex when generating the sources
    e.g. --debug

LINK <lib>...
    Libraries to link against when building the dictionary.
    <lib> can be Package::Lib, MyTarget, SomeLib
    with the same syntax as target_link_libraries() (PRIVATE is implied)
<!-- end SyntaxHighlightingPlugin -->
 
  • gaudi_install()
Deleted:
<
<
<!-- SyntaxHighlightingPlugin -->
gaudi_install(PYTHON [directory])
gaudi_install(SCRIPTS [directory])
gaudi_install(CMAKE [files|directories...])

First signature: PYTHON
^^^^^^^^^^^^^^^^^^^^^^^

This function installs a python package (and adds it to the temporary
PYTHONPATH used at runtime locally).

directory
    The path to the directory to install (relative to ${CMAKE_CURRENT_SOURCE_DIR}).
    Default value: python/

Second signature: SCRIPTS
^^^^^^^^^^^^^^^^^^^^^^^^^

This function installs a directory containing executable scripts (and adds
it to the temporary PATH used at runtime locally).

directory
    The path to the directory to install (absolute or relative to ${CMAKE_CURRENT_SOURCE_DIR}).
    Default value: scripts/
    The scripts inside this directory must have execution permission.

Third signature: CMAKE
^^^^^^^^^^^^^^^^^^^^^^

This function installs cmake files and directories.

files|directories...
    Paths to files or directories to install (relative to
    ${CMAKE_CURRENT_SOURCE_DIR} or absolute).

Caveat
^^^^^^

If directory is specified without a trailing slash (e.g. mydir), the 
directory itself will be installed.
If directory is specified with a trailing slash (e.g. mydir/), the content
of the directory will be installed.
See: https://cmake.org/cmake/help/latest/command/install.html#directory
<!-- end SyntaxHighlightingPlugin -->
 
  • gaudi_generate_confuserdb()
Deleted:
<
<
<!-- SyntaxHighlightingPlugin -->
gaudi_generate_confuserdb([modules])

This function adds ConfigurableUser specializations
to ${PROJECT_NAME}.confdb.

modules
    the list of modules that contain the configuration
    they must be inside ${CMAKE_CURRENT_SOURCE_DIR}/python/
    default value: ${package_name}.Configuration
        ${package_name} is the name of the subdirectory we are in
<!-- end SyntaxHighlightingPlugin -->
 
  • gaudi_check_python_module()
Deleted:
<
<
<!-- SyntaxHighlightingPlugin -->
gaudi_check_python_module(module1 module2...)

This function checks if the specified python modules are available.

module1 module2...
    a list of python modules
    If one of them cannot be imported by python, an error occurs.
<!-- end SyntaxHighlightingPlugin -->
 
  • gaudi_generate_version_header_file()
Deleted:
<
<
%CODE{"sh"}% gaudi_generate_version_header_file([name])
 
Changed:
<
<
This function generates a file ${name}Version.h in ${CMAKE_CURRENT_BINARY_DIR}/include with the following content (${NAME} is ${name} uppercased): .. code-block:: c
>
>

Building a stack of project at once

With the configuration it is possible to build a stack of project at once. CMake may configure all the projects of the stack in one go, enabling the compilation to be done in parallel for all the projects.
 
Changed:
<
<
#ifndef ${NAME}_VERSION_H #define ${NAME}_VERSION_H
>
>
Example of a stack: Gaudi, LHCb, Lbcom, Rec, Brunel
 
Changed:
<
<
#ifndef CALC_GAUDI_VERSION #define CALC_GAUDI_VERSION(maj,min) (((maj) << 16) + (min)) #endif

#define ${NAME}_MAJOR_VERSION ${PROJECT_VERSION_MAJOR} #define ${NAME}_MINOR_VERSION ${PROJECT_VERSION_MINOR} #define ${NAME}_PATCH_VERSION ${PROJECT_VERSION_PATCH}

#define ${NAME}_VERSION CALC_GAUDI_VERSION(${NAME}_MAJOR_VERSION,${NAME}_MINOR_VERSION)

>
>
%CODE{"sh"}% mkdir workspace ; cd workspace git clone # of all the projects of the desired stack cat < CMakeLists.txt cmake_minimum_required(VERSION 3.15)
 
Changed:
<
<
#endif // ${NAME}_VERSION_H
>
>
project(LHCbFullStack LANGUAGES CXX DESCRIPTION "LHCb full stack")
 
Changed:
<
<
name The name of the project. If no name is provided, the same file is generated but its name is toupper(${PROJECT_NAME})_VERSION.h and it is installed with the other headers.
>
>
add_subdirectory(Gaudi) add_subdirectory(LHCb) # add_subdirectory ... all the other project of the stack EOF
 %ENDCODE%
Line: 654 to 426
 Pro tip: do not document to much GaudiObjDesc so that people begrudge to use GaudiObjDesc.
Deleted:
<
<
-- ThomasCluzel - 2019-08-16
 \ No newline at end of file
Added:
>
>
-- ThomasCluzel - 2019-08-19

Revision 32019-08-16 - ThomasCluzel

Line: 1 to 1
 
META TOPICPARENT name="TWiki.WebPreferences"
This documentation is the updated version of https://twiki.cern.ch/twiki/bin/view/LHCb/GaudiCMakeConfiguration and is based on CMake 3.15.
Line: 135 to 135
 

Configuration of the project

Added:
>
>
The configuration requires at least CMake 3.15. CMake 3.15.0 was released on 2019-07-17.
<!-- SyntaxHighlightingPlugin -->
# Check CMake version
cmake --version
# if version <3.15
export PATH="/cvmfs/lhcb.cern.ch/lib/contrib/CMake/3.15.2/Linux-x86_64/bin:$PATH"
<!-- end SyntaxHighlightingPlugin -->
 The configuration is the step when CMake is called and produces the files for the build system (e.g. make, ninja).
Line: 644 to 654
 Pro tip: do not document to much GaudiObjDesc so that people begrudge to use GaudiObjDesc.
Changed:
<
<
-- ThomasCluzel - 2019-08-15
>
>
-- ThomasCluzel - 2019-08-16
 \ No newline at end of file

Revision 22019-08-15 - ThomasCluzel

Line: 1 to 1
 
META TOPICPARENT name="TWiki.WebPreferences"
Deleted:
<
<
 This documentation is the updated version of https://twiki.cern.ch/twiki/bin/view/LHCb/GaudiCMakeConfiguration and is based on CMake 3.15. It was written after the modernization of the configuration of Gaudi.
Line: 269 to 268
 %ENDCODE%
Added:
>
>

Adding a new sub-project to the project

 If a new sub-project is added to a project, its directory must be
Changed:
<
<
added to the list of sub-projects with:
>
>
added to the list of sub-projects in the top-level CMakeLists.txt alongside with the other sub-projects with:
 
<!-- SyntaxHighlightingPlugin -->
    1add_subdirectory(SubdirName)
<!-- end SyntaxHighlightingPlugin -->
Added:
>
>
The directory of the sub-project must also contain a CMakeLists.txt that looks like the one above.

Adding a new third-party dependency

First, look in the documentation of the dependency. If it uses CMake, it may provide a config file (a file named {DependencyName}Config.cmake). Otherwise, it is necessary to write a find module file (a file named Find{DependencyName}.cmake) that will do the look up of this dependency (find the include directory, find all the libraries, find any other useful files provided by the dependency and create some IMPORTED targets). (Have a look at the other find module files in the project to get an idea of what it should look like. They should be in cmake/modules.)

Then, add the look up of the dependency in the file cmake/{ProjectName}Dependencies.cmake (replace with the name of the dependency and with the minimal required version).

<!-- SyntaxHighlightingPlugin -->
# For mandatory dependencies
find_package(<DependencyName> <minVersion> ${__quiet})
set_package_properties(<DependencyName> PROPERTIES TYPE REQUIRED)

# For optional dependencies
if(GAUDI_USE_<DEPENDENCY_NAME>)
  find_package(<DependencyName> <minVersion> ${__quiet})
  if(CMAKE_FIND_PACKAGE_NAME) # if the lookup is perform from ProjectConfig.cmake
    # then, all optional dependencies become required
    set_package_properties(<DependencyName>  PROPERTIES TYPE REQUIRED)
  else()
    set_package_properties(<DependencyName>  PROPERTIES TYPE RECOMMENDED)
  endif()
endif()
# and add the option GAUDI_USE_<DEPENDENCY_NAME> in the top level =CMakeLists.tx=t
<!-- end SyntaxHighlightingPlugin -->

Finally, it is usable.

<!-- SyntaxHighlightingPlugin -->
gaudi_add_<type>(... LINK ... Dependency::Target ...)
<!-- end SyntaxHighlightingPlugin -->

Removing an old third-party dependency

If a dependency is no longer used (nothing defined by it is used anywhere), it is no use keeping to look for it. In this case, remove the chunk of code that looks for it in cmake/{ProjectName}Dependencies.cmake (see Adding a new third-party dependency).

Then remove the find module file Find{DependencyName}.cmake in cmake/modules if it exists.

 

Gaudi CMake functions to help the configuration

All the gaudi_*() functions are defined by Gaudi. Their content and documentation can be found
Line: 593 to 644
 Pro tip: do not document to much GaudiObjDesc so that people begrudge to use GaudiObjDesc.
Deleted:
<
<
-- ThomasCluzel - 2019-08-12
 \ No newline at end of file
Added:
>
>
-- ThomasCluzel - 2019-08-15

Revision 12019-08-12 - ThomasCluzel

Line: 1 to 1
Added:
>
>
META TOPICPARENT name="TWiki.WebPreferences"

This documentation is the updated version of https://twiki.cern.ch/twiki/bin/view/LHCb/GaudiCMakeConfiguration and is based on CMake 3.15. It was written after the modernization of the configuration of Gaudi.

Introduction

CMake is an Open Source, cross-platform configuration and build tool used in several projects around the world.

Among its advantages we can count the support that comes from a large user base and the CMake configuration language that doubles as a portable and powerful scripting language.

The main drawbacks of CMake are the syntax of its language (not very nice looking) and the lack of support for runtime environment definition, but, thanks to the power of the language, we can overcome the drawbacks.

Here I'll describe how to write the CMake configuration for projects and packages. See also the CMake Documentation.

Understanding and Writing CMake Code

A minimal introduction on the CMake syntax and conventions is mandatory for people who never used it. Info The syntax highlighting in the code blocks is not correct because SyntaxHighlightingPlugin does not understand the CMake language.

In CMake every statement is a function call, written as an identifier followed by optional spaces and the arguments to the function as a space-separated list enclosed in parentheses. The arguments to a function can span over several lines, and double quotes (") can be used to pass arguments containing spaces and new-lines. Examples of functions:

<!-- SyntaxHighlightingPlugin -->
message("hello world!")

if(1 GREATER 0)
  message("this is true")
else()
  message("this is false")
endif()
<!-- end SyntaxHighlightingPlugin -->

One can add comments to the code using # at the beginning of the comment text (spaces preceding # are ignored), like, e.g., in Unix shells and Python:

<!-- SyntaxHighlightingPlugin -->
# I'm a comment
if(TRUE)
     # this is always printed
     message("it's true")
else()
     # this is never printed
     message("it's false")
endif()
<!-- end SyntaxHighlightingPlugin -->

The CMake language supports variables, which are set with the function set and dereferenced with ${...}, e.g.:

<!-- SyntaxHighlightingPlugin -->
set(MyMessage "hello world")
message(${MyMessage})
<!-- end SyntaxHighlightingPlugin -->

Dereferencing of variables can be nested and works also in between double quotes:

<!-- SyntaxHighlightingPlugin -->
set(name MyName)
set(${name}_msg "This is ${name}")
message(${${name}_msg})
<!-- end SyntaxHighlightingPlugin -->

There is something special in the way CMake functions are invoked. CMake functions and macros (similar to functions) accept variable number of arguments and the only separators between arguments are spaces (tabs and new-lines too), so it might not be obvious how to pass optional arguments (like it's done in Python with named arguments). The solution found by CMake developers is to use keyword-separated lists of arguments. For example, we can imagine a function that requires a mandatory argument name and two optional lists of files, C sources and C++ sources. In CMake you could find it invoked like this:

<!-- SyntaxHighlightingPlugin -->
make_a_library(MyLibrary)

make_a_library(MyLibrary C_SOURCES file1.c file2.c file3.c)

make_a_library(MyLibrary CXX_SOURCES file1.cpp file2.cpp file3.cpp)

make_a_library(MyLibrary
               C_SOURCES file1.c file2.c file3.c
               CXX_SOURCES file1.cpp file2.cpp file3.cpp)
<!-- end SyntaxHighlightingPlugin -->

Warning, important Function names are case-insensitive, but variable names are case sensitive as well as string comparison.

CMake Configuration of a Gaudi-based Project

Several steps must be performed to build a Gaudi based project:
  • Set up the environment (if not already set up)
  • Configure the project with CMake (generate Makefile or build.ninja)
  • Compile the source files and link the binaries
  • Test the previously build binaries (optional but recommended)

Set up the environment

To set up the environment, some environment variables need to be set.
  • BINARY_TAG: the variable that describe the platform
  • CMAKE_PREFIX_PATH: is a path-like variable that must contain the list the list of path to:
    • the compiler e.g. g++, clang++ (the compiler may be a wrapper)
    • the build system e.g. make, ninja
    • all third-party dependencies e.g. Boost, ROOT
  • PATH (optional): may contain the paths to the compiler and the build system

There are several ways to set these variables:

  • use export several time (or run a shell script that will do so)
  • source a view (a shell script that sets the aforementioned variables to a directory of symlinks)
  • specify a toolchain to the configuration

With export

<!-- SyntaxHighlightingPlugin -->
export BINARY_TAG="x86_64-centos7-gcc8-opt"
export CMAKE_PREFIX_PATH="/path/to/g++:/path/to/boost:/path/to/ROOT:..."
<!-- end SyntaxHighlightingPlugin -->

With a view

<!-- SyntaxHighlightingPlugin -->
source /cvmfs/sft.cern.ch/lcg/views/LCG_96/x86_64-centos7-gcc8-opt/setup.sh
# the views may lack some stuff
export CMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH:/cvmfs/sft.cern.ch/lcg/releases/LCG_95/vectorclass/1.30/x86_64-centos7-gcc8-opt:/cvmfs/projects.cern.ch/intelsw/psxe/linux/x86_64/2019/vtune_amplifier"
<!-- end SyntaxHighlightingPlugin -->

With a toolchain

<!-- SyntaxHighlightingPlugin -->
# Either use
-D CMAKE_TOOLCHAIN_FILE=/path/to/a/toolchain # at configure time when calling cmake
# or
ln -s /path/to/a/toolchain toolchain.cmake # right away
<!-- end SyntaxHighlightingPlugin -->

Configuration of the project

The configuration is the step when CMake is called and produces the files for the build system (e.g. make, ninja).

Two directories must be specified:

  • the source tree: contains the sources
  • the build tree: will contain the outputs of the build

<!-- SyntaxHighlightingPlugin -->
cmake -S . -B build.$BINARY_TAG
# options can be passed at configure time
cmake -S . -B build.$BINARY_TAG -G Ninja # set the build system
cmake -S . -B build.$BINARY_TAG -D GAUDI_USE_AIDA=OFF # enable/disable a third party dependency
cmake -S . -B build.$BINARY_TAG -D CMAKE_BUILD_TYPE=Developer # select a build type (a set of compile and link options)
cmake -S . -B build.$BINARY_TAG -D CMAKE_TOOLCHAIN_FILE=toolchain.cmake # specify a toolchain
# several options may be specified with: -D ... -D ... -D ...
# ccmake and cmake-gui can be used

cmake -LH build.$BINARY_TAG # to see all the options and their help messages
<!-- end SyntaxHighlightingPlugin -->

Compilation of the project

Once the project is configured, several files are already in the build tree. They will be used to compile the project.

<!-- SyntaxHighlightingPlugin -->
cd build.$BINARY_TAG ; make # or ninja or an IDE
# or directly with CMake
cmake --build build.$BINARY_TAG
<!-- end SyntaxHighlightingPlugin -->

Test the binaries

Good developers test their code. To run the tests:
<!-- SyntaxHighlightingPlugin -->
cd build.$BINARY_TAG ; ctest -j `nproc` --output-on-failure --schedule-random
<!-- end SyntaxHighlightingPlugin -->

The wrapper

Doing all these steps each time may be tedious so there is a Makefile file at the top level of Gaudi-based projects to wrap the call to these commands.

<!-- SyntaxHighlightingPlugin -->
make # configure + compile
make test # run the tests
<!-- end SyntaxHighlightingPlugin -->

Modify the configuration

At the top level directory of a project and in every sub-project (package) there must be one file: CMakeLists.txt

The file at the top level directory describes the build of the whole project:

  • may contain a licence block
  • contains documentation (how to configure it, available options)
  • describes the project (name, version)
  • fetches the dependencies
  • sets options for the build (C++ standard)
  • list all the sub-projects (packages in sub-directories)
  • handles the installation
The files in the sub-projects directories:
  • describes the binaries that will be compiled (libraries, modules, executable, ROOT dictionaries)
  • register tests for these binaries
  • handles the installation of their python packages and scripts

Configuration of sub-projects

Look and feel of typical sub-project CMakeLists.txt:
<!-- SyntaxHighlightingPlugin -->
    1# {licence block if needed}
    2# {SubdirName} subdirectory
    3
    4# Build the library
    5gaudi_add_library(SubdirNameLib
    6                  SOURCES src/Lib/Counter.cpp
    7                          src/Lib/Event.cpp
    8                  LINK PUBLIC GaudiKernel)
    9
   10# Build the plugin
   11gaudi_add_module(SubdirName
   12                 SOURCES src/AbortEvent/AbortEventAlg.cpp
   13                         src/AlgSequencer/HelloWorld.cpp
   14                 LINK GaudiKernel
   15                      GaudiExamplesLib
   16                      ROOT::Tree
   17                      Rangev3::rangev3)
   18if(GAUDI_USE_AIDA) # optional dependency
   19    target_sources(SubdirName PRIVATE src/EvtColsEx/EvtColAlg.cpp
   20                                         src/Histograms/Aida2Root.cpp)
   21    target_link_libraries(SubdirName PRIVATE AIDA::aida)
   22endif()
   23
   24# Build the executable
   25gaudi_add_executable(Allocator
   26                        SOURCES src/Allocator/Allocator.cpp
   27                                src/Allocator/MyClass1.cpp
   28                        LINK SubdirNameLib
   29                            GaudiKernel)
   30
   31# Generate GaudiExamples_user.confdb
   32gaudi_generate_confuserdb()
   33
   34# Tests
   35gaudi_add_tests(QMTest)
   36gaudi_add_tests(nosetests)
   37
   38# Compiled python module
   39gaudi_add_python_module(PyExample
   40                        SOURCES src/PythonModule/Functions.cpp
   41                                src/PythonModule/PyExample.cpp
   42                        LINK Python::Python
   43                             Boost::python)
   44
   45# ROOT dictionaries
   46gaudi_add_dictionary(SubdirNameDict
   47                     HEADERFILES src/IO/dict.h
   48                     SELECTION src/IO/dict.xml
   49                     LINK SubdirNameLib)
   50
   51# Install python modules
   52gaudi_install(PYTHON)
   53# Install other scripts
   54gaudi_install(SCRIPTS)
<!-- end SyntaxHighlightingPlugin -->

If a new sub-project is added to a project, its directory must be added to the list of sub-projects with:

<!-- SyntaxHighlightingPlugin -->
    1add_subdirectory(SubdirName)
<!-- end SyntaxHighlightingPlugin -->

Gaudi CMake functions to help the configuration

All the gaudi_*() functions are defined by Gaudi. Their content and documentation can be found here.

List of defined functions:

  • gaudi_add_library()
<!-- SyntaxHighlightingPlugin -->
gaudi_add_library(lib_name
                  SOURCES file.cpp file2.cpp...
                  [LINK PUBLIC <lib>... PRIVATE <lib>... INTERFACE <lib>...])

This function builds a shared library with the given parameters.
It also provides the alias ${PROJECT_NAME}::${lib_name}
and configure the installation of the library and its public headers.
/!\ Public headers must be under "${CMAKE_CURRENT_SOURCE_DIR}/include"
    (e.g. ${CMAKE_CURRENT_SOURCE_DIR}/include/GaudiAlg/file.hpp)

lib_name
    the name of the target to build

SOURCES file1.cpp file2.cpp...
    the list of file to compile

LINK PUBLIC <lib>... PRIVATE <lib>... INTERFACE <lib>...
    <lib> can be Package::Lib, MyTarget, SomeLib
    with the same syntax as target_link_libraries()
<!-- end SyntaxHighlightingPlugin -->
  • gaudi_add_header_only_library()
<!-- SyntaxHighlightingPlugin -->
gaudi_add_header_only_library(lib_name
                              [LINK <lib>... ])

This function registers a header only library (a library that only have
header files (.h or .hpp)).
This function does not produce any object files at build time but
it create an interface target that one can link against at configure time.
It also provides the alias ${PROJECT_NAME}::${lib_name}
and configure the installation of the public headers.
/!\ Public headers must be under "${CMAKE_CURRENT_SOURCE_DIR}/include"
    (e.g. ${CMAKE_CURRENT_SOURCE_DIR}/include/GaudiHive/file.hpp)

lib_name
    the name of the target to build

LINK <lib>...
    <lib> can be Package::Lib, MyTarget, SomeLib
    with the same syntax as target_link_libraries() (INTERFACE is implied)
<!-- end SyntaxHighlightingPlugin -->
  • gaudi_add_module()
<!-- SyntaxHighlightingPlugin -->
gaudi_add_module(plugin_name
                 SOURCES file.cpp file2.cpp...
                 [LINK <lib>...]
                 [GENCONF_OPTIONS --opt1=val1 --opt2=val2...])

This function builds a plugin library with the given parameters.
It generates .components files with listcomponents and .confdb
and python modules with genconf.
It also configure the installation.

plugin_name
    the name of the target to build (not possible to link against)

SOURCES file1.cpp file2.cpp...
    the list of file to compile

LINK <lib>...
    <lib> can be Package::Lib, MyTarget, SomeLib
    with the same syntax as target_link_libraries() (PRIVATE is implied)

GENCONF_OPTIONS --opt1=val1 --opt2=val2...
    a list of additional arguments to pass to genconf
    e.g. --user-module=package.module --load-library=library
<!-- end SyntaxHighlightingPlugin -->
  • gaudi_add_python_module()
<!-- SyntaxHighlightingPlugin -->
gaudi_add_python_module(module_name
                        SOURCES file.cpp file2.cpp...
                        [LINK <lib>...]
                        [PACKAGE <path>])

This function builds a compiled python module from the sources
and install it.

SOURCES file1.cpp file2.cpp...
    the list of file to compile

LINK <lib>...
    <lib> can be Package::Lib, MyTarget, SomeLib
    with the same syntax as target_link_libraries() (PRIVATE is implied)
    LINK Python::Module is implied

PACKAGE <path>
    The path to the python package the compiled module should be part of
    and installed with.
    Default value: ${CMAKE_CURRENT_SOURCE_DIR}/python/${package_name}
        ${package_name} is the name of the subdirectory we are in
<!-- end SyntaxHighlightingPlugin -->
  • gaudi_add_executable()
<!-- SyntaxHighlightingPlugin -->
gaudi_add_executable(exe_name
                     SOURCES file.cpp file2.cpp...
                     [LINK <lib>...]
                     [TEST])

This function builds an executable with the given parameters.
It also configure its installation.

exe_name
    the name of the target to build

SOURCES file1.cpp file2.cpp...
    the list of file to compile

LINK <lib>...
    <lib> can be Package::Lib, MyTarget, SomeLib
    with the same syntax as target_link_libraries() (PRIVATE is implied)

TEST
    This option specify that the executable must be added to the test set
    to be run by ctest.
<!-- end SyntaxHighlightingPlugin -->
  • gaudi_add_tests()
<!-- SyntaxHighlightingPlugin -->
gaudi_add_tests(QMTest|nosetests|pytest [test_directory])

This function adds unit tests of a given test framework to the project.
Test names will be inferred from the directory name and files names.

QMTest
    Adds QMTest tests.
    Default test_directory is ${CMAKE_CURRENT_SOURCE_DIR}/tests/qmtest
    /!\ Each time a new .qmt file is added, reconfiguring the project with cmake is mandatory

nosetests
    Adds nosetests tests.
    Default test_directory is ${CMAKE_CURRENT_SOURCE_DIR}/tests/nose
    An imported target called nosetests must exist with a valid imported location.

pytest
    Adds pytest tests.
    Default test_directory is ${CMAKE_CURRENT_SOURCE_DIR}/tests/pytest
    An imported target called pytest must exist with a valid imported location.

test_directory
    The directory containing the test files.
    Providing a value for this argument overrides the default one.
    Do not put a "/" at the end.
<!-- end SyntaxHighlightingPlugin -->
  • gaudi_add_dictionary()
<!-- SyntaxHighlightingPlugin -->
gaudi_add_dictionary(dictionary
                     HEADERFILES header1.h header2.h...
                     SELECTION select.xml
                     [OPTIONS opt1 opt2...]
                     [LINK <lib>...])

This function generates the sources of a ROOT reflex dictionary. (build
target: ${dictionary}-gen)
Then it builds the dictionary as a plugin. (build target: ${dictionary})
Finally it installs the compiled dictionary and the _rdict.pcm files alongside
the other plugins of the project.
Futhermore, all the .rootmap files generated are merged in
${PROJECT_NAME}.rootmap and this file is installed with the shared
libraries of the project.

dictionary
    The name of the target to compile the dictionary.
    By convention, call it <GaudiSubDir>Dict

HEADERFILES header1.h header2.h...
    One or more C++ headers

SELECTION select.xml
    The selection file, XML

OPTIONS opt1 opt2...
    options to pass verbatim to genreflex when generating the sources
    e.g. --debug

LINK <lib>...
    Libraries to link against when building the dictionary.
    <lib> can be Package::Lib, MyTarget, SomeLib
    with the same syntax as target_link_libraries() (PRIVATE is implied)
<!-- end SyntaxHighlightingPlugin -->
  • gaudi_install()
<!-- SyntaxHighlightingPlugin -->
gaudi_install(PYTHON [directory])
gaudi_install(SCRIPTS [directory])
gaudi_install(CMAKE [files|directories...])

First signature: PYTHON
^^^^^^^^^^^^^^^^^^^^^^^

This function installs a python package (and adds it to the temporary
PYTHONPATH used at runtime locally).

directory
    The path to the directory to install (relative to ${CMAKE_CURRENT_SOURCE_DIR}).
    Default value: python/

Second signature: SCRIPTS
^^^^^^^^^^^^^^^^^^^^^^^^^

This function installs a directory containing executable scripts (and adds
it to the temporary PATH used at runtime locally).

directory
    The path to the directory to install (absolute or relative to ${CMAKE_CURRENT_SOURCE_DIR}).
    Default value: scripts/
    The scripts inside this directory must have execution permission.

Third signature: CMAKE
^^^^^^^^^^^^^^^^^^^^^^

This function installs cmake files and directories.

files|directories...
    Paths to files or directories to install (relative to
    ${CMAKE_CURRENT_SOURCE_DIR} or absolute).

Caveat
^^^^^^

If directory is specified without a trailing slash (e.g. mydir), the 
directory itself will be installed.
If directory is specified with a trailing slash (e.g. mydir/), the content
of the directory will be installed.
See: https://cmake.org/cmake/help/latest/command/install.html#directory
<!-- end SyntaxHighlightingPlugin -->
  • gaudi_generate_confuserdb()
<!-- SyntaxHighlightingPlugin -->
gaudi_generate_confuserdb([modules])

This function adds ConfigurableUser specializations
to ${PROJECT_NAME}.confdb.

modules
    the list of modules that contain the configuration
    they must be inside ${CMAKE_CURRENT_SOURCE_DIR}/python/
    default value: ${package_name}.Configuration
        ${package_name} is the name of the subdirectory we are in
<!-- end SyntaxHighlightingPlugin -->
  • gaudi_check_python_module()
<!-- SyntaxHighlightingPlugin -->
gaudi_check_python_module(module1 module2...)

This function checks if the specified python modules are available.

module1 module2...
    a list of python modules
    If one of them cannot be imported by python, an error occurs.
<!-- end SyntaxHighlightingPlugin -->
  • gaudi_generate_version_header_file()
<!-- SyntaxHighlightingPlugin -->
gaudi_generate_version_header_file([name])

This function generates a file ${name}Version.h in ${CMAKE_CURRENT_BINARY_DIR}/include
with the following content (${NAME} is ${name} uppercased):
.. code-block:: c

    #ifndef ${NAME}_VERSION_H
    #define ${NAME}_VERSION_H

    #ifndef CALC_GAUDI_VERSION
    #define CALC_GAUDI_VERSION(maj,min) (((maj) << 16) + (min))
    #endif

    #define ${NAME}_MAJOR_VERSION ${PROJECT_VERSION_MAJOR}
    #define ${NAME}_MINOR_VERSION ${PROJECT_VERSION_MINOR}
    #define ${NAME}_PATCH_VERSION ${PROJECT_VERSION_PATCH}

    #define ${NAME}_VERSION CALC_GAUDI_VERSION(${NAME}_MAJOR_VERSION,${NAME}_MINOR_VERSION)

    #endif // ${NAME}_VERSION_H

name
    The name of the project.
    If no name is provided, the same file is generated but its name is
    toupper(${PROJECT_NAME})_VERSION.h and it is installed with the
    other headers.
<!-- end SyntaxHighlightingPlugin -->

Using GaudiObjDesc (LHCb-specific)

Warning, important GaudiObjDesc has not been modernized because it should be removed soon. Do not use GaudiObjDesc in future project. However, if you need to maintain a package that uses GaudiObjDesc have a look at the old documentation here

Pro tip: do not document to much GaudiObjDesc so that people begrudge to use GaudiObjDesc.

-- ThomasCluzel - 2019-08-12

 
This site is powered by the TWiki collaboration platform Powered by PerlCopyright & 2008-2019 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback