C++ i CMake — bracia na zawsze, część II

C++ i CMake — bracia na zawsze, część II

W poprzedniej części W tej interesującej opowieści mówiono o organizacji biblioteki nagłówkowej w ramach generatora systemów budowy CMake.

Tym razem dodamy do niego kompilowalną bibliotekę oraz porozmawiamy o łączeniu modułów ze sobą.

Jak zwykle, ci, którzy nie mogą się doczekać, mogą od razu przejść do zaktualizowanego repozytorium i dotknąć wszystkiego własnymi rękami.


Spis treści

  1. Podziel
  2. Zasady

Podziel

Pierwszym krokiem do osiągnięcia naszego wysokiego celu jest podzielenie rozwijanego oprogramowania na uniwersalne, izolowane bloki, jednolite z perspektywy użytkownika.

W pierwszej części opisano standardowy blok – projekt z biblioteką nagłówkową. Teraz dodamy do naszego projektu kompilowalną bibliotekę.

W tym celu przeniesiemy implementację funkcji myfunc do osobnego .cpp-pliku:

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

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

Następnie zdefiniujemy kompilowalną bibliotekę (myfeature), która będzie składać się z uzyskanego na poprzednim kroku .cpp-pliku. Nowa biblioteka oczywiście wymaga już istniejących nagłówków, a aby to zapewnić, można i trzeba połączyć ją z istniejącym celem mylib.Dodatkowo połączenie między nimi jest publiczne, co oznacza, że wszystko, co będzie podłączone do celu myfeature, automatycznie otrzyma dodatkowo cel mylib. (dowiedz się więcej o sposobach łączenia).

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)

+###################################################################################################
+##
+##      Kompilowalna biblioteka
+##
+###################################################################################################
+
+add_library(myfeature src/mylib/myfeature.cpp)
+target_link_libraries(myfeature PUBLIC mylib)
+
+add_library(Mylib::myfeature ALIAS myfeature)
+

Następnie sprawimy, aby nowa biblioteka również była instalowana w systemie:

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

Należy zwrócić uwagę, że dla celu myfeature, jak i dla mylib. został wprowadzony pseudonim z prefiksem Mylib::. To samo jest zapisane dla obu celów podczas ich eksportowania do systemu. Daje to możliwość jednolitej pracy z celami w każdej schemacie powiązań.

Po tym pozostało przeprowadzić testy modułowe z nową biblioteką (funkcję myfunc wniesiono z nagłówka, więc teraz trzeba się zlinkować):

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
 )

Nagłówki (Mylib::mylib) nie muszą być już osobno dołączane, ponieważ, jak już wspomniano, są automatycznie dołączane razem z biblioteką (Mylib::myfeature).

I dodamy kilka szczegółów, aby zapewnić pomiar pokrycia z uwzględnieniem nowo wprowadzonej biblioteki:

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

Można dodać więcej bibliotek, plików wykonywalnych itp. W tym przypadku nie ma znaczenia, jak dokładnie są one powiązane ze sobą w ramach projektu. Ważne jest tylko to, jakie cele są interfejsem naszego modułu, czyli co wystaje na zewnątrz.

Zasady

Teraz mamy standardowe moduły-bloki i możemy nimi zarządzać: tworzyć z nich struktury dowolnej złożoności, instalując je w systemie lub łącząc je ze sobą w ramach jednego systemu budowania.

Instalacja w systemie

Jedną z opcji użycia modułu jest zainstalowanie naszego modułu w systemie.

cmake --build ścieżka/do/katalogu/budowy --target install

Po tym dołącza się go do każdego innego projektu za pomocą polecenia find_package.

find_package(Mylib 1.0 REQUIRED)

Dołączenie jako podmoduł

Inna opcja to dołączenie folderu z naszym projektem do innego projektu jako podmoduł za pomocą polecenia add_subdirectory.

Użycie

Metody powiązań są różne, ale wynik jest ten sam. W obu przypadkach w projekcie, który używa naszego modułu, będą dostępne cele Mylib::myfeature i Mylib::mylib, które mogą być używane na przykład tak:

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

W naszym przypadku bibliotekę Mylib::myfeature należy podłączyć wtedy, gdy potrzebne jest połączenie z biblioteką libmyfeature. Jeśli wystarczą nagłówki, warto użyć biblioteki Mylib::mylib.

Cele CMake mogą być podstępne, na przykład przeznaczone wyłącznie do przekazywania pewnych właściwości, zależności itd. Praca z nimi odbywa się jednak w sposób jednolity.

Co było wymagane.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster