Construction et packaging¶
CMake est devenu le système de build standard de l'écosystème C et C++. Les gestionnaires de paquets Conan 2 et vcpkg gèrent les dépendances tierces. Cette section couvre le CMake moderne avec les targets, les presets, la compilation croisee, les Dockerfiles multi-stage et l'intégration CI/CD.
CMake moderne — targets et propriétés¶
Le CMake moderne (3.15+) repose sur le concept de targets : chaque target est une unite avec ses propres propriétés de compilation, ses dépendances et ses options de visibilité (PRIVATE, INTERFACE, PUBLIC).
# CMakeLists.txt — projet complet avec targets modernes
cmake_minimum_required(VERSION 3.20)
project(items_api VERSION 1.0.0 LANGUAGES CXX)
# Standard C++17 pour tous les targets du projet
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) # Pas d'extensions GCC/Clang non-standard
# Options configurables a la compilation
option(BUILD_TESTS "Construire les tests" ON)
option(ENABLE_ASAN "Activer AddressSanitizer" OFF)
option(ENABLE_COVERAGE"Activer la couverture gcov" OFF)
# --- Bibliotheque de base (logique metier) ---
add_library(items_lib STATIC
src/database.cpp
)
target_include_directories(items_lib
PUBLIC src # Les consommateurs trouvent les headers dans src/
PRIVATE src/internal # Headers internes non exposes
)
target_link_libraries(items_lib PUBLIC sqlite3)
target_compile_options(items_lib PRIVATE
$<$<CXX_COMPILER_ID:GNU,Clang>:-Wall -Wextra -Wpedantic>
$<$<CXX_COMPILER_ID:MSVC>:/W4>
)
# --- Executable principal ---
add_executable(items_api src/main.cpp src/handlers.cpp)
target_link_libraries(items_api PRIVATE items_lib)
target_include_directories(items_api PRIVATE third_party)
# --- Options conditionnelles ---
if(ENABLE_ASAN)
target_compile_options(items_lib PUBLIC -fsanitize=address,undefined)
target_link_options(items_lib PUBLIC -fsanitize=address,undefined)
endif()
if(ENABLE_COVERAGE)
target_compile_options(items_lib PUBLIC --coverage)
target_link_options(items_lib PUBLIC --coverage)
endif()
# --- Tests ---
if(BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
# --- Installation ---
install(TARGETS items_api RUNTIME DESTINATION bin)
install(DIRECTORY src/ DESTINATION include/items_api
FILES_MATCHING PATTERN "*.hpp"
PATTERN "internal" EXCLUDE)
CMake Presets¶
Les presets CMake (fichier CMakePresets.json) standardisent les configurations de build et sont partageables en équipe.
{
"version": 6,
"cmakeMinimumRequired": { "major": 3, "minor": 20, "patch": 0 },
"configurePresets": [
{
"name": "base",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
}
},
{
"name": "dev",
"inherits": "base",
"displayName": "Developpement local",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"ENABLE_ASAN": "ON",
"BUILD_TESTS": "ON"
}
},
{
"name": "release",
"inherits": "base",
"displayName": "Release optimisee",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"ENABLE_ASAN": "OFF",
"BUILD_TESTS": "OFF"
}
},
{
"name": "ci",
"inherits": "base",
"displayName": "Pipeline CI",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
"ENABLE_COVERAGE": "ON",
"BUILD_TESTS": "ON"
}
},
{
"name": "cross-arm",
"inherits": "base",
"displayName": "Cross-compilation ARM Linux",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/cmake/toolchains/arm-linux-gnueabihf.cmake",
"BUILD_TESTS": "OFF"
}
}
],
"buildPresets": [
{ "name": "dev", "configurePreset": "dev" },
{ "name": "release", "configurePreset": "release" },
{ "name": "ci", "configurePreset": "ci" }
],
"testPresets": [
{
"name": "ci",
"configurePreset": "ci",
"output": { "outputOnFailure": true },
"execution": { "parallel": 4 }
}
]
}
# Utilisation des presets
cmake --preset dev # Configuration
cmake --build --preset dev # Compilation
ctest --preset ci # Tests CI
# Lister les presets disponibles
cmake --list-presets
Gestionnaires de paquets¶
Conan 2¶
Conan 2 est le gestionnaire de paquets C/C++ le plus complet. Il généré les fichiers d'intégration CMake.
# conanfile.txt — dependances du projet
[requires]
sqlite3/3.45.0
nlohmann_json/3.11.3
catch2/3.6.0
[generators]
CMakeDeps
CMakeToolchain
[layout]
cmake_layout
# Installation des dependances avec Conan 2
# Profile auto-detecte ou personnalise
conan install . --output-folder=build --build=missing
# Configuration CMake avec le toolchain Conan
cmake -B build \
-DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE=Release
cmake --build build
vcpkg¶
vcpkg est le gestionnaire de paquets Microsoft, intégré nativement a CMake et Visual Studio.
// vcpkg.json — manifest du projet
{
"name": "items-api",
"version": "1.0.0",
"dependencies": [
"sqlite3",
"nlohmann-json",
"catch2",
{
"name": "boost-asio",
"features": []
}
]
}
# Installation et integration vcpkg
git clone https://github.com/microsoft/vcpkg.git
./vcpkg/bootstrap-vcpkg.sh
# CMake utilise vcpkg via le toolchain
cmake -B build \
-DCMAKE_TOOLCHAIN_FILE=./vcpkg/scripts/buildsystems/vcpkg.cmake \
-DCMAKE_BUILD_TYPE=Release
Compilation croisee — toolchain CMake¶
# cmake/toolchains/arm-linux-gnueabihf.cmake
# Compilation croisee pour ARM Linux (ex: Raspberry Pi)
# Prerequis : apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
# Compilateurs croisees
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
# Sysroot (optionnel — racine du systeme cible)
# set(CMAKE_SYSROOT /path/to/sysroot)
# Recherche des headers et bibliotheques uniquement dans la sysroot
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# Utilisation du toolchain de cross-compilation
cmake --preset cross-arm
cmake --build --preset cross-arm
# Verification de l'architecture du binaire produit
file build/cross-arm/items_api
# items_api: ELF 32-bit LSB executable, ARM, ...
Types de build CMake¶
| Type | Optimisation | Debug info | Usage |
|---|---|---|---|
Debug | -O0 | Oui | Développement local, debugger |
Release | -O3 | Non | Production |
RelWithDebInfo | -O2 | Oui | Production avec traces de crash |
MinSizeRel | -Os | Non | Binaires embarqués, taille minimale |
Dockerfile multi-stage¶
Un Dockerfile multi-stage permet de compiler dans un environnement complet et de déployer dans une image minimale.
# Dockerfile — build C++ multi-stage
# Stage 1 : image de construction complete
FROM ubuntu:24.04 AS builder
RUN apt-get update && apt-get install -y --no-install-recommends \
cmake ninja-build gcc g++ \
libsqlite3-dev \
git ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /src
COPY . .
# Installation des dependances header-only
RUN mkdir -p third_party && \
# nlohmann/json et httplib sont copiees depuis le repo
ls third_party/
# Configuration et compilation Release
RUN cmake --preset release && \
cmake --build --preset release
# Stage 2 : image de runtime minimale
FROM ubuntu:24.04 AS runtime
# Uniquement les bibliotheques partagees necessaires au runtime
RUN apt-get update && apt-get install -y --no-install-recommends \
libsqlite3-0 \
&& rm -rf /var/lib/apt/lists/*
# Utilisateur non-root pour la securite
RUN useradd -r -s /bin/false appuser
USER appuser
WORKDIR /app
# Copie uniquement le binaire final depuis l'image builder
COPY --from=builder /src/build/release/items_api .
EXPOSE 8080
ENTRYPOINT ["./items_api"]
# Construction et lancement
docker build -t items-api:latest .
docker run -p 8080:8080 -v $(pwd)/data:/app/data items-api:latest
# Verification de la taille de l'image finale
docker image ls items-api:latest
# REPOSITORY TAG SIZE
# items-api latest ~30MB (vs ~500MB pour l'image builder)
Pipeline CI/CD — GitHub Actions¶
# .github/workflows/ci.yml
name: CI C++
on:
push:
branches: [main, develop]
pull_request:
jobs:
build-and-test:
strategy:
matrix:
os: [ubuntu-24.04, macos-14]
compiler: [gcc, clang]
exclude:
- os: macos-14
compiler: gcc
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Installer les dependances (Ubuntu)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y cmake ninja-build libsqlite3-dev \
gcovr lcov
- name: Installer les dependances (macOS)
if: runner.os == 'macOS'
run: brew install cmake ninja sqlite3
- name: Configurer le compilateur
run: |
if [ "${{ matrix.compiler }}" = "clang" ]; then
echo "CC=clang" >> $GITHUB_ENV
echo "CXX=clang++" >> $GITHUB_ENV
fi
- name: Configurer CMake (preset CI)
run: cmake --preset ci
- name: Compiler
run: cmake --build --preset ci
- name: Lancer les tests
run: ctest --preset ci
- name: Generer le rapport de couverture
if: matrix.os == 'ubuntu-24.04' && matrix.compiler == 'gcc'
run: |
gcovr --xml-pretty --exclude-unreachable-branches \
-r . build/ci -o coverage.xml
gcovr --html-details -o coverage_html/index.html \
-r . build/ci
- name: Publier la couverture
if: matrix.os == 'ubuntu-24.04' && matrix.compiler == 'gcc'
uses: codecov/codecov-action@v4
with:
file: coverage.xml
docker:
needs: build-and-test
runs-on: ubuntu-24.04
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: docker/build-push-action@v5
with:
push: false
tags: items-api:${{ github.sha }}
compile_commands.json
Le flag -DCMAKE_EXPORT_COMPILE_COMMANDS=ON dans les presets généré un fichier compile_commands.json dans le répertoire de build. Ce fichier est lu par clangd (le serveur LSP pour C/C++) pour l'autocompletion et les diagnostics dans VS Code, CLion et Neovim. Créer un lien symbolique ln -sf build/dev/compile_commands.json . à la racine du projet pour que les éditeurs le trouvent automatiquement.