C++ e CMake — irmãos para sempre, parte II

C++ e CMake — irmãos para sempre, parte II

Na parte anterior Neste interessante relato, falamos sobre a organização de uma biblioteca de cabeçalho dentro do gerador de sistemas de construção CMake.

Desta vez, vamos adicionar uma biblioteca compilável e também discutir sobre a interação entre os módulos.

Como antes, aqueles que estão impacientes podem logo ir para o repositório atualizado e experimentar tudo com as próprias mãos.


Conteúdo

  1. Divida
  2. Domine

Divida

A primeira coisa que devemos fazer para alcançarmos nosso grande objetivo é dividir o software em blocos universais isolados, uniformes do ponto de vista do usuário.

Na primeira parte, foi descrito um bloco padrão — um projeto com uma biblioteca de cabeçalho. Agora, vamos adicionar uma biblioteca compilável ao nosso projeto.

Para isso, vamos separar a implementação da função myfunc em um arquivo .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

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

Em seguida, definiremos a biblioteca compilável (myfeature), que será composta pelo arquivo gerado na etapa anterior. Obviamente, a nova biblioteca precisará dos cabeçalhos já existentes, e para garantir isso, devemos vincular ela com o alvo existente .cppmylib . Além disso, a vinculação entre eles é pública, o que significa que tudo o que for conectado ao alvo, automaticamente receberá também o alvo myfeaturemais sobre os métodos de vinculação . Além disso, a vinculação entre eles é pública, o que significa que tudo o que for conectado ao alvo (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 Compilável +## +################################################################################################### + +add_library(myfeature src/mylib/myfeature.cpp) +target_link_libraries(myfeature PUBLIC mylib) + +add_library(Mylib::myfeature ALIAS myfeature) +).

Em seguida, faremos com que a nova biblioteca também seja 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)

É importante notar que para o alvo

, assim como para myfeature, assim como para . Além disso, a vinculação entre eles é pública, o que significa que tudo o que for conectado ao alvo um alias com prefixo foi criado Mylib::. O mesmo está configurado para ambos os objetivos ao exportá-los para instalação no sistema. Isso permite um trabalho uniforme com os objetivos em qualquer esquema de vinculação.

Depois disso, resta conectar os testes de módulo com a nova biblioteca (a função myfunc foi removida do cabeçalho, então agora é preciso vincular):

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
 )

Cabeçalhos (Mylib::mylib) agora não precisam ser incluídos separadamente, porque, como já mencionado, eles são incluídos automaticamente junto com a biblioteca (Mylib::myfeature).

E vamos adicionar alguns detalhes para garantir a medição de cobertura com a 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
     )

É possível adicionar mais bibliotecas, executáveis, etc. Nesse caso, não importa como exatamente eles estão conectados entre si dentro do projeto. O que importa são os objetivos que são a interface do nosso módulo, ou seja, expostos externamente.

Domine

Agora temos módulos-padrões, e podemos dominá-los: criar estruturas de qualquer complexidade, instalando-os no sistema ou vinculando-os entre si dentro de um único sistema de compilação.

Instalação no sistema

Uma das opções para usar o módulo - instalar nosso módulo no sistema.

cmake --build caminho/para/diretório/de/compilação --target install

Depois disso, ele pode ser incluído em qualquer outro projeto usando o comando find_package.

find_package(Mylib 1.0 REQUIRED)

Inclusão como submódulo

Outra opção - conectar a pasta do nosso projeto a outro projeto como submódulo usando o comando add_subdirectory.

Uso

As maneiras de vinculação são diferentes, mas o resultado é o mesmo. Em ambos os casos, no projeto que usa nosso módulo, os objetivos estarão disponíveis Mylib::myfeature e Mylib::mylib, que podem ser utilizados, por exemplo, assim:

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

Especificamente no nosso caso, a biblioteca Mylib::myfeature deve ser conectada quando for necessário vincular com a biblioteca libmyfeature. Se apenas os cabeçalhos forem suficientes, então é melhor usar a biblioteca Mylib::mylib.

As metas do CMake podem ser complexas, por exemplo, projetadas apenas para transmitir certas propriedades, dependências, etc. Nesse sentido, o trabalho com elas é feito de uma maneira uniforme.

O que era necessário obter.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster