C++ und CMake — Brüder für immer, Teil II

C++ und CMake — Brüder für immer, Teil II

Im vorherigen Teil dieser spannenden Erzählung ging es um die Organisation einer Header-Bibliothek im Rahmen des CMake-Bau-Systems.

Diesmal fügen wir eine kompilierbare Bibliothek hinzu und besprechen die Verknüpfung der Module miteinander.

Wie gewohnt können die Ungeduldigen sofort zum aktualisierten Repository gehen und alles selbst ausprobieren.


Inhalt

  1. Teile
  2. Regiere

Teile

Das erste, was wir tun müssen, um unser hohes Ziel zu erreichen, ist, die entwickelte Software in universelle, isolierte Blöcke zu unterteilen, die aus der Sicht des Benutzers einheitlich sind.

Im ersten Teil wurde ein solcher Standardblock — ein Projekt mit einer Header-Bibliothek — beschrieben. Jetzt fügen wir unserem Projekt eine kompilierbare Bibliothek hinzu.

Dazu bringen wir die Implementierung der Funktion myfunc in eine separate .cpp-Datei:

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

         ~  siehe 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 
+
+namespace mylib
+{
+    bool myfunc (mystruct)
+    {
+        return true;
+    }
+}

Nun definieren wir die kompilierbare Bibliothek (myfeature), die aus der zuvor erhaltenen .cpp-Datei bestehen wird. Die neue Bibliothek benötigt offensichtlich bereits vorhandene Header, und um dies zu gewährleisten, sollte sie mit dem bestehenden Ziel verbunden werden mylib. Es handelt sich dabei um eine öffentliche Verbindung, was bedeutet, dass alles, was mit dem Ziel verbunden wird myfeature, automatisch auch das Ziel erhält mylib (mehr über die Verbindungsarten).

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)

+###################################################################################################
+##
+##      Kompilierte Bibliothek
+##
+###################################################################################################
+
+add_library(myfeature src/mylib/myfeature.cpp)
+target_link_libraries(myfeature PUBLIC mylib)
+
+add_library(Mylib::myfeature ALIAS myfeature)
+

Lassen Sie uns nun dafür sorgen, dass die neue Bibliothek ebenfalls im System installiert wird:

@@ -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)

Es ist wichtig zu beachten, dass für das Ziel myfeature, wie für mylib ein Alias mit dem Präfix Mylib::. Das Gleiche gilt für beide Ziele beim Exportieren zur Installation im System. Dies ermöglicht eine einheitliche Handhabung der Ziele bei jeder Bindungsschema.

Danach müssen die Modultests mit der neuen Bibliothek verbunden werden (die Funktion myfunc wurde aus dem Header herausgenommen, also muss jetzt verlinkt werden):

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
 )

Header (Mylib::mylib) müssen jetzt nicht mehr separat eingebunden werden, da sie, wie bereits erwähnt, automatisch mit der Bibliothek eingebunden werden (Mylib::myfeature).

Und wir fügen ein paar Details hinzu, um die Abdeckungsmessungen unter Berücksichtigung der neu hinzugefügten Bibliothek zu gewährleisten:

@@ -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
     )

Es können mehr Bibliotheken, ausführbare Dateien usw. hinzugefügt werden. Dabei spielt es keine Rolle, wie sie im Rahmen des Projekts miteinander verbunden sind. Wichtig ist nur, welche Ziele das Interface unseres Moduls sind, also die, die nach außen hin sichtbar sind.

Regiere

Jetzt haben wir Standardmodulblöcke, über die wir verfügen können: Wir können Strukturen beliebiger Komplexität daraus erstellen, sie im System installieren oder sie innerhalb eines einheitlichen Assemblierungssystems miteinander verbinden.

Installation im System

Eine der Möglichkeiten, das Modul zu verwenden, besteht darin, unser Modul im System zu installieren.

cmake --build pfad/zum/assemblierungsverzeichnis --target install

Anschließend kann es mit jedem anderen Projekt über den Befehl find_package.

find_package(Mylib 1.0 REQUIRED) verbunden werden.

Einbindung als Submodul

Eine andere Option besteht darin, den Ordner unseres Projekts als Submodul zu einem anderen Projekt mit dem Befehl zu verbinden. add_subdirectory.

Nutzung

Die Verknüpfungsmethoden sind unterschiedlich, aber das Ergebnis ist das gleiche. In beiden Fällen sind die Ziele im Projekt, das unser Modul verwendet, verfügbar. Mylib::myfeature und Mylib::mylib, die beispielsweise so verwendet werden können:

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

In unserem spezifischen Fall muss die Bibliothek Mylib::myfeature immer dann eingebunden werden, wenn eine Verlinkung mit der Bibliothek libmyfeature. Wenn nur Header-Dateien benötigt werden, dann sollte die Bibliothek verwendet werden. Mylib::mylib.

CMake-Ziele können knifflig sein, wenn sie beispielsweise nur dazu dienen, bestimmte Eigenschaften, Abhängigkeiten usw. weiterzureichen. Die Arbeit mit ihnen erfolgt jedoch auf eine einheitliche Weise.

Was genau gefordert war.

Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster