Learning cmake to build the system from scratch (1)

what is cmake

According to the definition of its official website, cmake is an open source cross-platform toolkit for building, testing and packaging software. Several concepts related to cmake need to be clarified, such as GCC, make and makefile.

  • GCC: GCC is the GNU Compiler Collection (that is, the GNU compiler suite), which can also be simply regarded as a compiler, which can compile many programming languages ​​(including C, C++, Objective-C, Fortran, Java, etc.)
  • make: The make tool can be regarded as an intelligent batch processing tool. It does not have the function of compiling and linking itself, but compiles and links by invoking user-specified commands in the makefile in a batch-like manner.
  • makefile, makefile is a collection of GCC commands, and the make tool compiles and links according to the commands in the makefile
  • cmake, when the project is very large, the handwritten makefile will be very annoying, and the makefile of different platforms will be different, so cmake can automatically generate the makefile according to CMakeLists.txt.

Getting Started

We already have a general understanding of cmake, and then we will introduce how to use cmake through a few examples provided by the official.

Build a single source file

The project has only one source file, and the structure is as follows. We usually create a new directory to store the products of cmake operation. Here I created a new build directory.

├── CMakeLists.txt
├── build
└── main.cc

The content of main.cc is as follows

#include <stdio.h>
#include <stdlib.h>

/**
 * power - Calculate the power of number.
 * @param base: Base value.
 * @param exponent: Exponent value.
 *
 * @return base raised to the power exponent.
 */
double power(double base, int exponent)
{
    int result = base;
    int i;

    if (exponent == 0) {
        return 1;
    }
    
    for(i = 1; i < exponent; ++i){
        result = result * base;
    }

    return result;
}

int main(int argc, char *argv[])
{
    if (argc < 3){
        printf("Usage: %s base exponent \n", argv[0]);
        return 1;
    }
    double base = atof(argv[1]);
    int exponent = atoi(argv[2]);
    double result = power(base, exponent);
    printf("%g ^ %d is %g\n", base, exponent, result);
    return 0;
}

The content of CMakeLists.txt is as follows:

# Cmake的最低版本号的要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (Demo1)

# 指定生成目标
add_executable(Demo main.cc)

Execute cmake in the build directory ... and then execute the make command to get the executable file of Demo1.

Same directory, multiple source files

If we extract the power function of main.cc in Demo1 and put it in MathFunctions.cc, the project structure is as follows:

├── CMakeLists.txt
├── MathFunctions.cc
├── MathFunctions.h
├── build
└── main.cc

So how to compile it, we can add MathFunctions.cc in the add_executable command, the effect is as follows add_executable(Demo main.cc MathFunctions.cc), but if there are many files, it is very troublesome to add one file by one. cmake provides the aux_source_directory command, which will search for all source files in the specified directory, and then save the results to the specified variable name. The content of the CMakeLists.txt file is as follows

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (Demo2)

# 查找目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)

# 指定生成目标
add_executable(Demo ${DIR_SRCS})

Multiple directories and multiple source files

Now we move MathFonction.h and MathFonction.cpp to the math directory, the project structure is as follows:

├── CMakeLists.txt
├── build
├── main.cc
└── math
    ├── CMakeLists.txt
    ├── MathFunctions.cc
    └── MathFunctions.h

Faced with this situation, we need to write a CmakeLists.txt file in the Demo3 directory and the math directory respectively. We can compile the files in the math directory into a static library and then call it from the main function.
The content of CMakeLists.txt in the Demo3 directory is as follows

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (Demo3)

# 查找目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)

# 添加 math 子目录
add_subdirectory(math)

# 指定生成目标
add_executable(Demo ${DIR_SRCS})

# 添加链接库
target_link_libraries(Demo MathFunctions)

add_subdictory(math) indicates that this project contains a subdirectory math, so that the CMakeLists.txt file and source code in the math directory will also be used, and the last line target_link_libraries indicates that the executable file needs to link a link library named MathFunctions. The content of CMakeLists.txt in the math directory is as follows

# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_LIB_SRCS 变量
aux_source_directory(. DIR_LIB_SRCS)

# 指定生成 MathFunctions 链接库
add_library (MathFunctions ${DIR_LIB_SRCS})

In this file, use the command add_library to compile the source files in the src directory into a static link library

custom build options

CMake allows adding compilation options to the project, so that the most suitable compilation scheme can be selected according to the user's environment and requirements. For example, the MathFunctions library can be set as an optional library. If this option is ON, the functions defined in the library will be used to Perform the operation, otherwise call the standard library's mathematical function library.
In order to achieve this purpose, we need to add this option to the top-level CMakeLists.txt, which reads as follows

cmake_minimum_required (VERSION 2.8)

# 项目信息
project (Demo4)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

# 是否使用自己的 MathFunctions 库
option (USE_MYMATH
	   "Use provided math implementation" ON)

# 加入一个配置头文件,用于处理 CMake 对源码的设置
configure_file (
  "${PROJECT_SOURCE_DIR}/config.h.in"
  "${PROJECT_BINARY_DIR}/config.h"
  )

# 是否加入 MathFunctions 库
if (USE_MYMATH)
  include_directories ("${PROJECT_SOURCE_DIR}/math")
  add_subdirectory (math)
  set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)

# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)

# 指定生成目标
add_executable (Demo ${DIR_SRCS})
target_link_libraries (Demo  ${EXTRA_LIBS})

The configure_file command is used to add a configuration file config.h, which is generated by CMake from config.h.in. Through this mechanism, some parameters and variables can be predefined to control the generation of code. The content of config.h.in is as follows :

#cmakedefine USE_MYMATH

The option command adds a USE_MYMATH option, and the default value is ON. Then decide whether to use the MathFoundations library written by myself according to the value of the USE_MYMATH variable

Then you need to change the main.cc file to determine whether to call the standard library according to the value of USE_MYMATH, the content is as follows:

#include <stdio.h>
#include <stdlib.h>
#include <config.h>

#ifdef USE_MYMATH
  #include <MathFunctions.h>
#else
  #include <math.h>
#endif


int main(int argc, char *argv[])
{
    if (argc < 3){
        printf("Usage: %s base exponent \n", argv[0]);
        return 1;
    }

    double base = atof(argv[1]);
    int exponent = atoi(argv[2]);

#ifdef USE_MYMATH
    printf("Now we use our own Math library. \n");
    double result = power(base, exponent);
#else
    printf("Now we use the standard library. \n");
    double result = pow(base, exponent);
#endif
    
    printf("%g ^ %d is %g\n", base, exponent, result);
    return 0;
}

It is worth noting that a config.h is introduced here, which predefines the value of USE_MYMATH. But we don't write this file directly, but it is automatically generated by CMake according to config.h.in.

at last

This article mainly introduces the simple use of cmake. For more articles, you can pay attention to the official account QStack.

Guess you like

Origin blog.csdn.net/QStack/article/details/128909710