Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
CMakeLists.txt 10.85 KiB
#####################################################################################
# (c) Copyright 1998-2023 CERN for the benefit of the LHCb and ATLAS collaborations #
#                                                                                   #
# This software is distributed under the terms of the Apache version 2 licence,     #
# copied verbatim in the file "LICENSE".                                            #
#                                                                                   #
# In applying this licence, CERN does not waive the privileges and immunities       #
# granted to it by virtue of its status as an Intergovernmental Organization        #
# or submit itself to any jurisdiction.                                             #
#####################################################################################
#[========================================================================[.rst:
Gaudi
-----

This file is the top level CMakeLists.txt that describes the whole
configuration of the build of Gaudi.

A few commands
^^^^^^^^^^^^^^

* Configure: ``cmake -S . -B build.$BINARY_TAG -D CMAKE_BUILD_TYPE=Developer [-G Ninja]``
* Compile: ``cmake --build build.$BINARY_TAG -j `nproc` ``
* Run tests: ``cd build.$BINARY_TAG ; ctest -j `nproc` ; cd ..``
* Install: ``cmake --install build.$BINARY_TAG [--prefix path/to/where/you/want]``
* Package (zip+rpm): ``cmake --build build.$BINARY_TAG -t package``

List of available options
^^^^^^^^^^^^^^^^^^^^^^^^^

An option is a cached variable that can be turned ON or OFF.
To get descriptions and values of these options:
  ``cmake -N -LH build.$BINARY_TAG``
after the configuration or use ccmake or cmake-gui.

* Optional dependencies
  * GAUDI_USE_AIDA
  * GAUDI_USE_XERCESC
  * GAUDI_USE_CLHEP
  * GAUDI_USE_HEPPDT
  * GAUDI_USE_CPPUNIT
  * GAUDI_USE_UNWIND
  * GAUDI_USE_GPERFTOOLS
  * GAUDI_USE_DOXYGEN
  * GAUDI_USE_INTELAMPLIFIER
  * GAUDI_USE_JEMALLOC
* Install options
  * GAUDI_INSTALL_OPTIONAL
* Install layout variables
  * CMAKE_INSTALL_BINDIR
  * CMAKE_INSTALL_LIBDIR
  * CMAKE_INSTALL_INCLUDEDIR
  * GAUDI_INSTALL_PLUGINDIR
  * GAUDI_INSTALL_PYTHONDIR
  * GAUDI_INSTALL_CONFIGDIR
* For sanitized build
  * GAUDI_GENCONF_NO_FAIL
* Compile options
  * GAUDI_ENABLE_GAUDIALG
  * GAUDI_ENABLE_GAUDIPARTPROP
  * GAUDI_REFLEX_COMPONENT_ALIASES
* Doxygen
  * DOXYGEN_WITH_LOCAL_MATHJAX
  * DOXYGEN_WITH_CPPREFERENCE_LINKS

To disable the build of tests, set the option ``BUILD_TESTING`` to FALSE.

When to re-configure the project manually?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* When a new .qmt file is added.
* When a new python package is added in a python/ folder that already
  had one installed python package.
* When a new release.notes*.html is added to GaudiRelease/doc/.

TWiki documentation
^^^^^^^^^^^^^^^^^^^

Developer's guide: `<https://twiki.cern.ch/twiki/bin/view/LHCb/GaudiCMake315Configuration>`_
Maintainer's guide: `<https://twiki.cern.ch/twiki/bin/view/LHCb/MaintainGaudiCMake315Configuration>`_

#]========================================================================]

cmake_minimum_required(VERSION 3.15)

project(Gaudi VERSION 38.0
              LANGUAGES CXX
              DESCRIPTION "Gaudi Software Framework"
              HOMEPAGE_URL "https://cern.ch/gaudi")

# Add the "Developer" build type
include(cmake/DeveloperBuildType.cmake)

# set RPATH (currently only on macOS)
if(APPLE)
  include(cmake/GaudiRPath.cmake)
endif()

# Set up the GAUDI_ATOMIC_LIBS variable
include(cmake/GaudiAtomicLibs.cmake)

# Import Gaudi functions (gaudi_*) ==> for documentation look in the file
include(cmake/GaudiToolbox.cmake)

# Export the list of compile commands
set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE BOOL "Enable/Disable output of compile_commands.json" FORCE)

set(GAUDI_USE_PYTHON_MAJOR 3 CACHE STRING "Major version of Python to use")
string(APPEND GAUDI_OPTIONAL_DEPENDENCIES "set(GAUDI_USE_PYTHON_MAJOR ${GAUDI_USE_PYTHON_MAJOR})\n")

# Find all the dependencies of the project
list(PREPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules") # (Find*.cmake)
include(cmake/GaudiDependencies.cmake)

string(APPEND GAUDI_OPTIONAL_DEPENDENCIES "
set(GAUDI_ENABLE_GAUDIALG ${GAUDI_ENABLE_GAUDIALG})
set(GAUDI_ENABLE_GAUDIPARTPROP ${GAUDI_ENABLE_GAUDIPARTPROP})
")

# The C++ standard used must be the same as ROOT's
if(NOT GAUDI_CXX_STANDARD)
  # Check if ROOT_CXX_STANDARD is already defined
  if(DEFINED ROOT_CXX_STANDARD)
    message(STATUS "ROOT_CXX_STANDARD is already defined by ROOT. Using it...")
  else()
    # Deduce CXX_STANDARD from ROOT_CXX_FLAGS
    set(ROOT_CXX_FLAGS_TEMP ${ROOT_CXX_FLAGS}) # Use a temporary variable to avoid modifying the original
    separate_arguments(ROOT_CXX_FLAGS_TEMP)
    list(FILTER ROOT_CXX_FLAGS_TEMP INCLUDE REGEX "-std=(c|gnu)\\+\\+[0-9]+")
    list(TRANSFORM ROOT_CXX_FLAGS_TEMP REPLACE "-std=(c|gnu)\\+\\+([0-9]+)" "\\2")
    if(NOT ROOT_CXX_FLAGS_TEMP)
      message(FATAL_ERROR "Cannot find the C++ standard of ROOT")
    endif()
    list(GET ROOT_CXX_FLAGS_TEMP 0 ROOT_CXX_STANDARD)
  endif()
  set(GAUDI_CXX_STANDARD ${ROOT_CXX_STANDARD} CACHE STRING "The version of C++ used to compile Gaudi")
endif()
message(STATUS "Gaudi will be built using C++${GAUDI_CXX_STANDARD} standard.")
set(CMAKE_CXX_STANDARD ${GAUDI_CXX_STANDARD})
set(CMAKE_CXX_STANDARD_REQUIRED TRUE) # do not fall back on older version
set(CMAKE_CXX_EXTENSIONS OFF) # strict c++.. instead of gnu++..

# Enable testing with CTest/CDash
include(CTest)

# These are test-only, private dependencies
if(BUILD_TESTING)
  find_package(Catch2 REQUIRED)
  include(Catch)
endif()

# Include sub-projects one by one without introducing dependency conflicts
add_subdirectory(GaudiPluginService)
add_subdirectory(GaudiPolicy)
add_subdirectory(GaudiKernel)
add_subdirectory(GaudiConfiguration)
add_subdirectory(GaudiCoreSvc)
add_subdirectory(GaudiUtils)
add_subdirectory(Gaudi)
add_subdirectory(GaudiAlg)
add_subdirectory(GaudiFunctional)
add_subdirectory(GaudiAud)
add_subdirectory(GaudiCommonSvc)
add_subdirectory(GaudiHive)
add_subdirectory(GaudiMonitor)
add_subdirectory(GaudiMP)
add_subdirectory(GaudiPartProp)
add_subdirectory(GaudiProfiling)
add_subdirectory(GaudiPython)
add_subdirectory(GaudiRelease)
add_subdirectory(GaudiSvc)
add_subdirectory(PartPropSvc)
add_subdirectory(RootCnv)
add_subdirectory(RootHistCnv)
add_subdirectory(GaudiExamples)

# Generate GAUDI_VERSION.h
gaudi_generate_version_header_file()

# Framework level tests
# Test scripts inside cmake/
gaudi_add_pytest(cmake/extract_qmtest_metadata.py
  PREFIX cmake.doctest.
  ROOT_DIR cmake
  OPTIONS --doctest-modules
)

if(NOT PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME) # If we are building the full stack as one project
  # we do not install nor package nor register CMake tests
  # but we add Gaudi's CMake modules to the CMAKE_MODULE_PATH for downstream projects
  list(PREPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
  set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} PARENT_SCOPE)
  return()
endif()

# Unit tests of gaudi_* functions
include(cmake/tests/testGaudiToolbox.cmake)
# Unit tests of the installation
include(cmake/tests/testGaudiInstallation.cmake)
# Unit tests of Gaudi as dependency in a downstream project (with config files)
include(cmake/tests/testGaudiDownstream.cmake)

# Installation of Gaudi
include(CMakePackageConfigHelpers)
# Generate the config files
configure_package_config_file(cmake/GaudiConfig.cmake.in ${PROJECT_NAME}Config.cmake
  INSTALL_DESTINATION "${GAUDI_INSTALL_CONFIGDIR}"
  PATH_VARS CMAKE_INSTALL_BINDIR CMAKE_INSTALL_LIBDIR CMAKE_INSTALL_INCLUDEDIR
            GAUDI_INSTALL_PLUGINDIR GAUDI_INSTALL_PYTHONDIR
  NO_CHECK_REQUIRED_COMPONENTS_MACRO)
write_basic_package_version_file(${PROJECT_NAME}ConfigVersion.cmake
  COMPATIBILITY AnyNewerVersion)
# Install the set of exported targets
install(EXPORT ${PROJECT_NAME} NAMESPACE ${PROJECT_NAME}::
            DESTINATION "${CMAKE_INSTALL_PREFIX}"
        FILE "${PROJECT_NAME}Targets.cmake"
            DESTINATION "${GAUDI_INSTALL_CONFIGDIR}")
# Install cmake files for downstream project to be able to use Gaudi
gaudi_install(CMAKE cmake/GaudiToolbox.cmake
                    cmake/header_build_test.tpl
                    cmake/GaudiDependencies.cmake
                    cmake/DeveloperBuildType.cmake
                    "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
                    "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
                    cmake/modules) # Find*.cmake

install(PROGRAMS
        cmake/extract_qmtest_metadata.py # used in gaudi_add_tests(QMTest)
        cmake/scan_dict_deps.py # used in gaudi_add_dictionary(...)
    DESTINATION "${GAUDI_INSTALL_CONFIGDIR}"
)

# Add an uninstall target
add_custom_target(uninstall
  COMMAND test -f ${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt &&
          xargs rm < ${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt &&
          rm ${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt &&
          echo ${PROJECT_NAME} uninstalled successfully. ||
          echo ${PROJECT_NAME} has not been installed yet or you need to be root to uninstall.
  COMMENT "Uninstalling ${PROJECT_NAME}")

# CPack configuration
set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
set(CPACK_PACKAGE_VENDOR "CERN-LHCb")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_DESCRIPTION}")
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
foreach(v IN ITEMS MAJOR MINOR PATCH)
   set(CPACK_PACKAGE_VERSION_${v} ${PROJECT_VERSION_${v}})
endforeach()
if(DEFINED BINARY_TAG)
  set(CPACK_SYSTEM_NAME ${BINARY_TAG})
elseif(DEFINED ENV{BINARY_TAG})
  set(CPACK_SYSTEM_NAME $ENV{BINARY_TAG})
endif()
set(CPACK_GENERATOR "ZIP;RPM") # package format
# The following line is needed to prevent the compilation of python modules before packaging (an incorrect version of python may be used).
# FIXME: the day we can tell CMake to prepend the call to rpm by the run script, do it and remove this line (something like ``set(CPACK_RPM_LAUNCHER ${CMAKE_BINARY_DIR}/run)``)
set(CPACK_RPM_SPEC_MORE_DEFINE "%global __os_install_post %(echo '%{__os_install_post}' | sed -e 's!/usr/lib[^[:space:]]*/brp-python-bytecompile[[:space:]].*$!!g')")
# -- for the sources
set(CPACK_SOURCE_IGNORE_FILES "/InstallArea/;/build\\\\..*/;/\\\\.git/;/\\\\.git.*")
set(CPACK_SOURCE_GENERATOR "ZIP;RPM")
include(CPack)

# Set the version of the project as a cache variable to be seen by other
# projects in the same super-project.
set(${PROJECT_NAME}_VERSION "${PROJECT_VERSION}" CACHE STRING "Version of ${PROJECT_NAME}" FORCE)

# Optionally enable compatibility with old-style CMake configurations, via helper module
option(GAUDI_LEGACY_CMAKE_SUPPORT "Enable compatibility with old-style CMake builds" "$ENV{GAUDI_LEGACY_CMAKE_SUPPORT}")
if(GAUDI_LEGACY_CMAKE_SUPPORT)
  find_file(legacy_cmake_config_support NAMES LegacyGaudiCMakeSupport.cmake)
  if(legacy_cmake_config_support)
    include(${legacy_cmake_config_support})
  else()
    message(FATAL_ERROR "GAUDI_LEGACY_CMAKE_SUPPORT set to TRUE, but cannot find LegacyGaudiCMakeSupport.cmake")
  endif()
endif()