CMake practice 4: install, test and add environment to generate installation package

Posted by mr_hacker on Fri, 24 Dec 2021 17:44:41 +0100

title: CMake Practice IV: install, test and add environment to generate installation package

categories: [actual combat iv]

tags:[CMake]

date: 2021/12/24

Author: hackett

WeChat official account: overtime ape

1. Installation test

CMake can also specify installation rules and add tests. These two functions can be performed by using make install and make test after generating the makefile. In GNU Makefile, you may need to write install and test pseudo targets and corresponding rules for this, but in CMake, such work also needs to simply call a few commands.

1.1 custom installation rules

First, in math / cmakelists Add the following two lines to the txt file:

# Specify the installation path of the MathFunctions library
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)

Indicates the installation path of the MathFunctions library. After that, also modify the CMakeLists file in the root directory and add the following lines at the end:

# Specify the installation path
install (TARGETS Demo DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/config.h"
         DESTINATION include)

Through the above customization, the generated Demo file and MathFunctions library libmathfunctions O files will be copied to / usr/local/bin, and MathFunctions H and generated config The H file is copied to / usr/local/include. We can verify (incidentally, / usr/local / here is the root directory of the default installation. You can specify which root directory these files should be copied to by modifying the value of CMAKE_INSTALL_PREFIX variable):

[root@hackett demo5]# make install
Consolidate compiler generated dependencies of target MathFunctions
[ 50%] Built target MathFunctions
Consolidate compiler generated dependencies of target demo
[100%] Built target demo
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/bin/demo
-- Installing: /usr/local/include/config.h
-- Installing: /usr/local/bin/libMathFunctions.a
-- Installing: /usr/local/include/myMath.h
[root@hackett demo5]# ls /usr/local/bin/
demo         libMathFunctions.a               
[root@iZwz97bu0gr8vx0j8l6kkzZ demo5]# ls /usr/local/include/
config.h    myMath.h

1.2 project addition test

Adding tests is also simple. CMake provides a testing tool called CTest. All we have to do is to call a series of add_ in the CMakeLists file of the project root directory. Test command.

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
# set the project name
project(demo5)

# Add a configuration header file to handle CMake's settings for the source code
configure_file (
    "${PROJECT_SOURCE_DIR}/config.h.in"
    "${PROJECT_BINARY_DIR}/config.h"
)
# Do you want to use your own MathFunctions library
option (USE_MYMATH
        "Use provided math implementation" ON)

# Add MathFunctions library
if (USE_MYMATH)
    include_directories ("${PROJECT_SOURCE_DIR}/math")
    add_subdirectory (math)
    set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)

aux_source_directory(. DIR_SRCS)

# Specify build target
add_executable(demo ${DIR_SRCS})
target_link_libraries(demo ${EXTRA_LIBS})

# Specify the installation path
install (TARGETS demo DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/config.h"
                 DESTINATION include)

enable_testing()
# Test whether the program runs successfully
add_test (test_run demo 3 2)

add_test (test_35_2 demo 35 2)
set_tests_properties (test_35_2 PROPERTIES PASS_REGULAR_EXPRESSION "37")

add_test (test_5_2 demo 5 2)
set_tests_properties (test_5_2 PROPERTIES PASS_REGULAR_EXPRESSION "7")

add_test (test_2_3 demo 2 3)
set_tests_properties (test_2_3 PROPERTIES PASS_REGULAR_EXPRESSION "5")

The above code contains four tests. First test_run is used to test whether the program runs successfully and returns a value of 0. The remaining three tests are used to test whether 35 + 2, 5 + 2 and 2 + 3 can get the correct results. Where PASS_REGULAR_EXPRESSION is used to test whether the output contains the following string.

Test results:

[root@hackett demo5]# make 
Consolidate compiler generated dependencies of target MathFunctions
[ 50%] Built target MathFunctions
Consolidate compiler generated dependencies of target demo
[ 75%] Building CXX object CMakeFiles/demo.dir/main.cpp.o
[100%] Linking CXX executable demo
[100%] Built target demo
[root@hackett demo5]# make test
Running tests...
Test project /root/workspace/cmake/demo5
    Start 1: test_run
1/4 Test #1: test_run .........................   Passed    0.00 sec
    Start 2: test_35_2
2/4 Test #2: test_35_2 ........................   Passed    0.00 sec
    Start 3: test_5_2
3/4 Test #3: test_5_2 .........................   Passed    0.00 sec
    Start 4: test_2_3
4/4 Test #4: test_2_3 .........................   Passed    0.00 sec

100% tests passed, 0 tests failed out of 4

Total Test time (real) =   0.01 sec

If you want to test more input data, writing test cases one by one like the above is too cumbersome. This can be achieved by writing macros:

# Define a macro to simplify testing
macro (do_test arg1 arg2 result)
  add_test (test_${arg1}_${arg2} demo ${arg1} ${arg2})
  set_tests_properties (test_${arg1}_${arg2}
    PROPERTIES PASS_REGULAR_EXPRESSION ${result})
endmacro (do_test)
 
# Use this macro for a series of data tests
do_test (35 2 "37")
do_test (5 52 "7")
do_test (2 3 "5")

For more detailed usage of CTest, you can refer to the CTest documentation through man 1 ctest.

2. Add version number

First modify the top-level CMakeLists file and add the following two lines after the project command:

set (Demo_VERSION_MAJOR 1)
set (Demo_VERSION_MINOR 0)

Specify the major version number and minor version number of the current project respectively.

After that, in order to get the version information in the code, we can modify it config.h.in File, add two predefined variables:

// the configured options and settings for Tutorial
#define Demo_VERSION_MAJOR @Demo_VERSION_MAJOR@
#define Demo_VERSION_MINOR @Demo_VERSION_MINOR@

In this way, the version information can be printed directly in the code:

#include <stdio.h>
#include <stdlib.h>
#include "config.h"

#ifdef USE_MYMATH
  #include "math/myMath.h"
#else
  #include <math.h>
#endif
int sub(int a, int b) {
    return (a - b);
}

int main(int argc, char *argv[]) {
    if (argc < 3) {
        printf("Usage: %s argv[1] argv[2] \n", argv[0]);
        return 1;
    }
    printf("version : %d.%d\n", Demo_VERSION_MAJOR, Demo_VERSION_MINOR);
    int a = atof(argv[1]);
    int b = atoi(argv[2]);

#ifdef USE_MYMATH
    printf("Now we use our own Math library. \n");
    int result = add(a, b);
    printf("%d + %d = %d\n", a, b, result);
#else
    printf("Now we use the main.cpp sub function. \n");
    int result = sub(a, b);
    printf("%d - %d = %d\n", a, b, result);
#endif
    return 0;
}

Operation results:

[root@hackett demo7]# cmake .
-- Configuring done
-- Generating done
-- Build files have been written to: /root/workspace/cmake/demo7
[root@hackett demo7]# make
Consolidate compiler generated dependencies of target MathFunctions
[ 25%] Building CXX object math/CMakeFiles/MathFunctions.dir/myMath.cpp.o
[ 50%] Linking CXX static library libMathFunctions.a
[ 50%] Built target MathFunctions
[ 75%] Building CXX object CMakeFiles/demo.dir/main.cpp.o
[100%] Linking CXX executable demo
[100%] Built target demo
[root@hackett demo7]# ./demo 2 3 
version : 1.0
Now we use our own Math library. 
2 + 3 = 5

3. Generate installation package

How to configure and generate installation packages on various platforms, including binary installation packages and source installation packages. In order to complete this task, we need to use CPack, which is also a tool provided by CMake for packaging.

First, cmakelists Add the following lines at the end of the txt file:

# Build a CPack installation package
include (InstallRequiredSystemLibraries)
set (CPACK_RESOURCE_FILE_LICENSE
  "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
set (CPACK_PACKAGE_VERSION_MAJOR "${Demo_VERSION_MAJOR}")
set (CPACK_PACKAGE_VERSION_MINOR "${Demo_VERSION_MINOR}")
include (CPack)

The above code does the following work:

  1. Import the InstallRequiredSystemLibraries module to import the CPack module later;
  2. Set some CPack related variables, including copyright information and version information. The version information uses the version number defined in the previous section;
  3. Import the CPack module.

Create a ` license Txt file

touch License.txt

The next work is to build the project as usual and execute the cpack command.

  • Generate binary installation package:
cpack -C CPackConfig.cmake
  • Generate source installation package
cpack -C CPackSourceConfig.cmake

We can try. After the project is generated, execute cpack - C cpackconfig Cmake command:

[root@hackett demo8]# cmake .
-- Configuring done
-- Generating done
-- Build files have been written to: /root/workspace/cmake/demo8
[root@hackett demo8]# cpack -C CPackConfig.cmake
CPack: Create package using STGZ
CPack: Install projects
CPack: - Run preinstall target for: demo8
CPack: - Install project: demo8 [CPackConfig.cmake]
CPack: Create package
CPack: - package: /root/workspace/cmake/demo8/demo8-1.0.1-Linux.sh generated.
CPack: Create package using TGZ
CPack: Install projects
CPack: - Run preinstall target for: demo8
CPack: - Install project: demo8 [CPackConfig.cmake]
CPack: Create package
CPack: - package: /root/workspace/cmake/demo8/demo8-1.0.1-Linux.tar.gz generated.
CPack: Create package using TZ
CPack: Install projects
CPack: - Run preinstall target for: demo8
CPack: - Install project: demo8 [CPackConfig.cmake]
CPack: Create package
CPack: - package: /root/workspace/cmake/demo8/demo8-1.0.1-Linux.tar.Z generated.
[root@hackett demo8]# ls
CMakeCache.txt  cmake_install.cmake  config.h     CPackConfig.cmake  CPackSourceConfig.cmake  demo                  demo8-1.0.1-Linux.tar.gz  install_manifest.txt  main.cpp  math
CMakeFiles      CMakeLists.txt       config.h.in  _CPack_Packages    CTestTestfile.cmake      demo8-1.0.1-Linux.sh  demo8-1.0.1-Linux.tar.Z   License.txt           Makefile

The three binary package files contain exactly the same content. We can execute one of them. An interactive installation interface automatically generated by CPack will appear:

[root@hackett demo8]# sh demo8-1.0.1-Linux.sh 
demo8 Installer Version: 1.0.1, Copyright (c) Humanity
This is a self-extracting archive.
The archive will be extracted to: /root/workspace/cmake/demo8

If you want to stop extracting, please press <ctrl-C>.


Do you accept the license? [yn]: 
y
By default the demo8 will be installed in:
  "/root/workspace/cmake/demo8/demo8-1.0.1-Linux"
Do you want to include the subdirectory demo8-1.0.1-Linux?
Saying no will install in: "/root/workspace/cmake/demo8" [Yn]: 
y

Using target directory: /root/workspace/cmake/demo8/demo8-1.0.1-Linux
Extracting, please wait...

Unpacking finished successfully

After completion, you will be prompted to install demo8-1.0 In the 1-linux subdirectory, we can go in and execute the program:

[root@hackett demo8]# ls
CMakeCache.txt  cmake_install.cmake  config.h     CPackConfig.cmake  CPackSourceConfig.cmake  demo               demo8-1.0.1-Linux.sh      demo8-1.0.1-Linux.tar.Z  main.cpp  math
CMakeFiles      CMakeLists.txt       config.h.in  _CPack_Packages    CTestTestfile.cmake      demo8-1.0.1-Linux  demo8-1.0.1-Linux.tar.gz  install_manifest.txt     Makefile
[root@hackett demo8]# ./demo8-1.0.1-Linux/bin/demo 3 2
version : 1.0
Now we use our own Math library. 
3 + 2 = 5

If you think the article is good, you can give a "three links", and the article is synchronized to the personal WeChat official account.

I'm hackett. I'll see you next time

Reference documents:

CMake introduction practice

CMake Tutorial

Topics: cmake Alibaba Cloud centos7