C++ et CMake - frères pour toujours, partie II

C++ et CMake - frères pour toujours, partie II

Dans la partie précédente Cette histoire amusante parlait de l'organisation d'une bibliothèque d'en-têtes au sein du générateur du système de build CMake.

Cette fois, nous y ajouterons une bibliothèque compilée et parlerons également de la liaison des modules entre eux.

Comme auparavant, ceux qui sont impatients peuvent immédiatement allez au référentiel mis à jour et touchez tout de vos propres mains.


Teneur

  1. Diviser
  2. Conquérir

Diviser

La première chose que nous devons faire pour atteindre notre noble objectif est de diviser les logiciels que nous développons en blocs universels, isolés et uniformes du point de vue de l'utilisateur.

Dans la première partie, un tel bloc standard a été décrit - un projet avec une bibliothèque d'en-tête. Ajoutons maintenant une bibliothèque compilée à notre projet.

Pour ce faire, retirons l'implémentation de la fonction myfunc dans un endroit séparé .cpp-déposer:

diff --git a/include/mylib/myfeature.hpp b/include/mylib/myfeature.hpp
index 43db388..ba62b4f 100644
--- a/include/mylib/myfeature.hpp
+++ b/include/mylib/myfeature.hpp
@@ -46,8 +46,5 @@ namespace mylib

         ~  see mystruct
      */
-    inline bool myfunc (mystruct)
-    {
-        return true;
-    }
+    bool myfunc (mystruct);
 }
diff --git a/src/mylib/myfeature.cpp b/src/mylib/myfeature.cpp
new file mode 100644
index 0000000..abb5004
--- /dev/null
+++ b/src/mylib/myfeature.cpp
@@ -0,0 +1,9 @@
+#include <mylib/myfeature.hpp>
+
+namespace mylib
+{
+    bool myfunc (mystruct)
+    {
+        return true;
+    }
+}

Ensuite on définit la bibliothèque à compiler (myfeature), qui sera constitué de ce qui a été obtenu à l’étape précédente .cpp-déposer. La nouvelle bibliothèque nécessite évidemment des en-têtes existants, et pour fournir cela, elle peut et doit être liée à l'objectif existant. mylib. De plus, la connexion entre eux est publique, ce qui signifie que tout ce à quoi la cible sera connectée myfeature, recevra automatiquement la charge et la cible mylib (en savoir plus sur les méthodes de tricot).

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 108045c..0de77b8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -64,6 +64,17 @@ target_compile_features(mylib INTERFACE cxx_std_17)

 add_library(Mylib::mylib ALIAS mylib)

+###################################################################################################
+##
+##      Компилируемая библиотека
+##
+###################################################################################################
+
+add_library(myfeature src/mylib/myfeature.cpp)
+target_link_libraries(myfeature PUBLIC mylib)
+
+add_library(Mylib::myfeature ALIAS myfeature)
+

Ensuite, nous veillerons à ce que la nouvelle bibliothèque soit également installée sur le système :

@@ -72,7 +83,7 @@ add_library(Mylib::mylib ALIAS mylib)

 install(DIRECTORY include/mylib DESTINATION include)

-install(TARGETS mylib EXPORT MylibConfig)
+install(TARGETS mylib myfeature EXPORT MylibConfig)
 install(EXPORT MylibConfig NAMESPACE Mylib:: DESTINATION share/Mylib/cmake)

 include(CMakePackageConfigHelpers)

Il convient de noter qu'aux fins myfeature, pour ce qui est de mylib un alias avec un préfixe a été créé Mylib::. La même chose est écrite dans les deux cas lors de leur exportation pour installation sur le système. Cela permet de travailler de manière uniforme avec des objectifs pour tout schéma contraignant.

Après cela, il ne reste plus qu'à lier les tests unitaires avec la nouvelle bibliothèque (fonction myfunc retiré du titre, vous devez donc maintenant créer un lien) :

diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 5620be4..bc1266c 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -4,7 +4,7 @@ add_executable(mylib-unit-tests test_main.cpp)
 target_sources(mylib-unit-tests PRIVATE mylib/myfeature.cpp)
 target_link_libraries(mylib-unit-tests
     PRIVATE
-        Mylib::mylib
+        Mylib::myfeature
         doctest::doctest
 )

Rubriques (Mylib::mylib) désormais, vous n'avez plus besoin de vous connecter séparément, car, comme déjà mentionné, ils sont automatiquement connectés avec la bibliothèque (Mylib::myfeature).

Et ajoutons quelques nuances pour garantir des mesures de couverture prenant en compte la bibliothèque nouvellement arrivée :

@@ -15,11 +15,16 @@ if(MYLIB_COVERAGE AND GCOVR_EXECUTABLE)
     target_compile_options(mylib-unit-tests PRIVATE --coverage)
     target_link_libraries(mylib-unit-tests PRIVATE gcov)

+    target_compile_options(myfeature PRIVATE --coverage)
+    target_link_libraries(myfeature PRIVATE gcov)
+
     add_custom_target(coverage
         COMMAND
             ${GCOVR_EXECUTABLE}
-                --root=${PROJECT_SOURCE_DIR}/include/
-                --object-directory=${CMAKE_CURRENT_BINARY_DIR}
+                --root=${PROJECT_SOURCE_DIR}/
+                --filter=${PROJECT_SOURCE_DIR}/include
+                --filter=${PROJECT_SOURCE_DIR}/src
+                --object-directory=${PROJECT_BINARY_DIR}
         DEPENDS
             check
     )

Vous pouvez ajouter plus de bibliothèques, d'exécutables, etc. Peu importe la manière exacte dont ils sont connectés les uns aux autres au sein du projet. La seule chose importante est de savoir quelles cibles constituent l'interface de notre module, c'est-à-dire qu'elles ressortent.

Conquérir

Nous disposons désormais de modules de blocs standards et nous pouvons les dominer : les composer en une structure de toute complexité, les installer dans un système ou les relier entre eux au sein d'un système d'assemblage unique.

Installation dans le système

L'une des options d'utilisation du module consiste à installer notre module dans le système.

cmake --build путь/к/сборочной/директории --target install

Après cela, il est connecté à tout autre projet à l'aide de la commande find_package.

find_package(Mylib 1.0 REQUIRED)

Connexion en tant que sous-module

Une autre option consiste à connecter le dossier contenant notre projet à un autre projet en tant que sous-module à l'aide de la commande add_subdirectory.

l'utilisation de

Les méthodes de liaison sont différentes, mais le résultat est le même. Dans les deux cas, les objectifs seront disponibles dans le projet grâce à notre module Mylib::myfeature и Mylib::mylib, qui peut être utilisé par exemple comme ceci :

add_executable(some_executable some.cpp sources.cpp)
target_link_libraries(some_executable PRIVATE Mylib::myfeature)

Plus précisément dans notre cas, la bibliothèque Mylib::myfeature doivent être connectés lorsqu'il est nécessaire d'établir un lien avec la bibliothèque libmyfeature. S'il y a suffisamment d'en-têtes, cela vaut la peine d'utiliser la bibliothèque Mylib::mylib.

Les cibles CMake peuvent être délicates, par exemple, destinées uniquement à transmettre certaines propriétés, dépendances, etc. Dans le même temps, travailler avec eux se déroule de la même manière.

C'est ce qu'il nous fallait obtenir.

Source: habr.com

Ajouter un commentaire