C++ e CMake — fratelli per sempre, parte II

C++ e CMake — fratelli per sempre, parte II

Nella parte precedente di questa interessante narrazione si parlava dell'organizzazione di una libreria di intestazione all'interno del generatore di sistemi di build CMake.

Questa volta aggiungeremo una libreria compilata e discuteremo della composizione dei moduli tra di loro.

Come prima, coloro che non possono aspettare possono subito andare al repository aggiornato e toccare tutto con mano.


Contenuto

  1. Dividi
  2. Domina

Dividi

La prima cosa da fare per raggiungere il nostro grande obiettivo è dividere il software in blocchi isolati e universali, omogenei dal punto di vista dell'utente.

Nella prima parte è stato descritto un tale blocco standard — un progetto con una libreria di intestazione. Ora aggiungeremo al nostro progetto una libreria compilata.

Per fare ciò, estrarremo l'implementazione della funzione myfunc in un file .cpp-file:

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

Poi definiremo la libreria compilabile (myfeature), che sarà composta dal file ottenuto nel passaggio precedente .cpp-file. La nuova libreria richiede evidentemente gli header esistenti e, per garantire ciò, è necessario e utile collegarla con l'obiettivo esistente mylib. Inoltre, il collegamento tra di loro è pubblico, il che significa che tutto ciò che sarà collegato all'obiettivo myfeature, riceverà automaticamente anche l'obiettivo mylib (ulteriori informazioni sui metodi di collegamento).

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)

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

Adesso faremo in modo che la nuova biblioteca venga installata nel sistema:

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

È importante notare che per l'obiettivo myfeature, così come per mylib è stato creato un alias con il prefisso Mylib::. Lo stesso è stato definito per entrambi gli obiettivi durante l'esportazione per l'installazione nel sistema. Questo consente un utilizzo uniforme degli obiettivi con qualsiasi schema di collegamento.

Dopo di ciò, resta da connettere i test modulari con la nuova biblioteca (la funzione myfunc è stata spostata dall'intestazione, quindi ora è necessario linkare):

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
 )

Intestazioni (Mylib::mylib) non deve più essere collegato separatamente, perché, come già detto, viene collegato automaticamente insieme alla libreria (Mylib::myfeature).

Aggiungiamo anche alcuni dettagli per garantire la misurazione della copertura tenendo conto della nuova libreria:

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

È possibile aggiungere più librerie, file eseguibili, ecc. Non importa come siano collegati all'interno del progetto. L'importante è quali obiettivi costituiscono l'interfaccia del nostro modulo, cioè quelli visibili esternamente.

Domina

Ora abbiamo moduli standard e possiamo controllarli: creare strutture di qualsiasi complessità, installandoli nel sistema o collegandoli tra loro all'interno di un'unica struttura di assemblaggio.

Installazione nel sistema

Una delle opzioni per utilizzare il modulo è installare il nostro modulo nel sistema.

cmake --build percorso/alla/directory/di/build --target install

Dopo di ciò può essere collegato a qualsiasi altro progetto usando il comando find_package.

find_package(Mylib 1.0 REQUIRED)

Collegamento come sott modulo

Un'altra opzione è collegare la cartella del nostro progetto a un altro progetto come sott modulo usando il comando add_subdirectory.

L'utilizzo di

Le modalità di collegamento sono varie, ma il risultato è lo stesso. In entrambi i casi, nel progetto che utilizza il nostro modulo, saranno disponibili obiettivi Mylib::myfeature e Mylib::mylib, che possono essere utilizzati, ad esempio, in questo modo:

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

Nel nostro caso, la libreria Mylib::myfeature deve essere collegata quando è necessario collegarsi alla libreria libmyfeature. Se sono sufficienti solo gli header, è meglio utilizzare la libreria Mylib::mylib.

Gli obiettivi di CMake possono essere ingannevoli, ad esempio, progettati solo per propagare alcune proprietà, dipendenze, e così via. Il lavoro con essi avviene in modo uniforme.

Ciò che si voleva ottenere.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster