Les bibliothèques "header-only" avec CMake
Tags: cpp, cmake, french
Published: 2022-02-02 10:17:42

---
layout: post
title: Les bibliothèques "header-only" avec CMake
published: true
tags: [Cpp, CMake, French]
---

## Introduction
Dans cet article, je vais vous expliquer comment créer et se servir d’une bibliothèque header-only. Si vous ne savez pas ce que c’est, ou si vous avez besoin d’un petit rappel, je vous invite à lire [cet article](https://baduit.github.io/2021/02/01/biblioth%C3%A8ques-header-only.html).

## Créer une bibliothèques header-only
Pour en créer une, on utilise presque la même méthode que pour une bibliothèque statique ou une partagée. Lors de l’appel à la fonction [add_library](https://cmake.org/cmake/help/latest/command/add_library.html), il suffit d’utiliser le mot-clef __INTERFACE__ au lieu de __STATIC__ ou __SHARED__.

Une bonne pratique est d’utiliser la fonction [target_sources](https://cmake.org/cmake/help/latest/command/target_sources.html), en arguments, les fichiers headers composant la bibliothèque. Cela leur permet d'apparaitre correctement lorsque le projet sera ouvert via un IDE, tel que Visual Studio par exemple.

Voici à quoi cela peut ressembler :
```CMake
# Create a library named 'Awesome'
add_library(Awesome INTERFACE)

# It is composed of 2 headers
target_sources(Awesome INTERFACE Awesome.hpp MoreAwesome.hpp)
```

## Utiliser une bibliothèques header-only
### Si elle a été créée avec CMake
Dans ce cas là, c’est tout simple, il suffit d’appeler la fonction [target_link_libraries](https://cmake.org/cmake/help/latest/command/target_link_libraries.html) comme vous le feriez pour n’importe quelle bibliothèque. Voici un exemple :
```Cmake
# Create a basic target
add_executable(my_exe main.cpp)
# Let's imagine the library is called header_lib and use it
target_link_libraries(my_exe header_lib)
```
Bien évidemment, comme pour inclure n’importe quel autre type de bibliothèque, vous devrez soit inclure le fichier __CMakeLists.txt__ de la bibliothèque avec la fonction [add_subdirectory](https://cmake.org/cmake/help/latest/command/add_subdirectory.html), soit sinon chercher directement la bibliothèque avec [find_library](https://cmake.org/cmake/help/latest/command/find_library.html), soit chercher le package avec [find_package](https://cmake.org/cmake/help/latest/command/find_package.html)

### Si elle n'a pas été créée avec CMake
La solution la plus simple est d’ajouter le dossier contenant les fichiers composant la bibliothèque dans le path où le compilateur cherchera les headers. Pour cela, c’est très simple, il suffit d’appeler la fonction [target_include_directories](https://cmake.org/cmake/help/latest/command/target_include_directories.html).
```CMake
add_executable(my_exe main.cpp)
# The source of the library are in the folder 'path/to/lib_sources'
target_include_directories(my_exe PRIVATE path/to/lib_sources)
```

Une autre solution un peu plus propre (et qui reste très simple) est de créer une bibliothèque avec cmake à partir des sources, comme vu au début de l’article. Ensuite, il suffit d’utiliser cette bibliothèque comme vu précédemment.

## Exemple complet
Imaginons un projet composé d’une bibliothèque header-only et d’un exécutable qui utilise cette bibliothèque. L’arborescence des fichiers est la suivante :
```
.
├── CMakeLists.txt
├── lib
│   ├── CMakeLists.txt
│   └── Commentinator
│       ├── Commentinator.hpp
│       └── Impl.hpp
└── src
    └── main.cpp
```

Commençons par le contenu du CMakeLists.txt de la bibliothèque.
```Cmake
# Create the library
add_library(Commentinator INTERFACE)

# Add the sources for a better integrations in the IDE
target_sources(Commentinator INTERFACE
               ${CMAKE_CURRENT_LIST_DIR}/Commentinator/Commentinator.hpp
			   ${CMAKE_CURRENT_LIST_DIR}/Commentinator/Impl.hpp)

# This library requires c++17
target_compile_features(Commentinator INTERFACE cxx_std_17)

# And the most important part set the include directories
target_include_directories(Commentinator INTERFACE ${CMAKE_CURRENT_LIST_DIR})
```

Et maintenant, celui de l’exécutable qui va utiliser cette bibliothèque :
```Cmake
# Basic stuff every CMake project need
cmake_minimum_required(VERSION 3.12)
project(bestProjectEver VERSION 1.2.0 DESCRIPTION "The best project ever created in the world.")

# Include the CMakeLists.txt of the library
add_subdirectory(lib)

# Create the executable named `example`
add_executable(example ${CMAKE_CURRENT_LIST_DIR}/src/main.cpp)

# Use the library
target_link_libraries(example Commentinator)
```

Et voilà, vous avez maintenant toutes les clefs en main pour utiliser et créer des bibliothèques header-only !

## Sources
* [https://cmake.org/cmake/help/latest/command/add_library.html#interface-libraries](https://cmake.org/cmake/help/latest/command/add_library.html#interface-libraries)
* [https://cmake.org/cmake/help/latest/command/find_library.html](https://cmake.org/cmake/help/latest/command/find_library.html)
* [https://cmake.org/cmake/help/latest/command/find_package.html](https://cmake.org/cmake/help/latest/command/find_package.html)
* [https://cmake.org/cmake/help/latest/command/add_subdirectory.html](https://cmake.org/cmake/help/latest/command/add_subdirectory.html)
* [https://cmake.org/cmake/help/latest/command/target_include_directories.html](https://cmake.org/cmake/help/latest/command/target_include_directories.html)
* [https://cmake.org/cmake/help/latest/command/target_link_libraries.html](https://cmake.org/cmake/help/latest/command/target_link_libraries.html)
* [https://cmake.org/cmake/help/latest/command/target_sources.html](https://cmake.org/cmake/help/latest/command/target_sources.html)