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

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

Затым вызначым кампіляваную бібліятэку (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)

Трэба звярнуць увагу, што для мэты 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

Дадаць каментар