C++ y CMake: hermanos para siempre, parte II

C++ y CMake: hermanos para siempre, parte II

En la parte anterior de este relato fascinante, se trataba de la organización de una biblioteca de encabezados en el generador de sistemas de construcción CMake.

Esta vez añadiremos una biblioteca compilable, y también hablaremos sobre la vinculación de módulos entre sí.

Como antes, aquellos que no puedan esperar pueden ir directamente al repositorio actualizado y experimentar todo por sí mismos.


Contenido

  1. Divide
  2. Domina

Divide

Lo primero que hay que hacer para alcanzar nuestro alto objetivo es dividir el software en bloques universales e isolados, uniformes desde el punto de vista del usuario.

En la primera parte se describió un bloque estándar: un proyecto con una biblioteca de encabezados. Ahora, añadiremos a nuestro proyecto una biblioteca compilable.

Para ello, extraeremos la implementación de la función myfunc en un archivo .cpp: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; + } +}

Luego, definiremos la biblioteca compilable (

myfeature), que consistirá en el archivo-obtenido en el paso anterior. La nueva biblioteca, evidentemente, requiere los encabezados existentes, y para garantizar esto, se puede y debe vincular con el objetivo existente .cpp:mylib . Además, la vinculación entre ellos es pública, lo que significa que todo lo que se conecte al objetivo, automáticamente recibirá también el objetivo ), que consistirá en el archivo, más sobre los métodos de vinculación . Además, la vinculación entre ellos es pública, lo que significa que todo lo que se conecte al objetivo (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 compilable +## +################################################################################################### + +add_library(myfeature src/mylib/myfeature.cpp) +target_link_libraries(myfeature PUBLIC mylib) + +add_library(Mylib::myfeature ALIAS myfeature) +).

A continuación, haremos que la nueva biblioteca también se instale en el 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)

Es importante señalar que para el objetivo

Es necesario prestar atención a que, para el objetivo ), que consistirá en el archivo, al igual que para . Además, la vinculación entre ellos es pública, lo que significa que todo lo que se conecte al objetivo se generó un seudónimo con el prefijo Mylib::. Lo mismo está definido para ambos objetivos al exportarlos para la instalación en el sistema. Esto permite un funcionamiento uniforme con los objetivos en cualquier esquema de enlace.

Después de esto, solo queda vincular las pruebas modulares con la nueva biblioteca (la función myfunc se ha sacado del encabezado, así que ahora necesita enlazarse):

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
 )

Los encabezados (Mylib::mylib) ya no necesitan ser incluidos por separado, porque, como ya se mencionó, se incluyen automáticamente junto con la biblioteca (Mylib::myfeature).

Y agreguemos un par de matices para garantizar las medidas de cobertura teniendo en cuenta la nueva biblioteca que ha llegado:

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

Se pueden agregar más bibliotecas, archivos ejecutables, etc. En este caso, no importa cómo estén vinculados entre sí dentro del proyecto. Solo importa qué objetivos son la interfaz de nuestro módulo, es decir, los que están visibles hacia afuera.

Domina

Ahora tenemos módulos estándar y podemos dominarlos: construir una estructura de cualquier complejidad, instalándolos en el sistema o vinculándolos entre sí dentro de un único sistema de construcción.

Instalación en el sistema

Una de las opciones para usar el módulo es instalar nuestro módulo en el sistema.

cmake --build ruta/a/directorio/de/construcción --target install

Después de esto, se puede incluir en cualquier otro proyecto usando el comando find_package.

find_package(Mylib 1.0 REQUIRED)

Incluir como submódulo

Otra opción es conectar la carpeta de nuestro proyecto a otro proyecto como submódulo usando el comando add_subdirectory.

Uso

Los métodos de enlace son diversos, pero el resultado es el mismo. En ambos casos, en el proyecto que utiliza nuestro módulo, estarán disponibles los objetivos Mylib::myfeature y Mylib::mylib, que pueden utilizarse, por ejemplo, así:

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

En nuestro caso específico, la biblioteca Mylib::myfeature debe conectarse cuando sea necesario vincularse con la biblioteca libmyfeature. Si solo se necesitan encabezados, entonces vale la pena utilizar la biblioteca Mylib::mylib.

Los objetivos de CMake pueden ser complicados, por ejemplo, destinados solo a pasar ciertas propiedades, dependencias, etc. Sin embargo, trabajar con ellos se realiza de una manera uniforme.

Lo que se requería obtener.

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster