C++ и CMake — братя за винаги, част II

C++ и CMake — братя за винаги, част II

В предишната част на тази занимателна история се говореше за организацията на заглавната библиотека в рамките на генератора на системи за компилиране CMake.

Този път ще добавим към него компилируема библиотека, а също така ще говорим за свързването на модулите помежду им.

Както и преди, за тези, които нямат търпение, могат веднага да преминат в актуализирания репозиторий и да опитат всичко с ръцете си.


Съдържание

  1. Разделяй
  2. Управлявай

Разделяй

Първото, което трябва да направим, за да постигнем нашата амбициозна цел, е да разделим разработвания софтуер на универсални изолирани блокове, които са единно изградени от гледна точка на потребителя.

В първата част беше описан такъв стандартен блок — проект с заглавна библиотека. Сега ще добавим в нашия проект компилируема библиотека.

За целта ще изнесем реализацията на функцията myfunc в отделен .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

         ~  виж 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;
+    }
+}

След това ще определим компилируемата библиотека (myfeature), която ще се състои от полученото на предишната стъпка .cpp-файл. Новата библиотека, очевидно, изисква вече съществуващите заглавия, и за да се осигури това, може и трябва да бъде свързана с вече съществуващата цел mylib. Освен това свързването между тях е публично, а това означава, че всичко, към което ще бъде свързана целта, автоматично ще получи в натоварването и целта myfeature, повече за начините на свързване mylib (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) +).

След това ще направим така, че новата библиотека също да бъде инсталирана в системата:

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

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

Трябва да обърнете внимание, че за целта myfeature, както и за mylib беше създаден псевдоним с префикс Mylib::. Същото е написано и за двете цели при експортиране за инсталиране в системата. Това осигурява еднообразна работа с целите при всяка схема на свързване.

След това остава да свържем модулните тестове с новата библиотека (функцията myfunc беше изнесена от заглавката, така че сега трябва да се линковат):

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
 )

Заглавията (Mylib::mylib) сега не трябва да се включват отделно, защото, както вече споменахме, те автоматично се включват заедно с библиотеката (Mylib::myfeature).

И да добавим няколко нюанса, за да осигурим измервания на покритието с отчитане на новата библиотека:

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

Може да добавим повече библиотеки, изпълними файлове и т.н. При това не е важно как точно са свързани помежду си в рамките на проекта. Важно е само кои цели представляват интерфейса на нашия модул, тоест какво е на повърхността.

Управлявай

Сега имаме стандартни модулни блокове и можем да ги управляваме: да изграждаме структури с произволна сложност, интегрирайки ги в системата или свързвайки ги помежду си в рамките на единна система за сборка.

Инсталация в системата

Един от вариантите за използване на модула е да инсталираме нашия модул в системата.

cmake --build път/к/сборочната/директория --target install

След това той се свързва в всеки друг проект с помощта на командата find_package.

find_package(Mylib 1.0 REQUIRED)

Свързване като подмодул

Друг вариант е да свържем папката с нашия проект към друг проект като подмодул с помощта на командата add_subdirectory.

Използването

Методите за свързване са различни, но резултатът е един и същ. И в двата случая, в проект, който използва нашия модул, целите ще бъдат достъпни. Mylib::myfeature и Mylib::mylib, които могат да се използват, например, по следния начин:

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

Конкретно в нашия случай, библиотеката Mylib::myfeature трябва да се свързва тогава, когато е необходимо да се линкне с библиотеката libmyfeature. Ако са достатъчни само заглавията, то тогава е по-добре да се използва библиотеката Mylib::mylib.

CMake целите могат да бъдат хитри, например, проектирани само за предаване на определени свойства, зависимости и т.н. Работата с тях се осъществява по един и същ начин.

Каквото и да е необходимо.

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster