
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 i dotknąć wszystkiego własnymi rękami.
Spis treści
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. ().
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 .
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.
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 installPo tym dołącza się go do każdego innego projektu za pomocą polecenia .
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 .
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
