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

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

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

Diesmal fügen wir eine kompilierbare Bibliothek hinzu und sprechen auch über die Anordnung der Module untereinander.

Wie immer können die Ungeduldigen sofort zum aktualisierten Repository wechseln und alles mit eigenen Händen ausprobieren.


Inhalt

  1. Teile
  2. Herrsche

Teile

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

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

Dazu ziehen 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;
+    }
+}

Dann definieren wir die kompilierbare Bibliothek (myfeature), die aus der zuvor erhaltenen .cpp-Datei bestehen wird. Offensichtlich benötigt die neue Bibliothek bereits vorhandene Header, und um dies zu gewährleisten, sollte sie mit dem bestehenden Ziel mylibverkoppelt werden. Die Verkoppelung zwischen ihnen ist öffentlich, was bedeutet, dass alles, was mit dem Ziel verbunden wird, automatisch auch das Ziel erhält. myfeatureWeitere Informationen zu den Verkoppelungsmöglichkeiten mylib (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)+################################################################################################### +## +## Kompilierbare Bibliothek +## +################################################################################################### + +add_library(myfeature src/mylib/myfeature.cpp) +target_link_libraries(myfeature PUBLIC mylib) + +add_library(Mylib::myfeature ALIAS myfeature) +).

Dann lassen wir die neue Bibliothek ebenfalls im System installieren:

@@ -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 zu beachten, dass für das Ziel

, wie auch für myfeature, wie auch für mylib Es wurde ein Pseudonym mit einem Präfix eingerichtet Mylib::. Dasselbe ist für beide Ziele beim Exportieren in das System festgelegt. Dies ermöglicht eine einheitliche Arbeit mit den Zielen bei jeder Bindungsstruktur.

Danach blieb es, die Modultests mit der neuen Bibliothek zu verknüpfen (die Funktion myfunc wurde aus dem Header herausgenommen, sodass jetzt eine Verlinkung erforderlich ist):

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
 )

Die 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 Nuancen hinzu, um die Messungen der Codeabdeckung unter Berücksichtigung der neu hinzugekommenen 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 weitere Bibliotheken, ausführbare Dateien usw. hinzugefügt werden. Dabei ist es unwichtig, wie sie im Rahmen des Projekts miteinander verknüpft sind. Wichtig ist nur, welche Ziele als Schnittstelle unseres Moduls fungieren, also nach außen sichtbar sind.

Herrsche

Jetzt haben wir Standardmodul-Blöcke, und wir können sie beherrschen: Sie zu einer beliebigen komplexen Struktur zusammenzustellen, sie im System zu installieren oder sie innerhalb eines gemeinsamen Build-Systems zu verlinken.

Installation im System

Eine Möglichkeit, das Modul zu nutzen — unser Modul im System zu installieren.

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

Danach kann es in jedem anderen Projekt mit dem Befehl find_package.

find_package(Mylib 1.0 REQUIRED)

Einbindung als Submodul

Eine andere Möglichkeit — den Ordner mit unserem Projekt im Rahmen eines anderen Projekts als Submodul mit dem Befehl einzubinden add_subdirectory.

Verwendung

Die Bindungsmethoden sind unterschiedlich, aber das Ergebnis ist dasselbe. In beiden Fällen sind in dem Projekt, das unser Modul verwendet, die Ziele 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)

Speziell in unserem Fall muss die Bibliothek Mylib::myfeature eingebunden werden, wenn es notwendig ist, sich mit der Bibliothek zu verlinken libmyfeature. Wenn nur die Header-Dateien ausreichend sind, sollte man die Bibliothek verwenden Mylib::mylib.

CMake-Ziele können trickreich sein, zum Beispiel nur dafür vorgesehen, um bestimmte Eigenschaften, Abhängigkeiten usw. weiterzugeben. Der Umgang mit ihnen erfolgt dabei einheitlich.

Was gefordert war.

Quelle: habr.com

60GB SSD 8Gb DDR4