C++ 和 CMake - 永远的兄弟,第二部分

C++ 和 CMake - 永远的兄弟,第二部分

在前一部分 这个有趣的故事讲述了在 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

添加评论