Cmake C

CMake is a generator of build systems that can produce Makefiles for Unix like systems, Visual Studio Solutions for Windows and XCode projects for Mac OS. All these from the same base – a single CMakeLists.txt file. But any magic – not just advanced technology – can be understood if we break it into stages. CMake is a tool for defining and managing code builds, primarily for C. CMake is a cross-platform tool; the idea is to have a single definition of how the project is built - which translates into specific build definitions for any supported platform. CMake is a powerful and robust build system. You specify what you want done, not how to do it. CMake then takes that information and generates the files needed to build the system. For example, CMake can generate solution (.sln) and project files (.vcxproj) that Visual Studio and Visual Studio Code use on Windows. CMake is a powerful and robust build system. You specify what you want done, not how to do it. CMake then takes that information and generates the files needed to build the system. For example, CMake can generate solution (.sln) and project files (.vcxproj) that Visual.

Recently, we have had several customers who decided to compile our C++ library under Linux. This process is documented in the README file and there is a post explaining how to compile the library with the Code::Blocks IDE. However, we hadn't yet documented how to use CMake to compile the library and use it in a program. This week, we are tackling this issue.
Note: we assume that you already have a minimal knowledge of the C++ language and of our programming libraries. If it is not the case, we recommend that you start by reading our post 'How to start in C++ with Yoctopuce modules' which explains how our library works.
First of all, a few words on CMake. CMake is neither a compiler nor an IDE, but it is a 'tool for managing the build process of software'. In other words, the role of CMake is not to actually build the executable, but to prepare a list of commands to be performed to generate the executable. Usually under Linux, one uses CMake to generate a GNU make file which then uses gcc or g++ to compile the source file and to create the executable.


CMake generates makefiles which enable you to compile the application with gcc


A CMake project is composed of source files and of one or several CMakeLists.txt files containing the required information to compile the application, such as the location of the source files, the name of the executable, the libraries to be used, and so on.
We could wonder why not using GNU make directly. Indeed, GNU make already enables us to describe the commands to be run to transform a .cpp file into an executable, but its syntax is very complex and becomes almost incomprehensible for large projects. As we are going to see below, the CMake syntax is much simpler, making the life of the developer easier as well.
Moreover, CMake is open source and is available on almost all platforms.
For these reasons, since version 1.10.42060 of our C++ library, we added a CMakeLists.txt file in the Sources subdirectory. This file contains all the compilation rules for our library. To use our C++ library in a CMake project, you only need to include this file and to reference our library with the yoctolib name.

A short example


In order to illustrate what we are saying, we are going to see all the steps to compile the following code:

#include <iostream>
#include 'yocto_api.h'
usingnamespace std;
int main(int argc, constchar* argv[])
{
string errmsg;
if(YAPI::RegisterHub('usb', errmsg)!=YAPI::SUCCESS){
cerr<<'RegisterHub error: '<< errmsg <<endl;
return1;
}
cout<<'Device list: '<<endl;
YModule*module =YModule::FirstModule();
while(module !=NULL){
cout<< module->get_serialNumber()<<' ';
cout<< module->get_productName()<<endl;
module = module->nextModule();
}
YAPI::FreeAPI();
return0;
}


This code displays the serial number and the product name of all the Yoctopuce modules connected on the USB ports of the machine. For more information on the functions that are used in this example, you can read the documentation of the C++ library. We save this code in a main.cpp file that we are going to compile.
To compile this code, you must have g++, CMake, and libusb-1.0-dev installed on the machine. On a Debian or Ubuntu based distribution, you can install all these packages with the following commands:

sudo apt-get update sudo apt-get install cmake sudo apt-get install build-essential gdb sudo apt-get install libusb-1.0-0-dev


Then, you must download the Yoctopuce C++ library. You can do so with Git or directly from our web site. The Sources subdirectory contains all the source files to be compiled to use our library, as well as the CMakeLists.txt file which is used by CMake.
Note the path of this directory, because you will need it later on. In our case, the library is unzipped in the /home/yocto/Yoctolib.CPP/ directory and we therefore need the /home/yocto/Yoctolib.CPP/Source path.

The CMakeLists.txt file


Now that we have our main.cpp file and all the dependencies installed on the machine, we can start to write the CMakeLists.txt file for our demo application. As explained above, this file contains all the instructions to compile the application.
We start by checking that the installed version of CMake is recent enough and by giving a name to the project, in our case the project is called 'Demo' and we need version 3.16 of CMake.

cmake_minimum_required (VERSION 3.16) project (Demo)


Then, we define the name of the executable and the source files to be compiled. In our case, the name of the executable is demo and there is only one source file: main.cpp. There is no need to add the source files of our C++ library, as we are going to include the CMakeLists.txt file of the library.


We are only missing the instructions to include the Yoctopuce C++ library. This task is easy because we already have a CMakeLists.txt file in the Sources subdirectory. This files contains the list of all the files of the library which must be compiled as well as the flags to pass to the compiler or to the linker to generate the executable.
Note: this file is present only since version 1.10.42060 of the library. If it is not present in your version, you must simply use a more recent version of our library.
The add_subdirectory command with the path of the Sources subdirectory of the library enables us to add the library. In our case, the path is /home/yocto/Yoctolib.CPP/Sources/. The second parameter compiled_yoctolib defines a subdirectory that CMake uses to compile the library.

add_subdirectory (/home/yocto/Yoctolib.CPP/Sources/ compiled_yoctolib)


Finally, we must specify that the demo executable uses the Yoctopuce library (Yoctolib).


Here is the complete CMakeLists.txt file:

# This is a minimal CMakeLists file which includes the Yoctopuce C++ lib.
cmake_minimum_required (VERSION 3.16)
project (Demo)
# Adds the executable called 'demo' that is built from the source files 'main.cpp'.
add_executable (demo main.cpp)
# Adds the Sources subfolder of the Yoctopuce C++ library.
add_subdirectory (/home/yocto/Yoctolib.CPP/Sources/ compiled_yoctolib)
# Links the executable to the Yoctopuce C++ library (YoctoLib).
target_link_libraries (demo LINK_PUBLIC YoctoLib)


Compiling

To generate the compilation files, you must run cmake:

[email protected]:~/tmp$ cmake . -- The C compiler identification is GNU 9.3.0 -- The CXX compiler identification is GNU 9.3.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/yocto/tmp


To actually compile the application, you must use GNU make with the make command:

[email protected]:~/tmp$ make Scanning dependencies of target YoctoLib [ 1%] Building CXX object compiled_yoctolib/CMakeFiles/YoctoLib.dir/yocto_accelerometer.cpp.o .. [ 97%] Linking CXX static library libYoctoLib.a [ 97%] Built target YoctoLib Scanning dependencies of target demo [ 98%] Building CXX object CMakeFiles/demo.dir/main.cpp.o [100%] Linking CXX executable demo [100%] Built target demo


There you are! the application is compiled and you can launch it with the ./demo command:

[email protected]:~/tmp$ sudo ./demo Device list: YLTCHRL1-CD28D Yocto-LatchedRelay


You can find the source code of this example on GitHub: https://github.com/yoctopuce-examples/cmake_example

Conclusion

CMake is a very handy tool when you code in C++. It is more convivial than GNU make. For comparison purposes, the CMakeLists.txt file of our C++ library is only 14 lines long while the GNU makefile is made of 938 lines..

Skip to main content

C++ project setup with CMake & unit tests (google test)

Published: 01-10-2019 Last update: 06-11-2019 Author: Remy van Elst Text only version of this article


❗ This post is over one year old. It may no longer be up to date. Opinions may have changed.

Table of Contents

  • CMakeLists.txt
  • Add some (example) source code and tests

This guide will show you how to setup a new C++ project with CMake and unit testsvia Google's test framework. With this setup you can get started right away with test-driven-development in C++. It is also simple enough to look and figureout how to add gtest to your existing project and start doing TDD on your legacy (existing) codebase.

Consider sponsoring me on Github. It means the world to me if you show your appreciation and you'll help pay the server costs.
You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $100 credit for 60 days.

The picture below shows the end result, a running unit test:

There are a million different ways to 'do' C++ projects, but using CMake andthe google testing framework has my preference. That's not to say that using a Makefile or Boost Unit Test is bad, use whatever suits your needs. This guide however will focus on just CMake and gtest.

It assumes a system running Ubuntu (18.04). It also works on Windows with mingw,but I haven't tested in with MSVC.

My preferred code editor is CLion from Jetbrains, which has most of this built in. This guide however focusses on the manual / command line way since CLion isnonfree (and paid) software.

The process is not that complicated:

  • Install software (cmake and googletest)
  • Create folder structure
  • Create the CMakeLists.txt files
  • Create some sample code and sample tests
  • Compile everything
  • Run the tests

Install cmake & googletest

I assume you already have your compiler installed and working. Installing cmakecan be done with the package manager on Ubuntu:

On Windows, you can use MinGW or cygwin to install your development tools including CMake. Clion offers a nice GUI for that.

Googletest is available as a git repository which you can clone and then copyinto your project. You could go all fancy with CMake scripts to download itif it's not already in your project, but since you can clone once and copy later on I choose not to automate it. Clone the repository:

gtest comes with a CMakeLists.txt so integrating it in your project is easy.

Folder structure

Create your C++ project folder. I like to keep the following structure for simpleprojects:

Here is a oneliner to create the folders:

Copy the googletest repository folder your cloned earlier into the lib/ folder.

If you have multiple components you can create extra sub folders, but that doesrequire tweaking the CMakeLists.txt files to work with multiple libraries.

Most of my personal projects are simple enough to fit into one folder as above.

In the tst folder the unit tests reside. I try to keep the tests limited to the same function in seperate files. In the above example I have Formula.h and Formula.cpp, which house the example Formula class. All unit tests relatedto this class thus should reside in Formula-test.cpp.

CMakeLists.txt

The file CMakeLists.txt contains a set of directives and instructionsdescribing the project's source files and targets (executable, library, orboth). This can get quite complex quite fast, CMake has many options. I try tokeep it simple in this guide.

I'm using a non-recommended way to include files. For simple projects with a few files you should use the following:

I'm using this:

That is a recursive search to include all *.cpp and *.h in the folder. Inmy IDE I have auto-reload enabled, that way I can't forget to add a fileto CMakeLists.txt every time. Is cleanmymac worth buying. For proper administration you should not use thissince it just includes everything, could have unwanted side-effects.

Cmake C

Update 2019-11-07: If you want Boost in this setup, read this article from me.

Each subdirectory in our case also needs a CMakeLists.txt file.

Main folder CMakeLists.txt

The name of the project is ExampleProject, that variable is used in other files.The rest of the file just includes the different subfolders. If you omit the include_directories(src), your tests will not be able to find the header files.

src folder CMakeLists.txt:

The name of the compiled program will be ExampleProject_run, which is whatwe defined in add_executable. The add_library is used to include the codein the unit tests.

tst folder CMakeLists.txt:

This list used the src defined library and adds the tests as a target. The compiled executable file is named ExampleProject_tst.

Add some (example) source code and tests

Cmake Command Not Found

At this point you start developing. But since this is a example setup, I'll adda simple class file to show you how to do the unit tests.

Source Code

Copy the below code into your project:

src/main.cpp:

src/Formula.h:

src/Formula.cpp:

This function returns the given int multiplied by 2.

Test code

The following code is to setup the unit tests.

tst/main.cpp:

This file will run all the tests and since we recursively included everythingwith CMake, it will effectively run all tests in all files in this folder.

tst/Formula-test.cpp:

The Google Test Primer is a great starting point to learn more on the specificsof the testing framework.

Compile all the things

Cmake C

Now that we have sourcecode and testcode in place we can compile everything (both the binary and the tests).

Do note that you should do this in the build folder. If you do it in the main folder it will work, but it will litter up the directory.

Output:

There are now a bunch of files and folders in the build folder, most important,the Makefile. You can now compile the project:

Output:

You now have two executable files, as defined in the CMakeLists.txt:

Cmake C 14

Run all the things

If all went well, the code should run:

Output:

The tests as well:

Output:

A quick one-liner to compile and run the tests. You can run this wheneveryou want to re-run the tests (after changing code for example):

Output:

As you can see I changed a unit test so that it failed.

Tags: boost, c++, cmake, cpp, development, googletest, linux, software, testing, ttd, tutorials

Cmake Configure_file