Cmake Subdirectory Example

  1. Cmake Subdirectory Example Free
  2. Cmake Add Subdirectory Example
  3. Cmake Add All Subdirectories
  4. Cmake Sublist Example
  5. Cmake Pass Variable To Subdirectory

Hi everyone! I’m starting the new project and I would like to make it using CMake in a good way from the beginning.

I’ve found the proposition of project structure at the modern CMake book and It look’s that it has sense but unfortunately I can’t found a nice example of how to make it alive.

If there is a more common or modern structure that should be used please point it out.

Based on instructions from the mentioned book I’ve created a similar but simplified (for now) directories structure.

Problem description Hi everyone! I’m starting the new project and I would like to make it using CMake in a good way from the beginning. I’ve found the proposition of project structure at the modern CMake book and It look’s that it has sense but unfortunately I can’t found a nice example of how to make it alive. If there is a more common or modern structure that should be used please. Cmake to generate a single build system for all the examples, but one may not want the targets to show up in the main build system. And I have a addsubdirectory entry that includes the EXCLUDEFROMALL ADDDIRECTORY (designer EXCLUDEFROMALL) but the directive is ignored and the sub-directory always get built by default. I am using cmake 2.4.7. Example that builds an executable (editor) and links a library (highlight) to it. Project structure is straightforward, it needs a master CMakeLists and a directory for each subproject: CMakeLists.txt editor/ CMakeLists.txt src/ editor.cpp highlight/ CMakeLists.txt include/ highlight.h src/ highlight.cpp. Everything comes together at the top-level CMakeLists.txt. This is the main entry point when running cmake.In the cmake several utility CMake scripts solve several small problems like finding the git version of the host machine and preventing me to build the project inside the source file tree.

I want to logically separate external libraries from the application, use separate CMakeLists.txt to build the external modules and I won’t use git submodules because as I’ve read somewhere the FetchContent_Declare should be used instead.

I want to create the following directories structure:

  • external directory will contain external libraries (like cli11, spdlog, etc.) which should be available in the src directory.
  • src directory will contain the main application.

And this is how the CMakeLists looks like:

  1. RootCMakeLists.txt:
  1. externalCMakeLists.txt:
    (I’m not sure if the separate requirements should be in the one CMakeLists.txt file or rather split into com .in files included in CMakeLists.txt.)
  1. srcCMakeLists.txt:

And below how the main.cpp file looks like:

In the described example I’m using two libraries intentionally because the spdlog is a library where including a header file is enough for building but in the case of cli11, the built library should be linked by a linker.

After cmake the repositories are downloaded and stored in build/_deps directory as:

Of course, it doesn’t build because the compiler can’t find the headers and library - it isn’t defined anywhere.

I’m pretty sure that I should use:

  • target_link_libraries for linking libraries
  • target_include_directories for including the headers

Unfortunately, I can’t find a similar example (which may indicate that I’m doing something wrong). And I’m not sure if should I use them in: src/CMakeLists.txt or rather in the root CMakeLists.txt and the propagate it down to src/CMakeLists.txt.

At the end I have some questions:

  1. How to manage includes in this case?
  2. How to manage libraries in this case?
  3. Should I use FetchContent_Declare or maybe git submodules as many other projects on github?
  4. FetchContent_Declare is ok for downloading libraries used in includes or rather should be used to download standalone modules like googletest or other things independent from the application?

Best regards,
Maciej

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

Cmake Subdirectory 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.

Students


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)
AddCmake Subdirectory Example


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

Cmake Subdirectory Example

To generate the compilation files, you must run cmake:

Cmake Subdirectory Example Free

[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

Cmake Add Subdirectory Example


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:

Cmake Add All Subdirectories

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

Cmake Sublist Example


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

Conclusion

Cmake Pass Variable To Subdirectory

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