C++ i CMake: germans per sempre, part II

C++ i CMake: germans per sempre, part II

A la part anterior Aquesta entretinguda història parlava de l'organització d'una biblioteca de capçaleres dins del generador del sistema de compilació CMake.

Aquesta vegada hi afegirem una biblioteca compilada i també parlarem d'enllaçar mòduls entre ells.

Com abans, els que estan impacients poden fer-ho immediatament aneu al repositori actualitzat i tocar-ho tot amb les teves pròpies mans.


Contingut

  1. Divideix
  2. Conquerir

Divideix

El primer que hem de fer per assolir el nostre alt objectiu és dividir el programari que desenvolupem en blocs universals, aïllats i uniformes des del punt de vista de l'usuari.

A la primera part, es va descriure un bloc estàndard: un projecte amb una biblioteca de capçalera. Ara afegim una biblioteca compilada al nostre projecte.

Per fer-ho, traiem la implementació de la funció myfunc en un separat .cpp-dossier:

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

Aleshores definim la biblioteca a compilar (myfeature), que consistirà en el que s'ha obtingut en el pas anterior .cpp-dossier. La nova biblioteca, òbviament, requereix capçaleres existents, i per tal de proporcionar-ho, pot i s'ha de relacionar amb el propòsit existent. mylib. A més, la connexió entre ells és pública, la qual cosa significa que tot allò al qual es connectarà l'objectiu myfeature, rebrà automàticament la càrrega i l'objectiu mylib (més sobre els mètodes de teixir).

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

A continuació, ens assegurarem que la nova biblioteca també estigui instal·lada al 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)

Cal tenir en compte que a efectes myfeature, quant a mylib s'ha creat un àlies amb un prefix Mylib::. El mateix s'escriu per a ambdós propòsits en exportar-los per instal·lar-los al sistema. Això fa possible treballar de manera uniforme amb objectius per a qualsevol esquema vinculant.

Després d'això, només queda enllaçar les proves unitàries amb la nova biblioteca (funció myfunc tret del títol, així que ara cal enllaçar):

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
 )

Encapçalaments (Mylib::mylib) ara no cal que us connecteu per separat, perquè, com ja s'ha dit, es connecten automàticament juntament amb la biblioteca (Mylib::myfeature).

I afegim un parell de matisos per garantir les mesures de cobertura tenint en compte la nova biblioteca:

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

Podeu afegir més biblioteques, executables, etc. No importa com estiguin exactament connectats entre si dins del projecte. L'únic important és quins objectius són la interfície del nostre mòdul, és a dir, sobresurten.

Conquerir

Ara tenim mòduls de bloc estàndard, i podem dominar-los: compondre'ls en una estructura de qualsevol complexitat, instal·lant-los en un sistema o enllaçant-los dins d'un únic sistema de muntatge.

Instal·lació al sistema

Una de les opcions per utilitzar el mòdul és instal·lar el nostre mòdul al sistema.

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

Després d'això, es connecta a qualsevol altre projecte mitjançant l'ordre find_package.

find_package(Mylib 1.0 REQUIRED)

Connexió com a submòdul

Una altra opció és connectar la carpeta amb el nostre projecte a un altre projecte com a submòdul mitjançant l'ordre add_subdirectory.

Utilitzar

Els mètodes d'enquadernació són diferents, però el resultat és el mateix. En ambdós casos, els objectius estaran disponibles al projecte mitjançant el nostre mòdul Mylib::myfeature и Mylib::mylib, que es pot utilitzar, per exemple, així:

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

Concretament en el nostre cas, la biblioteca Mylib::myfeature s'han de connectar quan cal enllaçar amb la biblioteca libmyfeature. Si hi ha prou capçaleres, val la pena utilitzar la biblioteca Mylib::mylib.

Els objectius CMake poden ser complicats, per exemple, destinats només a reenviar algunes propietats, dependències, etc. Al mateix temps, treballar amb ells es produeix de la mateixa manera.

Això és el que necessitàvem aconseguir.

Font: www.habr.com

Afegeix comentari