C ++ e CMake - Brothers Forever, Parte II

Amizade para sempre


Na parte anterior desta história divertida, falamos sobre a organização de uma biblioteca de cabeçalhos como parte do gerador do sistema de montagem do CMake.


Desta vez, adicionamos uma biblioteca compilada e também falamos sobre o layout dos módulos.


Como antes, quem não pode esperar pode ir imediatamente ao repositório atualizado e tocar em tudo com as próprias mãos.


Conteúdo


  1. Compartilhar
  2. Conquistar


Compartilhar


A primeira coisa a fazer para alcançar nosso objetivo elevado é dividir o software em desenvolvimento em blocos isolados universais, uniformes do ponto de vista do usuário.


A primeira parte descreveu um bloco padrão - um projeto com uma biblioteca de cabeçalhos. Agora vamos adicionar uma biblioteca compilada ao nosso projeto.


Para fazer isso, retiramos a implementação da função myfunc em um arquivo .cpp separado:


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

Em seguida, definimos a biblioteca compilada ( myfeature ), que consistirá no arquivo .cpp obtido na etapa anterior. A nova biblioteca, obviamente, requer cabeçalhos existentes e, para garantir isso, é possível e necessário combiná-la com o objetivo existente do mylib . Além disso, o link entre eles é público, o que significa que tudo o que o destino da myfeature será conectado myfeature automaticamente o destino do mylib na carga ( mais sobre como se conectar ).


 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 seguir, tornaremos a nova biblioteca também 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) 

Deve-se notar que, para o propósito myfeature , assim como para mylib , um alias foi prefixado com o prefixo Mylib:: . O mesmo é afirmado para os dois propósitos ao exportá-los para instalação no sistema. Isso torna possível trabalhar de maneira uniforme com os objetivos de qualquer esquema de vinculação .


Depois disso, resta tricotar testes de unidade com a nova biblioteca (a função myfunc foi myfunc do cabeçalho, agora você precisa 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 ) 

Os cabeçalhos ( Mylib::mylib ) agora não precisam ser conectados separadamente, porque, como já mencionado, eles são automaticamente conectados juntos à biblioteca ( Mylib::myfeature ).


E adicione algumas nuances para garantir as medições da cobertura, levando em consideração a biblioteca recém-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 ) 

Você pode adicionar mais bibliotecas, executáveis, etc. Não importa exatamente como elas são unidas na estrutura do projeto. A única coisa importante é quais objetivos são a interface do nosso módulo, ou seja, se destacam.



Conquistar


Agora temos módulos-blocos padrão e podemos dominá-los: criar uma estrutura de qualquer complexidade a partir deles, instalando-os em um sistema ou interconectando-os em um único sistema de montagem.


Instalação do sistema


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


 cmake --build /// --target install 

Depois disso, ele se conecta a qualquer outro projeto usando o find_package .


 find_package(Mylib 1.0 REQUIRED) 

Conexão como um submódulo


Outra opção é conectar a pasta ao nosso projeto a outro projeto como um submódulo usando o add_subdirectory .


Use


Os métodos de ligação são diferentes, mas o resultado é o mesmo. Nos dois casos, em um projeto usando nosso módulo, os objetivos Mylib::myfeature e Mylib::mylib estarão disponíveis, que podem ser usados, por exemplo, assim:


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

Especificamente, no nosso caso, a Mylib::myfeature precisa estar conectada quando for necessário libmyfeature biblioteca libmyfeature . Se houver cabeçalhos suficientes, você deverá usar a biblioteca Mylib::mylib .


Os destinos do CMake podem ser complicados, por exemplo, projetados apenas para encaminhar algumas propriedades, dependências etc. Ao mesmo tempo, o trabalho com eles ocorre de uma maneira única.


O que era necessário para receber.

Source: https://habr.com/ru/post/pt463295/


All Articles