[CMake Tool] Tool CMake Compilation Light Use (C/C++)

Table of contents

CMake compilation tool

1. Overview of CMake

2. Use of CMake

2.1 Notes

2.1.1 Comment lines

2.1.2 Comment block

2.2 Source files

2.1.1 Living in the same room

2.1.2 VIP rooms

2.3 Personal customization

2.2.1 Define variables

2.2.2 Specify the C++ standard used

2.2.3 Specify the output path

2.4 Search files

2.3.1 Method 1

2.3.2 Method 2

2.5 Include header files

2.6 Make dynamic or static libraries

2.6.1 Making a static library

2.6.2 Making static libraries

2.6.3 Specify the output path

2.6.3.1 Applicable to dynamic libraries

2.6.3.2 Applicable to dynamic libraries and static libraries

2.7 Include library files

2.7.1 Link static library

2.7.2 Link dynamic library

2.7.2.1 Link system dynamic library

2.7.2.2 Linking third-party dynamic libraries

2.8 Log

2.9 Variable operations

2.9.1 Use set splicing

2.9.2 Use list splicing

2.9.3 String removal

2.10 Macro definition

2.11 Predefined macros

2.12 Nested CMake

2.12.1 Node relationship

2.12.2 Add subdirectory

2.12.3 CMakeLists.txt in the root directory

2.12.4 CMakeLists.txt in calFunc directory

2.12.5 CMakeLists.txt in sotrFunc directory

2.12.6 CMakeLists.txt in the test1 directory

2.12.7 CMakeLists.txt in the test2 directory

2.12.8 Build the project


CMake compilation tool

1. Overview of CMake

        CMake is a project build tool and is cross-platform. Regarding project construction, we are also familiar with Makefile (project construction through the make command). Most IDE software integrates make, such as: VS's nmake, GNU make under Linux, Qt's qmake, etc. If you write it yourself Makefile, you will find that makefile usually depends on the current compilation platform, and the workload of writing makefile is relatively large, and it is easy to make mistakes when resolving dependencies.

         CMake can exactly solve the above problems. It allows developers to specify the compilation process of the entire project. According to the compilation platform, in the 自动生成本地化的Makefile和工程文件end the user only needs to makecompile. Therefore, CMake can be regarded as a tool that automatically generates Makefiles. Its compilation process is as shown below :

  • The blue dotted line indicates the process of building the project using the makefile.

  • The solid red line indicates the process of building the project using cmake.

After introducing the functions of CMake, let’s summarize its advantages:

  • Cross-platform.

  • Ability to manage large projects.

  • Simplify the compilation build process and compilation process.

  • Extensible: Modules with specific functions can be written for cmake to expand cmake functions.

2. Use of CMake

        CMake supports uppercase, lowercase, and mixed-case commands. If the tool used when writing the CMakeLists.txt file has a corresponding command prompt, then just follow the case and don't care too much.

2.1 Notes

2.1.1 Comment lines

CMake uses # for line comments , which can be placed anywhere.

# 这是一个 CMakeLists.txt 文件
cmake_minimum_required(VERSION 3.0.0)

2.1.2 Comment block

#[[ 这是一个 CMakeLists.txt 文件。
这是一个 CMakeLists.txt 文件
这是一个 CMakeLists.txt 文件]]
cmake_minimum_required(VERSION 3.0.0)

2.2 Source files

2.1.1 Living in the same room

  1. Preparation work, in order to facilitate testing, I have prepared several test files on my local computer.

  • 【add.cpp】

#include "head.h"
int Add(int x, int y) { return x + y; }
  • 【sub.cpp】

#include "head.h"
int Sub(int x, int y) { return x - y; }
  • 【mul.cpp】

#include "head.h"
int Mul(int x, int y) { return x * y; }
  • 【div.cpp】

#include "head.h"
int Div(int x, int y) { return x / y; }
  • 【head.h】

#pragma once
#include <iostream>
using namespace std;

int Add(int x, int y);
int Sub(int x, int y);
int Mul(int x, int y);
int Div(int x, int y);
  • 【main.cpp】

#include "head.h"

int main() 
{
    int a = 10;
    int b = 2;
    cout << a << "+" << b << "=" << Add(a, b) << endl;
    cout << a << "-" << b << "=" << Sub(a, b) << endl;
    cout << a << "*" << b << "=" << Mul(a, b) << endl;
    cout << a << "/" << b << "=" << Div(a, b) << endl;

    return 0;
}
  • 【Directory Structure】

[shaxiang@VM-8-14-centos data_structure_algorithm]$ tree .
.
|-- add.cpp
|-- CMakeLists.txt
|-- div.cpp
|-- head.h
|-- main.cpp
|-- mul.cpp
`-- sub.cpp

0 directories, 7 files
  1. Add CMakeLists.txt file

Add a new file CMakeLists.txt in the directory where the above source file is located . The content of the file is as follows:

# 指定使用的 cmake 的最低版本,可选,非必须,如果不加可能会有警告。
cmake_minimum_required(2.8)
# 定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
project(test)
# 定义工程会生成一个可执行程序。
add_executable(app main.cpp add.cpp sub.cpp div.cpp mul.cpp)

Next, we will introduce the three commands added in the CMakeLists.txt file in turn:

  • cmake_minimum_required : Specifies the minimum version of cmake to use, optional, not required. If not added, there may be a warning .

  • project : Define the project name, and specify the project version, project description, web homepage address, and supported languages ​​(all languages ​​are supported by default). If you do not need these, you can ignore them and just specify the project name.

  • add_executable : Defining the project will generate an executable program.

add_executable(可执行程序名 源文件名称)
  • The executable program name here has nothing to do with the project name in project .

  • The source file name can be one or multiple, if there are multiple available spaces or ; intervals.

# 样式1
add_executable(app add.c div.c main.c mult.c sub.c)
# 样式2
add_executable(app add.c;div.c;main.c;mult.c;sub.c)
  1. Execute CMake command

Everything is ready. After editing the CMakeLists.txt file, you can execute the cmake command.

[shaxiang@VM-8-14-centos data_structure_algorithm]$ tree .
.
|-- add.cpp
|-- CMakeLists.txt
|-- div.cpp
|-- head.h
|-- main.cpp
|-- mul.cpp
`-- sub.cpp

0 directories, 7 files

When the cmake command is executed , the commands in CMakeLists.txt will be executed, so be sure to make sure there are no errors when specifying the path to the cmake command.

After executing the command, check whether there are more files in the directory where the source file is located:

[shaxiang@VM-8-14-centos data_structure_algorithm]$ tree -L 1
.
|-- add.cpp
|-- CMakeCache.txt
|-- CMakeFiles
|-- CMakeLists.txt
|-- div.cpp
|-- head.h
|-- main.cpp
|-- mul.cpp
`-- sub.cpp

We can see that a makefile is generated in the corresponding directory . Then execute the make command to build the project and obtain the required executable program.

$ make
Scanning dependencies of target app
[ 16%] Building C object CMakeFiles/app.dir/add.c.o
[ 33%] Building C object CMakeFiles/app.dir/div.c.o
[ 50%] Building C object CMakeFiles/app.dir/main.c.o
[ 66%] Building C object CMakeFiles/app.dir/mult.c.o
[ 83%] Building C object CMakeFiles/app.dir/sub.c.o
[100%] Linking C executable app
[100%] Built target app

# 查看可执行程序是否已经生成
$ tree -L 1
.
├── add.c
├── app					# 生成的可执行程序
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
├── CMakeLists.txt
├── div.c
├── head.h
├── main.c
├── Makefile
├── mult.c
└── sub.c

Finally, the executable program app is compiled (the name is specified in CMakeLists.txt ).

2.1.2 VIP rooms

        As can be seen from the above example, if the cmake command is executed in the directory where the CMakeLists.txt file is located, some directories and files ( including makefile files ) will be generated . If the make command is executed based on the makefile file , the program will also be generated during the compilation process. Generating some intermediate files and an executable file will cause the entire project directory to look messy and difficult to manage and maintain. At this time, we can put the generated files that have nothing to do with the project source code into a corresponding directory. Inside, for example, name this directory build :

[shaxiang@VM-8-14-centos build]$ cmake ../
-- The C compiler identification is GNU 7.3.1
-- The CXX compiler identification is GNU 7.3.1
-- Check for working C compiler: /opt/rh/devtoolset-7/root/usr/bin/cc
-- Check for working C compiler: /opt/rh/devtoolset-7/root/usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /opt/rh/devtoolset-7/root/usr/bin/c++
-- Check for working CXX compiler: /opt/rh/devtoolset-7/root/usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/shaxiang/data_structure_algorithm/build

        Now the cmake command is executed in the build directory, but the CMakeLists.txt file is in the directory one level above the build directory, so the path specified after the cmake command is..., which is the directory one level above the current directory.

After the command is executed, a makefile will be generated in the build directory .

$ tree build -L 1
build
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
└── Makefile

1 directory, 3 files

        In this way, you can execute the make command in the build directory to compile the project, and the generated related files will naturally be stored in the build directory. In this way, all the files generated through cmake and make are completely isolated from the project source files, and each one goes back to his own home to find his own mother.

[shaxiang@VM-8-14-centos build]$ make
Scanning dependencies of target app
[ 20%] Building CXX object CMakeFiles/app.dir/main.cpp.o
[ 40%] Building CXX object CMakeFiles/app.dir/add.cpp.o
[ 60%] Building CXX object CMakeFiles/app.dir/sub.cpp.o
[ 80%] Building CXX object CMakeFiles/app.dir/div.cpp.o
[100%] Building CXX object CMakeFiles/app.dir/mul.cpp.o
Linking CXX executable app
[100%] Built target app
[shaxiang@VM-8-14-centos build]$ ls
app  CMakeCache.txt  CMakeFiles  cmake_install.cmake  Makefile

2.3 Personal customization

2.2.1 Define variables

        In the above example, a total of 5 source files are provided. Assuming that these five source files need to be used repeatedly, it is really troublesome to write out their names directly every time. At this time, we need to define a variable to refer to the file. The string corresponding to the name is stored, and you need to use set to define variables in cmake .

# SET 指令的语法是:
# [] 中的参数为可选项, 如不需要可以不写
SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
  • VAR : variable name

  • VALUE : variable value

# 方式1: 各个源文件之间使用空格间隔
# set(SRC_LIST add.c  div.c   main.c  mult.c  sub.c)

# 方式2: 各个源文件之间使用分号 ; 间隔
set(SRC_LIST add.c;div.c;main.c;mult.c;sub.c)
add_executable(app  ${SRC_LIST})

2.2.2 Specify the C++ standard used

        When writing a C++ program, you may use new features such as C++11, C++14, C++17, C++20, etc. Then you need to determine which one to use in the compilation command when compiling. standard:

$ g++ *.cpp -std=c++11 -o app

        In the above example, the parameter -std=c++11 is used to specify that the c++11 standard compiler is to be used. The C++ standard corresponds to a macro called DCMAKE_CXX_STANDARD . There are two ways to specify C++ standards in CMake:

  1. Specified through the set command in CMakeLists.txt .

#增加-std=c++11
set(CMAKE_CXX_STANDARD 11)
#增加-std=c++14
set(CMAKE_CXX_STANDARD 14)
#增加-std=c++17
set(CMAKE_CXX_STANDARD 17)

2. Specify the value of this macro when executing the cmake command .

#增加-std=c++11
cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=11
#增加-std=c++14
cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=14
#增加-std=c++17
cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=17

In the above example, the path after CMake needs to be modified as appropriate according to the actual situation.

2.2.3 Specify the output path

Specifying the path of the executable program output in CMake also corresponds to a macro called EXECUTABLE_OUTPUT_PATH . Its value is still set through the set command:

set(HOME /home/robin/Linux/Sort)
set(EXECUTABLE_OUTPUT_PATH ${HOME}/bin)
  • Line 1: Define a variable to store an absolute path.

  • Second line: Set the spliced ​​path value to the EXECUTABLE_OUTPUT_PATH macro. If the subdirectory in this path does not exist, it will be automatically generated without the need to create it manually.

        Since the executable program is obtained based on the makefile generated by the cmake command and then executed by the make command, if the relative path ./xxx/xxx is used when specifying the executable program generation path here, then ./ in this path will Corresponding to the directory where the makefile file is located .

[Write a compiled project based on the above]

# 指定使用的 cmake 的最低版本,可选,非必须,如果不加可能会有警告。
cmake_minimum_required(VERSION 2.8.12.2)
# 定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
project(test)

# 设置源文件为变量值SRC需要被执行调用
set(SRC main.cpp add.cpp sub.cpp div.cpp mul.cpp)
# 设置编译标准
set(CMAKE_CXX_STANDARD 98)
# 设置编译输出路径
set(EXECUTABLE_OUTPUT_PATH /home/shaxiang/data_structure_algorithm/build/A/B/C)

# 定义工程会生成一个可执行程序。
add_executable(app ${SRC})

2.4 Search files

        If there are many source files in a project, it is impossible to list each file in the project directory one by one when writing the CMakeLists.txt file. This is too troublesome and unrealistic. Therefore, CMake provides us with a command to search for files. You can use the aux_source_directory command or the file command.

2.3.1 Method 1

Use the aux_source_directory command in CMake to find all source files under a certain path . The command format is:

aux_source_directory(< dir > < variable >)
  • dir : The directory to search.

  • variable : Store the list of source files searched from the dir directory into this variable.

// 测试
# 指定使用的 cmake 的最低版本,可选,非必须,如果不加可能会有警告。
cmake_minimum_required(VERSION 2.8.12.2)
# 定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
project(test)

# 设置源文件为变量值SRC需要被执行调用
# 方法一:路径宏:PROJECT_BINARY_DIR  代表cmake..
aux_source_directory(${PROJECT_SOURCE_DIR} SRC)
# 设置编译标准
set(CMAKE_CXX_STANDARD 98)
# 设置编译输出路径
set(EXECUTABLE_OUTPUT_PATH /home/shaxiang/data_structure_algorithm/build/A/B/C)

# 定义工程会生成一个可执行程序。
add_executable(app ${SRC})

2.3.2 Method 2

        If there are many source files in a project, it is impossible to list each file in the project directory one by one when writing the CMakeLists.txt file. This is too troublesome. Therefore, CMake provides us with a command to search for files, which is file (of course, in addition to searching, you can also do other things through file) .

file(GLOB/GLOB_RECURSE 变量名 要搜索的文件路径和文件类型)
  • GLOB : Generate a list of all file names that meet the conditions searched in the specified directory and store it in a variable.

  • GLOB_RECURSE : Search the specified directory recursively, generate a list of the searched file names that meet the conditions, and store it in a variable.

Search all source files in the src directory of the current directory and store them in variables

file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
file(GLOB MAIN_HEAD ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)

The CMAKE_CURRENT_SOURCE_DIR macro indicates the path where the currently accessed CMakeLists.txt file is located .

You can add double quotes or not for the file path and type to be searched:

// 测试
# 指定使用的 cmake 的最低版本,可选,非必须,如果不加可能会有警告。
cmake_minimum_required(VERSION 2.8.12.2)
# 定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
project(test)

# 设置源文件为变量值SRC需要被执行调用
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
# 设置编译标准
set(CMAKE_CXX_STANDARD 98)
# 设置编译输出路径
set(EXECUTABLE_OUTPUT_PATH /home/shaxiang/data_structure_algorithm/build/A/B/C)

# 定义工程会生成一个可执行程序。
add_executable(app ${SRC})

2.5 Include header files

        When compiling project source files, it is often necessary to specify the header file path corresponding to the source file, so as to ensure that the compiler can find these header files during the compilation process and successfully pass the compilation. Setting the directories to be included in CMake is also very simple. It can be done with one command, which is include_directories :

include_directories(headpath)

For example, there are several source files, and their directory structure is as follows:

[shaxiang@VM-8-14-centos data_structure_algorithm]$ tree
.
|-- build
|-- CMakeLists.txt
|-- include
|   `-- head.h
`-- src
    |-- add.cpp
    |-- div.cpp
    |-- main.cpp
    |-- mul.cpp
    `-- sub.cpp

The contents of the CMakeLists.txt file are as follows :

# 指定使用的 cmake 的最低版本,可选,非必须,如果不加可能会有警告。
cmake_minimum_required(VERSION 2.8.12.2)
# 定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
project(test)

# 设置头文件编译路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 设置源文件编译路径
# set(SRC main.cpp add.cpp sub.cpp div.cpp mul.cpp)
# 方法一:路径宏:PROJECT_BINARY_DIR  代表cmake..
# aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC)
# 方法二:
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)

# 设置编译标准
set(CMAKE_CXX_STANDARD 98)
# 设置编译输出路径
set(EXECUTABLE_OUTPUT_PATH /home/shaxiang/data_structure_algorithm/build/A/B/C)

# 定义工程会生成一个可执行程序。
add_executable(app ${SRC})

        Among them, the sixth line specifies the path to the header file, and the value corresponding to the PROJECT_SOURCE_DIR macro is the directory that follows when we use the cmake command, which is usually the root directory of the project.

2.6 Make dynamic or static libraries

        Sometimes the source codes we write do not need to be compiled into executable programs, but some static libraries or dynamic libraries are generated for third parties to use. The following explains how to generate these two types of library files in cmake.

        Description: Static library [libxxx.so] in Linux, [libxxx.dll] in Windows, dynamic library [libxxx.lib] in Linux, [libxxx.a] in Windows

// 准备生成东静态库的文件
[shaxiang@VM-8-14-centos v2]$ tree
.
|-- build
|-- CMakeLists.txt
|-- include
|   `-- head.h
`-- src
    |-- add.cpp
    |-- div.cpp
    |-- mul.cpp
    `-- sub.cpp

3 directories, 6 files

2.6.1 Making a static library

In cmake, if you want to make a static library, the commands you need to use are as follows:

add_library(库名称 STATIC 源文件1 [源文件2] ...) 

        In Linux, the static library name is divided into three parts: lib + library name + .a . Here you only need to specify the name of the library. The other two parts will be automatically filled in when the file is generated.

        According to the above directory structure, the CMakeLists.txt file can be written like this:

# 指定使用的 cmake 的最低版本,可选,非必须,如果不加可能会有警告。
cmake_minimum_required(VERSION 2.8.12.2)
# 定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
project(test)

# 设置头文件编译路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 设置源文件编译路径
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
# 设置编译标准
set(CMAKE_CXX_STANDARD 98)

# 编译静态库
add_library(cal STATIC ${SRC})

This will eventually generate the corresponding static library file libcal.a .

2.6.2 Making static libraries

        In cmake, if you want to make a dynamic library, the commands you need to use are as follows:

add_library(库名称 SHARED 源文件1 [源文件2] ...) 

        In Linux, the dynamic library name is divided into three parts: lib + library name + .so . Here you only need to specify the name of the library. The other two parts will be automatically filled in when the file is generated.

        According to the above directory structure, the CMakeLists.txt file can be written like this:

# 指定使用的 cmake 的最低版本,可选,非必须,如果不加可能会有警告。
cmake_minimum_required(VERSION 2.8.12.2)
# 定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
project(test)

# 设置头文件编译路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 设置源文件编译路径
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
# 设置编译标准
set(CMAKE_CXX_STANDARD 98)

# 编译静态库
add_library(cal SHARED ${SRC})

This will eventually generate the corresponding dynamic library file libcal.so .

2.6.3 Specify the output path

2.6.3.1 Applicable to dynamic libraries

        For generated library files, the output path can be specified in the same way as for executable programs. Since the dynamic library generated under Linux has execution permission by default , you can specify the directory it generates in the same way as generating an executable program:

# 指定使用的 cmake 的最低版本,可选,非必须,如果不加可能会有警告。
cmake_minimum_required(VERSION 2.8.12.2)
# 定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
project(test)

# 设置头文件编译路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 设置源文件编译路径
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
# 设置编译标准
set(CMAKE_CXX_STANDARD 98)

# 设置生成东静态库的文件路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
add_library(cal SHARED ${SRC_LIST})

        For this method, you actually set a path to the EXECUTABLE_OUTPUT_PATH macro through the set command. This path is the path where the executable file is generated.

2.6.3.2 Applicable to dynamic libraries and static libraries

Since static libraries generated under Linux do not have executable permissions by default, you cannot use the EXECUTABLE_OUTPUT_PATH macro         when specifying the path to generate a static library. Instead, you should use LIBRARY_OUTPUT_PATH . This macro is applicable to both static library files and dynamic library files .

# 指定使用的 cmake 的最低版本,可选,非必须,如果不加可能会有警告。
cmake_minimum_required(VERSION 2.8.12.2)
# 定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
project(test)

# 设置头文件编译路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 设置源文件编译路径
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
# 设置编译标准
set(CMAKE_CXX_STANDARD 98)

# 设置生成东静态库的文件路径
set(LIBRARY_OUTPUT_PATH /home/shaxiang/data_structure_algorithm/v2/lib)
# 编译静态库
# add_library(cal SHARED ${SRC})
# add_library(cal STATIC ${SRC})

2.7 Include library files

        In the process of writing a program, you may use some dynamic libraries provided by the system or dynamic libraries or static library files produced by yourself. cmake also provides us with relevant commands for loading dynamic libraries.

2.7.1 Link static library

The test directory structure is as follows:

[shaxiang@VM-8-14-centos v3]$ tree
.
|-- build
|-- CMakeLists.txt
|-- include
|   `-- head.h
|-- lib
|   |-- libcal.a		// 静态库
|   `-- libcal.so		// 动态库
`-- src
    `-- main.cpp

4 directories, 5 files

In cmake, the command to link the static library is as follows:

link_libraries(<static lib> [<static lib>...])
  • Parameter 1: Specify the name of the static library to be linked: it can be the full name libxxx.a , or it can be the name xxx after pinching the head (lib) and removing the tail (.a) .

  • Parameter 2: The names of other static libraries to be linked.

If the static library is not provided by the system (make it yourself or use a static library provided by a third party), the static library may not be found. In this case, you can also specify the path of the static library:

link_directories(<lib path>)

In this way, the contents of the modified CMakeLists.txt file are as follows:

# 指定使用的 cmake 的最低版本,可选,非必须,如果不加可能会有警告。
cmake_minimum_required(VERSION 2.8.12.2)
# 定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
project(test)

# 设置头文件编译路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 设置源文件编译路径
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
# 设置编译标准
set(CMAKE_CXX_STANDARD 11)
# 设置包含静态库路径
link_directories(${PROJECT_SOURCE_DIR}/lib)
# 连接静态库
link_libraries(cal)
# 生成可执行程序
add_executable(app ${SRC})

After adding the 8th line of code, you can find the static library according to the path specified by the parameter.

2.7.2 Link dynamic library

The test directory structure is as follows:

[shaxiang@VM-8-14-centos v3]$ tree
.
|-- build
|-- CMakeLists.txt
|-- include
|   `-- head.h
|-- lib
|   |-- libcal.a		// 静态库
|   `-- libcal.so		// 动态库
`-- src
    `-- main.cpp

4 directories, 5 files

In cmake, the command to link the dynamic library is as follows:

target_link_libraries(
    <target> 
    <PRIVATE|PUBLIC|INTERFACE> <item>... 
    [<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
  • target : Specify the name of the file to load the dynamic library.

    • The file may be a source file

    • This file may be a dynamic library file

    • The file may be an executable file

  • PRIVATE|PUBLIC|INTERFACE : Access permissions for dynamic libraries, the default is PUBLIC

    • If there are no dependencies between the various dynamic libraries, there is no need to make any settings. There is no difference between the three. Generally, there is no need to specify, just use the default PUBLIC .

    • The link of dynamic library is transitive . If dynamic library A links to dynamic library B and C, and dynamic library D links to dynamic library A, then dynamic library D is equivalent to linking to dynamic library B and C, and can use the dynamic library. Methods defined in B and C.

    • target_link_libraries(A B C)
      target_link_libraries(D A)
    • PUBLIC : The library behind public will be linked to the previous target, and the symbols inside will also be exported and provided to third parties. PRIVATE : The library behind private is only linked to the previous target and terminated. The third party cannot detect which library you have adjusted. INTERFACE : The library introduced after interface will not be linked to the previous target and will only be exported. symbol.

2.7.2.1 Link system dynamic library

The linking of dynamic libraries is completely different from that of static libraries:

  • The static library will be packaged into the executable program during the linking phase of generating the executable program, so when the executable program starts, the static library will be loaded into the memory.

  • The dynamic library will not be packaged into the executable program during the linking phase of generating the executable program. The dynamic library will not be loaded into the memory until the executable program is started and the functions in the dynamic library are called.

Therefore, when specifying the dynamic library to be linked in cmake , the command should be written after the executable file is generated :

cmake_minimum_required(VERSION 3.0)
project(TEST)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
# 添加并指定最终生成的可执行程序名
add_executable(app ${SRC_LIST})
# 指定可执行程序要链接的动态库名字
target_link_libraries(app pthread)

In target_link_libraries(app pthread) :

  • app : Corresponds to the name of the finally generated executable program.

  • pthread : This is the dynamic library to be loaded by the executable program. This library is the thread library provided by the system. Its full name is libpthread.so . When specified, the head (lib) and tail (.so) are usually pinched.

2.7.2.2 Linking third-party dynamic libraries

        Assume that the test file main.cpp uses both the self-made dynamic library libcalc.so and the thread library provided by the system. At this time, the CMakeLists.txt file can be written as follows:

cmake_minimum_required(VERSION 3.0)
project(TEST)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
include_directories(${PROJECT_SOURCE_DIR}/include)
add_executable(app ${SRC_LIST})
target_link_libraries(app pthread calc)

        In the sixth line, pthread and calc are the names of the dynamic libraries to be linked to by the executable program app . When the executable program app is generated and the file is executed, the following error message will be prompted:

$ ./app 
./app: error while loading shared libraries: libcalc.so: cannot open shared object file: No such file or directory

        This is because after the executable program is started, the dynamic library calc is loaded , but it is not known where the dynamic library is placed. The location of the dynamic library to be linked is specified through a command. This command is also used to specify the location of the static library :

link_directories(path)

So the modified CMakeLists.txt file should look like this:

cmake_minimum_required(VERSION 3.0)
project(TEST)
file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
# 指定源文件或者动态库对应的头文件路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 指定要链接的动态库的路径
link_directories(${PROJECT_SOURCE_DIR}/lib)
# 添加并生成一个可执行程序
add_executable(app ${SRC_LIST})
# 指定要链接的动态库
target_link_libraries(app pthread calc)

        After specifying the path of the dynamic library through link_directories , when executing the generated executable program, there will be no problem that the dynamic library cannot be found.

Warm reminder: Use the target_link_libraries command to link to dynamic libraries or static library files .

2.8 Log

In CMake, you can use the user to display a message. The name of the command is message :

message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] "message to display" ...)
  • (none) : important news

  • STATUS : non-important message

  • WARNING : CMake warning, execution will continue

  • AUTHOR_WARNING : CMake warning (dev), execution will continue

  • SEND_ERROR : CMake error, continue execution, but skip the generation step

  • FATAL_ERROR : CMake error, terminate all processing

CMake's command line tool displays STATUS messages         on stdout and all other messages on stderr. CMake's GUI displays all messages in its log area.

        The text of CMake warning and error messages is displayed using a simple markup language. The text is not indented, lines that exceed the length are wrapped, and new lines are used as separators between paragraphs.

# 输出一般日志信息
message(STATUS "source path: ${PROJECT_SOURCE_DIR}")
# 输出警告信息
message(WARNING "source path: ${PROJECT_SOURCE_DIR}")
# 输出错误信息
message(FATAL_ERROR "source path: ${PROJECT_SOURCE_DIR}")

2.9 Variable operations

2.9.1 Use set splicing

        Sometimes the source files in the project are not necessarily in the same directory, but these source files eventually need to be compiled together to generate the final executable file or library file. If we use the file command to search for source files in each directory, we finally need to perform a string splicing operation. For string splicing, we can use the set command or the list command.

If you use set for string splicing, the corresponding command format is as follows:

set(变量名1 ${变量名1} ${变量名2} ...)

        The above command actually concatenates all the strings starting from the second parameter and finally stores the result in the first parameter. If there is original data in the first parameter, the original data will be overwritten.

# 指定使用的 cmake 的最低版本,可选,非必须,如果不加可能会有警告。
cmake_minimum_required(VERSION 2.8.12.2)
# 定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
project(test)

# 设置头文件编译路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 设置源文件编译路径
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
# 设置编译标准
set(CMAKE_CXX_STANDARD 11)
# 设置包含静态库路径
link_directories(${PROJECT_SOURCE_DIR}/lib)
# 连接静态库
link_libraries(cal)

# 拼接字符串练习
set(sTemp Hello_World)
set(strTemp ${sTemp} ${SRC})
message(${sTemp})   # 打印结果:Hello_World
message(${strTemp}) # 打印结果:Hello_World/home/shaxiang/test_cmake/v4/src/main.cpp

# 生成可执行程序
add_executable(app ${SRC})

2.9.2 Use list splicing

        If you use list for string splicing, the corresponding command format is as follows:

list(APPEND <list> [<element> ...])

        The function of list command is more powerful than set . String splicing is only one of its functions, so we need to specify the operation we want to do in the position of its first parameter. APPEND means appending data, and the following parameters are the same as set . .

# 指定使用的 cmake 的最低版本,可选,非必须,如果不加可能会有警告。
cmake_minimum_required(VERSION 2.8.12.2)
# 定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
project(test)

# 设置头文件编译路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 设置源文件编译路径
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
# 设置编译标准
set(CMAKE_CXX_STANDARD 11)
# 设置包含静态库路径
link_directories(${PROJECT_SOURCE_DIR}/lib)
# 连接静态库
link_libraries(cal)

# 拼接字符串练习
set(sTemp Hello_World )
set(strTemp ${sTemp} ${SRC})
message(${sTemp})   # 打印结果:Hello_World
message(${strTemp}) # 打印结果:Hello_World/home/shaxiang/test_cmake/v4/src/main.cpp

list(APPEND sTemp "XXX" "AAA" "QQQ")
message(${sTemp})   # 打印结果:Hello_WorldXXXAAAQQQ

# 生成可执行程序
add_executable(app ${SRC})

        In CMake, use the set command to create a list . Inside a list is a set of strings separated by semicolons; For example, the set(var abcde) command will create a list:a;b;c;d;e , but when the variable value is printed, abcde will be obtained .

2.9.3 String removal

        When we search a directory through file , we get all the source files in the directory, but some of the source files are not what we need, such as:

$ tree
.
├── add.cpp
├── div.cpp
├── main.cpp
├── mult.cpp
└── sub.cpp

0 directories, 5 files

        There are five source files in the current directory, among which main.cpp is a test file. If we want to generate a dynamic library from calculator-related source files for others to use, then we only need four source files: add.cpp, div.cp, mult.cpp, and sub.cpp . At this time, you need to remove main.cpp from the searched data. If you want to achieve this function, you can also use list

list(REMOVE_ITEM <list> <value> [<value> ...])

        From the above command prototype, you can see that deleting and appending data are similar, except that the first parameter becomes REMOVE_ITEM.

# 指定使用的 cmake 的最低版本,可选,非必须,如果不加可能会有警告。
cmake_minimum_required(VERSION 2.8.12.2)
# 定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
project(test)
# 设置编译标准
set(CMAKE_CXX_STANDARD 98)

# 设置头文件编译路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 设置源文件编译路径
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)

# 字符串移除练习
# 打印未移除前的字符串
message("删除前:"${SRC})
list(REMOVE_ITEM SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp)
message("删除后:"${SRC})
# 打印结果:
# 删除前:/home/shaxiang/test_cmake/v5/src/main.cpp/home/shaxiang/test_cmake/v5/src/mul.cpp/home/shaxiang/test_cmake/v5/src/sub.cpp/home/shaxiang/test_cmake/v5/src/add.cpp/home/shaxiang/test_cmake/v5/src/div.cpp
# 删除后:/home/shaxiang/test_cmake/v5/src/mul.cpp/home/shaxiang/test_cmake/v5/src/sub.cpp/home/shaxiang/test_cmake/v5/src/add.cpp/home/shaxiang/test_cmake/v5/src/div.cpp

# 定义工程会生成一个可执行程序。
add_executable(app ${SRC})

        As you can see, just assign the name of the file to be removed to the list on line 8 . But be sure to note that when searching for source files through the file command, you get the absolute path of the file (the path corresponding to each file in the list is an item, and they are all absolute paths), so you must also remove it when removing The absolute path of the file must be specified, otherwise the removal operation will not succeed .

There are other functions of the list command, but they are not commonly used, so I will not give examples one by one here.

  1. Get the length of list.

list(LENGTH <list> <output variable>)
  • LENGTH : Subcommand LENGTH is used to read the length of the list.

  • list : List of current operations.

  • output variable : Newly created variable used to store the length of the list.

  1. Read the element at the specified index in the list. Multiple indexes can be specified.

list(GET <list> <element index> [<element index> ...] <output variable>)
  • list : List of current operations.

  • element index : The index of the list element.

    • Numbering starts from 0, and the element with index 0 is the first element in the list.

    • Indexes can also be negative, with -1 representing the last element of the list, -2 representing the penultimate element of the list, and so on.

    • When the index (whether positive or negative) exceeds the length of the list, an error will be reported.

  • output variable : A newly created variable that stores the return result of the specified index element and is also a list.

  1. Concatenate the elements in the list using connectors (strings) to form a string

list (JOIN <list> <glue> <output variable>)
  • list : List of current operations.

  • glue : the specified connector (string).

  • output variable : a newly created variable that stores the returned string

  1. Finds whether the specified element exists in the list, if not found, returns -1

list(FIND <list> <value> <output variable>)
  • list: List of current operations.

  • value: The element to be searched in the list.

  • output variable: newly created variable.

    • If <value> exists in list <list> , return the index of <value> in the list.

    • Returns -1 if not found.

  1. Append elements to list

list (APPEND <list> [<element> ...])
  1. Insert an element into the list at index 0

list(INSERT <list> <element_index> <element> [<element> ...])
  1. Insert an element into the list at index 0

list (PREPEND <list> [<element> ...])
  1. Remove the last element from the list

list (POP_BACK <list> [<out-var>...])
  1. Remove the first element from the list

list (POP_FRONT <list> [<out-var>...])
  1. Removes the specified element from the list

list (REMOVE_ITEM <list> <value> [<value> ...])
  1. Removes the element at the specified index from the list

list (REMOVE_AT <list> <index> [<index> ...])
  1. Remove duplicate elements from list

list (REMOVE_DUPLICATES <list>)
  1. List flipping

list(REVERSE <list>)
  1. List sorting

list (SORT <list> [COMPARE <compare>] [CASE <case>] [ORDER <order>])
  • COMPARE : Specify the sorting method. The following values ​​are available:

    • STRING : Sort in alphabetical order, which is the default sorting method.

    • FILE_BASENAME : If it is a series of path names, basename will be used for sorting.

    • NATURAL : Sort using natural number order.

  • CASE : Indicates whether it is case sensitive. The following values ​​are available:

    • SENSITIVE : Sort in a case-sensitive manner, the default value.

    • INSENSITIVE : Sort in a case-insensitive manner.

  • ORDER : Specify the sorting order. The following values ​​are available:

    • ASCENDING : Sort in ascending order, the default value. DESCENDING : Sort in descending order.

2.10 Macro definition

When testing the program, we can add some macro definitions to the code and use these macros to control whether the codes take effect, as shown below:

#include "head.h"

#define NUM 10
int main() 
{
    int a = 10;
    int b = 2;

    for(int i = 0; i < NUM; i++) 
    {
        cout << a << "+" << b << "=" << Add(a, b) << endl;
        cout << a << "-" << b << "=" << Sub(a, b) << endl;

        cout << a << "*" << b << "=" << Mul(a, b) << endl;
        cout << a << "/" << b << "=" << Div(a, b) << endl;
    }

#ifdef DEBUG
    cout << "我是一个程序源哦!" << endl;
#endif
    return 0;
}

The DEBUG macro is judged on the seventh line of the program . If the macro is defined, the log output will be performed on the eighth line. If the macro is not defined, the eighth line is equivalent to being commented out, so it cannot be used in the end. See the log output ( this macro is not defined in the above code ).

In order to make testing more flexible, we can not define this macro in the code, but define it during testing. One way is to specify it in the gcc/g++ command, as follows:

$ gcc test.c -DDEBUG -o app

Specify the name of the macro to be defined through the parameter -D in the gcc/g++ command , which is equivalent to defining a macro in the code with the name DEBUG .

We can also do similar things in CMake , and the corresponding command is called add_definitions :

add_definitions(-D宏名称)

Write a CMakeLists.txt for the above source file with the following content:

# 指定使用的 cmake 的最低版本,可选,非必须,如果不加可能会有警告。
cmake_minimum_required(VERSION 2.8.12.2)
# 定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
project(test)
# 设置编译标准
set(CMAKE_CXX_STANDARD 98)

# 设置头文件编译路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 设置源文件编译路径
file(GLOB SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)

# 自定义的宏
add_definitions(-DDEBUG)
# 定义工程会生成一个可执行程序。
add_executable(app ${SRC})

2.11 Predefined macros

The following list summarizes some commonly used macros in CMake:

Macro Function
PROJECT_SOURCE_DIR The directory immediately following the cmake command is usually the root directory of the project.
PROJECT_BINARY_DIR Directory where cmake command is executed
CMAKE_CURRENT_SOURCE_DIR The path where the currently processed CMakeLists.txt is located
CMAKE_CURRENT_BINARY_DIR target compilation directory
EXECUTABLE_OUTPUT_PATH Redefine the location of the target binary executable file
LIBRARY_OUTPUT_PATH Redefine the storage location of the target link library file
PROJECT_NAME Returns the project name defined through the PROJECT directive
CMAKE_BINARY_DIR The actual build path of the project. Assuming that the build is performed in the build directory, the path obtained is the path of this directory.

2.12 Nested CMake

        If the project is large, or there are many source code directories in the project, if you only use one CMakeLists.txt when managing the project through CMake , then this file will be relatively complicated. One way to simplify the complexity is to give each source code Add a CMakeLists.txt file to each directory (not required for the header file directory), so that each file will not be too complex, and will be more flexible and easier to maintain.

Let’s first take a look at the directory structure below:

[shaxiang@VM-8-14-centos v6]$ tree
.
|-- bin
|-- calFunc
|   |-- add.cpp
|   |-- CMakeLists.txt
|   |-- div.cpp
|   |-- mul.cpp
|   `-- sub.cpp
|-- CMakeLists.txt
|-- include
|   `-- head.h
|-- lib
|-- sortFunc
|   |-- bubbleSort.cpp
|   `-- CMakeLists.txt
|-- test1
|   |-- CMakeLists.txt
|   `-- sort.cpp
`-- test2
    |-- cal.cpp
    `-- CMakeLists.txt

7 directories, 13 files

2.12.1 Node relationship

        As we all know, the Linux directory is a tree structure, so nested CMake is also a tree structure. The top-level CMakeLists.txt is the root node, followed by child nodes. Therefore, we need to know some information about the variable scope of the CMakeLists.txt file:

  • The variables in the root node CMakeLists.txt are globally valid.

  • Variables in the parent node CMakeLists.txt can be used in child nodes.

  • Variables in the sub-node CMakeLists.txt can only be used in the current node.

2.12.2 Add subdirectory

        Next, we also need to know how the relationship between parent and child nodes is established in CMake. Here we need to use a CMake command:

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
  • source_dir : Specifies the location of the CMakeLists.txt source file and code file, which actually means specifying a subdirectory.

  • binary_dir : Specifies the path of the output file. Generally, it does not need to be specified and can be ignored.

  • EXCLUDE_FROM_ALL : Targets in the subpath will not be included in the ALL target of the parent path by default, and will also be excluded from the IDE project file. Users must explicitly build targets under subpaths.

In this way, the parent-child relationship between CMakeLists.txt files is constructed.

2.12.3 CMakeLists.txt in the root directory

# 指定CMake版本的最低版本
cmake_minimum_required(VERSION 2.8.12.2)
# 指定项目名称
project(TestDeme)

# 指定头文件路径
set(HEADPATH ${PROJECT_SOURCE_DIR}/include)
# 指定静态库生成的路径
set(LIBPATH ${PROJECT_SOURCE_DIR}/lib)
# 指定可执行生成的路径
set(EXEPATH ${PROJECT_SOURCE_DIR}/bin)

# 指定库文件名称
set(CALCLIB calc)
set(SORTLIB sort)
# 指定可执行程序名称
set(APPNAME1 app1)
set(APPNAME2 app2)

# 给当前节点添加子目录 
add_subdirectory(calFunc)
add_subdirectory(sortFunc)
add_subdirectory(test1)
add_subdirectory(test2)

2.12.4 CMakeLists.txt in calFunc directory

# 指定CMake版本的最低版本
cmake_minimum_required(VERSION 2.8.12.2)
# 指定项目名称
project(Calc)

# 指定头文件目录
include_directories(${HEADPATH})
# 搜索源文件
aux_source_directory(./ SRC)
# 指定静态库生成路径
set(LIBRARY_OUTPUT_PATH ${LIBPATH})
# 生成静态库
add_library(${CALCLIB} STATIC ${SRC})

2.12.5 CMakeLists.txt in sotrFunc directory

# 指定CMake版本的最低版本
cmake_minimum_required(VERSION 2.8.12.2)
# 指定项目名称
project(Sort)

# 指定头文件目录
include_directories(${HEADPATH})
# 搜索源文件
aux_source_directory(./ SRC)
# 指定静态库生成路径
set(LIBRARY_OUTPUT_PATH ${LIBPATH})
# 生成静态库
add_library(${SORTLIB} STATIC ${SRC})

2.12.6 CMakeLists.txt in the test1 directory

# 指定CMake版本的最低版本
cmake_minimum_required(VERSION 2.8.12.2)
# 指定项目名称
project(Test1)

# 指定头文件路径
include_directories(${HEADPATH})
# 搜索源文件
aux_source_directory(./ SRC)
# 指定连接静态库的路径
link_directories(${LIBPATH})
# 连接静态库
link_libraries(${SORTLIB})
# 设置生成可执行文件的路径
set(EXECUTABLE_OUTPUT_PATH ${EXEPATH})
# 生成可执行文件
add_executable(${APPNAME1} ${SRC})

2.12.7 CMakeLists.txt in the test2 directory

# 指定CMake版本的最低版本
cmake_minimum_required(VERSION 2.8.12.2)
# 指定项目名称
project(Test2)

# 指定头文件路径
include_directories(${HEADPATH})
# 搜索源文件
aux_source_directory(./ SRC)
# 指定连接静态库的路径
link_directories(${LIBPATH})
# 连接静态库
link_libraries(${CALCLIB})
# 设置生成可执行文件的路径
set(EXECUTABLE_OUTPUT_PATH ${EXEPATH})
# 生成可执行文件
add_executable(${APPNAME2} ${SRC})

2.12.8 Build the project

[shaxiang@VM-8-14-centos v6]$ cd build/
[shaxiang@VM-8-14-centos build]$ cmake ..
-- The C compiler identification is GNU 7.3.1
-- The CXX compiler identification is GNU 7.3.1
-- Check for working C compiler: /opt/rh/devtoolset-7/root/usr/bin/cc
-- Check for working C compiler: /opt/rh/devtoolset-7/root/usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /opt/rh/devtoolset-7/root/usr/bin/c++
-- Check for working CXX compiler: /opt/rh/devtoolset-7/root/usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/shaxiang/test_cmake/v6/build
[shaxiang@VM-8-14-centos build]$ make
Scanning dependencies of target calc
[ 14%] Building CXX object calFunc/CMakeFiles/calc.dir/mul.cpp.o
[ 28%] Building CXX object calFunc/CMakeFiles/calc.dir/sub.cpp.o
[ 42%] Building CXX object calFunc/CMakeFiles/calc.dir/add.cpp.o
[ 57%] Building CXX object calFunc/CMakeFiles/calc.dir/div.cpp.o
Linking CXX static library ../../lib/libcalc.a
[ 57%] Built target calc
Scanning dependencies of target sort
[ 71%] Building CXX object sortFunc/CMakeFiles/sort.dir/bubbleSort.cpp.o
Linking CXX static library ../../lib/libsort.a
[ 71%] Built target sort
Scanning dependencies of target app1
[ 85%] Building CXX object test1/CMakeFiles/app1.dir/sort.cpp.o
Linking CXX executable ../../bin/app1
[ 85%] Built target app1
Scanning dependencies of target app2
[100%] Building CXX object test2/CMakeFiles/app2.dir/cal.cpp.o
Linking CXX executable ../../bin/app2
[100%] Built target app2
[shaxiang@VM-8-14-centos v6]$ tree -L 2
.
|-- bin
|   |-- app1
|   `-- app2
|-- build
|   |-- calFunc
|   |-- CMakeCache.txt
|   |-- CMakeFiles
|   |-- cmake_install.cmake
|   |-- Makefile
|   |-- sortFunc
|   |-- test1
|   `-- test2
|-- calFunc
|   |-- add.cpp
|   |-- CMakeLists.txt
|   |-- div.cpp
|   |-- mul.cpp
|   `-- sub.cpp
|-- CMakeLists.txt
|-- include
|   `-- head.h
|-- lib
|   |-- libcalc.a
|   `-- libsort.a
|-- sortFunc
|   |-- bubbleSort.cpp
|   `-- CMakeLists.txt
|-- test1
|   |-- CMakeLists.txt
|   `-- sort.cpp
`-- test2
    |-- cal.cpp
    `-- CMakeLists.txt

13 directories, 20 files

Guess you like

Origin blog.csdn.net/lx473774000/article/details/132659392