diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index b5d77d29aaca90a0f84b0e142b6cb0875df11242..11e88d05baddb93a285e5f50cd62fc881755176e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -3,7 +3,56 @@ image: gitlab-registry.cern.ch/ci-tools/ci-worker:cc7
 before_script:
     - source /cvmfs/cms.cern.ch/cmsset_default.sh
     - shopt -s expand_aliases  # allows aliases like cmsenv to be used
-    - yum install -y cmake3 openssl-devel python3 zsh
+    - yum install -y openssl-devel python3 zsh
+
+installation_cmake:
+    stage: build
+    variables:
+        GIT_STRATEGY: clone
+    tags:
+        - cvmfs
+    artifacts:
+        paths:
+        - Installer/
+    script:
+        - source /cvmfs/sft.cern.ch/lcg/views/LCG_104/x86_64-centos7-gcc12-opt/setup.sh 
+        # All the cd and mv gymnastics below is there to make sure install.sh
+        # picks up the version of Core we want to test.
+        # We start within a copy of the right version of Core. Rename it so we
+        # can move it more easily later.
+        - REPO=$PWD
+        - cd ..
+        - mv $REPO $REPO.bak
+        # Create an empty dir with the same name so GitLab copies artifacts.
+        - mkdir $REPO
+        - cd $REPO
+        # Now get the installer and run it.
+        - git clone https://gitlab.cern.ch/lmoureau/Darwin.git -b feature/cmake Installer  # TODO
+        # Move the backup repo to the installer folder. The installer will pick it up.
+        - mv $REPO.bak Installer/Core
+        # Compile everything (with ninja!)
+        - cmake Installer -B build -G Ninja
+        - cmake --build build -j
+
+test_cmake:
+    stage: test
+    variables:
+        GIT_STRATEGY: none
+    tags:
+        - cvmfs
+    artifacts:
+        when: always
+        paths:
+          - Installer/Core.build/bin/printDarwinSoftwareVersion
+          - Installer/Core.build/test_report.xml
+          - Installer/Core.build/Testing/Temporary/LastTest.log
+        reports:
+          junit: Installer/Core.build/test_report.xml
+    script:
+        - source /cvmfs/sft.cern.ch/lcg/views/LCG_104/x86_64-centos7-gcc12-opt/setup.sh
+        - cd Installer/Core.build
+        - ctest --output-junit test_report.xml -j$(nproc)
+
 
 installation:
     stage: build
@@ -15,6 +64,7 @@ installation:
         paths:
         - DAS/
     script:
+        - yum install -y cmake3
         # All the cd and mv gymnastics below is there to make sure install.sh
         # picks up the version of Core we want to test.
         # We start within a copy of the right version of Core. Rename it so we
@@ -62,6 +112,7 @@ analysis:
         GIT_STRATEGY: none
     tags:
         - cvmfs
+    allow_failure: true
     artifacts:
         when: on_failure
         paths:
@@ -73,66 +124,6 @@ analysis:
         - src/Core/Ntupliser/test/runAnalysis.sh test/mc test/MINIAODSIMv2-DYToLL_M-50_13TeV_pythia8_cff-UL18.root yes
         - src/Core/Ntupliser/test/runAnalysis.sh test/data test/MINIAODv2-DYToLL_M-50_13TeV_pythia8_cff-UL18.root no
 
-common_tools:
-    stage: test
-    variables:
-        GIT_STRATEGY: none
-    tags:
-        - cvmfs
-    script:
-        - cd DAS/CMSSW_*
-        - cmsenv
-        - test/$SCRAM_ARCH/testGenericSFApplier -l all
-
-helpers:
-    stage: test
-    tags:
-        - cvmfs
-    variables:
-        GIT_STRATEGY: none
-    script:
-        - cd DAS/CMSSW_*
-        - cmsenv
-        - src/Core/Ntupliser/test/runHelpers.sh
-
-objects:
-    stage: test
-    tags:
-        - cvmfs
-    variables:
-        GIT_STRATEGY: none
-    script:
-        - cd DAS/CMSSW_*
-        - cmsenv
-        - test/$SCRAM_ARCH/Weight -l all
-        - test/$SCRAM_ARCH/PhysicsObject -l all
-        - test/$SCRAM_ARCH/Jet -l all
-        - test/$SCRAM_ARCH/Lepton -l all
-        - test/$SCRAM_ARCH/Photon -l all
-        - test/$SCRAM_ARCH/Di -l all
-
-unfolding:
-    stage: test
-    tags:
-        - cvmfs
-    variables:
-        GIT_STRATEGY: none
-    script:
-        - cd DAS/CMSSW_*
-        - cmsenv
-        - test/$SCRAM_ARCH/testUnfold -l all
-
-toy:
-    stage: test
-    tags:
-        - cvmfs
-    variables:
-        GIT_STRATEGY: none
-    script:
-        - cd DAS/CMSSW_*
-        - cmsenv
-        - test/$SCRAM_ARCH/testToy -l all
-
 pages:
     stage: deploy
     variables:
diff --git a/BTagging/CMakeLists.txt b/BTagging/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..61b22b60915ad03f705d5e8c61a1dc030fd33302
--- /dev/null
+++ b/BTagging/CMakeLists.txt
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+core_add_library(SOURCES BTagCalibration.cc)
+core_add_executable(applyBTagSF)
+core_add_executable(getBTagBinnedDiscriminant)
+core_add_executable(getBTagFraction NO_EXAMPLE)
+core_add_executable(getBTagPerformance NO_EXAMPLE)
diff --git a/BTagging/bin/BuildFile.xml b/BTagging/bin/BuildFile.xml
deleted file mode 100644
index 5113252b047c701438d68ecda931482514e5c5ed..0000000000000000000000000000000000000000
--- a/BTagging/bin/BuildFile.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<flags CXXFLAGS="-g -DDEBUG -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<lib name="stdc++fs" />
-
-<use name="darwin" />
-
-<use name="root" />
-<use name="rootmath" />
-<use name="rootgraphics"/>
-
-<use name="Core/Objects" />
-<use name="Core/CommonTools" />
-
-<bin name="getBTagBinnedDiscriminant" file="getBTagBinnedDiscriminant.cc" />
-<bin name="getBTagFraction" file="getBTagFraction.cc" />
-<bin name="getBTagPerformance" file="getBTagPerformance.cc" />
-
-<bin name="applyBTagSF" file="applyBTagSF.cc">
-    <use name="Core/BTagging" />
-</bin> 
diff --git a/BTagging/bin/applyBTagSF.cc b/BTagging/bin/applyBTagSF.cc
index 9747c1d3fceeac5baf2fbd866ab80b678ba0cc50..da9a408b01a6a797b51d955d35ce551147c01caf 100644
--- a/BTagging/bin/applyBTagSF.cc
+++ b/BTagging/bin/applyBTagSF.cc
@@ -171,7 +171,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/BTagging/bin/getBTagBinnedDiscriminant.cc b/BTagging/bin/getBTagBinnedDiscriminant.cc
index 72eb59e70b6db644e9bbde7637013c893e0d6817..9e4e95d0e5f20d675e43b3b997fd58e86fe2c210 100644
--- a/BTagging/bin/getBTagBinnedDiscriminant.cc
+++ b/BTagging/bin/getBTagBinnedDiscriminant.cc
@@ -122,7 +122,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/BTagging/bin/getBTagFraction.cc b/BTagging/bin/getBTagFraction.cc
index 10936158dc6b0a0d9615b49dfd2c087fba0fd121..0b3362772cd1a2abbf227e9c5f49bdce07b559f9 100644
--- a/BTagging/bin/getBTagFraction.cc
+++ b/BTagging/bin/getBTagFraction.cc
@@ -76,7 +76,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/BTagging/bin/getBTagPerformance.cc b/BTagging/bin/getBTagPerformance.cc
index f5f1bccbb3591b553e2d1f6453e91c2d4fc92201..be5ec85bffd59406217d995db7517cd930003991 100644
--- a/BTagging/bin/getBTagPerformance.cc
+++ b/BTagging/bin/getBTagPerformance.cc
@@ -80,7 +80,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/BTagging/src/BuildFile.xml b/BTagging/src/BuildFile.xml
deleted file mode 100644
index 6962fdc9de2ee86aba6b6a7c9c166f6617cc2c12..0000000000000000000000000000000000000000
--- a/BTagging/src/BuildFile.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<flags CXXFLAGS="-g -DDEBUG -Wall -std=c++17" />
-
-<use name="root" />
-<use name="rootmath" />
-<use name="rootgraphics" />
-
-<export>
-    <lib name="CoreBTagging"/>
-</export>
-
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2cea66bf1becbac7cdd4bb3403c2abf035ecddd1
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+cmake_minimum_required(VERSION 3.20..3.26 FATAL_ERROR)
+
+project(Core
+        VERSION 3.0
+        DESCRIPTION "Das Analysis System"
+        HOMEPAGE_URL https://dasanalysissystem.docs.cern.ch/
+        LANGUAGES CXX)
+
+# Forbid in-source builds
+if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
+    message(FATAL_ERROR "${CMAKE_PROJECT_NAME} does not support in-source builds")
+endif()
+
+# Import vendored CMake modules
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+
+# Dependencies
+find_package(Darwin 1.0 REQUIRED)
+find_package(Eigen3 3.4 REQUIRED NO_MODULE)
+find_package(TUnfold 17.9 REQUIRED)
+include(GNUInstallDirs)
+include(CoreHelpers)
+
+# These settings affect all compilations so we set them here
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+include_directories("${CMAKE_SOURCE_DIR}/..")  # TODO
+
+add_compile_definitions("DARWIN_GIT_REPO=\"${CMAKE_SOURCE_DIR}\"")
+add_compile_definitions("DARWIN_EXAMPLE=\"${CMAKE_SOURCE_DIR}/CommonTools/doc/example.info\"")
+
+# https://github.com/root-project/root/issues/8308#issuecomment-1143791946
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
+
+# Support modules
+add_subdirectory(CommonTools)
+add_subdirectory(Objects)
+
+# Physics modules
+add_subdirectory(BTagging)
+#add_subdirectory(JEC)
+add_subdirectory(JetObservables)
+add_subdirectory(JetVetoMaps)
+add_subdirectory(Muons)
+add_subdirectory(Normalisation)
+add_subdirectory(Ntupliser)
+add_subdirectory(Photons)
+add_subdirectory(Prefiring)
+add_subdirectory(PUprofile)
+add_subdirectory(PUstaubSauger)
+add_subdirectory(Trigger)
+add_subdirectory(Unfolding)
+add_subdirectory(Uncertainties)  # Needs to come after unfolding
diff --git a/CommonTools/CMakeLists.txt b/CommonTools/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c710f0a06effa53b4ae6c96b67b2380f9e176c25
--- /dev/null
+++ b/CommonTools/CMakeLists.txt
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+core_add_library(
+    SOURCES ControlPlots.cc
+    TESTS   templateEventLoop templateSimpleExec testGenericSFApplier
+)
+install(PROGRAMS scripts/template DESTINATION "${CMAKE_INSTALL_BINDIR}")
diff --git a/CommonTools/scripts/template b/CommonTools/scripts/template
old mode 100755
new mode 100644
index 794d0850f0a3c3d8261015706cff4023a0aa0361..ac4a619f836de1d39095dc7a5f0f44e9bbd080bc
--- a/CommonTools/scripts/template
+++ b/CommonTools/scripts/template
@@ -1,52 +1,142 @@
-#!/bin/zsh
+#! /usr/bin/env python3
 
-if [[ "${PWD##*/}" != "bin" ]]
-then
-    echo "You should run this command from a bin directory"
-    exit 1
-fi
+import argparse
+from pathlib import Path
+from typing import Optional
 
-if [[ $# -le 1 ]]
-then
-    echo "template type newname"
-    echo "\twhere\ttype = EventLoop or SimpleExec"
-    echo "\t     \tnewname = name of new executable"
-    exit 1
-fi
 
-typ=$1
-newname=$2
+def find_git_root(location: Path) -> Optional[Path]:
+    """
+    Finds the root of the git repo to which `location` belongs.
+    """
 
-template="$CMSSW_BASE/src/Core/CommonTools/test/template$typ.cc"
-newexec=$newname.cc
+    # Git doesn't discover across filesystems by default
+    if location.is_mount():
+        return None
 
-if [[ ! -f $template ]]
-then
-    #ls $template
-    echo "$typ is not recognised"
-    exit 1
-fi
+    # Found it!
+    if (location / '.git').is_dir():
+        return location
 
-if [[ -f $newexec ]]
-then
-    echo "$newexec already exists"
-    exit 1
-fi
+    # Check the parent folder
+    return find_git_root(location.parent)
 
-cat $template | sed "s/$typ/$newname/g" > $newname.cc
 
-echo "A new file has been created: $newname.cc"
+def deduce_module_name(here: Path, git_root: Path) -> str:
+    """
+    Deduces the module name from the current directory.
+    """
 
-if [[ ! -f BuildFile.xml ]]
-then
-    echo "<flags CXXFLAGS=\"-g -DDEBUG -O3 -std=c++17\" />\n<flags CPPDEFINES='DARWIN_GIT_REPO=\"\$(CMSSW_BASE)/src/Core\"'/>\n<flags CPPDEFINES='DARWIN_EXAMPLE=\"\$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>\n\n<use name=\"root\" />\n\n<use name=\"Core/Objects\" />\n\n<use name=\"Core/CommonTools\" />\n\n" > BuildFile.xml
+    if here == git_root:
+        raise ValueError('Cannot deduce module name.')
 
-    echo "A new BuildFile has been created."
-fi
+    return here.relative_to(git_root).parts[0]
 
-echo "<bin name=\"$newname\" file=\"$newname.cc\" />" >> BuildFile.xml
 
+def get_template(git_root: Path, type: str) -> str:
+    """
+    Loads the code of a template executable.
+    """
 
-echo "A new entry has been added in the BuildFile"
+    with (git_root / 'CommonTools' / 'test' / f'template{type}.cc').open() as f:
+        return f.read()
 
-echo "Don't forget to compile & reset the CMSSW environment to be able to run the executable"
+
+def get_executable_path(git_root: Path, module: str, exec_name: str) -> Path:
+    """
+    Returns the path at which the executable file will be created.
+    """
+
+    return git_root / module / 'bin' / f'{exec_name}.cc'
+
+
+def patch_main_cmakelists(git_root: Path, module: str) -> None:
+    """
+    Adds module as a subdirectory of the main CMakeLists.txt, if needed.
+    """
+
+    cmakelists = git_root / 'CMakeLists.txt'
+
+    # First check if the add_subdirectory is already there.
+    with cmakelists.open() as f:
+        if f'add_subdirectory({module}' in f.read():
+            return  # Nothing to do
+
+    # Append the new add_subdirectory line.
+    with cmakelists.open('a') as f:
+        f.write(f'add_subdirectory({module})\n')
+    print('Patched CMakeLists.txt')
+
+
+def patch_module_cmakelists(git_root: Path, module: str, exec_name: str) -> None:
+    """
+    Adds the executable to the module CMakeLists.txt, creating it if needed.
+    """
+
+    cmakelists = git_root / module / 'CMakeLists.txt'
+
+    # First check if the executable is already there.
+    action = 'Created'
+    if cmakelists.exists():
+        action = 'Patched'
+        with cmakelists.open() as f:
+            if f'core_add_executable({exec_name}' in f.read():
+                return  # Nothing to do
+
+    # Create parent folders if needed.
+    cmakelists.parent.mkdir(parents=True, exist_ok=True)
+
+    # Append the new core_add_executable line.
+    with cmakelists.open('a') as f:
+        f.write(f'core_add_executable({exec_name})\n')
+    print(f'{action} {module}/CMakeLists.txt')
+
+
+def create_executable(location: Path, code: str) -> None:
+    """
+    Creates the executable file.
+    """
+
+    # Create parent folders if needed.
+    location.parent.mkdir(parents=True, exist_ok=True)
+    with location.open('w') as f:
+        f.write(code)
+
+
+if __name__ == '__main__':
+    RED = '\033[0;31m'
+    GREEN = '\033[0;32m'
+    RESET = '\033[0m'
+
+    parser = argparse.ArgumentParser(description='Creates a template executable')
+    parser.add_argument('type', metavar='type', choices=('EventLoop', 'SimpleExec'),
+                        help='EventLoop or SimpleExec')
+    parser.add_argument('module', nargs='?', default=None, type=str,
+                        help='Module to create the executable in')
+    parser.add_argument('newname',
+                        help='Name of the new executable')
+    args = parser.parse_args()
+
+    try:
+        # Checks
+        here = Path().resolve()
+        git_root = find_git_root(here)
+        if not (git_root / 'CMakeLists.txt').is_file():
+            raise ValueError('Cannot find the main CMakeLists.txt')
+
+        module = args.module or deduce_module_name(here, git_root)
+        exec_path = get_executable_path(git_root, module, args.newname)
+        if exec_path.exists():
+            raise ValueError(f'File {exec_path.relative_to(git_root)} already exists')
+
+        # Do it!
+        template = get_template(git_root, args.type)
+
+        patch_main_cmakelists(git_root, module)
+        patch_module_cmakelists(git_root, module, args.newname)
+        create_executable(exec_path, template.replace(args.type, args.newname))
+
+        print(f'Created {exec_path.relative_to(git_root)}')
+        print(f"{GREEN}Don't forget to compile and install to be able to run the executable{RESET}")
+    except Exception as e:
+        print(f'{RED}Error: {e}{RESET}')
diff --git a/CommonTools/test/BuildFile.xml b/CommonTools/test/BuildFile.xml
deleted file mode 100644
index bb9e513b7068ba2f848777dc285f42e5bb3a1c93..0000000000000000000000000000000000000000
--- a/CommonTools/test/BuildFile.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<flags CXXFLAGS="-g  -DDEBUG -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<lib name="stdc++fs" />
-
-<use name="darwin" />
-
-<use name="root" />
-
-<use name="Core/CommonTools" />
-
-<bin name="templateEventLoop" file="templateEventLoop.cc" />
-<bin name="templateSimpleExec" file="templateSimpleExec.cc" />
-<bin name="testGenericSFApplier" file="testGenericSFApplier.cc" />
diff --git a/CommonTools/test/templateEventLoop.cc b/CommonTools/test/templateEventLoop.cc
index e996bf8778831a92d6254d04e9dc83730f7f5e07..d578a5998b41e3c8febd358f1efe2672178c6bbe 100644
--- a/CommonTools/test/templateEventLoop.cc
+++ b/CommonTools/test/templateEventLoop.cc
@@ -78,7 +78,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/CommonTools/test/templateSimpleExec.cc b/CommonTools/test/templateSimpleExec.cc
index ead957c8dea0b0505d3e791687f6d7d5f23b50e1..bd9d618464cbc27f941fa671c97db66c44f000f8 100644
--- a/CommonTools/test/templateSimpleExec.cc
+++ b/CommonTools/test/templateSimpleExec.cc
@@ -45,7 +45,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         fs::path input, output;
 
diff --git a/JEC/CMakeLists.txt b/JEC/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..cdd1af75efe494c0f01b594803915daa6cb3fb5e
--- /dev/null
+++ b/JEC/CMakeLists.txt
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+core_add_library(SOURCES DoubleCrystalBall.cc Resolution.cc Scale.cc)
+core_add_executable(applyJERsmearing)
+core_add_executable(fitJetResolution)
+core_add_executable(getJERtables)
+core_add_executable(getJEScurvesMCtruth)
+core_add_executable(getJEScurvesResiduals)
+core_add_executable(getPtAveBalance)
+core_add_executable(printJERtables)
+core_add_executable(applyJEScorrections)
+core_add_executable(fitJetResponse)
+core_add_executable(getJEScurvesFlavour)
+core_add_executable(getJEScurvesOffset)
+core_add_executable(getJetResponse)
+core_add_executable(getPtBalance)
diff --git a/JEC/bin/BuildFile.xml b/JEC/bin/BuildFile.xml
deleted file mode 100644
index ab124541f2b9bd3baf4df8f0eebe175f9bb6883a..0000000000000000000000000000000000000000
--- a/JEC/bin/BuildFile.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<flags CXXFLAGS="-g  -DDEBUG -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<lib name="stdc++fs" />
-
-<use name="darwin" />
-
-<use name="root" />
-<use name="rootmath" />
-<use name="rootgraphics"/>
-
-<use name="Core/Objects" />
-<use name="Core/CommonTools" />
-<use name="Core/JEC" />
-
-<bin name="applyJEScorrections" file="applyJEScorrections.cc"/>
-<bin name="applyJERsmearing" file="applyJERsmearing.cc"/>
-<bin name="getJetResponse" file="getJetResponse.cc"/>
-<bin name="getPtBalance" file="getPtBalance.cc" />
-<bin name="getPtAveBalance" file="getPtAveBalance.cc" />
-<bin name="fitJetResponse" file="fitJetResponse.cc" />
-<bin name="fitJetResolution" file="fitJetResolution.cc"/>
-<!--<bin name="printJERtables" file="printJERtables.cc" />      -->
-
-<!-- executables to analyse JetMET tables -->
-<!--<bin name="getJERtables" file="getJERtables.cc" />-->
-<bin name="getJEScurvesOffset" file="getJEScurvesOffset.cc" />
-<bin name="getJEScurvesMCtruth" file="getJEScurvesMCtruth.cc" />
-<bin name="getJEScurvesResiduals" file="getJEScurvesResiduals.cc" />
-<!--<bin name="getJEScurvesFlavour" file="getJEScurvesFlavour.cc" />-->
diff --git a/JEC/bin/applyJERsmearing.cc b/JEC/bin/applyJERsmearing.cc
index 820b8fd814e05696f5afbbd4482d4c9e896bccec..9a09f4628ee6d3ba288bf6f370a1d3a3366bac97 100644
--- a/JEC/bin/applyJERsmearing.cc
+++ b/JEC/bin/applyJERsmearing.cc
@@ -158,7 +158,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/JEC/bin/applyJEScorrections.cc b/JEC/bin/applyJEScorrections.cc
index 871fdb00c88cb1d72b71b2da4462cc91b9bcc0a5..fab2310ae38fcd939543ffe96f1a63a967c5ec27 100644
--- a/JEC/bin/applyJEScorrections.cc
+++ b/JEC/bin/applyJEScorrections.cc
@@ -138,7 +138,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/JEC/bin/fitJetResolution.cc b/JEC/bin/fitJetResolution.cc
index 140627f28a7ae7b16edc4ca439c5cc14b3622301..32a7e8d35063a6640295c558d00f7dfe99358240 100644
--- a/JEC/bin/fitJetResolution.cc
+++ b/JEC/bin/fitJetResolution.cc
@@ -246,7 +246,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         fs::path input, output;
 
diff --git a/JEC/bin/fitJetResponse.cc b/JEC/bin/fitJetResponse.cc
index 2b5c740a4532d00082bece4ff1c9a4cdc6819d28..b29723371043376536956d2756148ad794bf7605 100644
--- a/JEC/bin/fitJetResponse.cc
+++ b/JEC/bin/fitJetResponse.cc
@@ -483,7 +483,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         fs::path input, output;
 
diff --git a/JEC/bin/getJEScurvesMCtruth.cc b/JEC/bin/getJEScurvesMCtruth.cc
index 375ae55c8eeb93e3072e5f7a0925ed60c44065a9..d1bdcae651108c4ebc7188ab7553a27b14e9b356 100644
--- a/JEC/bin/getJEScurvesMCtruth.cc
+++ b/JEC/bin/getJEScurvesMCtruth.cc
@@ -100,7 +100,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         fs::path input, output;
 
diff --git a/JEC/bin/getJEScurvesOffset.cc b/JEC/bin/getJEScurvesOffset.cc
index 29773c8051a24156f56ca3d16adace545653fd0c..6bad5c4c1c44af1120f45872e8ac0aeb091d1fa9 100644
--- a/JEC/bin/getJEScurvesOffset.cc
+++ b/JEC/bin/getJEScurvesOffset.cc
@@ -71,7 +71,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         fs::path input, output;
 
diff --git a/JEC/bin/getJEScurvesResiduals.cc b/JEC/bin/getJEScurvesResiduals.cc
index 0da32ae89b7499e012fdcee096d6edc88df78848..ef950e150b302162200a87bcbf6f0d3e91d0784e 100644
--- a/JEC/bin/getJEScurvesResiduals.cc
+++ b/JEC/bin/getJEScurvesResiduals.cc
@@ -63,7 +63,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         fs::path input, output;
 
diff --git a/JEC/bin/getJetResponse.cc b/JEC/bin/getJetResponse.cc
index d5528630b11f687010528dafec11a81e6650103c..a1aa58c9dd09bc6e8832583985d873fa5f3d0bb5 100644
--- a/JEC/bin/getJetResponse.cc
+++ b/JEC/bin/getJetResponse.cc
@@ -186,7 +186,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/JEC/bin/getPtAveBalance.cc b/JEC/bin/getPtAveBalance.cc
index 57c67e0a3da77f02d27e203bf31d881bc47ae4fd..08fae2c1482c07af955b56841c32d4e646835a0a 100644
--- a/JEC/bin/getPtAveBalance.cc
+++ b/JEC/bin/getPtAveBalance.cc
@@ -243,7 +243,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         fs::path input, output;
 
diff --git a/JEC/bin/getPtBalance.cc b/JEC/bin/getPtBalance.cc
index b8474daeb63be3f7448190deff5171968a3a1bb8..9e07eeb5c0ae7c8e1c1d638c2c0c478c98565c22 100644
--- a/JEC/bin/getPtBalance.cc
+++ b/JEC/bin/getPtBalance.cc
@@ -247,7 +247,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/JEC/src/BuildFile.xml b/JEC/src/BuildFile.xml
deleted file mode 100644
index f5e3c6f78911dcc9ef58fb21f9110c3f122688b0..0000000000000000000000000000000000000000
--- a/JEC/src/BuildFile.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<flags CXXFLAGS="-g -DDEBUG -Wall -std=c++17" />
-
-<use name="boost" />
-
-<use name="root" />
-<use name="rootmath" />
-<use name="rootgraphics" />
-
-<use name="Core/Objects" />
-<use name="Core/CommonTools" />
-
-<use name="CondFormats/JetMETObjects" />
-<use name="JetMETCorrections/Modules" />
-
-<lib name="stdc++fs" />
-
-<export>
-    <lib name="CoreJEC"/>
-</export>
diff --git a/JEC/test/BuildFile.xml b/JEC/test/BuildFile.xml
deleted file mode 100644
index d2972b2bae5aca708cd1559257050db4f8178904..0000000000000000000000000000000000000000
--- a/JEC/test/BuildFile.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<flags CXXFLAGS="-g -O2 -std=c++17" />
-
-<use name="root" />
-<use name="rootgraphics" />
-
-<use name="Core/CommonTools" />
-<use name="Core/JEC" />
-
-<bin name="DoubleCrystalBall" file="DoubleCrystalBall.cc" />
-<bin name="ModifiedGaussianCore" file="ModifiedGaussianCore.cc" />
diff --git a/JetObservables/BuildFile.xml b/JetObservables/BuildFile.xml
deleted file mode 100644
index edc6401a2ba2508b51003d3a9a6751a0042da61d..0000000000000000000000000000000000000000
--- a/JetObservables/BuildFile.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<use name="root"/>
-<use name="rootmath" />
-<use name="Core/Objects" />
-<lib name="stdc++fs" />
-<use name="Core/JetObservables" />
-
-<export><lib name="1"/></export>
diff --git a/JetObservables/CMakeLists.txt b/JetObservables/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f8f7095d3abc7443db025dfda43252daf488d74a
--- /dev/null
+++ b/JetObservables/CMakeLists.txt
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+core_add_library(SOURCES MuellerNavelet.cc)
+core_add_executable(applyDijetSkim)
+core_add_executable(applyZJetSkim)
+core_add_executable(getMNobservables NO_EXAMPLE)
diff --git a/JetObservables/bin/BuildFile.xml b/JetObservables/bin/BuildFile.xml
deleted file mode 100644
index 3985ea244ee98701f9457c14fbc35b94da3776ad..0000000000000000000000000000000000000000
--- a/JetObservables/bin/BuildFile.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<flags CXXFLAGS="-g  -DDEBUG -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<lib name="stdc++fs" />
-
-<use name="darwin" />
-
-<use name="root" />
-<use name="Core/Objects" />
-<use name="Core/CommonTools" />
-<use name="Core/JetObservables" />
-
-<bin name="getMNobservables" file="getMNobservables.cc" />
-<bin name="applyDijetSkim" file="applyDijetSkim.cc" />
-<bin name="applyZJetSkim" file="applyZJetSkim.cc" />
diff --git a/JetObservables/bin/applyDijetSkim.cc b/JetObservables/bin/applyDijetSkim.cc
index 8d20ce359f355fbde0c5a5a70ac1e62c8408a840..732ecdcc4d864e6a42c6d6dc9ca680eb3a02fe02 100644
--- a/JetObservables/bin/applyDijetSkim.cc
+++ b/JetObservables/bin/applyDijetSkim.cc
@@ -116,7 +116,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/JetObservables/bin/applyZJetSkim.cc b/JetObservables/bin/applyZJetSkim.cc
index b87c77d0e5dcd6d221d220644574a72e1b7f35de..be70c59ce3a065b97cb98a84612d730c9d6ad76c 100644
--- a/JetObservables/bin/applyZJetSkim.cc
+++ b/JetObservables/bin/applyZJetSkim.cc
@@ -127,7 +127,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/JetObservables/bin/getMNobservables.cc b/JetObservables/bin/getMNobservables.cc
index c40759b263a856438edb73c9933bd9efd716bb8d..18ad5a862868fee9da1f65919a54f1290598771c 100644
--- a/JetObservables/bin/getMNobservables.cc
+++ b/JetObservables/bin/getMNobservables.cc
@@ -274,7 +274,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/JetObservables/interface/MuellerNavelet.h b/JetObservables/interface/MuellerNavelet.h
index e444e927169a4fc6a8b3261b057d10ee57e245ac..de1051626f56032406d703d9009730566cb6beba 100644
--- a/JetObservables/interface/MuellerNavelet.h
+++ b/JetObservables/interface/MuellerNavelet.h
@@ -1,9 +1,11 @@
-#ifndef DAS_MN_OBS
-#define DAS_MN_OBS
-#include <list>
-#include <vector>
+#pragma once
+
 #include "Core/Objects/interface/Jet.h"
+
 #include <algorithm>
+#include <list>
+#include <optional>
+#include <vector>
 
 ////////////////////////////////////////////////////////////////////////////////
 /// The namespace MN_Helper contains the classes that are needed by getMNobservables.cc
@@ -139,4 +141,3 @@ std::vector<Jet> GetMiniJets (std::vector<Jet> jets, const std::pair<Jet,Jet>& M
 }
 
 } // end of namespace DAS::MN
-#endif
diff --git a/JetObservables/src/BuildFile.xml b/JetObservables/src/BuildFile.xml
deleted file mode 100644
index 485d8673f44e86d44ecf06219a9fc6eade3d6d4c..0000000000000000000000000000000000000000
--- a/JetObservables/src/BuildFile.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<flags CXXFLAGS="-g -DDEBUG -Wall -std=c++17" />
-<use name="root" />
-<use name="rootgraphics" />
-<use name="rootmath" />
-<lib name="stdc++fs" />
-<use name="Core/Objects" />
-
-<export>
-    <lib name="CoreJetObservables" />
-</export>
diff --git a/JetObservables/src/MuellerNavelet.cc b/JetObservables/src/MuellerNavelet.cc
index 5731c1176910703e529ed8ccad1218f2d059843e..9aaf68efff3d493b516fbbfdb389c6869d2aa4fb 100644
--- a/JetObservables/src/MuellerNavelet.cc
+++ b/JetObservables/src/MuellerNavelet.cc
@@ -3,6 +3,7 @@
 #include <Math/VectorUtil.h>
 #include <math.h>
 #include <numeric>
+#include <optional>
 
 #include "Core/JetObservables/interface/MuellerNavelet.h"
 
diff --git a/JetVetoMaps/CMakeLists.txt b/JetVetoMaps/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b98e7484f59a9abb0e8fb19471250d7bf6efb961
--- /dev/null
+++ b/JetVetoMaps/CMakeLists.txt
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+core_add_executable(applyConservativeVetoMap LIBRARIES CommonTools)
+core_add_executable(getConservativeMap NO_EXAMPLE)
diff --git a/JetVetoMaps/bin/BuildFile.xml b/JetVetoMaps/bin/BuildFile.xml
deleted file mode 100644
index 79eaf2dcddf016606fc0bf72d89d66be5e45d01e..0000000000000000000000000000000000000000
--- a/JetVetoMaps/bin/BuildFile.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<flags CXXFLAGS="-g  -DDEBUG -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<lib name="stdc++fs" />
-
-<use name="darwin" />
-
-<use name="root" />
-<use name="rootmath" />
-
-<use name="Core/Objects" />
-<use name="Core/CommonTools" />
-
-<bin name="applyConservativeVetoMap" file="applyConservativeVetoMap.cc" />
-<bin name="getConservativeMap" file="getConservativeMap.cc" />
diff --git a/JetVetoMaps/bin/applyConservativeVetoMap.cc b/JetVetoMaps/bin/applyConservativeVetoMap.cc
index a7d0878df585e6233d7e3b74e42c7faf412278d8..44c2110a76567f65ef291bd6e4b49741e1a862a6 100644
--- a/JetVetoMaps/bin/applyConservativeVetoMap.cc
+++ b/JetVetoMaps/bin/applyConservativeVetoMap.cc
@@ -102,7 +102,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/JetVetoMaps/bin/getConservativeMap.cc b/JetVetoMaps/bin/getConservativeMap.cc
index cf033f9d6f5a6b528c2bcfaaafe8fe79280247f3..e2eb62e6158856f3c3fc636c23979d7d7812797c 100644
--- a/JetVetoMaps/bin/getConservativeMap.cc
+++ b/JetVetoMaps/bin/getConservativeMap.cc
@@ -69,7 +69,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         fs::path input, output;
 
diff --git a/MET/CMakeLists.txt b/MET/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e79bcb855dc96c9c1a1f4e8dfe09f39367e0fac5
--- /dev/null
+++ b/MET/CMakeLists.txt
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+core_add_executable(applyMETfilters LIBRARIES CommonTools)
+core_add_executable(getMETfraction)
diff --git a/MET/bin/BuildFile.xml b/MET/bin/BuildFile.xml
deleted file mode 100644
index 47e3ff8f68dbe8578882564805ff5116e05a0b13..0000000000000000000000000000000000000000
--- a/MET/bin/BuildFile.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<flags CXXFLAGS="-g  -DDEBUG -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<lib name="stdc++fs" />
-
-<use name="darwin" />
-
-<use name="root" />
-<use name="rootmath" />
-
-<use name="Core/CommonTools" />
-<use name="Core/Objects" />
-
-<bin name="applyMETfilters" file="applyMETfilters.cc" />
-<bin name="getMETfraction" file="getMETfraction.cc" />
diff --git a/MET/bin/applyMETfilters.cc b/MET/bin/applyMETfilters.cc
index 3254507ce4b6377e22c55425b3f02c859c3bb6a0..a29107fbd8d839c81aacceb6062df6d208e66c51 100644
--- a/MET/bin/applyMETfilters.cc
+++ b/MET/bin/applyMETfilters.cc
@@ -185,7 +185,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/MET/bin/getMETfraction.cc b/MET/bin/getMETfraction.cc
index 61a5c549c9e26921e7ca4fd02cb099d6580a3da3..1878a56e782a1ca7e945883290b7c54aec534d3e 100644
--- a/MET/bin/getMETfraction.cc
+++ b/MET/bin/getMETfraction.cc
@@ -132,7 +132,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/Muons/CMakeLists.txt b/Muons/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e5c0d6e6100d4b24ef79493a29e30009cb36888a
--- /dev/null
+++ b/Muons/CMakeLists.txt
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+core_add_library(SOURCES RoccoR.cc)
+core_add_executable(applyDimuonSkim)
+core_add_executable(applyDimuonTriggerStrategy)
+core_add_executable(applyMuonEffCorr)
+core_add_executable(applyRochesterCorr)
+core_add_executable(getDimuonSpectrum NO_EXAMPLE)
diff --git a/Muons/bin/BuildFile.xml b/Muons/bin/BuildFile.xml
deleted file mode 100644
index 673b7c3b7f62562d092188175d3673af35019641..0000000000000000000000000000000000000000
--- a/Muons/bin/BuildFile.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<flags CXXFLAGS="-g -O3  -std=c++1z" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<lib name="stdc++fs" />
-
-<use name="root" />
-<use name="boost" />
-<use name="darwin" />
-
-<use name="Core/Objects" />
-<use name="Core/CommonTools" />
-
-<bin name="applyMuonEffCorr" file="applyMuonEffCorr.cc" />
-<bin name="applyRochesterCorr" file="applyRochesterCorr.cc,RoccoR.cc" />
-<bin name="getDimuonSpectrum" file="getDimuonSpectrum.cc" />
-<bin name="applyDimuonTriggerStrategy" file="applyDimuonTriggerStrategy.cc" />
-<bin name="applyDimuonSkim" file="applyDimuonSkim.cc" />
diff --git a/Muons/bin/applyDimuonSkim.cc b/Muons/bin/applyDimuonSkim.cc
index 05ec2a642bd996fdbfbe68932e028ab3583654cc..cecce6de40b2c2b20028d975e0077bee6a9ad0fb 100644
--- a/Muons/bin/applyDimuonSkim.cc
+++ b/Muons/bin/applyDimuonSkim.cc
@@ -129,7 +129,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/Muons/bin/applyDimuonTriggerStrategy.cc b/Muons/bin/applyDimuonTriggerStrategy.cc
index 2a9c50371eee93a28dee99e59577a02ce437e1ed..119c7aeb260dab36789bb5674c19b5527b891241 100644
--- a/Muons/bin/applyDimuonTriggerStrategy.cc
+++ b/Muons/bin/applyDimuonTriggerStrategy.cc
@@ -179,7 +179,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/Muons/bin/applyMuonEffCorr.cc b/Muons/bin/applyMuonEffCorr.cc
index e511cea048ec6615723946389477a70732f50969..b3d8b5d1b704a2852cc0fa00bde4dc11ca825449 100644
--- a/Muons/bin/applyMuonEffCorr.cc
+++ b/Muons/bin/applyMuonEffCorr.cc
@@ -288,7 +288,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/Muons/bin/applyRochesterCorr.cc b/Muons/bin/applyRochesterCorr.cc
index b20bbace2044636176d5597aeeab5056668fa65b..47d6bbe03824d46564a1c89e7eea7fb54aba4bbf 100644
--- a/Muons/bin/applyRochesterCorr.cc
+++ b/Muons/bin/applyRochesterCorr.cc
@@ -192,7 +192,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/Muons/bin/getDimuonSpectrum.cc b/Muons/bin/getDimuonSpectrum.cc
index 9b83baaf33a2c233a13db3d5c785211993507d10..140e8f69337be2a5531e43bdce896b447fb11c1a 100644
--- a/Muons/bin/getDimuonSpectrum.cc
+++ b/Muons/bin/getDimuonSpectrum.cc
@@ -152,7 +152,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/Muons/bin/RoccoR.h b/Muons/interface/RoccoR.h
similarity index 100%
rename from Muons/bin/RoccoR.h
rename to Muons/interface/RoccoR.h
diff --git a/Muons/bin/RoccoR.cc b/Muons/src/RoccoR.cc
similarity index 100%
rename from Muons/bin/RoccoR.cc
rename to Muons/src/RoccoR.cc
diff --git a/Normalisation/BuildFile.xml b/Normalisation/BuildFile.xml
deleted file mode 100644
index 580c68688fb65d5d3748aa7db5f44f9054f97fe4..0000000000000000000000000000000000000000
--- a/Normalisation/BuildFile.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<use name="root"/> 
-<use name="rootmath" />
-<use name="Core/Objects" />
-<lib name="stdc++fs" />
-<export>
-    <lib name="1"/>
-</export>
-
diff --git a/Normalisation/CMakeLists.txt b/Normalisation/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a59d05a4a969c15f8d7aff23f509cc132f5de762
--- /dev/null
+++ b/Normalisation/CMakeLists.txt
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+core_add_library(SOURCES LumiUnc.cc TriggerLumi.cc DEPENDS Darwin::Darwin)
+#core_add_executable(applyDataLumiZeroBias)  FIXME
+core_add_executable(applyDataNormalisation LIBRARIES CommonTools)
+#core_add_executable(applyDataPrescalesZeroBias)  FIXME
+core_add_executable(applyMClumi LIBRARIES CommonTools)
+core_add_executable(applyNormFactor)
+core_add_executable(getSumWeights NO_EXAMPLE)
diff --git a/Normalisation/bin/BuildFile.xml b/Normalisation/bin/BuildFile.xml
deleted file mode 100644
index f62d116aa093794ee99b01008006d06fd89dd8f9..0000000000000000000000000000000000000000
--- a/Normalisation/bin/BuildFile.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<flags CXXFLAGS="-g -DDEBUG -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<use name="darwin" />
-
-<use name="boost" />
-
-<use name="root" />
-<use name="rootmath" />
-<use name="rootgraphics"/>
-
-<lib name="stdc++fs" />
-
-<use name="Core/Objects" />
-<use name="Core/CommonTools" />
-<use name="Core/Normalisation" />
-
-<bin name="applyDataNormalisation" file="applyDataNormalisation.cc" />
-<!--<bin name="applyPrefPrescales" file="applyPrefPrescales.cc" />-->
-
-<bin name="getSumWeights" file="getSumWeights.cc" />
-<bin name="applyMClumi" file="applyMClumi.cc" />
-<bin name="applyNormFactor" file="applyNormFactor.cc" />
-
-<!--<bin name="applyDataLumiZeroBias" file="applyDataLumiZeroBias.cc" />-->
-<!--<bin name="applyDataPrescalesZeroBias" file="applyDataPrescalesZeroBias.cc" />-->
-<!--<bin name="applyPrefPrescalesZeroBias" file="applyPrefPrescalesZeroBias.cc" />-->
diff --git a/Normalisation/bin/applyDataNormalisation.cc b/Normalisation/bin/applyDataNormalisation.cc
index 8d1adb490190c8aa8ff92daf820b05be973c95ac..ccd97d6710d3525b8c3462f627bfbe1dba66f1a7 100644
--- a/Normalisation/bin/applyDataNormalisation.cc
+++ b/Normalisation/bin/applyDataNormalisation.cc
@@ -163,7 +163,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/Normalisation/bin/applyMClumi.cc b/Normalisation/bin/applyMClumi.cc
index a6f8470fcd8aa9c76161efe9d705599a6e392db4..5b245a8667ffd8184ac09054c9ed522831ae3f40 100644
--- a/Normalisation/bin/applyMClumi.cc
+++ b/Normalisation/bin/applyMClumi.cc
@@ -139,7 +139,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/Normalisation/bin/applyNormFactor.cc b/Normalisation/bin/applyNormFactor.cc
index f301e2caf8fb372583320217088ecd891721af1a..255b677ef8f1fca3323c9bac569a4792f03e5086 100644
--- a/Normalisation/bin/applyNormFactor.cc
+++ b/Normalisation/bin/applyNormFactor.cc
@@ -89,7 +89,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/Normalisation/bin/applyPrefPrescales.cc b/Normalisation/bin/applyPrefPrescales.cc
deleted file mode 100644
index 4c63817ba124799f9698282ca86a08047bfd2a70..0000000000000000000000000000000000000000
--- a/Normalisation/bin/applyPrefPrescales.cc
+++ /dev/null
@@ -1,225 +0,0 @@
-#include <cassert>
-#include <iostream>
-#include <limits>
-#include <cstdlib>
-#include <vector>
-#include <map>
-#include <experimental/filesystem>
-
-#include "Core/Objects/interface/Jet.h"
-#include "Core/Objects/interface/Event.h"
-
-#include "Core/CommonTools/interface/Looper.h"
-#include "Core/CommonTools/interface/MetaInfo.h"
-#include "Core/CommonTools/interface/terminal.h"
-#include "Core/CommonTools/interface/toolbox.h"
-#include "Core/CommonTools/interface/ControlPlots.h"
-
-#include <TROOT.h>
-#include <TString.h>
-#include <TChain.h>
-#include <TFile.h>
-#include <TH2.h>
-
-#include "Math/VectorUtil.h"
-#include "TriggerEff.h"
-
-#include "applyDataNormalisation.h"
-#include "Core/Prefiring/interface/applyPrefiringWeights.h"
-
-using namespace std;
-using namespace experimental::filesystem;
-using namespace DAS;
-
-////////////////////////////////////////////////////////////////////////////////
-/// Application of prefiring weights in data or simulation.
-///
-/// Calls a functor which apply the prefiring weights and then normalise with prescales
-void applyPrefPrescales 
-             (const fs::path& input,  //!< name of input root file 
-              const fs::path& output, //!< name of output root file
-              PrefOpt prefOpt, //!< option to choose the right map(s)
-              const fs::path& lumi_file,      //!< path to text file with effective luminosities
-              const fs::path& turnon_file,    //!< path to text file with turn-on points
-              const fs::path& trigger_curves, //!< file with efficiency curves
-              string& strategy,               //!< 'pt' or 'eta', only 'pt' has been tested for this command
-                                              //!< (see the documentation of `Normalisation/bin/applyDataNormalisation.h`
-              string& method,                 //!< 'presc'-> use the prescales in dataset, 'lumi'-> not implemented in this context
-              int nSplit = 1, //!< number of jobs/tasks/cores
-              int nNow = 0)   //!< index of job/task/core
-{
-    // Get old file, old tree and set top branch address
-    assert(fs::exists(input));
-    TChain * oldchain = new TChain("events"); // arg = path inside the ntuple
-    oldchain->Add(input.c_str());
-
-    Event * evnt = nullptr;
-    oldchain->SetBranchAddress("recEvent", &evnt);
-    vector<RecJet> * recJets = nullptr;
-    oldchain->SetBranchAddress("recJets", &recJets);
-    vector<FourVector> * hltJets;
-    oldchain->SetBranchAddress("hltJets", &hltJets);
-    Trigger * trigger = nullptr;
-    oldchain->SetBranchAddress("trigger", &trigger);
-
-    if (fs::exists(output))
-        cerr << red << output << " will be overwritten\n" << normal;
-    TFile * newfile = TFile::Open(output.c_str(), "RECREATE");
-    TTree * newtree = oldchain->CloneTree(0);
-
-    MetaInfo metainfo(newtree);
-    if (nNow == 0) metainfo.Print();
-    metainfo.AddCorrection("PrefiringWeights");
-    metainfo.AddCorrection("normalised");
-    metainfo.AddRecEvWgt("Prefup");
-    metainfo.AddRecEvWgt("Prefdown");
-    bool isMC = metainfo.isMC();
-
-    vector<GenJet> * genJets = nullptr;
-    if (isMC) oldchain->SetBranchAddress("genJets", &genJets);
-
-    int year = metainfo.year();
-    assert(year > 2015 && year < 2019);
-
-    //Calling functor to apply prefiring weights
-    applyPrefiringWeightsFunctor apply(year, prefOpt, isMC);
-    
-    //Define control plots for prefiring weights
-    ControlPlots::isMC = isMC;
-    ControlPlots raw("raw");
-    vector<ControlPlots> calib { ControlPlots("nominal_befNorm"),
-                                 ControlPlots("upper_befNorm"  ),
-                                 ControlPlots("lower_befNorm"  ) };
-    auto totRecWgt = [&](size_t i) {
-        return (isMC ? evnt->genWgts.front() : 1) * evnt->weights.at(i);
-    };
-
-    //Calling functor to apply data prescales
-    DataNormalisation normalisation (lumi_file, turnon_file, trigger_curves, strategy, method, year);
-    newfile->cd();
-
-    //Define control plots for normalisation
-    ControlPlots::isMC = false;
-    ControlPlots corrNoTrigEff("corrNoTrigEff");
-
-    vector<ControlPlots> corr ;
-    for (int i=0; i<metainfo.GetNRecEvWgts(); i++)
-        corr.push_back(ControlPlots(metainfo.GetRecEvWgt(i)));
-
-    cout << "looping over events:" << endl;
-
-    Looper looper(__func__, oldchain, nSplit, nNow);
-    while (looper.Next()) {
-        //apply prefiring weights and fill their control plots
-        if (isMC) raw(*genJets, evnt->genWgts.front());
-        raw(*recJets, totRecWgt(0));
-        apply(*evnt, *recJets);
-        for (size_t i = 0; i < calib.size(); ++i) {
-            if (isMC) calib.at(i)(*genJets, evnt->genWgts.front());
-            if (recJets->size() == 0) continue;
-            calib.at(i)(*recJets, totRecWgt(i));
-        }
-        //apply data prescales and fill their control plots
-        auto leadingJet = normalisation(*evnt, *recJets, *hltJets, *trigger);
-        if (evnt->weights.front()>0)
-            newtree->Fill();
-        if (normalisation.eff(leadingJet)>0)
-            corrNoTrigEff(*recJets, evnt->weights.front()*normalisation.eff(leadingJet));
-        if (normalisation.eff(leadingJet)>0) {
-            for (size_t i = 0; i < corr.size(); ++i)
-                corr.at(i)(*recJets, evnt->weights.at(i));
-        }
-
-        // Exclusive curves are filled (i.e. one event can populate only a trigger curve).
-        // The ibit value is determined by the leading jet but also the other jets of the
-        // event can populate the trigger curve.
-        if (normalisation.eff(leadingJet) > 0) {
-            for (auto& jet: *recJets) {
-                auto y = abs(jet.Rapidity());
-                auto w = evnt->weights.front();
-                normalisation.eff.contribs.at(normalisation.ibit)->Fill(jet.CorrPt(), y, w);
-            }
-        }
-
-        //cout << normalisation.eff.contribs.at(ibit)->GetTitle() << ' ' << it->second.turnon << ' ' << leading_pt << endl;
-        
-        
-    }
-
-    cout << "saving" << endl;
-    newtree->AutoSave();
-    corrNoTrigEff.Write(newfile);
-    for (size_t i = 0; i < corr.size(); ++i)
-        corr.at(i).Write(newfile);
-    TDirectory * controlplots = newfile->mkdir("controlplots");
-    controlplots->cd();
-    for (TH2 * h: normalisation.eff.contribs) {
-        h->SetDirectory(controlplots);
-        h->Write();   
-    }
-    if (nNow == 0) {
-            normalisation.eff.h->SetDirectory(controlplots);
-        normalisation.eff.h->Write();
-    }
-
-    raw.Write(newfile);
-    for (size_t i = 0; i < calib.size(); ++i)
-        calib.at(i).Write(newfile);
-    TDirectory * controlplotsPref = newfile->mkdir("Prefiring");
-    apply.Write(controlplotsPref);
-
-    newfile->Close();
-    delete oldchain;
-}
-
-#ifndef DOXYGEN_SHOULD_SKIP_THIS
-int main (int argc, char * argv[])
-{
-    TH1::SetDefaultSumw2();
-    gROOT->SetBatch();
-
-    if (argc < 6) {
-        cout << argv[0] << " input output option [nSplit [nNow]]\n"
-             << "\twhere\tinput = n-tuple\n"
-             << "\t     \toutput = modified n-tuple\n"
-             << "\t     \toption = `AverageMap` (default; only possible option for MC), `MapsPerEra`, or `SmoothMapsPerEra`\n"
-             << "     \tlumi_file = 2-column file with 'trigger lumi' (should be in `$DAS_WORKAREA/tables/lumi`)\n"
-             << "     \tturnon_file = 2-column file with 'trigger turn-on' (output of `getTriggerTurnons`, should also be in `$DAS_WORKAREA/tables/triggers`)\n"
-             << "     \ttrigger_turnons = root file with output of `getTriggerTurnons`"
-             << "     \tstrategy = 'pt' -> leading pt jet in the tracker acceptance is used to trigger the event and calculate the effciency\n"
-             << "     \t           'eta'-> Not implemented in this context\n"
-             << "     \t           (see `$DAS_SOFTWARE/Core/Normalisation/bin/applyDataNormalisation.h`)\n"
-             << "     \tmethod = 'presc' -> use the prescales, 'lumi' -> not implemented in this context"
-             << endl;
-        return EXIT_SUCCESS;
-    }
-
-    fs::path input = argv[1],
-             output = argv[2];
-
-    TString option = argv[3];
-    PrefOpt prefOpt = option == "MapsPerEra"       ?   PrefOpt::kMapsPerEra       :
-                      option == "SmoothMapsPerEra" ?   PrefOpt::kSmoothMapsPerEra :
-                    /*option == "AverageMap"       ?*/ PrefOpt::kAverageMap       ;
-    
-    fs::path lumi_file = argv[4],
-             turnon_file = argv[5],
-             trigger_curves = argv[6];
-    string strategy = argv[7];
-    string method = argv[8];
-    int nNow = 0, nSplit = 1;
-    if ( strategy == string("eta") ) {
-        cerr << "strategy 'eta' has an undefined behaviour in this context\n";
-        return EXIT_FAILURE;
-    }
-    if ( method == string("lumi") ) {
-        cerr << "method 'lumi' has an undifined behaviour in this context\n";
-        return EXIT_FAILURE;
-    }
-    if (argc > 9) nSplit = atoi(argv[9]);
-    if (argc > 10) nNow = atoi(argv[10]);
-
-    applyPrefPrescales(input, output, prefOpt, lumi_file, turnon_file, trigger_curves, strategy, method, nSplit, nNow);
-    return EXIT_SUCCESS;
-}
-#endif
diff --git a/Normalisation/bin/applyPrefPrescalesZeroBias.cc b/Normalisation/bin/applyPrefPrescalesZeroBias.cc
deleted file mode 100644
index c43663d22bde01170aa4bbf44fad41616bc7b418..0000000000000000000000000000000000000000
--- a/Normalisation/bin/applyPrefPrescalesZeroBias.cc
+++ /dev/null
@@ -1,185 +0,0 @@
-#include <cassert>
-#include <iostream>
-#include <limits>
-#include <cstdlib>
-#include <vector>
-#include <map>
-#include <experimental/filesystem>
-
-#include "Core/CommonTools/interface/Looper.h"
-#include "Core/CommonTools/interface/MetaInfo.h"
-#include "Core/CommonTools/interface/terminal.h"
-#include "Core/Objects/interface/Jet.h"
-#include "Core/Objects/interface/Event.h"
-#include "Core/CommonTools/interface/toolbox.h"
-#include "Core/CommonTools/interface/ControlPlots.h"
-
-#include <TROOT.h>
-#include <TString.h>
-#include <TChain.h>
-#include <TFile.h>
-#include <TH2.h>
-
-#include "Math/VectorUtil.h"
-#include "TriggerEff.h"
-
-#include "Core/Prefiring/interface/applyPrefiringWeights.h"
-
-using namespace std;
-using namespace experimental::filesystem;
-using namespace DAS;
-
-////////////////////////////////////////////////////////////////////////////////
-///// Application of prefiring weights in data or simulation.
-/////
-///// Calls a functor
-
-
-void applyPrefNormZeroBias 
-             (const fs::path& input,  //!< name of input root file 
-              const fs::path& output, //!< name of output root file
-              PrefOpt prefOpt, //!< option to choose the right map(s)
-              auto total_lumi,
-              auto maxpt,
-              int nSplit = 1, //!< number of jobs/tasks/cores
-              int nNow = 0)   //!< index of job/task/core
-{
-    // Get old file, old tree and set top branch address
-    assert(fs::exists(input));
-    TChain * oldchain = new TChain("events"); // arg = path inside the ntuple
-    oldchain->Add(input.c_str());
-
-    Event * evnt = nullptr;
-    oldchain->SetBranchAddress("event", &evnt);
-    vector<RecJet> * recJets = nullptr;
-    oldchain->SetBranchAddress("recJets", &recJets);
-    Trigger * trigger = nullptr;
-    oldchain->SetBranchAddress("trigger", &trigger);
-
-    if (fs::exists(output))
-        cerr << red << output << " will be overwritten\n" << normal;
-    TFile * newfile = TFile::Open(output.c_str(), "RECREATE");
-    TTree * newtree = oldchain->CloneTree(0);
-
-    MetaInfo metainfo(newtree);
-    if (nNow == 0) metainfo.Print();
-    metainfo.AddCorrection("PrefiringWeights");
-    metainfo.AddCorrection("normalised");
-    metainfo.AddRecEvWgt("Prefup");
-    metainfo.AddRecEvWgt("Prefdown");
-    bool isMC = metainfo.isMC();
-
-    vector<GenJet> * genJets = nullptr;
-    if (isMC) oldchain->SetBranchAddress("genJets", &genJets);
-
-    int year = metainfo.year();
-    assert(year > 2015 && year < 2019);
-    
-    //Define prefiring weight functor
-    applyPrefiringWeightsFunctor apply(year, prefOpt, isMC);
-
-    //Define control plots for prefiring weights
-    ControlPlots::isMC = isMC;
-    ControlPlots raw("raw");
-    vector<ControlPlots> calib { ControlPlots("nominal_befNorm"),
-                                 ControlPlots("upper_befNorm"  ),
-                                 ControlPlots("lower_befNorm"  ) };
-    auto totRecWgt = [&](size_t i) {
-        return (isMC ? evnt->genWgts.front() : 1) * evnt->recWgts.at(i);
-    };
-
-    assert(total_lumi > 0);
-    auto inv_total_lumi = 1./total_lumi;
-
-    newfile->cd();
-
-    // Define control plots for normalisation
-     ControlPlots::isMC = false;
-
-    vector<ControlPlots> corr ;
-    for (int i=0; i<metainfo.GetNRecEvWgts(); i++)
-        corr.push_back(ControlPlots(metainfo.GetRecEvWgt(i)));
-
-    cout << "looping over events:" << endl;
-
-    Looper looper(__func__, oldchain, nSplit, nNow);
-    while (looper.Next()) {
-    // apply prefiring weights
-    if (isMC) raw(*genJets, evnt->genWgts.front());
-        raw(*recJets, totRecWgt(0));
-        apply(*evnt, *recJets);
-        for (size_t i = 0; i < calib.size(); ++i) {
-            if (isMC) calib.at(i)(*genJets, evnt->genWgts.front());
-            if(recJets->size()==0) continue;
-            calib.at(i)(*recJets, totRecWgt(i));
-        }
-
-        //apply normalisation
-        // // we find the leading jet in tracker acceptance
-        auto leadingInTk = recJets->begin();
-        while (leadingInTk != recJets->end()
-                && abs(leadingInTk->Rapidity()) >= 2.5)
-            ++leadingInTk;
-        // removed events alreadu covered by jet triggers
-        if (leadingInTk != recJets->end() && leadingInTk->CorrPt() >= maxpt) continue;
-        // setting the inverse of the eff lumi to the event including correction of for the trigger efficiency
-        // corrections applied to all the prefiring variations
-       for (size_t i = 0; i < corr.size(); ++i)
-            evnt->recWgts.at(i) *= inv_total_lumi;
-
-        newtree->Fill();
-        for(size_t i=0; i<corr.size(); i++){
-            if(recJets->size()==0) continue;
-            corr.at(i)(*recJets, evnt->recWgts.at(i));
-        }
-    }
-
-    cout << "saving" << endl;
-    newtree->AutoSave();
-    raw.Write(newfile);
-    for (size_t i = 0; i < calib.size(); ++i)
-        calib.at(i).Write(newfile);
-    TDirectory * controlplotsPref = newfile->mkdir("Prefiring");
-    apply.Write(controlplotsPref);
-    for (size_t i = 0; i < corr.size(); ++i)
-        corr.at(i).Write(newfile);
-    auto controlplots = newfile->mkdir("controlplots");
-    controlplots->cd();
-    newfile->Close();
-    delete oldchain;
-}
-
-#ifndef DOXYGEN_SHOULD_SKIP_THIS
-int main (int argc, char * argv[])
-{
-    TH1::SetDefaultSumw2();
-    gROOT->SetBatch();
-
-    if (argc < 4) {
-        cout << argv[0] << " input output option [nSplit [nNow]]\n"
-             << "\twhere\tinput = n-tuple\n"
-             << "\t     \toutput = modified n-tuple\n"
-             << "\t     \toption = `AverageMap` (default; only possible option for MC), `MapsPerEra`, or `SmoothMapsPerEra`\n"
-             << flush;
-        return EXIT_SUCCESS;
-    }
-
-    fs::path input = argv[1],
-             output = argv[2];
-
-    TString option = argv[3];
-    PrefOpt prefOpt = option =="MapsPerEra"       ?   PrefOpt::kMapsPerEra       :
-                      option =="SmoothMapsPerEra" ?   PrefOpt::kSmoothMapsPerEra :
-                    /*option =="AverageMap"       ?*/ PrefOpt::kAverageMap       ;
-
-    auto total_lumi = atof(argv[4]),
-         maxpt = atof(argv[5]);
-    int nNow = 0, nSplit = 1;
-    if (argc > 6) nSplit = atoi(argv[6]);
-    if (argc > 7) nNow = atoi(argv[7]);
-
-    applyPrefNormZeroBias(input, output, prefOpt, total_lumi, maxpt, nSplit, nNow);
-    return EXIT_SUCCESS;
-}
-#endif
- 
diff --git a/Normalisation/bin/getSumWeights.cc b/Normalisation/bin/getSumWeights.cc
index 36036e3e552abc2ed9bddfe2e8d6068a99e16e37..f0b8b9c8239d1da86eda57ef3ee353c4837df63c 100644
--- a/Normalisation/bin/getSumWeights.cc
+++ b/Normalisation/bin/getSumWeights.cc
@@ -73,7 +73,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/Normalisation/src/BuildFile.xml b/Normalisation/src/BuildFile.xml
deleted file mode 100644
index 170fab5cb122a6f6001420ed974888ab2c9df0ae..0000000000000000000000000000000000000000
--- a/Normalisation/src/BuildFile.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<flags CXXFLAGS="-g -DDEBUG -Wall -std=c++17" />
-
-<use name="root" />
-<use name="rootgraphics"/>
-<use name="rootmath" />
-<use name="darwin" />
-<lib name="stdc++fs" />
-<use name="Core/Objects" />
-
-<export>
-    <lib name="CoreNormalisation"/>
-</export>
-
diff --git a/Ntupliser/CMakeLists.txt b/Ntupliser/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e653e1f6e85759300e67ab26d694419a0ca104bc
--- /dev/null
+++ b/Ntupliser/CMakeLists.txt
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+core_add_executable(mergeNtuples)
diff --git a/Ntupliser/bin/BuildFile.xml b/Ntupliser/bin/BuildFile.xml
deleted file mode 100644
index 210418c9c3cfbad2a56b8f336154eabccea1b35f..0000000000000000000000000000000000000000
--- a/Ntupliser/bin/BuildFile.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<flags CXXFLAGS="-g -DDEBUG -O3 -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<use name="darwin" />
-
-<use name="root" />
-<use name="rootgraphics"/>
-<use name="rootmath"/>
-
-<use name="boost" />
-
-<use name="Core/Objects" />
-<use name="Core/CommonTools" />
-
-<lib name="stdc++fs" />
-
-<bin name="mergeNtuples" file="mergeNtuples.cc" />
diff --git a/Ntupliser/bin/mergeNtuples.cc b/Ntupliser/bin/mergeNtuples.cc
index 9151ad9a952770ab762c6864ab3801724148ba75..971bada967338aa4974ab2b1ee442b1319f3817d 100644
--- a/Ntupliser/bin/mergeNtuples.cc
+++ b/Ntupliser/bin/mergeNtuples.cc
@@ -139,7 +139,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/Ntupliser/test/BuildFile.xml b/Ntupliser/test/BuildFile.xml
index 80363c337402072bb4167252b088c7f47fe46c1c..2e6e5c1a52e7422b6d7d08c9098a7cfcbb16ddd2 100644
--- a/Ntupliser/test/BuildFile.xml
+++ b/Ntupliser/test/BuildFile.xml
@@ -1,6 +1,6 @@
 <environment>
     <bin file="TestHelper.cc">
-        <flags TEST_RUNNER_ARGS=" /bin/zsh Core/Ntupliser/test mkFastSimTestSample.sh runAnalysis.sh runHelpers.sh"/>
+        <flags TEST_RUNNER_ARGS=" /bin/zsh Core/Ntupliser/test mkFastSimTestSample.sh runAnalysis.sh"/>
         <use name="FWCore/Utilities"/>
     </bin>
 </environment>
diff --git a/Ntupliser/test/runHelpers.sh b/Ntupliser/test/runHelpers.sh
deleted file mode 100755
index ab4e7c16c9b958aad6393d7e98f70ee8e074b953..0000000000000000000000000000000000000000
--- a/Ntupliser/test/runHelpers.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/zsh
-set -e
-
-# counter
-N=0
-
-cd $CMSSW_BASE/bin/$SCRAM_ARCH/
-for i in $(grep -rIL .)
-do
-    echo "\x1B[1m$i\x1B[0m"
-    out=$($i -h | grep "\-e \[ --example \]          Print config example" || test $? = 1)
-    if [[ -n $out ]]
-    then
-        ./$i -e
-        ((N=N+1))
-    fi
-done
-
-# this is a safety in case the grep no longer works bc of a change in ProtoDarwin
-[[ N -gt 0 ]]
diff --git a/Objects/CMakeLists.txt b/Objects/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..401d5773adb3aab594beee34b6010356bf3a3223
--- /dev/null
+++ b/Objects/CMakeLists.txt
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+core_add_library(
+    TARGET_NAME CoreObjects
+    SOURCES Event.cc
+    TESTS   Di Jet Lepton Photon PhysicsObject Weight
+)
+root_generate_dictionary(CoreObjects_rdict
+                         MODULE CoreObjects
+                         LINKDEF "${CMAKE_SOURCE_DIR}/Objects/src/LinkDef.h")
diff --git a/Objects/interface/Photon.h b/Objects/interface/Photon.h
index e91915c1ec121a2decb184b291ad4e93d3c044a5..337b06dfa059c25302d4976e3b9d8dbf5b777638 100644
--- a/Objects/interface/Photon.h
+++ b/Objects/interface/Photon.h
@@ -4,6 +4,8 @@
 
 #include <TString.h>
 
+#include <array>
+
 namespace DAS {
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/Objects/interface/PhysicsObject.h b/Objects/interface/PhysicsObject.h
index b0a4819e7d6c4525582ad2914c04baa749eacf98..89872ef699f3dcc4299c1e73c87af540f701b42e 100644
--- a/Objects/interface/PhysicsObject.h
+++ b/Objects/interface/PhysicsObject.h
@@ -84,11 +84,6 @@ inline std::ostream& operator<< (std::ostream& s, const DAS::PhysicsObject& obj)
 // TODO: comparison (order by pt)
 
 #if defined(__ROOTCLING__)
-#pragma link C++ class DAS::FourVector +;
-#pragma link C++ class std::vector<DAS::FourVector> +;
-
 #pragma link C++ class DAS::AbstractPhysicsObject +;
-
 #pragma link C++ class DAS::PhysicsObject +;
-#pragma link C++ class std::vector<DAS::PhysicsObject> +;
 #endif
diff --git a/Objects/interface/Weight.h b/Objects/interface/Weight.h
index feb58dbbecb85b5bf110be3ba974b18674a74373..3e5c38e974728877157989c27981b7ca48868297 100644
--- a/Objects/interface/Weight.h
+++ b/Objects/interface/Weight.h
@@ -47,3 +47,8 @@ inline Weights& operator*= (Weights& wgts, const double v) { for (auto& w: wgts)
 inline Weights& operator/= (Weights& wgts, const double v) { for (auto& w: wgts) w /= v; return wgts; }
 
 } // end of DAS namespace
+
+#ifdef __ROOTCLING__
+#pragma link C++ class DAS::Weight +;
+#endif // __ROOTCLING__
+
diff --git a/Objects/src/LinkDef.h b/Objects/src/LinkDef.h
new file mode 100644
index 0000000000000000000000000000000000000000..fa51ff75618c3efaf06fc9600056bf1cb7c0ce1e
--- /dev/null
+++ b/Objects/src/LinkDef.h
@@ -0,0 +1,8 @@
+#ifdef __ROOTCLING__
+#include "Core/Objects/interface/Weight.h"
+#include "Core/Objects/interface/Jet.h"
+#include "Core/Objects/interface/Lepton.h"
+#include "Core/Objects/interface/Photon.h"
+#include "Core/Objects/interface/Event.h"
+#include "Core/Objects/interface/Di.h"
+#endif // __ROOTCLING__
diff --git a/Objects/test/BuildFile.xml b/Objects/test/BuildFile.xml
deleted file mode 100644
index 73565c90656ece5cbbf87ff8d33959593924f788..0000000000000000000000000000000000000000
--- a/Objects/test/BuildFile.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<flags CXXFLAGS="-g  -DDEBUG -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<use name="boost" />
-<use name="root" />
-
-<use name="Core/Objects" />
-
-<bin name="Weight" file="Weight.cc" />
-<bin name="PhysicsObject" file="PhysicsObject.cc" />
-<bin name="Jet" file="Jet.cc" />
-<bin name="Lepton" file="Lepton.cc" />
-<bin name="Photon" file="Photon.cc" />
-<bin name="Di" file="Di.cc" />
diff --git a/Objects/test/PhysicsObject.cc b/Objects/test/PhysicsObject.cc
index 1ad27edf5b0c5b54ac03006762d0825ef302d038..a2a4477a174d7020824d776dd86e328e4fa7160c 100644
--- a/Objects/test/PhysicsObject.cc
+++ b/Objects/test/PhysicsObject.cc
@@ -43,7 +43,6 @@ BOOST_AUTO_TEST_CASE( weights )
 {
     PhysicsObjectDummy obj;
     BOOST_TEST( obj.weights.size() == 1);
-    BOOST_REQUIRE_NO_THROW( obj.weights[0] );
     BOOST_TEST( obj.weights[0] == 1);
 }
 
diff --git a/PUprofile/CMakeLists.txt b/PUprofile/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ce9a4fec12f8518c996e0b33abf2c1f6b1220eaa
--- /dev/null
+++ b/PUprofile/CMakeLists.txt
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+core_add_executable(applyDiffPUprofCorrection LIBRARIES CommonTools Objects)
+core_add_executable(applyPUprofCorrection LIBRARIES CommonTools Objects)
+core_add_executable(getPUprofile LIBRARIES Objects)
diff --git a/PUprofile/bin/BuildFile.xml b/PUprofile/bin/BuildFile.xml
deleted file mode 100644
index e1f2085af437111d6175632f11f004a3cb33b14d..0000000000000000000000000000000000000000
--- a/PUprofile/bin/BuildFile.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<flags CXXFLAGS="-g  -DDEBUG -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<lib name="stdc++fs" />
-
-<use name="darwin" />
-
-<use name="root" />
-<use name="rootgraphics"/>
-
-<use name="boost" />
-
-<use name="Core/Objects" />
-<use name="Core/CommonTools" />
-
-<bin name="getPUprofile" file="getPUprofile.cc" />
-<bin name="applyPUprofCorrection" file="applyPUprofCorrection.cc" />
-<bin name="applyDiffPUprofCorrection" file="applyDiffPUprofCorrection.cc" />
-
diff --git a/PUprofile/bin/applyDiffPUprofCorrection.cc b/PUprofile/bin/applyDiffPUprofCorrection.cc
index 613dd4b3edcdae8c1422504259afd023d556a93b..99721ee0551ba4a0030b46600295d00582d8ca08 100644
--- a/PUprofile/bin/applyDiffPUprofCorrection.cc
+++ b/PUprofile/bin/applyDiffPUprofCorrection.cc
@@ -220,7 +220,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/PUprofile/bin/applyPUprofCorrection.cc b/PUprofile/bin/applyPUprofCorrection.cc
index 79e0e8bdf3bb3143c040683c7c72110a20ea2c97..5e278d5a1282dc3bc15a84fa0a8a4773a15b188c 100644
--- a/PUprofile/bin/applyPUprofCorrection.cc
+++ b/PUprofile/bin/applyPUprofCorrection.cc
@@ -170,7 +170,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/PUprofile/bin/getPUprofile.cc b/PUprofile/bin/getPUprofile.cc
index 21f5ba61a92a399b2e6a0bd63b0b13b71cde1af2..44c64508a15dd2a5d6c31626342df4c111c98887 100644
--- a/PUprofile/bin/getPUprofile.cc
+++ b/PUprofile/bin/getPUprofile.cc
@@ -178,7 +178,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/PUstaubSauger/BuildFile.xml b/PUstaubSauger/BuildFile.xml
deleted file mode 100644
index f8c456410030b22eb762895bf2c8c474fa0250ae..0000000000000000000000000000000000000000
--- a/PUstaubSauger/BuildFile.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<use name="root"/> 
-<use name="rootmath"/> 
-<lib name="stdc++fs" />
-<use name="Core/Objects"/>
-<export>
-    <lib   name="1"/>
-</export>
diff --git a/PUstaubSauger/CMakeLists.txt b/PUstaubSauger/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a64b3669401dd7d69aa7be4f50c90ff4c1ebbb6b
--- /dev/null
+++ b/PUstaubSauger/CMakeLists.txt
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+core_add_executable(applyPUcleaning LIBRARIES CommonTools)
+core_add_executable(applyPUcleaningHT LIBRARIES CommonTools)
+core_add_executable(getHighScalePUeventIDs NO_EXAMPLE)
+core_add_executable(getHighScalePUeventIDsHT NO_EXAMPLE)
diff --git a/PUstaubSauger/bin/BuildFile.xml b/PUstaubSauger/bin/BuildFile.xml
deleted file mode 100644
index fcdb1a3260b285441096284bd7097864199f9466..0000000000000000000000000000000000000000
--- a/PUstaubSauger/bin/BuildFile.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<flags CXXFLAGS="-g  -DDEBUG -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<lib name="stdc++fs" />
-
-<use name="darwin" />
-
-<use name="root" />
-<use name="rootgraphics"/>
-
-<use name="Core/Objects" />
-<use name="Core/CommonTools" />
-
-<bin name="applyPUcleaning" file="applyPUcleaning.cc" />
-<bin name="getHighScalePUeventIDs" file="getHighScalePUeventIDs.cc" />
-
-<bin name="applyPUcleaningHT" file="applyPUcleaningHT.cc" />
-<bin name="getHighScalePUeventIDsHT" file="getHighScalePUeventIDsHT.cc" />
diff --git a/PUstaubSauger/bin/applyPUcleaning.cc b/PUstaubSauger/bin/applyPUcleaning.cc
index cdff09a43b37138420a2c0d8388ba035c0a20c31..fad0000432a77aed353a77e7b914fb160b372abb 100644
--- a/PUstaubSauger/bin/applyPUcleaning.cc
+++ b/PUstaubSauger/bin/applyPUcleaning.cc
@@ -191,7 +191,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/PUstaubSauger/bin/applyPUcleaningHT.cc b/PUstaubSauger/bin/applyPUcleaningHT.cc
index 48843fde345fb7992be4bb0f3714405ed9456574..af5896020c3a9a5e59f705107b16e8635ac67e35 100644
--- a/PUstaubSauger/bin/applyPUcleaningHT.cc
+++ b/PUstaubSauger/bin/applyPUcleaningHT.cc
@@ -190,7 +190,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/PUstaubSauger/bin/getHighScalePUeventIDs.cc b/PUstaubSauger/bin/getHighScalePUeventIDs.cc
index c40a7d2b8c37e3ded1e3695cb5f7c49c8f36273c..46aea02a793b97a6439ca8e09bbc00a2767886f3 100644
--- a/PUstaubSauger/bin/getHighScalePUeventIDs.cc
+++ b/PUstaubSauger/bin/getHighScalePUeventIDs.cc
@@ -95,7 +95,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/PUstaubSauger/bin/getHighScalePUeventIDsHT.cc b/PUstaubSauger/bin/getHighScalePUeventIDsHT.cc
index d48b615437c2f22ceddf0d8e3e4b35cc7a07a088..5a5a30f5b5c439cc0f9adae6a9975d10bf1390aa 100644
--- a/PUstaubSauger/bin/getHighScalePUeventIDsHT.cc
+++ b/PUstaubSauger/bin/getHighScalePUeventIDsHT.cc
@@ -98,7 +98,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/Photons/CMakeLists.txt b/Photons/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8c248a38a37026e1803cbca1b1473c3cdfc914ef
--- /dev/null
+++ b/Photons/CMakeLists.txt
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+core_add_executable(applyPhotonCSEV)
+core_add_executable(applyPhotonID)
diff --git a/Photons/bin/BuildFile.xml b/Photons/bin/BuildFile.xml
deleted file mode 100644
index ec25ab3518d28160e3cc93e2b1ba41a76ee04c91..0000000000000000000000000000000000000000
--- a/Photons/bin/BuildFile.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<flags CXXFLAGS="-g -O3  -std=c++1z" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<lib name="stdc++fs" />
-
-<use name="root" />
-<use name="boost" />
-<use name="darwin" />
-
-<use name="Core/Objects" />
-<use name="Core/CommonTools" />
-
-<bin name="applyPhotonID" file="applyPhotonID.cc" />
-<bin name="applyPhotonCSEV" file="applyPhotonCSEV.cc" />
diff --git a/Photons/bin/applyPhotonCSEV.cc b/Photons/bin/applyPhotonCSEV.cc
index e665e3d08b0fa8bb269ec96f64e04b1dbf1b3816..eaa6bb4ab53973c04a832f1451acd7f04cc2cad0 100644
--- a/Photons/bin/applyPhotonCSEV.cc
+++ b/Photons/bin/applyPhotonCSEV.cc
@@ -159,7 +159,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/Photons/bin/applyPhotonID.cc b/Photons/bin/applyPhotonID.cc
index 4e82dc515e613a38811ff3c3e9c6ccdd62d09adf..03caa379359c2fd4ed4adc438e9207a98e1559f6 100644
--- a/Photons/bin/applyPhotonID.cc
+++ b/Photons/bin/applyPhotonID.cc
@@ -147,7 +147,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/Prefiring/CMakeLists.txt b/Prefiring/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..660703f08cf6e594fbc7a688c59bbac46b0a9ec6
--- /dev/null
+++ b/Prefiring/CMakeLists.txt
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+core_add_executable(applyPrefiringWeights LIBRARIES CommonTools)
+core_add_executable(fitPrefiringCorrections NO_EXAMPLE)
diff --git a/Prefiring/bin/BuildFile.xml b/Prefiring/bin/BuildFile.xml
deleted file mode 100644
index 168ef6886a2a5c7e457e9fa0f611e6771f68dc2b..0000000000000000000000000000000000000000
--- a/Prefiring/bin/BuildFile.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<flags CXXFLAGS="-g -DDEBUG -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<use name="darwin" />
-
-<use name="boost" />
-
-<use name="root" />
-<use name="rootmath" />
-<use name="rootgraphics"/>
-
-<lib name="stdc++fs" />
-
-<use name="Core/Objects" />
-<use name="Core/CommonTools" />
-<use name="Core/Normalisation" />
-
-<bin name="applyPrefiringWeights" file="applyPrefiringWeights.cc" />
-<bin name="fitPrefiringCorrections" file="fitPrefiringCorrections.cc" />
diff --git a/Prefiring/bin/applyPrefiringWeights.cc b/Prefiring/bin/applyPrefiringWeights.cc
index 6db8fde5228fc04691023deafc386d4cdc5e03d3..eb648fba7e0f63ddef5cd6ed5586db71e4b0fa56 100644
--- a/Prefiring/bin/applyPrefiringWeights.cc
+++ b/Prefiring/bin/applyPrefiringWeights.cc
@@ -117,7 +117,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/Prefiring/bin/fitPrefiringCorrections.cc b/Prefiring/bin/fitPrefiringCorrections.cc
index a5bddbd6df58659d875e5279f900ab8e78135ca8..1ff08f2985b9428f557ce1530606ead272bf7444 100644
--- a/Prefiring/bin/fitPrefiringCorrections.cc
+++ b/Prefiring/bin/fitPrefiringCorrections.cc
@@ -221,7 +221,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         fs::path input, output;
 
diff --git a/README.md b/README.md
index 5c2af2807571bbf575ced80127ab59c5e711f224..ef2708459ba794a82cda4f6efa56119d6e4e7198 100644
--- a/README.md
+++ b/README.md
@@ -3,10 +3,13 @@
 [![pipeline status](https://gitlab.cern.ch/paconnor/software/badges/master/pipeline.svg)](https://gitlab.cern.ch/paconnor/software/-/commits/main) 
 [![coverage report](https://gitlab.cern.ch/paconnor/software/badges/master/coverage.svg)](https://gitlab.cern.ch/paconnor/software/-/commits/main) 
 
-The software is developed on top of CMSSW.
-It allows to conduct the jet analyses from official CMS data sets to the results ready for publication.
+The software is developed on top of Darwin.
+It allows to conduct analyses from official CMS data sets to the results ready for publication.
+
+The software is made of two parts:
+* CMSSW-based tools for the production of *n*-tuples.
+* Modules to apply physics selections and corrections specific to CMS, modifying *n*-tuples step by step until distributions can be obtained and unfolded. This part of the framework is compiled with CMake.
 
-In addition to the production of *n*-tuples, the basic principle of the software is to modify the Monte Carlo *n*-tuples step by step to make them resemble as much as possible to the data, and then to unfold.
 It encompasses the following steps:
  1. *n*-tuplisation
  2. Basic treatement of data and MC (the list of correction is not exhaustive):
@@ -19,9 +22,11 @@ It encompasses the following steps:
 In alphabetical order:
  - [CommonTools](CommonTools/README.md): some common tools for development and running (no physics in this directory)
  - [JEC](JEC/README.md): apply JES corrections and JER smearing corrections
+ - [Muons](Muons/README.md): select muons and apply scale factors
  - [Normalisation](Normalisation/README.md): normalisation of data and simulation after merging
  - [Ntupliser](Ntupliser/README.md): code for *n*-tuplisation with CRAB jobs
  - [Objects](Objects/README.md): code for the objects in the *n*-tuples
+ - [Photons](Photons/README.md): select photons and apply scale factors
  - [Prefiring](Prefiring/README.md): code to apply the prefiring correction in data
  - [PUprofile](PUprofile/README.md): tools to perform the pile-up profile reweighting in simulation
  - [PUstaubSauger](PUstaubSauger/README.md): tool to clean up the simulation from the badly sampled simulation
diff --git a/Trigger/BuildFile.xml b/Trigger/BuildFile.xml
deleted file mode 100644
index 400136a60b75441ba3bbb4d345fd726b65bf4950..0000000000000000000000000000000000000000
--- a/Trigger/BuildFile.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<use name="root"/> 
-<use name="rootgraphics"/> 
-<lib name="stdc++fs" />
-<export>
-    <lib   name="1"/>
-</export>
diff --git a/Trigger/CMakeLists.txt b/Trigger/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ee31627d5beb5e4e3c9893fab187b972cc8647c3
--- /dev/null
+++ b/Trigger/CMakeLists.txt
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+core_add_executable(getTriggerCurves)
+core_add_executable(getTriggerTurnons)
+
diff --git a/Trigger/bin/BuildFile.xml b/Trigger/bin/BuildFile.xml
deleted file mode 100644
index b4ab048cc2b4d355bac2c497fc2104a45a6f374f..0000000000000000000000000000000000000000
--- a/Trigger/bin/BuildFile.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<flags CXXFLAGS="-g  -DDEBUG -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<lib name="stdc++fs" />
-
-<use name="darwin" />
-<use name="boost" />
-
-<use name="root" />
-<use name="rootmath" />
-<use name="rootgraphics"/>
-
-<use name="Core/Objects" />
-<use name="Core/CommonTools" />
-
-<bin name="getTriggerCurves" file="getTriggerCurves.cc"/>
-<bin name="getTriggerTurnons" file="getTriggerTurnons.cc" />
diff --git a/Trigger/bin/getTriggerCurves.cc b/Trigger/bin/getTriggerCurves.cc
index 2527b8b5e218f4ef0bc7fa4158ed5ec2d68ee2be..1610f75de6620556fab273763a0221b6881682eb 100644
--- a/Trigger/bin/getTriggerCurves.cc
+++ b/Trigger/bin/getTriggerCurves.cc
@@ -321,7 +321,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/Trigger/bin/getTriggerTurnons.cc b/Trigger/bin/getTriggerTurnons.cc
index a84c6742b54ddcfdd8c9478120109d543bcc0871..e4ca7beb86a891241177d127663764d5053b2837 100644
--- a/Trigger/bin/getTriggerTurnons.cc
+++ b/Trigger/bin/getTriggerTurnons.cc
@@ -184,7 +184,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         fs::path input, outputRoot, outputTxt;
 
diff --git a/Trigger/src/BuildFile.xml b/Trigger/src/BuildFile.xml
deleted file mode 100644
index 4816c321cea396db336954747e91a79804912322..0000000000000000000000000000000000000000
--- a/Trigger/src/BuildFile.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<flags CXXFLAGS="-g -DDEBUG -Wall -std=c++17" />
-
-<use name="root" />
-<use name="rootgraphics" />
-
-<lib name="stdc++fs" />
-
-<export>
-    <lib name="CoreTrigger"/>
-</export>
diff --git a/Uncertainties/BuildFile.xml b/Uncertainties/BuildFile.xml
deleted file mode 100644
index 39f32635eae9653ff8f1f0248ac337297114f722..0000000000000000000000000000000000000000
--- a/Uncertainties/BuildFile.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<use name="boost"/> 
-<use name="root"/> 
-<use name="rootmath"/> 
-<use name="darwin" />
-<use name="tunfold" />
-<use name="eigen" />
-<lib name="stdc++fs" />
-<use name="Core/Objects"/>
-<export>
-    <lib   name="1"/>
-</export>
diff --git a/Uncertainties/CMakeLists.txt b/Uncertainties/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ea4fc537ec66508f504b75717a6ec71c0cd95598
--- /dev/null
+++ b/Uncertainties/CMakeLists.txt
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+core_add_library(
+    SOURCES Teddy.cc
+    DEPENDS Eigen3::Eigen Unfolding
+    TESTS   toy
+)
+core_add_executable(getToyCalculation)
diff --git a/Uncertainties/bin/BuildFile.xml b/Uncertainties/bin/BuildFile.xml
deleted file mode 100644
index 1ca122d660b502d845b8c5c6db501149befdd00b..0000000000000000000000000000000000000000
--- a/Uncertainties/bin/BuildFile.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<flags CXXFLAGS="-g -O3 -DDEBUG -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<use name="darwin" />
-<use name="tunfold" />
-<use name="boost" />
-<use name="eigen" />
-
-<use name="root" />
-<use name="rootmath" />
-<use name="rootgraphics"/>
-
-<lib name="stdc++fs" />
-
-<use name="Core/Objects" />
-<use name="Core/CommonTools" />
-<use name="Core/Unfolding" />
-<use name="Core/Uncertainties" />
-
-<bin name="getToyCalculation" file="getToyCalculation.cc" />
diff --git a/Uncertainties/bin/getToyCalculation.cc b/Uncertainties/bin/getToyCalculation.cc
index 9a2ded0eb1bdb89665a697718912db419f863481..19c8e7d7a1e1eb6b2d042eed11f8a45a7f92f7d2 100644
--- a/Uncertainties/bin/getToyCalculation.cc
+++ b/Uncertainties/bin/getToyCalculation.cc
@@ -211,7 +211,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         fs::path input, output;
 
diff --git a/Uncertainties/test/BuildFile.xml b/Uncertainties/test/BuildFile.xml
deleted file mode 100644
index 766b0fbad470da38bb852fcd664cf34847de847f..0000000000000000000000000000000000000000
--- a/Uncertainties/test/BuildFile.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<flags CXXFLAGS="-g -O3 -DDEBUG -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<use name="darwin" />
-<use name="tunfold" />
-<use name="eigen" />
-<use name="boost" />
-
-<use name="root" />
-<use name="rootmath" />
-<use name="rootgraphics"/>
-
-<lib name="stdc++fs" />
-
-<use name="Core/Objects" />
-<use name="Core/CommonTools" />
-<use name="Core/Unfolding" />
-<use name="Core/Uncertainties" />
-
-<bin name="testToy" file="toy.cc" />
diff --git a/Unfolding/BuildFile.xml b/Unfolding/BuildFile.xml
deleted file mode 100644
index d4c3f62af4664994d1c209449b7f30a52f6400e6..0000000000000000000000000000000000000000
--- a/Unfolding/BuildFile.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<use name="root"/> 
-<use name="rootmath"/> 
-<use name="darwin" />
-<use name="tunfold" />
-<use name="eigen" />
-<lib name="stdc++fs" />
-<lib name="TreePlayer" />
-<use name="Core/Objects"/>
-<export>
-    <lib   name="1"/>
-</export>
diff --git a/Unfolding/CMakeLists.txt b/Unfolding/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..12abde10113c9aba9900a1e1e08a4b1aa1400f17
--- /dev/null
+++ b/Unfolding/CMakeLists.txt
@@ -0,0 +1,29 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+core_add_library(
+    SOURCES
+        BF.cc
+        HTn.cc
+        MjjYmax.cc
+        MjjYbYs.cc
+        MNjets.cc
+        Observable.cc
+        PtY.cc
+        Variations.cc
+        ZPtY.cc
+    DEPENDS
+        Darwin::Darwin
+        Eigen3::Eigen
+        ROOT::TreePlayer
+        TUnfold::TUnfold
+    TESTS
+        unfold
+)
+core_add_executable(getLmatrix)
+core_add_executable(getUnfBinning)
+core_add_executable(getUnfHist)
+core_add_executable(getUnfHistPt NO_EXAMPLE)
+core_add_executable(getUnfPhysDist)
+core_add_executable(unfold)
diff --git a/Unfolding/bin/BuildFile.xml b/Unfolding/bin/BuildFile.xml
deleted file mode 100644
index 84a940bd6c3f61481caff5d5c93c68f52a5ee30f..0000000000000000000000000000000000000000
--- a/Unfolding/bin/BuildFile.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<flags CXXFLAGS="-g -O3 -DDEBUG -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<use name="darwin" />
-<use name="tunfold" />
-<use name="boost" />
-
-<use name="root" />
-<use name="rootmath" />
-<use name="rootgraphics"/>
-
-<lib name="stdc++fs" />
-
-<use name="Core/Objects" />
-<use name="Core/CommonTools" />
-<use name="Core/Unfolding" />
-
-<bin name="getUnfHistPt" file="getUnfHistPt.cc" />
-<bin name="getUnfHist" file="getUnfHist.cc" />
-
-<bin name="unfold" file="unfold.cc" />
-<bin name="getLmatrix" file="getLmatrix.cc" />
-<bin name="getUnfBinning" file="getUnfBinning.cc" />
-<bin name="getUnfPhysDist" file="getUnfPhysDist.cc" />
diff --git a/Unfolding/bin/getLmatrix.cc b/Unfolding/bin/getLmatrix.cc
index c8d9d8026e09838ae1f56bcddc0e8ec2baa51aac..366bb4701490eb8e2b5dfd283e22bfd2ff13c80e 100644
--- a/Unfolding/bin/getLmatrix.cc
+++ b/Unfolding/bin/getLmatrix.cc
@@ -95,7 +95,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
         DT::MetaInfo::versions["TUnfold"] = TUnfold::GetTUnfoldVersion();
 
         fs::path input, output;
diff --git a/Unfolding/bin/getUnfBinning.cc b/Unfolding/bin/getUnfBinning.cc
index 0af48e1ff91e7d35338ca27badd9303505d5c87a..5e69106b8e668810c81500a749565e09704dc354 100644
--- a/Unfolding/bin/getUnfBinning.cc
+++ b/Unfolding/bin/getUnfBinning.cc
@@ -66,7 +66,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
         DT::MetaInfo::versions["TUnfold"] = TUnfold::GetTUnfoldVersion();
 
         fs::path outputGen, outputRec;
diff --git a/Unfolding/bin/getUnfHist.cc b/Unfolding/bin/getUnfHist.cc
index 158202ea6e1d19c9d0180d8fddb3b2495a882a72..253e38b33fd50f90017ef206a9a6610ea40f7053 100644
--- a/Unfolding/bin/getUnfHist.cc
+++ b/Unfolding/bin/getUnfHist.cc
@@ -125,7 +125,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
         DT::MetaInfo::versions["TUnfold"] = TUnfold::GetTUnfoldVersion();
 
         vector<fs::path> inputs;
diff --git a/Unfolding/bin/getUnfHistPt.cc b/Unfolding/bin/getUnfHistPt.cc
index 0dd321656d0bcda84199a8922efb62d2519ddd1c..f390af3db57f5dc99e1ee12bb8593410c2b10334 100644
--- a/Unfolding/bin/getUnfHistPt.cc
+++ b/Unfolding/bin/getUnfHistPt.cc
@@ -261,7 +261,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
 
         vector<fs::path> inputs;
         fs::path output;
diff --git a/Unfolding/bin/getUnfPhysDist.cc b/Unfolding/bin/getUnfPhysDist.cc
index fea41e28904ecb74f1f6e8a284db33557a8b9acf..fcec5736fb2682cb76fcbc52ea8e68dbad2b1ea3 100644
--- a/Unfolding/bin/getUnfPhysDist.cc
+++ b/Unfolding/bin/getUnfPhysDist.cc
@@ -347,7 +347,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
         DT::MetaInfo::versions["TUnfold"] = TUnfold::GetTUnfoldVersion();
 
         fs::path input, output;
diff --git a/Unfolding/bin/unfold.cc b/Unfolding/bin/unfold.cc
index 58f079c078b5e91e138d3d0967f8c83437d7a3a0..5bf4330d825dc9c300f32cc980b3cc7f47bb45d7 100644
--- a/Unfolding/bin/unfold.cc
+++ b/Unfolding/bin/unfold.cc
@@ -972,7 +972,6 @@ int main (int argc, char * argv[])
 {
     try {
         DT::StandardInit();
-        DT::MetaInfo::versions["CMSSW"] = getenv("CMSSW_VERSION");
         DT::MetaInfo::versions["TUnfold"] = TUnfold::GetTUnfoldVersion();
 
         fs::path inputData, inputMC, output;
diff --git a/Unfolding/src/BuildFile.xml b/Unfolding/src/BuildFile.xml
deleted file mode 100644
index 27c38650945ce3cc363d036d26a603354a3c7eec..0000000000000000000000000000000000000000
--- a/Unfolding/src/BuildFile.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<flags CXXFLAGS="-g -O3 -DDEBUG -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-
-<use name="eigen" />
-<use name="root" />
-<use name="rootgraphics"/>
-
-<use name="darwin" />
-<use name="tunfold" />
-
-<use name="Core/Objects" />
-
-<export>
-    <lib name="CoreUnfolding"/>
-</export>
diff --git a/Unfolding/test/BuildFile.xml b/Unfolding/test/BuildFile.xml
deleted file mode 100644
index 2adac946ab87b4e667afad9b0cfece86e8ea9b98..0000000000000000000000000000000000000000
--- a/Unfolding/test/BuildFile.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<flags CXXFLAGS="-g -O3 -DDEBUG -Wall -std=c++17" />
-<flags CPPDEFINES='DARWIN_GIT_REPO=\"$(CMSSW_BASE)/src/Core\"'/>
-<flags CPPDEFINES='DARWIN_EXAMPLE=\"$(CMSSW_BASE)/src/Core/CommonTools/doc/example.info\"'/>
-
-<use name="darwin" />
-<use name="tunfold" />
-<use name="boost" />
-
-<use name="root" />
-<use name="rootmath" />
-<use name="rootgraphics"/>
-
-<lib name="stdc++fs" />
-
-<use name="Core/Objects" />
-<use name="Core/CommonTools" />
-<use name="Core/Unfolding" />
-
-<bin name="testUnfold" file="unfold.cc" />
diff --git a/cmake/CoreHelpers.cmake b/cmake/CoreHelpers.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..a9943c8fe7418386456d456825ef45516a749118
--- /dev/null
+++ b/cmake/CoreHelpers.cmake
@@ -0,0 +1,127 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+# This module contains functions to factilitate creating libraries and
+# executables from the code layout in Core. Functions in this module expect the
+# following folder structure:
+#
+#   Module/
+#       CMakeLists.txt
+#       bin/
+#       interface/
+#       src/
+#       test/
+#
+# The `bin` folder contains executables, `interface` the headers and `src` the
+# source code of supporting code, and `test` contains files for testing.
+
+enable_testing()
+
+# Returns the name of the current module in the variable passed as argument.
+function(core_current_module_name)
+    cmake_path(GET CMAKE_CURRENT_SOURCE_DIR FILENAME modname)
+    set(${ARGV0} ${modname} PARENT_SCOPE)
+endfunction()
+
+# Creates a test from a module in scram layout. The optional LIBRARIES
+# parameter gives a list of targets to link against. The test will be called
+# without arguments.
+function(core_add_test)
+    cmake_parse_arguments(PARSE_ARGV 2 ARG "" "" "LIBRARIES")
+    set(test_name ${ARGV0}_${ARGV1})
+    add_executable(${test_name} test/${ARGV1}.cc)
+    # We always need Darwin
+    target_link_libraries(${test_name} PRIVATE Darwin::Darwin ${ARG_LIBRARIES})
+    if (TARGET ${ARGV0})
+        # If there is a library, usually we also need it
+        target_link_libraries(${test_name} PRIVATE ${ARGV0})
+    endif()
+    add_test(NAME ${test_name} COMMAND ${test_name})
+endfunction()
+
+# Creates a library from a module in scram layout. The SOURCES parameter gives
+# the list of source files to include in the shared object, to be found in the
+# `src` subdirectory. The optional DEPENDS parameter is a list of libraries to
+# link against. The optional TESTS parameter gives a list of test file names
+# (without extension) to be passed to core_add_test(). The library is named
+# `lib<PROJECT_NAME><MODULE>.so`.
+#
+# This function always creates a target named after the current module. It is
+# usually the library target created with add_library(). The name of the
+# library target can optionally be customized by passing TARGET_NAME. In that
+# case, an alias target is created with the module name. This is intended to
+# work around ROOT bug #15792 for modules that need ROOT dictionaries.
+function(core_add_library)
+    cmake_parse_arguments(PARSE_ARGV 0 ARG "" "TARGET_NAME" "DEPENDS;SOURCES;TESTS")
+    list(TRANSFORM ARG_SOURCES PREPEND src/)
+
+    core_current_module_name(modname)
+
+    # TARGET_NAME is needed to work around for ROOT bug 15792.
+    if (DEFINED ARG_TARGET_NAME)
+        set(target ${ARG_TARGET_NAME})
+    else()
+        set(target ${modname})
+    endif()
+
+    add_library(${target} SHARED ${ARG_SOURCES})
+    # Set library names to libCoreABC.so without changing the target name
+    set_target_properties(${target} PROPERTIES OUTPUT_NAME ${PROJECT_NAME}${modname})
+    target_include_directories(${target} PUBLIC  "interface")
+    target_include_directories(${target} PRIVATE "src")
+    target_link_libraries(${target} PUBLIC ${ARG_DEPENDS})
+    install(TARGETS ${target}
+            RUNTIME DESTINATION "${CMAKE_INSTALL_LIBDIR}")
+
+    if (NOT "${target}" STREQUAL "${modname}")
+        # Create an ALIAS target with the module name for convenience
+        add_library(${modname} ALIAS ${target})
+    endif()
+
+    # Tests
+    foreach(test IN LISTS ARG_TESTS)
+        core_add_test(${modname} ${test})
+    endforeach()
+endfunction()
+
+# Creates an executable from a module in scram layout. The only mandatory
+# argument is the name of the executable. A source file with the same name is
+# expected to exist in the `bin` subfolder. The optional LIBRARIES parameter
+# gives a list of libraries to link against.
+#
+# If a library exists for the current module, it is automatically linked to the
+# executable. Darwin is always linked in.
+#
+# A test is automatically added to check that the executable produces a helper
+# when run with `-h` and an example when run with `-e`. If NO_EXAMPLE is given,
+# the test passes even if the executable has no example.
+function(core_add_executable)
+    cmake_parse_arguments(PARSE_ARGV 1 ARG "NO_EXAMPLE" "" "LIBRARIES")
+
+    core_current_module_name(modname)
+
+    add_executable(${ARGV0} bin/${ARGV0}.cc)
+    # We always need Darwin
+    target_link_libraries(${ARGV0} PRIVATE Darwin::Darwin ${ARG_LIBRARIES})
+    if (TARGET ${modname})
+        # If there is a library, usually we also need it
+        target_link_libraries(${ARGV0} PRIVATE ${modname})
+    endif()
+    install(TARGETS ${ARGV0}
+            RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
+
+    # Check helper strings
+    if (ARG_NO_EXAMPLE)
+        set(grep_string "Help screen")
+    else()
+        set(grep_string "Print config example")
+    endif()
+    add_test(NAME ${modname}_${ARGV0}_helper COMMAND ${ARGV0} -h)
+    set_property(TEST ${modname}_${ARGV0}_helper
+	    	 PROPERTY PASS_REGULAR_EXPRESSION "${grep_string}")
+    # Check that it can print an example
+    if (NOT ARG_NO_EXAMPLE)
+        add_test(NAME ${modname}_${ARGV0}_example COMMAND ${ARGV0} -e)
+    endif()
+endfunction()