cmake入门系列总结三
版本说明
版本 | 作者 | 日期 | 备注 |
---|---|---|---|
0.1 | loon | 2019.3.13 | 初稿 |
目录
一、主旨
这节的主旨是安装和测试,为项目添加安装规则和测试支持。
二、安装规则
安装规则非常简单。对于printHelloWorld库,我们通过将以下两行添加到printHelloWorld的CMakeLists.txt文件来设置库和要安装的头文件:
install (TARGETS printHelloWorld DESTINATION bin)
install (FILES printHelloWorld.h DESTINATION include)
对于应用程序,将以下行添加到顶级CMakeLists.txt文件以安装可执行文件和配置的头文件:
# add the install targets
install (TARGETS helloWorld DESTINATION bin)
install (FILES "${PROJECT_SOURCE_DIR}/helloWorldConfig.h"
DESTINATION include)
这就是它的全部。此时,您应该能够构建成功,然后键入make install(或从IDE构建INSTALL目标),它将安装相应的头文件,库和可执行文件。CMake变量CMAKE_INSTALL_PREFIX用于确定文件的安装位置。
目录结构(创建一个install目录):
zy@zy-virtual-machine:~/test/cmake_test/hello_world$ tree ./
./
├── build
├── CMakeLists.txt
├── helloWorldConfig.h
├── helloWorldConfig.h.in
├── install
├── main.c
└── printHelloWorld
├── CMakeLists.txt
├── printHelloWorld.c
└── printHelloWorld.h
3 directories, 7 files
printHelloWorld目录下的CMakeLists.txt最终:
add_library(printHelloWorld printHelloWorld.c)
install(TARGETS printHelloWorld DESTINATION bin)
install(FILES "printHelloWorld.h" DESTINATION include)
顶级CMakeLists.txt最终:
cmake_minimum_required(VERSION 2.8)
project(helloWorld)
configure_file(
"${PROJECT_SOURCE_DIR}/helloWorldConfig.h.in"
"${PROJECT_SOURCE_DIR}/helloWorldConfig.h"
)
include_directories(
"${PROJECT_SOURCE_DIR}/printHelloWorld"
"${PROJECT_SOURCE_DIR}"
)
add_subdirectory(printHelloWorld)
add_executable(helloWorld main.c)
target_link_libraries(helloWorld printHelloWorld)
install(TARGETS helloWorld DESTINATION bin)
install(FILES "${PROJECT_SOURCE_DIR}/helloWorldConfig.h"
DESTINATION include)
运行过程及结果(使用-DCMAKE_INSTALL_PREFIX来指定安装路径):
zy@zy-virtual-machine:~/test/cmake_test/hello_world/build$ cmake ..
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/zy/test/cmake_test/hello_world/build
zy@zy-virtual-machine:~/test/cmake_test/hello_world/build$ cmake -DCMAKE_INSTALL_PREFIX=/home/zy/test/cmake_test/hello_world/install/ ..
-- Configuring done
-- Generating done
-- Build files have been written to: /home/zy/test/cmake_test/hello_world/build
zy@zy-virtual-machine:~/test/cmake_test/hello_world/build$ make
Scanning dependencies of target printHelloWorld
[ 25%] Building C object printHelloWorld/CMakeFiles/printHelloWorld.dir/printHelloWorld.c.o
[ 50%] Linking C static library libprintHelloWorld.a
[ 50%] Built target printHelloWorld
Scanning dependencies of target helloWorld
[ 75%] Building C object CMakeFiles/helloWorld.dir/main.c.o
[100%] Linking C executable helloWorld
[100%] Built target helloWorld
zy@zy-virtual-machine:~/test/cmake_test/hello_world/build$ make install
[ 50%] Built target printHelloWorld
[100%] Built target helloWorld
Install the project...
-- Install configuration: ""
-- Installing: /home/zy/test/cmake_test/hello_world/install/bin/helloWorld
-- Up-to-date: /home/zy/test/cmake_test/hello_world/install/include/helloWorldConfig.h
-- Installing: /home/zy/test/cmake_test/hello_world/install/bin/libprintHelloWorld.a
-- Up-to-date: /home/zy/test/cmake_test/hello_world/install/include/printHelloWorld.h
zy@zy-virtual-machine:~/test/cmake_test/hello_world/build$ ./helloWorld
Use my print hello world library?
zy@zy-virtual-machine:~/test/cmake_test/hello_world/build$ cd ..
zy@zy-virtual-machine:~/test/cmake_test/hello_world$ cd build/
zy@zy-virtual-machine:~/test/cmake_test/hello_world/build$ rm * -rf
zy@zy-virtual-machine:~/test/cmake_test/hello_world/build$ cd ..
zy@zy-virtual-machine:~/test/cmake_test/hello_world$ tree .
.
├── build
├── CMakeLists.txt
├── helloWorldConfig.h
├── helloWorldConfig.h.in
├── install
│ ├── bin
│ │ ├── helloWorld
│ │ └── libprintHelloWorld.a
│ └── include
│ ├── helloWorldConfig.h
│ └── printHelloWorld.h
├── main.c
└── printHelloWorld
├── CMakeLists.txt
├── printHelloWorld.c
└── printHelloWorld.h
5 directories, 11 files
三、添加测试
添加测试也是一个相当简单的过程。在顶级CMakeLists.txt文件的末尾,我们可以添加许多基本测试来验证应用程序是否正常工作。
include(CTest)
# 测试程序是否可运行
add_test(test_run helloWorld)
# 测试信息是否正确
add_test(helloWorldUsage helloWorld)
set_tests_properties (helloWorldUsage PROPERTIES PASS_REGULAR_EXPRESSION "Use my print hello world library?")
构建完成后,可以运行“ctest”命令行工具来运行测试。第一个测试只是验证应用程序运行,不会发生段错误或以其他方式崩溃,并且返回值为零。这是CTest测试的基本形式。接下来的几个测试都使用PASS_REGULAR_EXPRESSION测试属性来验证测试的输出是否包含某些字符串。
这个时候我们运行,由于运行结果为“Use my print hello world library?”,所以两个测试用例都是通过的(make编译后make test或者ctest均可):
loon@loon-virtual-machine:~/work/cmake_test/helloWorld/build$ make
[ 50%] Built target printHelloWorld
[100%] Built target helloWorld
loon@loon-virtual-machine:~/work/cmake_test/helloWorld/build$ make test
Running tests...
Test project /home/loon/work/cmake_test/helloWorld/build
Start 1: test_run
1/2 Test #1: test_run ......................... Passed 0.00 sec
Start 2: helloWorldUsage
2/2 Test #2: helloWorldUsage .................. Passed 0.00 sec
100% tests passed, 0 tests failed out of 2
Total Test time (real) = 0.01 sec
loon@loon-virtual-machine:~/work/cmake_test/helloWorld/build$ ctest
Test project /home/loon/work/cmake_test/helloWorld/build
Start 1: test_run
1/2 Test #1: test_run ......................... Passed 0.00 sec
Start 2: helloWorldUsage
2/2 Test #2: helloWorldUsage .................. Passed 0.00 sec
100% tests passed, 0 tests failed out of 2
Total Test time (real) = 0.02 sec
如果我们再增加一个测试用例:
add_test(error_show helloWorld)
set_tests_properties(error_show PROPERTIES PASS_REGULAR_EXPRESSION "123")
那么由于运行结果中没有“123”这个字符串,那么测试就会报错:
loon@loon-virtual-machine:~/work/cmake_test/helloWorld/build$ make
-- Configuring done
-- Generating done
-- Build files have been written to: /home/loon/work/cmake_test/helloWorld/build
[ 50%] Built target printHelloWorld
[100%] Built target helloWorld
loon@loon-virtual-machine:~/work/cmake_test/helloWorld/build$ ctest
Test project /home/loon/work/cmake_test/helloWorld/build
Start 1: test_run
1/3 Test #1: test_run ......................... Passed 0.00 sec
Start 2: helloWorldUsage
2/3 Test #2: helloWorldUsage .................. Passed 0.00 sec
Start 3: error_show
3/3 Test #3: error_show .......................***Failed Required regular expression not found.Regex=[123
] 0.00 sec
67% tests passed, 1 tests failed out of 3
Total Test time (real) = 0.02 sec
The following tests FAILED:
3 - error_show (Failed)
Errors while running CTest
如果要添加大量测试来测试不同的输入值,可以考虑创建如下的宏:
#define a macro to simplify adding tests, then use it
macro (do_test arg result)
add_test (TutorialComp${arg} Tutorial ${arg})
set_tests_properties (TutorialComp${arg}
PROPERTIES PASS_REGULAR_EXPRESSION ${result})
endmacro (do_test)
# do a bunch of result based tests
do_test (25 "25 is 5")
do_test (-25 "-25 is 0")
对于do_test的每次调用,将根据传递的参数向项目添加另一个测试,其中包含名称,输入和结果。
以上那种就是变量替换的方式,将arg和result做了替换,然后在下面只需要增加do_test表达式即可。
四、最后
其实,总结到这一步,cmake的套路基本上已经有些清晰了,也就和编程语言类似,定义一些变量、特殊字符、表达式、宏、函数等,将我们使用shell脚本和Makefile、测试命令等的过程进行了封装,形成这样一个集构建、编译、测试于一体的工具,让我们能更快更方便的去构建、编译和测试项目。
此外,更多的测试用法可以查找Ctest这个工具,我们明显可以看出这个是用include包含了Ctest来使用test功能的。