diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index fb60ca72a7c624abce3e2f26edede713ff050ac8..2f98937466ff3358fb0d30d78026b08537d09d70 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -13,3 +13,13 @@ compilation:
         - source /cvmfs/cms.cern.ch/cmsset_default.sh
         - yum install -y python3 zsh
         - make
+
+cmake:
+    stage: build
+    tags:
+        - cvmfs
+    script:
+        - source /cvmfs/cms.cern.ch/cmsset_default.sh
+        - yum install -y cmake3 python3 zsh
+        - ./install.sh
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b9bda2f882df87369d440f3ad0bcb51f240b1aa9
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: GPLv3-or-later
+#                                                                                                                     
+# SPDX-FileCopyrightText: Louis Moureaux <louis.moureaux@cern.ch>
+
+cmake_minimum_required(VERSION 3.17...3.28 FATAL_ERROR)                                                               
+
+# Set a useful default install directory but let the user override it
+set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/tools" CACHE PATH
+    "Install path prefix, prepended onto install directories.")
+
+# Also set a default build type - optimized build with debug information
+set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
+    "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel ...")
+
+project(Installer VERSION 1.0 LANGUAGES C)  # Need a language for GNUInstallDirs
+
+include(ExternalProject)
+include(GNUInstallDirs)
+
+install(FILES libgit2.xml TYPE SYSCONF)
+
+set(TUNFOLD_HEADERS TUnfold.h
+                    TUnfoldBinning.h
+                    TUnfoldBinningXML.h
+                    TUnfoldDensity.h
+                    TUnfoldIterativeEM.h
+                    TUnfoldSys.h
+)
+ExternalProject_Add(TUnfold
+    URL                 https://www.desy.de/~sschmitt/TUnfold/TUnfold_V17.9.tgz
+    URL_HASH            SHA256=d7f66f6a0e007eb946180643b8879bb2b8918441106bc0305b82a97391a391dc
+    SOURCE_DIR          "${CMAKE_SOURCE_DIR}/TUnfold"
+    CONFIGURE_COMMAND   ""
+    BUILD_COMMAND       make lib TUNFOLDVERSION='V17'
+    BUILD_IN_SOURCE     TRUE
+    INSTALL_COMMAND     install -DT libunfold.so <INSTALL_DIR>/${CMAKE_INSTALL_LIBDIR}/libtunfold.so
+            COMMAND     install TUnfoldV17Dict_rdict.pcm <INSTALL_DIR>/${CMAKE_INSTALL_LIBDIR}/
+            COMMAND     install -d <INSTALL_DIR>/${CMAKE_INSTALL_INCLUDEDIR}/TUnfold
+            COMMAND     install ${TUNFOLD_HEADERS} <INSTALL_DIR>/${CMAKE_INSTALL_INCLUDEDIR}/TUnfold/
+    INSTALL_DIR         "${CMAKE_INSTALL_PREFIX}"
+)
+configure_file(tunfold.xml.in tunfold.xml)
+install(FILES "${CMAKE_BINARY_DIR}/tunfold.xml" TYPE SYSCONF)
+
+ExternalProject_Add(ProtoDarwin
+    GIT_REPOSITORY      https://gitlab.cern.ch/paconnor/ProtoDarwin.git
+    GIT_TAG             origin/master
+    SOURCE_DIR          "${CMAKE_SOURCE_DIR}/ProtoDarwin"
+    CMAKE_ARGS          -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR> -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+    INSTALL_DIR         "${CMAKE_INSTALL_PREFIX}"
+    TEST_AFTER_INSTALL  ON
+)
+configure_file(protodarwin.xml.in protodarwin.xml)
+install(FILES "${CMAKE_BINARY_DIR}/protodarwin.xml" TYPE SYSCONF)
+
+ExternalProject_Add(tables
+    GIT_REPOSITORY      https://gitlab.cern.ch/DasAnalysisSystem/tables.git
+    GIT_TAG             origin/master
+    SOURCE_DIR          "${CMAKE_SOURCE_DIR}/tables"
+    CONFIGURE_COMMAND   ""
+    BUILD_COMMAND       ""
+    INSTALL_COMMAND     ""
+)
diff --git a/install.sh b/install.sh
new file mode 100755
index 0000000000000000000000000000000000000000..758274b33642983b7a9101f30a013c0cd0ba316c
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+set -e
+
+BASE_DIR=$PWD
+
+# Get a CMSSW if we don't have one
+if [ -z $CMSSW_BASE ]; then
+    version=CMSSW_12_4_0
+    [ ! -d $version ] && cmsrel $version
+    cd $version
+    cmsenv
+    unset version
+fi
+
+# Set up libgit2
+cd $CMSSW_BASE
+scram setup $BASE_DIR/libgit2.xml
+
+# Download and build supporting tools
+cd $BASE_DIR
+cmake3 -B .build
+cmake3 --build .build --target install -j$(nproc)
+
+# Get Core
+cd $CMSSW_BASE/src
+[ ! -d Core ] && git clone https://gitlab.cern.ch/DasAnalysisSystem/Core.git
+
+# Set up scram tools in CMSSW -- must be done after fetching Core
+cd $CMSSW_BASE
+for xml in $BASE_DIR/tools/etc/*.xml; do
+    scram setup $xml
+done
diff --git a/protodarwin.xml.in b/protodarwin.xml.in
new file mode 100644
index 0000000000000000000000000000000000000000..49896af108c40ac585dd543f0735c0e91d5b7da0
--- /dev/null
+++ b/protodarwin.xml.in
@@ -0,0 +1,21 @@
+<tool name="protodarwin" version="1.0"> <!-- TODO -->
+  <lib name="DarwinUserInfo"/>
+  <lib name="DarwinMetaInfo"/>
+  <lib name="DarwinOptions"/>
+  <lib name="DarwinObjects"/>
+  <info url="https://protodarwin.docs.cern.ch"/>
+  <client>
+    <environment name="DARWIN" default="${CMAKE_SOURCE_DIR}"/>
+    <environment name="INCLUDE" default="${CMAKE_INSTALL_FULL_INCLUDEDIR}/ProtoDarwin"/>
+    <environment name="LIBDIR" default="${CMAKE_INSTALL_FULL_LIBDIR}"/>
+  </client>
+  <use name="boost" />
+  <use name="boost_program_options" />
+  <runtime name="DARWIN_BASE" value="${CMAKE_SOURCE_DIR}" type="path"/>
+  <runtime name="DARWIN_FIRE_AND_FORGET" value="$CMSSW_BASE/lib/$SCRAM_ARCH" type="path"/><!-- TODO -->
+  <runtime name="PATH" value="${CMAKE_INSTALL_FULL_BINDIR}" type="path"/>
+  <runtime name="LD_LIBRARY_PATH" value="${CMAKE_INSTALL_FULL_LIBDIR}" type="path"/>
+  <runtime name="PYTHON3PATH" value="${CMAKE_INSTALL_PREFIX}/python" type="path"/>
+  <runtime name="DARWIN_GIT_REPO" value="$CMSSW_BASE/src/Core" type="path"/><!-- TODO -->
+  <runtime name="DARWIN_TABLES" value="${CMAKE_SOURCE_DIR}/tables" type="path"/>
+</tool>
diff --git a/tunfold.xml.in b/tunfold.xml.in
new file mode 100644
index 0000000000000000000000000000000000000000..f19a1e205cc62b5a6fd23bf95ea65b468e5257fa
--- /dev/null
+++ b/tunfold.xml.in
@@ -0,0 +1,13 @@
+<tool name="tunfold" version="17.9">
+  <lib name="tunfold"/>
+  <info url="https://www.desy.de/~sschmitt/tunfold.html"/>
+  <client>
+    <environment name="TUNFOLD_BASE" default="${CMAKE_SOURCE_DIR}/TUnfold"/><!-- FIXME Needed? -->
+    <environment name="INCLUDE" default="${CMAKE_INSTALL_FULL_INCLUDEDIR}/TUnfold"/>
+    <environment name="LIBDIR"  default="${CMAKE_INSTALL_FULL_LIBDIR}"/>
+  </client>
+  <use name="root_cxxdefaults"/>
+  <lib name="XMLIO" />
+  <lib name="XMLParser" />
+  <runtime name="LD_LIBRARY_PATH" value="$LIBDIR" type="path"/>
+</tool>