📜 ⬆️ ⬇️

The complete guide to CMake. Part Three: Testing and Packaging


Introduction


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.


Launch 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 .


Test Example


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


Ways to turn on testing


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

Execution testing


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.


Sample packaging


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


Package execution


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.


Completion


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