CMake Learning Notes

CMake Learning Notes

CMake Learning Notes

Chapter 1 Understanding CMake

1.1 CMake Introduction

The make tool completes and automatically maintains the compilation work through a file called Makefile . The Makefile describes the compilation and linking rules of the entire project. Most IDEs have this tool, such as:

Visual C++’s nmake, GNU make under Linux, QT’s qmake, etc. This brings a serious problem: software is cross-platform and must ensure that it can be compiled on different platforms. If you use the above make tools, you have to write a Makefile for each standard, which is already quite frustrating.

CMake was born to address this issue, allowing developers to write a platform-independent CMakeLists.txt file that specifies the entire compilation process. It generates localized Makefiles and project files based on the platform, and finally executes make to compile.

1.2.1 CMake Features

1. Open source

2. Cross-platform and can generate native compilation configuration files. On Linux/Unix platforms, it generates Makefile, on MAC systems it can generate Xcode, and on Windows platforms, it can generate MSVC files.

3. Simplifies the compilation and build process. The toolchain of CMake is very simple: cmake + make

1.2.2 CMake Download and Installation

Linux distributions include installation packages for cmake , which can be added directly from the source. Note your CMake version, as there are minimum requirements in the program. You can also download the source code from the official website and compile it yourself. Here we choose the second option.

Download the source package https://cmake.org/download/ The author uses cmake-3.9.1 version on Ubuntu 16.04

sudo tar zxvf cmake-3.9.1-Linux-x86_64.tar.gz

sudo apt-get install tree

tree -L 2 cmake-3.9.1-Linux-x86_64sudo mv cmake-3.9.1-Linux-x86_64 /opt/cmake-3.9.1

sudo ln -sf /opt/cmake-3.9.1/bin/* /usr/bin/

cmake-gui

1.3 Using CMake in Linux Development

The process of using CMake tools under Linux is as follows:

Write CMakeLists.txt

Execute cmake PATH (the directory where CMakeLists.txt is located)

Use make command to compile.

The process is relatively simple. The author refers to online resources and personal learning, and chooses to explain using demo examples. Chapter 2 Using CMake

2.1

Usage of CMakeLists

2.1.1 Syntax

In CMakelist, command names are case-insensitive, while parameters and variables are case-sensitive.

In CMake, using “#” indicates a comment for that line of code.

Use ${} for variable references.

SET(variable value) to define custom variables.

2.1.2 Internal Variables

CMAKE_C_COMPILER : Specify the C compiler.

EXECUTABLE_OUTPUT_PATH : Path for executable files.

LIBRARY_OUTPUT_PATH : Path for library files.

CMAKE_BUILD_TYPE : Build type (Debug, Release, etc.).

BUILD_SHARED_LIBS : Choose static library .a or dynamic link library .so.

2.1.3 Commands

1) # CMake Minimum version requirement

cmake_minimum_required (VERSION 2.8)

2) Project Information

project (Demo2)

3) aux_source_directory Find all source files in the current directory and save the names to the DIR_SRCS variable.

aux_source_directory(. DIR_SRCS)

4) add_executable Generate target files for the project.

add_executable(Demo ${DIR_SRCS})

5) target_link_libraries Link several libraries to the target library file.

target_link_libraries(myProject comm) # Link to libhello.so library, default to link dynamic library first.

target_link_libraries(myProject libcomm.a) # Explicitly specify to link static library.

target_link_libraries(myProject libcomm.so) # Explicitly specify to link dynamic library.

target_link_libraries(<name> lib1 lib2 lib3)

The linking order must comply with the gcc linking order rules, where the linked libraries should be placed after the libraries that depend on them. For instance, if in the above command, lib1 depends on lib2, and lib2 depends on lib3, then the order must strictly be lib1 lib2 lib3, otherwise an error will occur.

You can also customize the linking options, such as for lib1 using -WL option, target_link_libraries(<name> lib1 -WL, lib2 lib3).

6) add_library Generate static and dynamic libraries.

add_library(libname [SHARED|STATIC] source1 source2 … sourceN)

add_library (hello STATIC ${LIBHELLO_SRC}) #Generate static library.

add_library (hello SHARED ${LIBHELLO_SRC}) #Generate dynamic library.7) SET_TARGET_PROPERTIES Set output alias, so if you want “hello_static” to be displayed as “hello”, set as follows:

SET_TARGET_PROPERTIES (hello_static PROPERTIES OUTPUT_NAME “hello”)

GET_TARGET_PROPERTY (OUTPUT_VALUE hello_static OUTPUT_NAME) #Get value.

8) include_directories Set header file locations, equivalent to g++ -I, can use relative or absolute paths, or custom variables.

include_directories(../../../thirdparty/comm/include)

9) link_directories Add directories of libraries to be linked, equivalent to the -L option of g++ command.

link_directories(directory1 directory2 …)

Example:link_directories(“/home/server/third/lib”)

10) link_libraries Add paths of libraries to be linked.

Syntax:

link_libraries(library1 <debug | optimized> library2 …)

# Directly specify the full path.

link_libraries(“/home/server/third/lib/libcommon.a”)

# In the following example, only the library name, CMake will automatically search in the included directories.

link_libraries(iconv)

# Pass in variables.

link_libraries(${RUNTIME_LIB})

# You can also link multiple libraries.

link_libraries(“/opt/MATLAB/R2012a/bin/glnxa64/libeng.so” “/opt/MATLAB/R2012a/bin/glnxa64/libmx.so”)

11) SET_TARGET_PROPERTIES Used to set output names.

SET_TARGET_PROPERTIES (target1 target2 …PROPERTIES prop1 value1 prop2 value2 …)

SET_TARGET_PROPERTIES (hello PROPERTIES VERSION 1.2 SOVERSION 1) to implement dynamic library version numbers.

VERSION refers to the dynamic library version, SOVERSION refers to the API version.

SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME “hello”) to output libhello_static.a as libhello.a

12) GET_TARGET_PROPERTY Get property values.

GET_TARGET_PROPERTY (VAR target property) VAR:variable target: target property: property

GET_TARGET_PROPERTY (OUTPUT_VALUE hello_static OUTPUT_NAME)

13) MESSAGE Print messages during CMake.

MESSAGE (STATUS “This is the hello_static OUTPUT_NAME: ” ${OUTPUT_VALUE})

14) add_library Import existing libraries.

add_library(<name> [STATIC | SHARED | MODULE | UNKNOWN] IMPORTED)

Import an existing <name> library file, usually used with set_target_properties, which specifies the path of the imported library.

For example:

add_library(test SHARED IMPORTED)

set_target_properties( test #Specify target library name

PROPERTIES IMPORTED_LOCATION #Specify the parameter to set

libs/src/${ANDROID_ABI}/libtest.so #Set the path of the imported library)

15) set Command

# Set the output path for executable files (EXCUTABLE_OUTPUT_PATH is a global variable).

set(EXECUTABLE_OUTPUT_PATH [output_path])

# Set the output path for library files (LIBRARY_OUTPUT_PATH is a global variable).

set(LIBRARY_OUTPUT_PATH [output_path])

# Set C++ compilation parameters (CMAKE_CXX_FLAGS is a global variable).

set(CMAKE_CXX_FLAGS “-Wall std=c++11”)

# Set source file collections (SOURCE_FILES is a local variable).

set(SOURCE_FILES main.cpp test.cpp …)

# Set build type: debug or release. Debug version will generate related debugging information, which can be debugged using GDB; release version will not generate debugging information.

set(CMAKE_BUILD_TYPE DEBUG)

# Set compiler type.

SET(CMAKE_C_FLAGS_DEBUG “-g -Wall”)

# Set low version g++ compiler support for c++11, higher versions are automatically recognized.

set(CMAKE_CXX_STANDARD 11)

Note that where ADD_EXECUTABLE or ADD_LIBRARY is used, if you need to change the target storage path, you must add the above definitions at that location.

16) add_subdirectory

If there are subdirectories in the current directory, you can use add_subdirectory, and the subdirectory must also contain a CMakeLists.txt.

# sub_dir Specifies the location of the subdirectory containing CMakeLists.txt and source files.

# binary_dir is the output path, which can usually be omitted.

add_subdirectory(sub_dir [binary_dir])

17) File operation commands file

# Write message to filename, will overwrite the original content of the file.

file(WRITE filename “message”)

# Write message to filename, will append to the end of the file.

file(APPEND filename “message”)

# Rename file.

file(RENAME <oldname> <newname>)

# Delete file, equivalent to rm command.

file(REMOVE [file1 …])

# Create directory.

file(MAKE_DIRECTORY [dir1 dir2 …])

# This command will place the paths of all files with the suffix .cpp in this directory and all subfolders into the variable SRC_LIST.

file(GLOB_RECURSE SRC_LIST “*.cpp”)

file(GLOB_RECURSE HEADERS “*.h”)

file(GLOB_RECURSE FORMS “*.ui”)

file(GLOB_RECURSE RESOURCES “*.qrc”)18) find_library Find the directory of libraries and place the found path into the variable.

find_library(RUNTIME_LIB_VAR rt /usr/lib /usr/local/lib NO_DEFAULT_PATH)

CMake will search in the directories, if none of the directories contain it, the value RUNTIME_LIB_VAR will be assigned NO_DEFAULT_PATH.

19) add_definitions

Add -D definitions to C/C++ compiler, for example:

add_definitions(-DENABLE_DEBUG -DABC), parameters are separated by spaces.

If your code defines #ifdef ENABLE_DEBUG #endif, this code block will be effective.

20) add_dependencies Define dependencies for the target, ensuring that other targets are built before compiling this target.

add_dependencies(target-name depend-target1 depend-target2 …)

2.2 CMake Application Examples

2.2.1 demo1 Multiple source files in the same directory

#CMake Minimum required version #

cmake_minimum_required(VERSION 2.8)#DEMO1 Project name#

project (DEMO1)

#Indicate that cross-compilation is being used, if you want to use the gcc that comes with Ubuntu, you do not need to specify cross-compilation.

SET (CMAKE_SYSTEM_NAME Linux)

#Specify the C cross-compiler.

SET (CMAKE_C_COMPILER “arm-linux-gnueabihf-gcc”)

#Specify the installation directory of the cross-compiler.

SET(CMAKE_FIND_ROOT_PATH “/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/”)

#Indicate that the final generated elf file is called main, followed by the source files introduced by the program.

add_executable(main main.c test1.c)

Create a build folder, and perform cmake .. in the build folder to generate the CMake project files.

Here, to re-run cmake, just delete the build folder.

Using the generated Makefile, execute the make command, and transfer it to the development board using the scp command.add_executable(main main.c test1.c)

There may be confusion here: 1. If there are many .c files in a project file, do I need to add many .c files? 2. Not all source files are needed, selective compilation.

set(SRC_LIST ./main.c ./ test1.c ./test2.c)Function can select the required source files.

aux_source_directory(. SRC_LIST) Process all source files in this directory into bin.

add_executable(main ${SRC_LIST})

2.2.2 demo2 Multiple source files in multiple directories

The root directory contains CMakeLists.txt and src source files. We also need to write a CMakeLists.txt in the source file, and configure it here.

Configure the Linux compilation environment in three steps.

aux_source_directory(. SRC_LIST) Process all source files in this directory into bin files.

include_directories(../include) Include header file paths.

add_executable(main ${SRC_LIST}) Generate main executable file.

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) Set output path, files will be stored in the bin folder.

This program has a similar feel to our microcontroller development program.

The bin folder is where the generated program is stored, and the build folder contains the CMake project files.

include is for header files.

2.2.3 demo3 Support for GDB debugging

Support for gdb debugging: generally under Linux development, to debug a program, the -g option must be added during compilation.

arm-linux-gnueabihf-gcc gdbtest.c -o gdbtest -g

The executable file compiled this way will contain debugging information. Similarly, CMake also easily supports gdb debugging.

You just need to specify -g to enable it in Debug mode.

Chapter 3 Creating and Using Shared Libraries

3.1 Create dynamic library libmath.so and static library libmath.a

demo4 Create math library

Here we choose to create a library file from a math.c file.

Create a CMakeLists.txt file under the lib_test folder, and math.c, math.h.

Create a lib folder to store the generated library files.

3.2 Linking dynamic libraries and header files

demo5 link_include

–link_directories: Add non-standard shared library search paths.

–target_link_libraries: Link the target file with library files. lib can be both dynamic and static libraries, and if there are only static libraries in the lib directory, this writing will link to the static library.

We can specify which one to link.

target_link_libraries (D libmath.so)

target_link_libraries (D libmath.a)

3.3 Application Examples

In the code file, we will not list them here.

Chapter 4 Summary

This case and the materials are all compiled from online resources for learning and summarizing. If there are shortcomings, please forgive me, and for any issues with the document or other thoughts, you can communicate with me.

You can leave a message in the background for the PDF: “CMake Learning Notes”

Leave a Comment