1. 程式人生 > 其它 >CMake實戰四:安裝測試和新增環境生成安裝包

CMake實戰四:安裝測試和新增環境生成安裝包


title: CMake實戰四:安裝測試和新增環境生成安裝包

categories:[實戰四]

tags:[CMake]

date: 2021/12/24

作者:hackett 微信公眾號:加班猿

1、安裝測試

CMake 也可以指定安裝規則,以及新增測試。這兩個功能分別可以通過在產生 Makefile 後使用 make installmake test 來執行。在 GNU Makefile 裡,你可能需要為此編寫 installtest 兩個偽目標和相應的規則,但在 CMake 裡,這樣的工作同樣只需要簡單的呼叫幾條命令。

1.1定製安裝規則

首先先在 math/CMakeLists.txt 檔案裡新增下面兩行:

# 指定 MathFunctions 庫的安裝路徑
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)

指明 MathFunctions 庫的安裝路徑。之後同樣修改根目錄的 CMakeLists 檔案,在末尾新增下面幾行:

# 指定安裝路徑
install (TARGETS Demo DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/config.h"
         DESTINATION include)

通過上面的定製,生成的 Demo 檔案和 MathFunctions 函式庫 libMathFunctions.o 檔案將會被複制到 /usr/local/bin 中,而 MathFunctions.h 和生成的 config.h 檔案則會被複制到 /usr/local/include 中。我們可以驗證一下(順帶一提的是,這裡的 /usr/local/ 是預設安裝到的根目錄,可以通過修改 CMAKE_INSTALL_PREFIX 變數的值來指定這些檔案應該拷貝到哪個根目錄):

[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工程新增測試

新增測試同樣很簡單。CMake 提供了一個稱為 CTest 的測試工具。我們要做的只是在專案根目錄的 CMakeLists 檔案中呼叫一系列的 add_test 命令。

CMakeLists.txt

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

# 加入一個配置標頭檔案,用於處理 CMake 對原始碼的設定
configure_file (
    "${PROJECT_SOURCE_DIR}/config.h.in"
    "${PROJECT_BINARY_DIR}/config.h"
)
# 是否使用自己的 MathFunctions 庫
option (USE_MYMATH
        "Use provided math implementation" ON)

# 是否加入 MathFunctions 庫
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)

# 指定生成目標
add_executable(demo ${DIR_SRCS})
target_link_libraries(demo ${EXTRA_LIBS})

# 指定安裝路徑
install (TARGETS demo DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/config.h"
                 DESTINATION include)

enable_testing()
# 測試程式是否成功執行
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")

上面的程式碼包含了四個測試。第一個測試 test_run 用來測試程式是否成功執行並返回 0 值。剩下的三個測試分別用來測試 35 + 2 、5 + 2、2 + 3是否都能得到正確的結果。其中 PASS_REGULAR_EXPRESSION 用來測試輸出是否包含後面跟著的字串。

測試結果:

[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

如果要測試更多的輸入資料,像上面那樣一個個寫測試用例未免太繁瑣。這時可以通過編寫巨集來實現:

# 定義一個巨集,用來簡化測試工作
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)
 
# 使用該巨集進行一系列的資料測試
do_test (35 2 "37")
do_test (5 52 "7")
do_test (2 3 "5")

關於 CTest 的更詳細的用法可以通過 man 1 ctest 參考 CTest 的文件。

2、新增版本號

首先修改頂層 CMakeLists 檔案,在 project 命令之後加入如下兩行:

set (Demo_VERSION_MAJOR 1)
set (Demo_VERSION_MINOR 0)

分別指定當前的專案的主版本號和副版本號。

之後,為了在程式碼中獲取版本資訊,我們可以修改 config.h.in 檔案,新增兩個預定義變數:

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

這樣就可以直接在程式碼中列印版本資訊了:

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

執行結果:

[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、生成安裝包

如何配置生成各種平臺上的安裝包,包括二進位制安裝包和原始碼安裝包。為了完成這個任務,我們需要用到 CPack ,它同樣也是由 CMake 提供的一個工具,專門用於打包。

首先在頂層的 CMakeLists.txt 檔案尾部新增下面幾行:

# 構建一個 CPack 安裝包
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)

上面的程式碼做了以下幾個工作:

  1. 匯入 InstallRequiredSystemLibraries 模組,以便之後匯入 CPack 模組;
  2. 設定一些 CPack 相關變數,包括版權資訊和版本資訊,其中版本資訊用了上一節定義的版本號;
  3. 匯入 CPack 模組。

建立一個``License.txt`檔案

touch License.txt

接下來的工作是像往常一樣構建工程,並執行 cpack 命令。

  • 生成二進位制安裝包:
cpack -C CPackConfig.cmake
  • 生成原始碼安裝包
cpack -C CPackSourceConfig.cmake

我們可以試一下。在生成專案後,執行 cpack -C CPackConfig.cmake 命令:

[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

這 3 個二進位制包檔案所包含的內容是完全相同的。我們可以執行其中一個。此時會出現一個由 CPack 自動生成的互動式安裝介面:

[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

完成後提示安裝到了 demo8-1.0.1-Linux 子目錄中,我們可以進去執行該程式:

[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

如果你覺得文章還不錯,可以給個"三連",文章同步到個人微信公眾號[加班猿]

我是hackett,我們下期見

參考文件:

CMake入門實戰

CMake Tutorial