C ++ and CMake - Brothers Forever, Part II

Friendship forever


In the previous part of this entertaining story, we talked about organizing a header library as part of the CMake assembly system generator.


This time we add the compiled library to it, and also talk about the layout of the modules with each other.


As before, those who can’t wait, can immediately go to the updated repository and touch everything with their own hands.


Content


  1. Share
  2. Conquer


Share


The first thing to do to achieve our lofty goal is to divide the software under development into universal isolated blocks that are uniform from the user's point of view.


The first part described such a standard block - a project with a header library. Now let's add a compiled library to our project.


To do this, we take out the implementation of the myfunc function in a separate .cpp file:


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

Then we define the compiled library ( myfeature ), which will consist of the .cpp file obtained in the previous step. The new library, obviously, requires existing headers, and in order to ensure this, you can and should knit it with the existing purpose of mylib . Moreover, the link between them is public, which means that everything that the myfeature target will be connected to myfeature automatically receive the mylib target in the load ( more about how to connect ).


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

Next, we will make the new library also installed on the system:


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

It should be noted that for the purpose myfeature , as well as for mylib , an alias was prefixed with the prefix Mylib:: . The same thing is written for both purposes when exporting them for installation in the system. This makes it possible to work uniformly with goals for any linking scheme .


After that, it remains to knit unit tests with the new library (the myfunc function has been myfunc from the header, so now you need to 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 ) 

Headers ( Mylib::mylib ) now do not need to be connected separately, because, as already mentioned, they are automatically connected together with the library ( Mylib::myfeature ).


And add a couple of nuances to ensure coverage measurements taking into account the newly arrived library:


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

You can add more libraries, executables, etc. It doesn’t matter how exactly they are knitted together in the framework of the project. The only important thing is what goals are the interface of our module, that is, stick out.



Conquer


Now we have standard modules-blocks, and we can dominate them: make up a structure of any complexity from them, installing them in a system or interconnecting them within a single assembly system.


System Installation


One of the options for using the module is to install our module in the system.


 cmake --build /// --target install 

After that, it connects to any other project using the find_package .


 find_package(Mylib 1.0 REQUIRED) 

Connection as a submodule


Another option is to connect the folder with our project to another project as a submodule using the add_subdirectory .


Using


The binding methods are different, but the result is the same. In both cases, in a project using our module, the goals Mylib::myfeature and Mylib::mylib will be available, which can be used, for example, like this:


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

Specifically, in our case, the Mylib::myfeature needs to be connected when it is necessary to libmyfeature library. If there are enough headers, then you should use the Mylib::mylib library.


CMake targets can be tricky, for example, designed only to forward some properties, dependencies, etc. At the same time, work with them occurs in a single way.


What was required to receive.

Source: https://habr.com/ru/post/463295/


All Articles