C++ e CMake - irmáns para sempre, parte II

C++ e CMake - irmáns para sempre, parte II

Na parte anterior Esta entretida historia falou sobre a organización dunha biblioteca de cabeceiras dentro do xerador do sistema de compilación CMake.

Nesta ocasión engadirémoslle unha biblioteca compilada, e tamén falaremos de vincular módulos entre si.

Como antes, os que están impacientes poden inmediatamente vai ao repositorio actualizado e toca todo coas túas propias mans.


Contido

  1. Dividir
  2. Conquista

Dividir

O primeiro que debemos facer para acadar o noso elevado obxectivo é dividir o software que desenvolvemos en bloques universais, illados e uniformes desde o punto de vista do usuario.

Na primeira parte, describiuse un bloque estándar deste tipo: un proxecto cunha biblioteca de cabeceiras. Agora imos engadir unha biblioteca compilada ao noso proxecto.

Para iso, imos sacar a implementación da función myfunc nun separado .cpp- arquivo:

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

Despois definimos a biblioteca a compilar (myfeature), que consistirá no obtido no paso anterior .cpp- arquivo. Obviamente, a nova biblioteca require cabeceiras existentes e, para proporcionar isto, pode e debe estar ligada ao propósito existente. mylib. Ademais, a conexión entre eles é pública, o que significa que todo o que se conectará o obxectivo myfeature, recibirá automaticamente a carga e o destino mylib (máis sobre os métodos de tricô).

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ón, asegurarémonos de que a nova biblioteca tamén estea instalada no 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)

Cómpre sinalar que para o efecto myfeature, como para mylib creouse un alias cun prefixo Mylib::. O mesmo escríbese para ambos os efectos ao exportalos para a súa instalación no sistema. Isto fai posible traballar uniformemente con obxectivos para calquera esquema vinculante.

Despois disto, só queda vincular as probas unitarias coa nova biblioteca (función myfunc eliminado do título, agora tes que enlazar):

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
 )

Títulos (Mylib::mylib) agora non precisa conectarse por separado, porque, como xa se mencionou, están conectados automaticamente xunto coa biblioteca (Mylib::myfeature).

E engademos un par de matices para garantir as medidas de cobertura tendo en conta a biblioteca recentemente chegada:

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

Podes engadir máis bibliotecas, executables, etc. Non importa como estean exactamente conectados entre si dentro do proxecto. O único importante é que obxectivos son a interface do noso módulo, é dicir, que sobresaen.

Conquista

Agora temos módulos de bloque estándar, e podemos dominalos: compoñelos nunha estrutura de calquera complexidade, instalándoos nun sistema ou ligándoos entre si nun único sistema de montaxe.

Instalación no sistema

Unha das opcións para usar o módulo é instalar o noso módulo no sistema.

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

Despois diso, conéctase a calquera outro proxecto mediante o comando find_package.

find_package(Mylib 1.0 REQUIRED)

Conexión como submódulo

Outra opción é conectar o cartafol co noso proxecto a outro proxecto como submódulo mediante o comando add_subdirectory.

Usar

Os métodos de unión son diferentes, pero o resultado é o mesmo. En ambos os casos, os obxectivos estarán dispoñibles no proxecto mediante o noso módulo Mylib::myfeature и Mylib::mylib, que se pode usar, por exemplo, así:

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

Concretamente no noso caso, a biblioteca Mylib::myfeature debe estar conectado cando sexa necesario enlazar coa biblioteca libmyfeature. Se hai cabeceiras suficientes, paga a pena usar a biblioteca Mylib::mylib.

Os obxectivos de CMake poden ser complicados, por exemplo, destinados só a reenviar algunhas propiedades, dependencias, etc. Ao mesmo tempo, o traballo con eles ocorre do mesmo xeito.

Iso era o que necesitabamos conseguir.

Fonte: www.habr.com

Engadir un comentario