C++ và CMake - anh em mãi mãi, phần II

C++ và CMake - anh em mãi mãi, phần II

Trong phần trước Câu chuyện thú vị này nói về việc tổ chức thư viện tiêu đề trong trình tạo hệ thống xây dựng CMake.

Lần này chúng ta sẽ thêm một thư viện đã biên dịch vào nó và cũng nói về việc liên kết các mô-đun với nhau.

Như trước đây, những người thiếu kiên nhẫn có thể ngay lập tức đi đến kho lưu trữ cập nhật và chạm vào mọi thứ bằng chính đôi tay của bạn.


nội dung

  1. Chia
  2. Chinh phục

Chia

Điều đầu tiên chúng tôi cần làm để đạt được mục tiêu cao cả của mình là chia phần mềm chúng tôi phát triển thành các khối phổ quát, biệt lập, thống nhất theo quan điểm của người dùng.

Trong phần đầu tiên, khối tiêu chuẩn như vậy đã được mô tả - một dự án có thư viện tiêu đề. Bây giờ hãy thêm một thư viện đã biên dịch vào dự án của chúng ta.

Để làm điều này, chúng ta hãy thực hiện chức năng myfunc ở một nơi riêng biệt .cpp-tài liệu:

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

Sau đó, chúng tôi xác định thư viện sẽ được biên dịch (myfeature), sẽ bao gồm những gì thu được ở bước trước .cpp-tài liệu. Thư viện mới rõ ràng yêu cầu các tiêu đề hiện có và để cung cấp điều này, nó có thể và nên gắn liền với mục đích hiện có mylib. Hơn nữa, kết nối giữa chúng là công khai, có nghĩa là mọi thứ mà mục tiêu sẽ được kết nối myfeature, sẽ tự động nhận tải và mục tiêu mylib (thêm về phương pháp đan).

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

Tiếp theo, chúng tôi sẽ đảm bảo rằng thư viện mới cũng được cài đặt trên hệ thống:

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

Cần lưu ý rằng vì mục đích myfeature, đối với mylib một bí danh có tiền tố đã được tạo Mylib::. Điều tương tự cũng được viết cho cả hai mục đích khi xuất chúng để cài đặt trên hệ thống. Điều này giúp có thể làm việc thống nhất với các mục tiêu cho bất kỳ kế hoạch ràng buộc.

Sau đó, tất cả những gì còn lại là liên kết các bài kiểm tra đơn vị với thư viện mới (hàm myfunc đã bị xóa khỏi tiêu đề nên bây giờ bạn cần dẫn link):

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
 )

Tiêu đề (Mylib::mylib) bây giờ bạn không cần kết nối riêng, vì như đã đề cập, chúng được tự động kết nối cùng với thư viện (Mylib::myfeature).

Và hãy thêm một số sắc thái để đảm bảo các phép đo mức độ phù hợp có tính đến thư viện mới xuất hiện:

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

Bạn có thể thêm nhiều thư viện, tệp thực thi, v.v. Việc chúng được kết nối với nhau chính xác như thế nào trong dự án không quan trọng. Điều quan trọng duy nhất là mục tiêu nào là giao diện của mô-đun của chúng tôi, tức là chúng nổi bật.

Chinh phục

Bây giờ chúng tôi có các mô-đun khối tiêu chuẩn và chúng tôi có thể thống trị chúng: kết hợp chúng thành một cấu trúc có độ phức tạp bất kỳ, cài đặt chúng vào một hệ thống hoặc liên kết chúng với nhau trong một hệ thống lắp ráp duy nhất.

Cài đặt vào hệ thống

Một trong những lựa chọn để sử dụng mô-đun là cài đặt mô-đun của chúng tôi vào hệ thống.

cmake --build путь/к/сборочной/директории --target install

Sau đó, nó được kết nối với bất kỳ dự án nào khác bằng lệnh find_package.

find_package(Mylib 1.0 REQUIRED)

Kết nối dưới dạng mô-đun con

Một tùy chọn khác là kết nối thư mục với dự án của chúng tôi với dự án khác dưới dạng mô hình con bằng lệnh add_subdirectory.

Sử dụng

Các phương pháp ràng buộc là khác nhau, nhưng kết quả là như nhau. Trong cả hai trường hợp, các mục tiêu sẽ có sẵn trong dự án bằng mô-đun của chúng tôi Mylib::myfeature и Mylib::mylib, có thể được sử dụng, ví dụ như thế này:

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

Cụ thể trong trường hợp của chúng tôi, thư viện Mylib::myfeature cần kết nối khi cần liên kết với thư viện libmyfeature. Nếu có đủ tiêu đề thì nên sử dụng thư viện Mylib::mylib.

Ví dụ: mục tiêu CMake có thể phức tạp, chỉ nhằm mục đích chuyển tiếp một số thuộc tính, phần phụ thuộc, v.v. Đồng thời, làm việc với họ cũng diễn ra theo cách tương tự.

Đó là những gì chúng tôi cần để có được.

Nguồn: www.habr.com

Thêm một lời nhận xét