This article is about testing and packaging software with CMake, a flexible and versatile set of utilities for developing various software products. It is strongly recommended to read the first and second parts of the manual in order to avoid misunderstanding the syntax and principle of CMake.
Below are examples of using the CMake language that you should practice using. Experiment with the source code, changing existing commands and adding new ones. To run these examples, install CMake from the official site .
As mentioned earlier, CMake supports automated software testing. This feature is very easy to use - just write a few commands in the usual CMakeLists.txt
, and then run the tests using ctest
or make test
. At your disposal there is verification of the output of programs, dynamic memory analysis and much more.
We consider the process of testing the program with a specific example. The source file Multiply.c
contains the following code:
#include <stdio.h> #include <stdlib.h> #define ARG_COUNT 3 int main(const int argc, const char *argv[]) { if (argc != ARG_COUNT) { fprintf(stderr, "Error!\n"); return EXIT_FAILURE; } const int first = atoi(argv[1]); const int second = atoi(argv[2]); printf("The result is: %d\n", first * second); return EXIT_SUCCESS; }
This code displays the result of multiplying the two arguments in the console. Please note that an error situation is also possible if the actual number of arguments does not satisfy the expected: in this case, Error will be output to the error stream Error!
.
In the same directory is the CMakeLists.txt
file describing the build process, containing the code below:
cmake_minimum_required(VERSION 3.0) project(MyProgram) add_executable(Multiply Multiply.c) set(MULTIPLY_TIMEOUT 1) # : enable_testing() # : add_test(FirstTest Multiply 15 207) add_test(SecondTest Multiply -54 -785) add_test(ThirdTest Multiply 85234) # : set_tests_properties(FirstTest SecondTest ThirdTest PROPERTIES TIMEOUT ${MULTIPLY_TIMEOUT}) set_tests_properties(FirstTest PROPERTIES PASS_REGULAR_EXPRESSION "The result is: 3105" FAIL_REGULAR_EXPRESSION "Error!") set_tests_properties(SecondTest PROPERTIES PASS_REGULAR_EXPRESSION "The result is: 42390" FAIL_REGULAR_EXPRESSION "Error!") set_tests_properties(ThirdTest PROPERTIES PASS_REGULAR_EXPRESSION "Error!")
Consider everything in order. The first four commands should be familiar to you from the previous article , and the next enable_testing
command raises a number of questions. In essence, this command only notifies CMake of your intention to test the program, simultaneously generating some configuration files, the existence of which you don’t need to know.
The following three add_test
add tests to the current project. The short form of this command takes the name of the test as the first argument, and the subsequent arguments form the shell command to run the test.
A series of commands set_tests_properties
sets the behavior of individual tests. After the list of test names follows the PROPERTIES
keyword, which signals the beginning of the list of properties that have the form < > < >
and are specified for the selected tests. Full list of available properties is here .
For all tests, the maximum execution time in one second is set by the TIMEOUT
property, and then for subsequent tests, the expected output is set by the PASS_REGULAR_EXPRESSION
and FAIL_REGULAR_EXPRESSION
(for example, if The result is: 3105
coincides with the test, then the FirstTest
test continues, and if it matches with the expression Error!
test stops and is considered failed).
There is an analogue of the command enable_testing
- this is the inclusion of the CTest
module through the include
command. In general, the inclusion of a module is more universal, but there is still a difference between them.
The enable_testing
command enables testing for the current directory, as well as for all subsequent ones. It should be in the root CMakeLists.txt
, since CTest expects the test file in the root of the assembly.
Turning on the CTest
module configures the project for testing via CTest / CDash, and also automatically determines the BUILD_TESTING
option, which accepts the truth if testing is possible (by default, ON
). Thus, when using this command, it is reasonable to describe the testing process in a similar way:
if(BUILD_TESTING) add_test(FirstTest Test 1) add_test(SecondTest Test 2) add_test(ThirdTest Test 3) # ... endif()
A series of cmake . && cmake --build . && ctest .
commands cmake . && cmake --build . && ctest .
cmake . && cmake --build . && ctest .
run all three tests. The ctest -R <RegularExpression>
executes the test suite that satisfies the specified regular expression. For example, the command ctest -R ThirdTest
runs only the third test.
To create a package of source files, libraries and executable files, all you have to do is to install the necessary files using the install
command, and then turn on the CPack
module CPack
the include
command:
# "Multiply" "bin": install(TARGETS Multiply DESTINATION bin) # : set(CPACK_PACKAGE_NAME "Multiply") set(CPACK_PACKAGE_VENDOR "MyCompany") set(CPACK_PACKAGE_CONTACT "https://myprojectsite.org") set(CPACK_DEBIAN_PACKAGE_MAINTAINER "mycontacts@gmail.com") set(CPACK_PACKAGE_DESCRIPTION "The most stupid program ever written") # : set(CPACK_GENERATOR "DEB") # "CPack": include(CPack)
In this case, the install
command notifies the packet generator about the target installation directory Multiply
. Without writing installation commands, packet generation is not possible.
The following lists the characteristics of a package by specifying several variables. In fact, there is an abundance of such variables that properly package. Most of them are optional, but some package generators require their definition. A list of variables common to all package generators is available here .
Definition of the variable CPACK_GENERATOR
is CPACK_GENERATOR
- it is a list of package generators called by the cpack
utility. In this case, it takes the value of DEB
, therefore, a debian-package is generated in the root directory of the overview application.
Finally, the CPack
module is CPack
, which configures the future package of the project, using the previously defined variables and the installation command for the executable file, as well as adding two assembly targets — package
and package_source
(respectively, binary assembly and source code assembly).
A series of cmake . && cmake --build . && cmake --build . --target package
commands cmake . && cmake --build . && cmake --build . --target package
cmake . && cmake --build . && cmake --build . --target package
cmake . && cmake --build . && cmake --build . --target package
runs the selected generator to create a binary package, and the cmake . && cmake --build . && cmake --build . --target package_source
command cmake . && cmake --build . && cmake --build . --target package_source
cmake . && cmake --build . && cmake --build . --target package_source
cmake . && cmake --build . && cmake --build . --target package_source
generate a source package right in the root directory.
In this cycle of articles full guide to CMake came to an end. I hope that you have extracted a lot of useful material, as well as improved your skills in programming. Good luck!
Source: https://habr.com/ru/post/433822/
All Articles