Aller au contenu

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.