C++ și CMake - frați pentru totdeauna, partea a II-a

C++ și CMake - frați pentru totdeauna, partea a II-a

În partea anterioară Această poveste distractivă a vorbit despre organizarea unei biblioteci de antet în cadrul generatorului de sistem de compilare CMake.

De data aceasta, vom adăuga o bibliotecă compilată și vom vorbi, de asemenea, despre legarea modulelor între ele.

Ca și înainte, cei care sunt nerăbdători pot imediat accesați depozitul actualizat și atingeți totul cu propriile mâini.


Conținut

  1. Divide
  2. A cuceri

Divide

Primul lucru pe care trebuie să-l facem pentru a ne atinge obiectivul înalt este să împărțim software-ul pe care îl dezvoltăm în blocuri universale, izolate, care sunt uniforme din punctul de vedere al utilizatorului.

În prima parte, a fost descris un astfel de bloc standard - un proiect cu o bibliotecă de antet. Acum să adăugăm o bibliotecă compilată la proiectul nostru.

Pentru a face acest lucru, să scoatem implementarea funcției myfunc într-un separat .cpp-fişier:

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

Apoi definim biblioteca de compilat (myfeature), care va consta în ceea ce s-a obținut în pasul anterior .cpp-fişier. Noua bibliotecă necesită evident antete existente și, pentru a oferi acest lucru, poate și ar trebui să fie legată de scopul existent. mylib. Mai mult decât atât, legătura dintre ele este publică, ceea ce înseamnă că tot ceea ce va fi conectat ținta myfeature, va primi automat sarcina și ținta mylib (mai multe despre metodele de tricotat).

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

În continuare, ne vom asigura că noua bibliotecă este instalată și pe sistem:

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

Trebuie remarcat faptul că în acest scop myfeature, cât pentru mylib a fost creat un alias cu un prefix Mylib::. Același lucru este scris pentru ambele scopuri atunci când le exportați pentru instalare pe sistem. Acest lucru face posibilă lucrul uniform cu obiective pentru orice schema de legare.

După aceasta, tot ce rămâne este să legați testele unitare cu noua bibliotecă (funcția myfunc scos din titlu, așa că acum trebuie să faceți un link):

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
 )

Titluri (Mylib::mylib) acum nu trebuie să vă conectați separat, deoarece, așa cum am menționat deja, acestea sunt conectate automat împreună cu biblioteca (Mylib::myfeature).

Și să adăugăm câteva nuanțe pentru a asigura măsurătorile de acoperire, ținând cont de biblioteca nou sosită:

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

Puteți adăuga mai multe biblioteci, executabile etc. Nu contează cât de exact sunt conectate între ele în cadrul proiectului. Singurul lucru important este care ținte sunt interfața modulului nostru, adică ies în evidență.

A cuceri

Acum avem module bloc standard și le putem domina: să le compunem într-o structură de orice complexitate, instalându-le într-un sistem sau conectându-le între ele într-un singur sistem de asamblare.

Instalare în sistem

Una dintre opțiunile de utilizare a modulului este instalarea modulului nostru în sistem.

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

După aceea, este conectat la orice alt proiect folosind comanda find_package.

find_package(Mylib 1.0 REQUIRED)

Conexiune ca submodul

O altă opțiune este să conectăm folderul cu proiectul nostru la un alt proiect ca submodul folosind comanda add_subdirectory.

Folosi

Metodele de legare sunt diferite, dar rezultatul este același. În ambele cazuri, obiectivele vor fi disponibile în proiect folosind modulul nostru Mylib::myfeature и Mylib::mylib, care poate fi folosit, de exemplu, astfel:

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

Mai exact în cazul nostru, biblioteca Mylib::myfeature trebuie conectat atunci când este necesar să se conecteze cu biblioteca libmyfeature. Dacă există suficiente anteturi, atunci merită să folosiți biblioteca Mylib::mylib.

Țintele CMake pot fi dificile, de exemplu, menite doar să transmită unele proprietăți, dependențe etc. În același timp, lucrul cu ei are loc în același mod.

Asta trebuia să obținem.

Sursa: www.habr.com

Adauga un comentariu