前言

CMake 是一个跨平台开源构建系统,可以构建、测试和打包软件。它可用于支持多个本地构建环境,包括 make,Apple 的 xcodeMicrosoft Visual Studio

CMake Examples 是一个包括现代 CMake 的配置例子的仓库。这些示例以类似教程的格式列出。第一个示例非常基本,并且利用前面的示例来缓慢增加复杂性,以显示更复杂的用例。

cmake-examples-ChineseCMake Examples 项目的中文版。

该学习笔记只介绍了 CMake Examples 项目的一部分例子。

操作系统(本地):Windows 10 专业版

参考文档

  1. CMake Examples

  2. cmake-examples-Chinese

  3. Using CMake in MSYS2

  4. Step 4: Installing and Testing

  5. Step 7: Packaging an Installer

Prerequisites

本博文使用 MSYS2 作为运行 C++CMake 的工作环境。

关于如何安装 MSYS2 可以参考官方文档 MSYS2 或者 00020-GCC on Windows-windows10

运行开始菜单的 “MSYS2 MSYS”。安装 CMake。

1
2
pacman -S mingw-w64-x86_64-cmake
pacman -S make

MSYS2CMake 可以参考 Using CMake in MSYS2

MSYS2CMake 默认使用 Ninja 作为构建工具。可以通过 -G 指定。

When running the CMake configuration command, it’s recommended to explicitly specify the desired build file generator with the -G option. MSYS2 provided CMake defaults to Ninja (but this is not the default in upstream CMake, so it’s safest to explicitly specify it).

Thus, to configure and build a CMake based project, you can run the following commands:

1
2
$ cmake -G Ninja <path-to-source> -DCMAKE_BUILD_TYPE=Release
$ cmake --build .

The relevant generator alternatives are:

  • -G Ninja

  • -G "MSYS Makefiles"

  • -G "MinGW Makefiles"

If building by invoking cmake --build, the same command works for all generator choices. Alternatively, to build by directly invoking the build tool, you can call ninja, make or mingw32-make respectively for those three alternatives.

version

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
lyf@DESKTOP-GV2QHKN MINGW64 ~
$ cmake --version
cmake version 3.23.2

CMake suite maintained and supported by Kitware (kitware.com/cmake).

lyf@DESKTOP-GV2QHKN MINGW64 ~
$ make --version
GNU Make 4.3
为 x86_64-pc-msys 编译
Copyright (C) 1988-2020 Free Software Foundation, Inc.
许可证:GPLv3+:GNU 通用公共许可证第 3 版或更新版本<http://gnu.org/licenses/gpl.html>。
本软件是自由软件:您可以自由修改和重新发布它。
在法律允许的范围内没有其他保证。

lyf@DESKTOP-GV2QHKN MINGW64 ~
$ which cmake
/mingw64/bin/cmake

lyf@DESKTOP-GV2QHKN MINGW64 ~
$ which make
/usr/bin/make

lyf@DESKTOP-GV2QHKN MINGW64 ~
$

01-basic

A-hello-cmake

Files
  1. 运行开始菜单的 “MSYS2 MinGW x64”,运行下面命令构建项目目录。
1
2
3
4
5
6
mkdir cmake-examples
cd cmake-examples
mkdir 01-basic
cd 01-basic
mkdir A-hello-cmake
cd A-hello-cmake
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
# Set the minimum version of CMake that can be used
# To find the cmake version run
# $ cmake --version
cmake_minimum_required(VERSION 3.5)

# Set the project name
project(hello_cmake)

# Add an executable
add_executable(${PROJECT_NAME} main.cpp)
  1. 创建 main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
#include <iostream>

int main(int argc, char *argv[])
{
std::cout << "Hello CMake!" << std::endl;
return 0;
}
Introduction

这是一个基础的 hello world 例子。

1
2
3
4
5
6
7
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake
$ tree
.
├── CMakeLists.txt
└── main.cpp

0 directories, 2 files
  • CMakeLists.txt: CMake 的配置文件。

  • main.cpp: 一个简单的 Hello World cpp 文件。

Concepts
CMakeLists.txt

CMakeLists.txt 是一个存储 CMake commands 的文件,当在一个目录中运行 cmake 时,它将要寻找这个文件。如果没有这个文件,cmake 将要报错。

Minimum CMake version

当使用 CMake 创建一个项目时,你能指定支持的 CMake 的最低版本。

1
cmake_minimum_required(VERSION 3.5)
Projects

CMake 生成可以包含项目名称,以便在使用多个项目时,更轻松地引用某些变量。

1
project(hello_cmake)
Creating an Executable

add_executable() 命令可以从指定的源文件生成可执行文件,在此示例中为 main.cppadd_executable() 函数的第一个参数是要生成的可执行文件的名称,第二个参数是要编译的源文件的列表。

1
add_executable(hello_cmake main.cpp)

有些人经常使项目名称和可执行文件名称相同。这允许你指定 CMakeLists.txt 如下所示:

1
2
3
cmake_minimum_required(VERSION 2.6)
project (hello_cmake)
add_executable(${PROJECT_NAME} main.cpp)

在此示例中,project() 函数将创建一个值为 hello_cmake 的变量 ${PROJECT_NAME}。然后,可以将其传递给 add_executable() 函数以输出 hello_cmake 可执行文件。

Binary Directory

运行 cmake 命令的根文件夹或顶级文件夹称为 CMAKE_BINARY_DIR,并且是所有二进制文件的根文件夹。CMake 支持外部构建内部构建两种方式生成二进制文件。

内部构建

内部构建在与源代码相同的目录结构中生成所有临时生成文件。这意味着所有 Makefiles and object files 都散布在源代码代码中。要内部构建目标,请在根目录中运行 cmake 命令。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake
$ which cmake
/mingw64/bin/cmake

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake
$ which make
/usr/bin/make

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake
$ ls
CMakeLists.txt main.cpp

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake
$ cmake . -G "MSYS Makefiles"
-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake
$ tree
.
├── cmake_install.cmake
├── CMakeCache.txt
├── CMakeFiles
│   ├── 3.23.2
│   │   ├── CMakeCCompiler.cmake
│   │   ├── CMakeCXXCompiler.cmake
│   │   ├── CMakeDetermineCompilerABI_C.bin
│   │   ├── CMakeDetermineCompilerABI_CXX.bin
│   │   ├── CMakeRCCompiler.cmake
│   │   ├── CMakeSystem.cmake
│   │   ├── CompilerIdC
│   │   │   ├── a.exe
│   │   │   ├── CMakeCCompilerId.c
│   │   │   └── tmp
│   │   └── CompilerIdCXX
│   │   ├── a.exe
│   │   ├── CMakeCXXCompilerId.cpp
│   │   └── tmp
│   ├── cmake.check_cache
│   ├── CMakeDirectoryInformation.cmake
│   ├── CMakeOutput.log
│   ├── CMakeTmp
│   ├── hello_cmake.dir
│   │   ├── build.make
│   │   ├── cmake_clean.cmake
│   │   ├── compiler_depend.make
│   │   ├── compiler_depend.ts
│   │   ├── depend.make
│   │   ├── DependInfo.cmake
│   │   ├── flags.make
│   │   └── progress.make
│   ├── Makefile.cmake
│   ├── Makefile2
│   ├── progress.marks
│   └── TargetDirectories.txt
├── CMakeLists.txt
├── main.cpp
└── Makefile

8 directories, 30 files

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake
$ make
[ 50%] Building CXX object CMakeFiles/hello_cmake.dir/main.cpp.obj
[100%] Linking CXX executable hello_cmake.exe
[100%] Built target hello_cmake

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake
$ ls
cmake_install.cmake CMakeFiles hello_cmake.exe Makefile
CMakeCache.txt CMakeLists.txt main.cpp

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake
$ ./hello_cmake.exe
Hello CMake!

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake
$
外部构建

外部构建允许您创建单个构建文件夹,该文件夹可以位于文件系统上的任何位置。所有临时构建文件和对象文件都位于此目录中,保持源代码目录的清洁。若要外部构建,请在the build folder中运行 cmake 命令,并将其指向包含根 CMakeLists.txt 文件的目录。如果要从头开始重新创建 cmake 环境,请使用外部构建,只需删除上面内部构建生成的文件,然后重新运行 cmake

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake
$ ls
CMakeLists.txt main.cpp

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake
$ mkdir build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake
$ ls
build CMakeLists.txt main.cpp

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake
$ cd build/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake/build
$ ls

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake/build
$ cmake ..
-- Building for: Ninja
-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake/build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake/build
$ cmake --build .
[2/2] Linking CXX executable hello_cmake.exe

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake/build
$ ls
build.ninja CMakeCache.txt hello_cmake.exe
cmake_install.cmake CMakeFiles

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake/build
$ ./hello_cmake.exe
Hello CMake!

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake/build
$ cd ..

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake
$ tree
.
├── build
│   ├── build.ninja
│   ├── cmake_install.cmake
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   │   ├── 3.23.2
│   │   │   ├── CMakeCCompiler.cmake
│   │   │   ├── CMakeCXXCompiler.cmake
│   │   │   ├── CMakeDetermineCompilerABI_C.bin
│   │   │   ├── CMakeDetermineCompilerABI_CXX.bin
│   │   │   ├── CMakeRCCompiler.cmake
│   │   │   ├── CMakeSystem.cmake
│   │   │   ├── CompilerIdC
│   │   │   │   ├── a.exe
│   │   │   │   ├── CMakeCCompilerId.c
│   │   │   │   └── tmp
│   │   │   └── CompilerIdCXX
│   │   │   ├── a.exe
│   │   │   ├── CMakeCXXCompilerId.cpp
│   │   │   └── tmp
│   │   ├── cmake.check_cache
│   │   ├── CMakeOutput.log
│   │   ├── CMakeTmp
│   │   ├── hello_cmake.dir
│   │   │   └── main.cpp.obj
│   │   ├── rules.ninja
│   │   └── TargetDirectories.txt
│   └── hello_cmake.exe
├── CMakeLists.txt
└── main.cpp

9 directories, 21 files

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/A-hello-cmake
$

B-hello-headers

Files
  1. 运行开始菜单的 “MSYS2 MinGW x64”,运行下面命令构建项目目录。
1
2
3
cd ..
mkdir B-hello-headers
cd B-hello-headers
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Set the minimum version of CMake that can be used
# To find the cmake version run
# $ cmake --version
cmake_minimum_required(VERSION 3.5)

# Set the project name
project(hello_headers)

# Create a sources variable with a link to all cpp files to compile
file(GLOB SOURCES "src/*.cpp")

# Add an executable with the above sources
add_executable(hello_headers ${SOURCES})

# Set the directories that should be included in the build command for this target
# when running g++ these will be included as -I/directory/path/
target_include_directories(hello_headers
PRIVATE
${PROJECT_SOURCE_DIR}/include
)
  1. 创建 include/Hello.h 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
#ifndef __HELLO_H__
#define __HELLO_H__

class Hello
{
public:
void print();
};

#endif
  1. 创建 src/Hello.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
#include <iostream>

#include "Hello.h"

void Hello::print()
{
std::cout << "Hello Headers!" << std::endl;
}
  1. 创建 src/main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
#include "Hello.h"

int main(int argc, char *argv[])
{
Hello hi;
hi.print();
return 0;
}
Introduction

该例子使用不同目录包含头文件和源文件。

1
2
3
4
5
6
7
8
9
10
11
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers
$ tree
.
├── CMakeLists.txt
├── include
│   └── Hello.h
└── src
├── Hello.cpp
└── main.cpp

2 directories, 4 files
  • CMakeLists.txt: CMake 的配置文件。

  • include/Hello.h: 头文件。

  • src/Hello.cpp: 源文件。

  • src/main.cpp: main 文件。

Concepts
Directory Paths

CMake 语法指定了许多变量,这些变量可用于帮助在项目或源代码树中查找有用的目录。其中一些包括:

Variable Info
CMAKE_SOURCE_DIR The root source directory.
CMAKE_CURRENT_SOURCE_DIR The current source directory if using sub-projects and directories.
PROJECT_SOURCE_DIR The source directory of the current cmake project.
CMAKE_BINARY_DIR The root binary / build directory. This is the directory where you run the cmake command.
CMAKE_CURRENT_BINARY_DIR The build directory you are currently in.
PROJECT_BINARY_DIR The build directory for the current project.
Source Files Variable

通过创建包含源文件的变量,你可以更清楚地了解这些文件,并轻松地将它们添加到多个命令中,例如,add_executable() 函数。

1
2
3
4
5
6
7
# Create a sources variable with a link to all cpp files to compile
set(SOURCES
src/Hello.cpp
src/main.cpp
)

add_executable(${PROJECT_NAME} ${SOURCES})

SOURCES 变量中设置特定文件名的替代方法是使用 GLOB 命令通过通配符模式匹配来查找文件。

1
file(GLOB SOURCES "src/*.cpp")
Including Directories

当你有不同的文件夹时,可以使用 target_include_directories() 函数使编译器知道它们。在编译此目标时,这会将这些目录添加到具有 -I 标志的编译器中,例如 -I /directory/path

1
2
3
4
target_include_directories(target
PRIVATE
${PROJECT_SOURCE_DIR}/include
)
Building the Example
Standard Output
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers
$ mkdir build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers
$ cd build/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build
$ cmake .. -G "MSYS Makefiles"
-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build
$ make
[ 33%] Building CXX object CMakeFiles/hello_headers.dir/src/Hello.cpp.obj
[ 66%] Building CXX object CMakeFiles/hello_headers.dir/src/main.cpp.obj
[100%] Linking CXX executable hello_headers.exe
[100%] Built target hello_headers

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build
$ ls
cmake_install.cmake CMakeFiles Makefile
CMakeCache.txt hello_headers.exe

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build
$ ./hello_headers.exe
Hello Headers!

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build
$
Verbose Output

在前面的示例中,运行 make 命令时,输出仅显示生成的状态。若要查看用于调试目的的完整输出,可以在运行 make 时添加 VERBOSE=1 标志。

下面显示了 VERBOSE 输出,对输出的检查显示了要添加到 c++ 编译器命令中的 include 目录。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build
$ make clean

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build
$ ls
cmake_install.cmake CMakeCache.txt CMakeFiles Makefile

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build
$ make VERBOSE=1
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -S/F/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers -B/F/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build --check-build-system CMakeFiles/Makefile.cmake 0
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_progress_start /F/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build/CMakeFiles /F/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build//CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build”
make -f CMakeFiles/hello_headers.dir/build.make CMakeFiles/hello_headers.dir/depend
make[2]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build”
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_depends "MSYS Makefiles" /F/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers /F/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers /F/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build /F/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build /F/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build/CMakeFiles/hello_headers.dir/DependInfo.cmake --color=
make[2]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build”
make -f CMakeFiles/hello_headers.dir/build.make CMakeFiles/hello_headers.dir/build
make[2]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build”
[ 33%] Building CXX object CMakeFiles/hello_headers.dir/src/Hello.cpp.obj
/D/lyf_computer_language/msys64/mingw64/bin/c++.exe -I/F/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/include -MD -MT CMakeFiles/hello_headers.dir/src/Hello.cpp.obj -MF CMakeFiles/hello_headers.dir/src/Hello.cpp.obj.d -o CMakeFiles/hello_headers.dir/src/Hello.cpp.obj -c /F/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/src/Hello.cpp
[ 66%] Building CXX object CMakeFiles/hello_headers.dir/src/main.cpp.obj
/D/lyf_computer_language/msys64/mingw64/bin/c++.exe -I/F/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/include -MD -MT CMakeFiles/hello_headers.dir/src/main.cpp.obj -MF CMakeFiles/hello_headers.dir/src/main.cpp.obj.d -o CMakeFiles/hello_headers.dir/src/main.cpp.obj -c /F/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/src/main.cpp
[100%] Linking CXX executable hello_headers.exe
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E rm -f CMakeFiles/hello_headers.dir/objects.a
/D/lyf_computer_language/msys64/mingw64/bin/ar.exe qc CMakeFiles/hello_headers.dir/objects.a "CMakeFiles/hello_headers.dir/src/Hello.cpp.obj" "CMakeFiles/hello_headers.dir/src/main.cpp.obj"
/D/lyf_computer_language/msys64/mingw64/bin/c++.exe -Wl,--whole-archive CMakeFiles/hello_headers.dir/objects.a -Wl,--no-whole-archive -o hello_headers.exe -Wl,--out-implib,libhello_headers.dll.a -Wl,--major-image-version,0,--minor-image-version,0 -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
make[2]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build”
[100%] Built target hello_headers
make[1]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build”
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_progress_start /F/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build/CMakeFiles 0

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/B-hello-headers/build
$

C-static-library

Files
  1. 运行开始菜单的 “MSYS2 MinGW x64”,运行下面命令构建项目目录。
1
2
3
cd ../..
mkdir C-static-library
cd C-static-library
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
cmake_minimum_required(VERSION 3.5)

project(hello_library)

##############################################
# Create a library
##############################################

# Generate the static library from the library sources
add_library(hello_library STATIC
src/Hello.cpp
)

target_include_directories(hello_library
PUBLIC
${PROJECT_SOURCE_DIR}/include
)

###############################################
# Create an executable
###############################################

# Add an executable with the above sources
add_executable(hello_binary
src/main.cpp
)

# link the new hello_library target with the hello_binary target
target_link_libraries(hello_binary
PRIVATE
hello_library
)
  1. 创建 include/static/Hello.h 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
#ifndef __HELLO_H__
#define __HELLO_H__

class Hello
{
public:
void print();
};

#endif
  1. 创建 src/Hello.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
#include <iostream>

#include "static/Hello.h"

void Hello::print()
{
std::cout << "Hello Static Library!" << std::endl;
}
  1. 创建 src/main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
#include "static/Hello.h"

int main(int argc, char *argv[])
{
Hello hi;
hi.print();
return 0;
}
Introduction

显示一个 hello world 示例,该示例首先创建并链接静态链接库。这是一个简化的示例,显示库和二进制文件位于同一文件夹中。

1
2
3
4
5
6
7
8
9
10
11
12
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/C-static-library
$ tree
.
├── CMakeLists.txt
├── include
│   └── static
│   └── Hello.h
└── src
├── Hello.cpp
└── main.cpp

3 directories, 4 files
  • CMakeLists.txt: CMake 的配置文件。

  • include/static/Hello.h: 头文件。

  • src/Hello.cpp: 源文件。

  • src/main.cpp: main 文件。

Concepts
Adding a Static Library

add_library() 函数用于从某些源文件创建库。这称为:

1
2
3
add_library(hello_library STATIC
src/Hello.cpp
)

这将用于创建一个名为 libhello_library.a 的静态库,其中包含 add_library 调用中的源文件。

Populating Including Directories

在此示例中,我们使用作用域设置为 PUBLICtarget_include_directories() 函数在库中包含目录。

1
2
3
4
target_include_directories(hello_library
PUBLIC
${PROJECT_SOURCE_DIR}/include
)

This will cause the included directory used in the following places:

  • When compiling the library.

  • When compiling any additional target that links the library.

The meaning of scopes are:

  • PRIVATE - the directory is added to this target’s include directories

  • INTERFACE - the directory is added to the include directories for any targets that link this library.

  • PUBLIC - As above, it is included in this library and also any targets that link this library.

For public headers it is often a good idea to have your include folder be “namespaced” with sub-directories.

The directory passed to target_include_directories will be the root of your include directory tree and your C++ files should include the path from there to your header.

For this example you can see that we do it as follows:

1
#include "static/Hello.h"

Using this method means that there is less chance of header filename clashes when you use multiple libraries in your project.

Linking a Library

创建将使用库的可执行文件时,必须告知编译器该库。这可以使用 target_link_libraries() 函数来完成。

1
2
3
4
5
6
7
8
add_executable(hello_binary
src/main.cpp
)

target_link_libraries( hello_binary
PRIVATE
hello_library
)

This tells CMake to link the hello_library against the hello_binary executable during link time. It will also propagate any include directories with PUBLIC or INTERFACE scope from the linked library target.

Building the Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/C-static-library
$ mkdir build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/C-static-library
$ cd build/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/C-static-library/build
$ cmake .. -G "MSYS Makefiles"
-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/01-basic/C-static-library/build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/C-static-library/build
$ make
[ 25%] Building CXX object CMakeFiles/hello_library.dir/src/Hello.cpp.obj
[ 50%] Linking CXX static library libhello_library.a
[ 50%] Built target hello_library
[ 75%] Building CXX object CMakeFiles/hello_binary.dir/src/main.cpp.obj
[100%] Linking CXX executable hello_binary.exe
[100%] Built target hello_binary

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/C-static-library/build
$ ls
cmake_install.cmake CMakeFiles libhello_library.a
CMakeCache.txt hello_binary.exe Makefile

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/C-static-library/build
$ ./hello_binary.exe
Hello Static Library!

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/C-static-library/build
$

D-shared-library

Files
  1. 运行开始菜单的 “MSYS2 MinGW x64”,运行下面命令构建项目目录。
1
2
3
cd ../..
mkdir D-shared-library
cd D-shared-library/
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
cmake_minimum_required(VERSION 3.5)

project(hello_library)

#########################################
# Create a library
#########################################

# Generate the shared library from the library sources
add_library(hello_library SHARED
src/Hello.cpp
)

add_library(hello::library ALIAS hello_library)

target_include_directories(hello_library
PUBLIC
${PROJECT_SOURCE_DIR}/include
)

#########################################
# Create an executable
#########################################

# Add an executable with the above sources
add_executable(hello_binary
src/main.cpp
)

# link the new hello_library target with the hello_binary target
target_link_libraries(hello_binary
PRIVATE
hello::library
)
  1. 创建 include/shared/Hello.h 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
#ifndef __HELLO_H__
#define __HELLO_H__

class Hello
{
public:
void print();
};

#endif
  1. 创建 src/Hello.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
#include <iostream>

#include "shared/Hello.h"

void Hello::print()
{
std::cout << "Hello Shared Library!" << std::endl;
}
  1. 创建 src/main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
#include "shared/Hello.h"

int main(int argc, char *argv[])
{
Hello hi;
hi.print();
return 0;
}
Introduction

该示例首先创建并链接共享库,然后显示了如何创建别名目标。

1
2
3
4
5
6
7
8
9
10
11
12
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/D-shared-library
$ tree
.
├── CMakeLists.txt
├── include
│   └── shared
│   └── Hello.h
└── src
├── Hello.cpp
└── main.cpp

3 directories, 4 files
  • CMakeLists.txt: CMake 的配置文件。

  • include/shared/Hello.h: 头文件。

  • src/Hello.cpp: 源文件。

  • src/main.cpp: main 文件。

Concepts
Adding a Shared Library

add_library() 函数也可以用于从某些源文件创建共享库。这称为:

1
2
3
add_library(hello_library SHARED
src/Hello.cpp
)

这将用于创建一个名为 libhello_library.so 的共享库,并将源文件传递给 add_library() 函数。

Alias Target

顾名思义,别名目标是目标的替代名称,可以在只读上下文中代替实际目标名称使用。

1
add_library(hello::library ALIAS hello_library)

如下所示,这允许你在将目标与其他目标链接时使用别名引用目标。

Linking a Shared Library

链接共享库与链接静态库相同。创建可执行文件时,使用 target_link_library() 函数指向库。

1
2
3
4
5
6
7
8
add_executable(hello_binary
src/main.cpp
)

target_link_libraries(hello_binary
PRIVATE
hello::library
)

这将指示 CMake 使用别名目标名称将 hello_libraryhello_binary 可执行文件链接起来。

Building the Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/D-shared-library
$ mkdir build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/D-shared-library
$ cd build/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/D-shared-library/build
$ cmake .. -G "MSYS Makefiles"
-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/01-basic/D-shared-library/build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/D-shared-library/build
$ make
[ 25%] Building CXX object CMakeFiles/hello_library.dir/src/Hello.cpp.obj
[ 50%] Linking CXX shared library libhello_library.dll
[ 50%] Built target hello_library
[ 75%] Building CXX object CMakeFiles/hello_binary.dir/src/main.cpp.obj
[100%] Linking CXX executable hello_binary.exe
[100%] Built target hello_binary

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/D-shared-library/build
$ ls
cmake_install.cmake hello_binary.exe Makefile
CMakeCache.txt libhello_library.dll
CMakeFiles libhello_library.dll.a

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/D-shared-library/build
$ ./hello_binary.exe
Hello Shared Library!

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/D-shared-library/build
$

E-installing

Files
  1. 运行开始菜单的 “MSYS2 MinGW x64”,运行下面命令构建项目目录。
1
2
3
cd ../..
mkdir E-installing
cd E-installing
  1. 创建 cmake-examples.conf 文件,粘贴下面代码。
1
# Sample configuration file that could be installed
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
cmake_minimum_required(VERSION 3.5)

project(cmake_examples_install)

#########################################
# Create a library
#########################################

# Generate the shared library from the library sources
add_library(cmake_examples_inst SHARED
src/Hello.cpp
)

target_include_directories(cmake_examples_inst
PUBLIC
${PROJECT_SOURCE_DIR}/include
)

###########################################
# Create an executable
###########################################

# Add an executable with the above sources
add_executable(cmake_examples_inst_bin
src/main.cpp
)

# link the new hello_library target with the hello_binary target
target_link_libraries(cmake_examples_inst_bin
PRIVATE
cmake_examples_inst
)

###################################################
# Install
###################################################

# Binaries
install(TARGETS cmake_examples_inst_bin
DESTINATION bin)

# Library
# Note: may not work on windows
install(TARGETS cmake_examples_inst
LIBRARY DESTINATION lib)

# Header files
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/
DESTINATION include)
# Cofig
install(FILES cmake-examples.conf
DESTINATION etc)
  1. 创建 include/installing/Hello.h 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
#ifndef __HELLO_H__
#define __HELLO_H__

class Hello
{
public:
void print();
};

#endif
  1. 创建 src/Hello.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
#include <iostream>

#include "installing/Hello.h"

void Hello::print()
{
std::cout << "Hello Install!" << std::endl;
}
  1. 创建 src/main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
#include "installing/Hello.h"

int main(int argc, char *argv[])
{
Hello hi;
hi.print();
return 0;
}
Introduction

此示例演示如何生成 make install 目标以在系统上安装文件和二进制文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/E-installing
$ tree
.
├── cmake-examples.conf
├── CMakeLists.txt
├── include
│   └── installing
│   └── Hello.h
└── src
├── Hello.cpp
└── main.cpp

3 directories, 5 files
  • CMakeLists.txt: CMake 的配置文件。

  • cmake-examples.conf: 配置文件。

  • include/installing/Hello.h: 头文件。

  • src/Hello.cpp: 源文件。

  • src/main.cpp: main 文件。

Concepts
Installing

CMake 提供了添加 make install 目标的功能,以允许用户安装 二进制文件其他文件。基本安装位置由变量 CMAKE_INSTALL_PREFIX 控制,该变量可以使用 ccmake 或通过调用 cmake (cmake .. -DCMAKE_INSTALL_PREFIX=/install/location) 来设置。

安装的文件由 install() 函数控制。

1
2
install (TARGETS cmake_examples_inst_bin
DESTINATION bin)

将从目标 cmake_examples_inst_bin 生成的 二进制文件 安装到 ${CMAKE_INSTALL_PREFIX}/bin 目录中。

1
2
install (TARGETS cmake_examples_inst
LIBRARY DESTINATION lib)

将从目标 cmake_examples_inst 生成的 共享库 安装到 ${CMAKE_INSTALL_PREFIX}/lib 目录中。

1
2
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/
DESTINATION include)

将用于针对 cmake_examples_inst 库进行开发的 头文件 安装到 ${CMAKE_INSTALL_PREFIX}/include 目录中。

1
2
install (FILES cmake-examples.conf
DESTINATION etc)

配置文件 安装到 ${CMAKE_INSTALL_PREFIX}/etc 目录中。

Building the Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/E-installing
$ mkdir build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/E-installing
$ cd build/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/E-installing/build
$ cmake .. -G "MSYS Makefiles"
-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/01-basic/E-installing/build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/E-installing/build
$ make
[ 25%] Building CXX object CMakeFiles/cmake_examples_inst.dir/src/Hello.cpp.obj
[ 50%] Linking CXX shared library libcmake_examples_inst.dll
[ 50%] Built target cmake_examples_inst
[ 75%] Building CXX object CMakeFiles/cmake_examples_inst_bin.dir/src/main.cpp.obj
[100%] Linking CXX executable cmake_examples_inst_bin.exe
[100%] Built target cmake_examples_inst_bin

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/E-installing/build
$ cmake --install . --prefix "/f/home/lyf/installdir/"
-- Install configuration: ""
-- Installing: F:/home/lyf/installdir/bin/cmake_examples_inst_bin.exe
-- Installing: F:/home/lyf/installdir/lib/libcmake_examples_inst.dll.a
-- Installing: F:/home/lyf/installdir/bin/libcmake_examples_inst.dll
-- Installing: F:/home/lyf/installdir/include
-- Installing: F:/home/lyf/installdir/include/installing
-- Installing: F:/home/lyf/installdir/include/installing/Hello.h
-- Installing: F:/home/lyf/installdir/etc/cmake-examples.conf

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/E-installing/build
$ ls
cmake_examples_inst_bin.exe install_manifest.txt
cmake_install.cmake libcmake_examples_inst.dll
CMakeCache.txt libcmake_examples_inst.dll.a
CMakeFiles Makefile

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/E-installing/build
$ ./cmake_examples_inst_bin.exe
Hello Install!

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/E-installing/build
$

The CMake variable CMAKE_INSTALL_PREFIX is used to determine the root of where the files will be installed. If using the cmake --install command, the installation prefix can be overridden via the --prefix argument. For example:

1
cmake --install . --prefix "/home/myuser/installdir"

Navigate to the install directory and verify that the installed cmake_examples_inst_bin runs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
lyf@DESKTOP-GV2QHKN MINGW64 /f/home/lyf/installdir
$ tree
.
├── bin
│   ├── cmake_examples_inst_bin.exe
│   └── libcmake_examples_inst.dll
├── etc
│   └── cmake-examples.conf
├── include
│   └── installing
│   └── Hello.h
└── lib
└── libcmake_examples_inst.dll.a

5 directories, 5 files

lyf@DESKTOP-GV2QHKN MINGW64 /f/home/lyf/installdir
$ cd bin/

lyf@DESKTOP-GV2QHKN MINGW64 /f/home/lyf/installdir/bin
$ ./cmake_examples_inst_bin.exe
Hello Install!

lyf@DESKTOP-GV2QHKN MINGW64 /f/home/lyf/installdir/bin
$

F-build-type

Files
  1. 运行开始菜单的 “MSYS2 MinGW x64”,运行下面命令构建项目目录。
1
2
3
cd ../..
mkdir F-build-type
cd F-build-type
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Set the minimum version of CMake that can be used
# To find the cmake version run
# $ cmake --version
cmake_minimum_required(VERSION 3.5)

# Set a default build type if none was specified
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message("Setting build type to 'RelWithDebInfo' as none was specified.")
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

# Set the project name
project(build_type)

# Add an executable
add_executable(cmake_examples_build_type main.cpp)
  1. 创建 main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
#include <iostream>

int main(int argc, char *argv[])
{
std::cout << "Hello Build Type!" << std::endl;
return 0;
}
Introduction

CMake 具有许多内置的生成配置,可用于编译项目。它们指定优化级别以及调试信息是否要包含在二进制文件中。

提供的级别包括:

  • Release - Adds the -O3 -DNDEBUG flags to the compiler.

  • Debug - Adds the -g flag.

  • MinSizeRel - Adds -Os -DNDEBUG.

  • RelWithDebInfo - Adds -O2 -g -DNDEBUG flags.

1
2
3
4
5
6
7
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/F-build-type
$ tree
.
├── CMakeLists.txt
└── main.cpp

0 directories, 2 files
  • CMakeLists.txt: CMake 的配置文件。

  • main.cpp: main 文件。

Concepts
Set Build Type

Passing into cmake

1
cmake .. -DCMAKE_BUILD_TYPE=Release
Set Default Build Type

CMake 提供的默认生成类型是不包含用于优化的编译器标志。对于某些项目,您可能希望设置默认生成类型,这样就不必记得设置它。

为此,你可以将以下内容添加到顶级 CMakeLists.txt

1
2
3
4
5
6
7
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message("Setting build type to 'RelWithDebInfo' as none was specified.")
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
"MinSizeRel" "RelWithDebInfo")
endif()
Building the Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/F-build-type
$ mkdir build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/F-build-type
$ cd build/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build
$ cmake .. -G "MSYS Makefiles"
Setting build type to 'RelWithDebInfo' as none was specified.
-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build
$ make VERBOSE=1
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -S/F/vscode/cpp_projects/cmake-examples/01-basic/F-build-type -B/F/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build --check-build-system CMakeFiles/Makefile.cmake 0
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_progress_start /F/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build/CMakeFiles /F/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build//CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build”
make -f CMakeFiles/cmake_examples_build_type.dir/build.make CMakeFiles/cmake_examples_build_type.dir/depend
make[2]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build”
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_depends "MSYS Makefiles" /F/vscode/cpp_projects/cmake-examples/01-basic/F-build-type /F/vscode/cpp_projects/cmake-examples/01-basic/F-build-type /F/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build /F/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build /F/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build/CMakeFiles/cmake_examples_build_type.dir/DependInfo.cmake --color=
make[2]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build”
make -f CMakeFiles/cmake_examples_build_type.dir/build.make CMakeFiles/cmake_examples_build_type.dir/build
make[2]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build”
[ 50%] Building CXX object CMakeFiles/cmake_examples_build_type.dir/main.cpp.obj
/D/lyf_computer_language/msys64/mingw64/bin/c++.exe -O2 -g -DNDEBUG -MD -MT CMakeFiles/cmake_examples_build_type.dir/main.cpp.obj -MF CMakeFiles/cmake_examples_build_type.dir/main.cpp.obj.d -o CMakeFiles/cmake_examples_build_type.dir/main.cpp.obj -c /F/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/main.cpp
[100%] Linking CXX executable cmake_examples_build_type.exe
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E rm -f CMakeFiles/cmake_examples_build_type.dir/objects.a
/D/lyf_computer_language/msys64/mingw64/bin/ar.exe qc CMakeFiles/cmake_examples_build_type.dir/objects.a "CMakeFiles/cmake_examples_build_type.dir/main.cpp.obj"
/D/lyf_computer_language/msys64/mingw64/bin/c++.exe -O2 -g -DNDEBUG -Wl,--whole-archive CMakeFiles/cmake_examples_build_type.dir/objects.a -Wl,--no-whole-archive -o cmake_examples_build_type.exe -Wl,--out-implib,libcmake_examples_build_type.dll.a -Wl,--major-image-version,0,--minor-image-version,0 -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
make[2]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build”
[100%] Built target cmake_examples_build_type
make[1]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build”
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_progress_start /F/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build/CMakeFiles 0

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build
$ ls
cmake_examples_build_type.exe CMakeCache.txt Makefile
cmake_install.cmake CMakeFiles

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build
$ ./cmake_examples_build_type.exe
Hello Build Type!

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/F-build-type/build
$

G-compile-flags

Files
  1. 运行开始菜单的 “MSYS2 MinGW x64”,运行下面命令构建项目目录。
1
2
3
cd ../..
mkdir G-compile-flags
cd G-compile-flags
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
cmake_minimum_required(VERSION 3.5)

# Set a default C++ compile flag
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEX2" CACHE STRING "Set C++ Compiler Flags" FORCE)

# Set the project name
project(compile_flags)

# Add an executable
add_executable(cmake_examples_compile_flags main.cpp)

target_compile_definitions(cmake_examples_compile_flags
PRIVATE EX3)
  1. 创建 main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<iostream>

int main(int argc, char *argv[])
{
std::cout << "Hello Compile Flags!" << std::endl;

// only print if compile flag set
#ifdef EX2
std::cout << "Hello Compile Flag EX2!" << std::endl;
#endif

#ifdef EX3
std::cout << "Hello Compile Flag Ex3!" << std::endl;
#endif

return 0;
}
Introduction

CMake 支持以多种不同的方式设置编译标志:

  • 使用 target_compile_definitions() 函数。

  • 使用 CMAKE_C_FLAGSCMAKE_CXX_FLAGS 变量。

1
2
3
4
5
6
7
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags
$ tree
.
├── CMakeLists.txt
└── main.cpp

0 directories, 2 files
  • CMakeLists.txt: CMake 的配置文件。

  • main.cpp: main 文件。

Concepts
Set Per-Target C++ Flags

在现代 CMake 中设置 C++ 标志的推荐方法是使用 per-target flags,这些标志可以通过 target_compile_definitions() 函数填充到其他目标。这将填充库的 INTERFACE_COMPILE_DEFINITIONS,并根据范围将定义推送到链接的目标。

1
2
3
target_compile_definitions(cmake_examples_compile_flags
PRIVATE EX3
)

这将导致编译器在编译目标时添加定义 -DEX3

如果目标是一个库,并且已选择作用域 PUBLICINTERFACE,则该定义也将包含在链接此目标的任何可执行文件中。

对于编译器选项,您还可以使用 target_compile_options() 函数。

Set Default C++ Flags

CMAKE_CXX_FLAGS 的默认值为空或包含生成类型的适当标志。

若要设置额外的默认编译标志,可以将以下内容添加到顶级 CMakeLists.txt

1
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEX2" CACHE STRING "Set C++ Compiler Flags" FORCE)

CMAKE_CXX_FLAGS 类似,其他选项包括:

  • 使用 CMAKE_C_FLAGS 设置 C 编译器标志。

  • 使用 CMAKE_LINKER_FLAGS 设置链接器标志。

The values CACHE STRING "Set C++ Compiler Flags" FORCE from the above command are used to force this variable to be set in the CMakeCache.txt file.

Once set the CMAKE_C_FLAGS and CMAKE_CXX_FLAGS will set a compiler flag / definition globally for all targets in this directory or any included sub-directories. This method is not recommended for general usage now and the target_compile_definitions function is preferred.

Set CMake Flags

Similar to the build type a global C++ compiler flag can be set using the following methods.

Passing into cmake

1
cmake .. -DCMAKE_CXX_FLAGS="-DEX3"
Building the Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags
$ mkdir build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags
$ cd build/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build
$ cmake .. -G "MSYS Makefiles"
-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build
$ make VERBOSE=1
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -S/F/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags -B/F/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build --check-build-system CMakeFiles/Makefile.cmake 0
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_progress_start /F/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles /F/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build//CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build”
make -f CMakeFiles/cmake_examples_compile_flags.dir/build.make CMakeFiles/cmake_examples_compile_flags.dir/depend
make[2]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build”
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_depends "MSYS Makefiles" /F/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags /F/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags /F/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build /F/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build /F/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles/cmake_examples_compile_flags.dir/DependInfo.cmake --color=
make[2]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build”
make -f CMakeFiles/cmake_examples_compile_flags.dir/build.make CMakeFiles/cmake_examples_compile_flags.dir/build
make[2]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build”
[ 50%] Building CXX object CMakeFiles/cmake_examples_compile_flags.dir/main.cpp.obj
/D/lyf_computer_language/msys64/mingw64/bin/c++.exe -DEX3 -DEX2 -MD -MT CMakeFiles/cmake_examples_compile_flags.dir/main.cpp.obj -MF CMakeFiles/cmake_examples_compile_flags.dir/main.cpp.obj.d -o CMakeFiles/cmake_examples_compile_flags.dir/main.cpp.obj -c /F/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/main.cpp
[100%] Linking CXX executable cmake_examples_compile_flags.exe
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E rm -f CMakeFiles/cmake_examples_compile_flags.dir/objects.a
/D/lyf_computer_language/msys64/mingw64/bin/ar.exe qc CMakeFiles/cmake_examples_compile_flags.dir/objects.a "CMakeFiles/cmake_examples_compile_flags.dir/main.cpp.obj"
/D/lyf_computer_language/msys64/mingw64/bin/c++.exe -DEX2 -Wl,--whole-archive CMakeFiles/cmake_examples_compile_flags.dir/objects.a -Wl,--no-whole-archive -o cmake_examples_compile_flags.exe -Wl,--out-implib,libcmake_examples_compile_flags.dll.a -Wl,--major-image-version,0,--minor-image-version,0 -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
make[2]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build”
[100%] Built target cmake_examples_compile_flags
make[1]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build”
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_progress_start /F/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles 0

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build
$ ls
cmake_examples_compile_flags.exe CMakeCache.txt Makefile
cmake_install.cmake CMakeFiles

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build
$ ./cmake_examples_compile_flags.exe
Hello Compile Flags!
Hello Compile Flag EX2!
Hello Compile Flag Ex3!

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/G-compile-flags/build
$

H-third-party-library

Files
  1. 运行开始菜单的 “MSYS2 MinGW x64”,运行下面命令构建项目目录。
1
2
3
cd ../..
mkdir H-third-party-library
cd H-third-party-library
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cmake_minimum_required(VERSION 3.5)

# Set the project name
project(third_party_include)

# find a boost install with the libraries filesystem and system
find_package(Boost 1.46.1 REQUIRED COMPONENTS filesystem system)

# check if boost was found
if(Boost_FOUND)
message("boost found")
else()
message(FATAL_ERROR "Cannot find Boost")
endif()

# Add an executable
add_executable(third_party_include main.cpp)

# link against the boost libraries
target_link_libraries(third_party_include
PRIVATE
Boost::filesystem
)
  1. 创建 main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/filesystem.hpp>

int main(int argc, char *argv[])
{
std::cout << "Hello Third Party Include!" << std::endl;

// use a shared ptr
boost::shared_ptr<int> isp(new int(4));

// trivial use of boost filesystem
boost::filesystem::path path = "/usr/share/cmake/modules";
if(path.is_relative())
{
std::cout << "Path is relative" << std::endl;
}
else
{
std::cout << "Path is not relative" << std::endl;
}

return 0;
}
Introduction

几乎所有重要的项目都需要包含第三方库、头文件或程序。CMake 支持使用 find_package() 函数查找这些工具的路径。这将从 CMAKE_MODULE_PATH 中的文件夹列表中搜索格式为 FindXXX.cmakeCMake 模块。在 linux 上,默认搜索路径将包括 /usr/share/cmake/Modules

本教程中的文件如下:

1
2
3
4
5
6
7
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/H-third-party-library
$ tree
.
├── CMakeLists.txt
└── main.cpp

0 directories, 2 files
  • CMakeLists.txt: CMake 的配置文件。

  • main.cpp: main 文件。

Requirements

此示例要求 boost 安装在默认系统位置。

1
pacman -S mingw-w64-x86_64-boost
Concepts
Finding a Package

As mentioned above the find_package() function will search for CMake modules in the formant “FindXXX.cmake” from the list of folders in CMAKE_MODULE_PATH. The exact format of the arguments to find_package will depend on the module you are looking for. This is typically documented at the top of the FindXXX.cmake file.

A basic example of finding boost is below:

1
find_package(Boost 1.46.1 REQUIRED COMPONENTS filesystem system)

The arguments are:

  • Boost - Name of the library. This is part of used to find the module file FindBoost.cmake.

  • 1.46.1 - The minimum version of boost to find.

  • REQUIRED - Tells the module that this is required and to fail if it cannot be found.

  • COMPONENTS - The list of components to find in the library.

Boost includes can take more arguments and also make use of other variables.

Checking if the package is found

Most included packages will set a variable XXX_FOUND, which can be used to check if the package is available on the system.

In this example the variable is Boost_FOUND:

1
2
3
4
5
6
if(Boost_FOUND)
message ("boost found")
include_directories(${Boost_INCLUDE_DIRS})
else()
message (FATAL_ERROR "Cannot find Boost")
endif()
Exported Variables

After a package is found it will often export variables which can inform the user where to find the library, header, or executable files. Similar to the XXX_FOUND variable, these are package specific and are typically documented at the top of the FindXXX.cmake file.

The variables exported in this example include:

  • Boost_INCLUDE_DIRS - The path to the boost header files.

In some cases you can also check these variables by examining the cache using ccmake or cmake-gui.

Alias / Imported targets

Most modern CMake libraries export ALIAS targets in their module files. The benefit of imported targets are that they can also populate include directories and linked libraries.

For example, starting from v3.5+ of CMake, the Boost module supports this. Similar to using your own ALIAS target for libraires, an ALIAS in a module can make referencing found targets easier.

In the case of Boost, all targets are exported using the Boost:: identifier and then the name of the subsystem. For example you can use:

  • Boost::boost for header only libraries

  • Boost::system for the boost system library.

  • Boost::filesystem for filesystem library.

As with your own targets, these targets include their dependencies, so linking against Boost::filesystem will automatically add Boost::boost and Boost::system dependencies.

To link against an imported target you can use the following:

1
2
3
4
target_link_libraries(third_party_include
PRIVATE
Boost::filesystem
)
Non-alias targets

While most modern libraries use imported targets, not all modules have been updated. In the case where a library hasn’t been updated you will often find the following variables available:

  • xxx_INCLUDE_DIRS - A variable pointing to the include directory for the library.

  • xxx_LIBRARY - A variable pointing to the library path.

These can then be added to your target_include_directories and target_link_libraries as:

1
2
3
4
5
6
7
8
9
10
11
# Include the boost headers
target_include_directories( third_party_include
PRIVATE ${Boost_INCLUDE_DIRS}
)

# link against the boost libraries
target_link_libraries( third_party_include
PRIVATE
${Boost_SYSTEM_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
)
Building the Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/H-third-party-library
$ mkdir build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/H-third-party-library
$ cd build/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/H-third-party-library/build
$ cmake .. -G "MSYS Makefiles"
-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found Boost: D:/lyf_computer_language/msys64/mingw64/include (found suitable version "1.79.0", minimum required is "1.46.1") found components: filesystem system
boost found
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/01-basic/H-third-party-library/build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/H-third-party-library/build
$ make
[ 50%] Building CXX object CMakeFiles/third_party_include.dir/main.cpp.obj
[100%] Linking CXX executable third_party_include.exe
[100%] Built target third_party_include

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/H-third-party-library/build
$ ls
cmake_install.cmake CMakeFiles third_party_include.exe
CMakeCache.txt Makefile

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/H-third-party-library/build
$ ./third_party_include.exe
Hello Third Party Include!
Path is relative

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/H-third-party-library/build
$

I-compiling-with-clang

Files
  1. 运行开始菜单的 “MSYS2 MSYS”,安装 Clang toolchain
1
2
pacman -S --needed base-devel mingw-w64-clang-x86_64-toolchain
pacman -S cmake
  1. 运行开始菜单的 “MSYS2 MinGW Clang x64”,运行下面命令构建项目目录。
1
2
3
cd /f/vscode/cpp_projects/cmake-examples/01-basic/
mkdir I-compiling-with-clang
cd I-compiling-with-clang
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
# Set the minimum version of CMake that can be used
# To find the cmake version run
# $ cmake --version
cmake_minimum_required(VERSION 3.5)

# Set the project name
project(hello_cmake)

# Add an executable
add_executable(hello_cmake main.cpp)
  1. 创建 main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
#include <iostream>

int main(int argc, char *argv[])
{
std::cout << "Hello CMake!" << std::endl;
return 0;
}
Introduction

使用 CMake 构建时,可以设置 CC++ 编译器。

本教程中的文件如下:

1
2
3
4
5
6
7
lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/01-basic/I-compiling-with-clang
$ tree
.
├── CMakeLists.txt
└── main.cpp

0 directories, 2 files
  • CMakeLists.txt: CMake 的配置文件。

  • main.cpp: main 文件。

Concepts
Compiler Option

CMake exposes options to control the programs used to compile and link your code. These programs include:

  • CMAKE_C_COMPILER - The program used to compile c code.

  • CMAKE_CXX_COMPILER - The program used to compile c++ code.

  • CMAKE_LINKER - The program used to link your binary.

Setting Flags

As described in the Build Type example, you can set CMake options using either a cmake gui or by passing from the command line.

Below is an example of passing the compiler via the command line.

1
cmake .. -DCMAKE_C_COMPILER=clang-3.6 -DCMAKE_CXX_COMPILER=clang++-3.6

After setting these options, when your run make clang will be used to compile your binary.

Building the Examples
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/01-basic/I-compiling-with-clang
$ mkdir build.clang

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/01-basic/I-compiling-with-clang
$ cd build.clang/

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/01-basic/I-compiling-with-clang/build.clang
$ cmake .. -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
-- The C compiler identification is Clang 14.0.4
-- The CXX compiler identification is Clang 14.0.4
System is unknown to cmake, create:
Platform/MINGW64_NT-10.0-19044 to use this system, please post your config file on discourse.cmake.org so it can be added to cmake
-- Detecting C compiler ABI info
System is unknown to cmake, create:
Platform/MINGW64_NT-10.0-19044 to use this system, please post your config file on discourse.cmake.org so it can be added to cmake
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /clang64/bin/clang.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
System is unknown to cmake, create:
Platform/MINGW64_NT-10.0-19044 to use this system, please post your config file on discourse.cmake.org so it can be added to cmake
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /clang64/bin/clang++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /f/vscode/cpp_projects/cmake-examples/01-basic/I-compiling-with-clang/build.clang

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/01-basic/I-compiling-with-clang/build.clang
$ make
[ 50%] Building CXX object CMakeFiles/hello_cmake.dir/main.cpp.obj
[100%] Linking CXX executable hello_cmake
[100%] Built target hello_cmake

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/01-basic/I-compiling-with-clang/build.clang
$ ls
cmake_install.cmake CMakeCache.txt CMakeFiles hello_cmake.exe Makefile

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/01-basic/I-compiling-with-clang/build.clang
$ ./hello_cmake.exe
Hello CMake!

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/01-basic/I-compiling-with-clang/build.clang
$

J-building-with-ninja

Files
  1. 运行开始菜单的 “MSYS2 MinGW x64”,运行下面命令构建项目目录。
1
2
3
cd /f/vscode/cpp_projects/cmake-examples/01-basic/
mkdir J-building-with-ninja
cd J-building-with-ninja
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
# Set the minimum version of CMake that can be used
# To find the cmake version run
# $ cmake --version
cmake_minimum_required(VERSION 3.5)

# Set the project name
project(hello_cmake)

# Add an executable
add_executable(hello_cmake main.cpp)
  1. 创建 main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
#include <iostream>

int main(int argc, char *argv[])
{
std::cout << "Hello CMake!" << std::endl;
return 0;
}
Introduction

As mentioned, CMake is a meta-build system that can be used to create the build files for many other build tools. This example shows how to have CMake use the ninja build tool.

The files in this tutorial are below:

1
2
3
4
5
6
7
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/J-building-with-ninja
$ tree
.
├── CMakeLists.txt
└── main.cpp

0 directories, 2 files
  • CMakeLists.txt - Contains the CMake commands you wish to run.

  • main.cpp - A simple “Hello World” cpp file.

Concepts
Generators

CMake generators are responsible for writing the input files (e.g. Makefiles) for the underlying build system. Running cmake --help will show the generators available.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/J-building-with-ninja
$ cmake --help
Usage

cmake [options] <path-to-source>
cmake [options] <path-to-existing-build>
cmake [options] -S <path-to-source> -B <path-to-build>

Specify a source directory to (re-)generate a build system for it in the
current working directory. Specify an existing build directory to
re-generate its build system.

Options
-S <path-to-source> = Explicitly specify a source directory.
-B <path-to-build> = Explicitly specify a build directory.
-C <initial-cache> = Pre-load a script to populate the cache.
-D <var>[:<type>]=<value> = Create or update a cmake cache entry.
-U <globbing_expr> = Remove matching entries from CMake cache.
-G <generator-name> = Specify a build system generator.
-T <toolset-name> = Specify toolset name if supported by
generator.
-A <platform-name> = Specify platform name if supported by
generator.
--toolchain <file> = Specify toolchain file
[CMAKE_TOOLCHAIN_FILE].
--install-prefix <directory> = Specify install directory
[CMAKE_INSTALL_PREFIX].
-Wdev = Enable developer warnings.
-Wno-dev = Suppress developer warnings.
-Werror=dev = Make developer warnings errors.
-Wno-error=dev = Make developer warnings not errors.
-Wdeprecated = Enable deprecation warnings.
-Wno-deprecated = Suppress deprecation warnings.
-Werror=deprecated = Make deprecated macro and function warnings
errors.
-Wno-error=deprecated = Make deprecated macro and function warnings
not errors.
--preset <preset>,--preset=<preset>
= Specify a configure preset.
--list-presets = List available presets.
-E = CMake command mode.
-L[A][H] = List non-advanced cached variables.
--build <dir> = Build a CMake-generated project binary tree.

--install <dir> = Install a CMake-generated project binary
tree.
--open <dir> = Open generated project in the associated
application.
-N = View mode only.
-P <file> = Process script mode.
--find-package = Legacy pkg-config like mode. Do not use.
--graphviz=[file] = Generate graphviz of dependencies, see
CMakeGraphVizOptions.cmake for more.
--system-information [file] = Dump information about this system.
--log-level=<ERROR|WARNING|NOTICE|STATUS|VERBOSE|DEBUG|TRACE>
= Set the verbosity of messages from CMake
files. --loglevel is also accepted for
backward compatibility reasons.
--log-context = Prepend log messages with context, if given
--debug-trycompile = Do not delete the try_compile build tree.
Only useful on one try_compile at a time.
--debug-output = Put cmake in a debug mode.
--debug-find = Put cmake find in a debug mode.
--debug-find-pkg=<pkg-name>[,...]
= Limit cmake debug-find to the
comma-separated list of packages
--debug-find-var=<var-name>[,...]
= Limit cmake debug-find to the
comma-separated list of result variables
--trace = Put cmake in trace mode.
--trace-expand = Put cmake in trace mode with variable
expansion.
--trace-format=<human|json-v1>
= Set the output format of the trace.
--trace-source=<file> = Trace only this CMake file/module. Multiple

options allowed.
--trace-redirect=<file> = Redirect trace output to a file instead of
stderr.
--warn-uninitialized = Warn about uninitialized values.
--no-warn-unused-cli = Don't warn about command line options.
--check-system-vars = Find problems with variable usage in system
files.
--profiling-format=<fmt> = Output data for profiling CMake scripts.
Supported formats: google-trace
--profiling-output=<file> = Select an output path for the profiling data

enabled through --profiling-format.
--help,-help,-usage,-h,-H,/? = Print usage information and exit.
--version,-version,/V [<f>] = Print version number and exit.
--help-full [<f>] = Print all help manuals and exit.
--help-manual <man> [<f>] = Print one help manual and exit.
--help-manual-list [<f>] = List help manuals available and exit.
--help-command <cmd> [<f>] = Print help for one command and exit.
--help-command-list [<f>] = List commands with help available and exit.
--help-commands [<f>] = Print cmake-commands manual and exit.
--help-module <mod> [<f>] = Print help for one module and exit.
--help-module-list [<f>] = List modules with help available and exit.
--help-modules [<f>] = Print cmake-modules manual and exit.
--help-policy <cmp> [<f>] = Print help for one policy and exit.
--help-policy-list [<f>] = List policies with help available and exit.
--help-policies [<f>] = Print cmake-policies manual and exit.
--help-property <prop> [<f>] = Print help for one property and exit.
--help-property-list [<f>] = List properties with help available and
exit.
--help-properties [<f>] = Print cmake-properties manual and exit.
--help-variable var [<f>] = Print help for one variable and exit.
--help-variable-list [<f>] = List variables with help available and exit.

--help-variables [<f>] = Print cmake-variables manual and exit.

Generators

The following generators are available on this platform (* marks default):
Visual Studio 17 2022 = Generates Visual Studio 2022 project files.
Use -A option to specify architecture.
Visual Studio 16 2019 = Generates Visual Studio 2019 project files.
Use -A option to specify architecture.
Visual Studio 15 2017 [arch] = Generates Visual Studio 2017 project files.
Optional [arch] can be "Win64" or "ARM".
Visual Studio 14 2015 [arch] = Generates Visual Studio 2015 project files.
Optional [arch] can be "Win64" or "ARM".
Visual Studio 12 2013 [arch] = Generates Visual Studio 2013 project files.
Optional [arch] can be "Win64" or "ARM".
Visual Studio 11 2012 [arch] = Generates Visual Studio 2012 project files.
Optional [arch] can be "Win64" or "ARM".
Visual Studio 10 2010 [arch] = Deprecated. Generates Visual Studio 2010
project files. Optional [arch] can be
"Win64" or "IA64".
Visual Studio 9 2008 [arch] = Generates Visual Studio 2008 project files.
Optional [arch] can be "Win64" or "IA64".
Borland Makefiles = Generates Borland makefiles.
NMake Makefiles = Generates NMake makefiles.
NMake Makefiles JOM = Generates JOM makefiles.
MSYS Makefiles = Generates MSYS makefiles.
MinGW Makefiles = Generates a make file for use with
mingw32-make.
Green Hills MULTI = Generates Green Hills MULTI files
(experimental, work-in-progress).
Unix Makefiles = Generates standard UNIX makefiles.
* Ninja = Generates build.ninja files.
Ninja Multi-Config = Generates build-<Config>.ninja files.
Watcom WMake = Generates Watcom WMake makefiles.
CodeBlocks - MinGW Makefiles = Generates CodeBlocks project files.
CodeBlocks - NMake Makefiles = Generates CodeBlocks project files.
CodeBlocks - NMake Makefiles JOM
= Generates CodeBlocks project files.
CodeBlocks - Ninja = Generates CodeBlocks project files.
CodeBlocks - Unix Makefiles = Generates CodeBlocks project files.
CodeLite - MinGW Makefiles = Generates CodeLite project files.
CodeLite - NMake Makefiles = Generates CodeLite project files.
CodeLite - Ninja = Generates CodeLite project files.
CodeLite - Unix Makefiles = Generates CodeLite project files.
Eclipse CDT4 - NMake Makefiles
= Generates Eclipse CDT 4.0 project files.
Eclipse CDT4 - MinGW Makefiles
= Generates Eclipse CDT 4.0 project files.
Eclipse CDT4 - Ninja = Generates Eclipse CDT 4.0 project files.
Eclipse CDT4 - Unix Makefiles= Generates Eclipse CDT 4.0 project files.
Kate - MinGW Makefiles = Generates Kate project files.
Kate - NMake Makefiles = Generates Kate project files.
Kate - Ninja = Generates Kate project files.
Kate - Unix Makefiles = Generates Kate project files.
Sublime Text 2 - MinGW Makefiles
= Generates Sublime Text 2 project files.
Sublime Text 2 - NMake Makefiles
= Generates Sublime Text 2 project files.
Sublime Text 2 - Ninja = Generates Sublime Text 2 project files.
Sublime Text 2 - Unix Makefiles
= Generates Sublime Text 2 project files.


lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/J-building-with-ninja
$
Calling a Generator

To call a CMake generator you can use the -G command line switch, for example:

1
cmake .. -G Ninja

After doing the above CMake will generate the required Ninja build files, which can be run from using the ninja command.

1
2
3
4
$ cmake .. -G Ninja

$ ls
build.ninja CMakeCache.txt CMakeFiles cmake_install.cmake rules.ninja
Building the Examples

Below is sample output from building this example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/J-building-with-ninja
$ mkdir build.ninja

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/J-building-with-ninja
$ cd build.ninja/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/J-building-with-ninja/build.ninja
$ cmake .. -G Ninja
-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/01-basic/J-building-with-ninja/build.ninja

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/J-building-with-ninja/build.ninja
$ ninja
[2/2] Linking CXX executable hello_cmake.exe

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/J-building-with-ninja/build.ninja
$ ls
build.ninja CMakeCache.txt hello_cmake.exe
cmake_install.cmake CMakeFiles

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/J-building-with-ninja/build.ninja
$ ./hello_cmake.exe
Hello CMake!

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/J-building-with-ninja/build.ninja
$

K-imported-targets

Files
  1. 运行开始菜单的 “MSYS2 MinGW x64”,运行下面命令构建项目目录。
1
2
3
cd /f/vscode/cpp_projects/cmake-examples/01-basic/
mkdir K-imported-targets
cd K-imported-targets
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cmake_minimum_required(VERSION 3.5)

# Set the project name
project(imported_targets)

# find a boost install with the libraries filesystem and system
find_package(Boost 1.46.1 REQUIRED COMPONENTS filesystem system)

# check if boost was found
if(Boost_FOUND)
message("boost found")
else()
message(FATAL_ERROR "Cannot find Boost")
endif()

# Add an executable
add_executable(imported_targets main.cpp)

# link against the boost libraries
target_link_libraries(imported_targets
PRIVATE
Boost::filesystem
)
  1. 创建 main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/filesystem.hpp>

int main(int argc, char *argv[])
{
std::cout << "Hello Third Party Include!" << std::endl;

// use a shared ptr
boost::shared_ptr<int> isp(new int(4));

// trivial use of boost filesystem
boost::filesystem::path path = "/usr/share/cmake/modules";
if(path.is_relative())
{
std::cout << "Path is relative" << std::endl;
}
else
{
std::cout << "Path is not relative" << std::endl;
}

return 0;
}
Introduction

As previously mentioned in the third party library, newer versions of CMake allow you to link third party libraries using imported ALIAS targets.

The files in this tutorial are below:

1
2
3
4
5
6
7
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/K-imported-targets
$ tree
.
├── CMakeLists.txt
└── main.cpp

0 directories, 2 files
  • CMakeLists.txt - Contains the CMake commands you wish to run.

  • main.cpp - The source file with main.

Requirements

This example requires the following:

  • CMake v3.5+

  • The boost libraries to be installed in a default system location.

1
pacman -S mingw-w64-x86_64-boost
Concepts
Imported Target

Imported targets are read-only targets that are exported by FindXXX modules.

To include boost filesystem you can do the following:

1
2
3
4
target_link_libraries( imported_targets
PRIVATE
Boost::filesystem
)

Linking against Boost::filesystem will automatically add Boost::boost and Boost::system dependencies.

Building the Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/K-imported-targets
$ mkdir build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/K-imported-targets
$ cd build/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/K-imported-targets/build
$ cmake .. -G "MSYS Makefiles"
-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found Boost: D:/lyf_computer_language/msys64/mingw64/include (found suitable version "1.79.0", minimum required is "1.46.1") found components: filesystem system
boost found
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/01-basic/K-imported-targets/build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/K-imported-targets/build
$ make
[ 50%] Building CXX object CMakeFiles/imported_targets.dir/main.cpp.obj
[100%] Linking CXX executable imported_targets.exe
[100%] Built target imported_targets

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/K-imported-targets/build
$ ls
cmake_install.cmake CMakeFiles Makefile
CMakeCache.txt imported_targets.exe

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/K-imported-targets/build
$ ./imported_targets.exe
Hello Third Party Include!
Path is relative

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/K-imported-targets/build
$

L-cpp-standard

Since the release of C++11 and C++14 a common use case is to invoke the compiler to use these standards. As CMake has evolved, it has added features to make this easier and new versions of CMake have changed how this is achieved.

The following examples show different methods of setting the C++ standard and what versions of CMake they are available from.

The examples include:

  • common-method - A simple version that should work with most versions of CMake.

  • cxx-standard - Using the CMAKE_CXX_STANDARD variable introduced in CMake v3.1.

  • compile-features - Using the target_compile_features function introduced in CMake v3.1.

i-common-method
Files
  1. 运行开始菜单的 “MSYS2 MinGW x64”,运行下面命令构建项目目录。
1
2
3
4
5
cd /f/vscode/cpp_projects/cmake-examples/01-basic/
mkdir L-cpp-standard
cd L-cpp-standard
mkdir i-common-method
cd i-common-method
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Set the minimum version of CMake that can be used
# To find the cmake version run
# $ cmake --version
cmake_minimum_required(VERSION 2.8)

# Set the project name
project(hello_cpp11)

# try conditional compilation
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)

# check results and add flag
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

# Add an executable
add_executable(hello_cpp11 main.cpp)
  1. 创建 main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
#include <iostream>

int main(int argc, char *argv[])
{
auto message = "Hello C++11";
std::cout << message << std::endl;
return 0;
}
Introduction

This example shows a common method to set the C++ Standard. This can be used with most versions of CMake. However, if you are targeting a recent version of CMake there are more convenient methods available.

The files in this tutorial are below:

1
2
3
4
5
6
7
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method
$ tree
.
├── CMakeLists.txt
└── main.cpp

0 directories, 2 files
  • CMakeLists.txt - Contains the CMake commands you wish to run.

  • main.cpp - A simple “Hello World” cpp file targeting C++11.

Concepts

Checking Compile flags

CMake has support for attempting to compile a program with any flags you pass into the function CMAKE_CXX_COMPILER_FLAG. The result is then stored in a variable that you pass in.

For example:

1
2
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)

This example will attempt to compile a program with the flag -std=c++11 and store the result in the variable COMPILER_SUPPORTS_CXX11.

The line include(CheckCXXCompilerFlag) tells CMake to include this function to make it available for use.

Adding the flag

Once you have determined if the compile supports a flag, you can then use the standard cmake methods to add this flag to a target. In this example we use the CMAKE_CXX_FLAGS to propegate the flag to all targets.

1
2
3
4
5
6
7
if(COMPILER_SUPPORTS_CXX11)#
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)#
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

The above example only checks for the gcc version of the compile flags and supports fallback from C++11 to the pre-standardisation C+\+0x flag. In real usage you may want to check for C14, or add support for different methods of setting the compile, e.g. -std=gnu11.

Building the Examples

Below is sample output from building this example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method
$ mkdir build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method
$ cd build/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build
$ cmake .. -G "MSYS Makefiles"
CMake Deprecation Warning at CMakeLists.txt:4 (cmake_minimum_required):
Compatibility with CMake < 2.8.12 will be removed from a future version of
CMake.

Update the VERSION argument <min> value or use a ...<max> suffix to tell
CMake that the project does not need compatibility with older versions.


-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Performing Test COMPILER_SUPPORTS_CXX11
-- Performing Test COMPILER_SUPPORTS_CXX11 - Success
-- Performing Test COMPILER_SUPPORTS_CXX0X
-- Performing Test COMPILER_SUPPORTS_CXX0X - Success
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build
$ make VERBOSE=1
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -S/F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method -B/F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build --check-build-system CMakeFiles/Makefile.cmake 0
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_progress_start /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build/CMakeFiles /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build//CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build”
make -f CMakeFiles/hello_cpp11.dir/build.make CMakeFiles/hello_cpp11.dir/depend
make[2]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build”
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_depends "MSYS Makefiles" /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build/CMakeFiles/hello_cpp11.dir/DependInfo.cmake --color=
make[2]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build”
make -f CMakeFiles/hello_cpp11.dir/build.make CMakeFiles/hello_cpp11.dir/build
make[2]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build”
[ 50%] Building CXX object CMakeFiles/hello_cpp11.dir/main.cpp.obj
/D/lyf_computer_language/msys64/mingw64/bin/c++.exe -std=c++11 -MD -MT CMakeFiles/hello_cpp11.dir/main.cpp.obj -MF CMakeFiles/hello_cpp11.dir/main.cpp.obj.d -o CMakeFiles/hello_cpp11.dir/main.cpp.obj -c /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/main.cpp
[100%] Linking CXX executable hello_cpp11.exe
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E rm -f CMakeFiles/hello_cpp11.dir/objects.a
/D/lyf_computer_language/msys64/mingw64/bin/ar.exe qc CMakeFiles/hello_cpp11.dir/objects.a "CMakeFiles/hello_cpp11.dir/main.cpp.obj"
/D/lyf_computer_language/msys64/mingw64/bin/c++.exe -std=c++11 -Wl,--whole-archive CMakeFiles/hello_cpp11.dir/objects.a -Wl,--no-whole-archive -o hello_cpp11.exe -Wl,--out-implib,libhello_cpp11.dll.a -Wl,--major-image-version,0,--minor-image-version,0 -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
make[2]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build”
[100%] Built target hello_cpp11
make[1]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build”
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_progress_start /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build/CMakeFiles 0

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build
$ ls
cmake_install.cmake CMakeCache.txt CMakeFiles hello_cpp11.exe Makefile

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build
$ ./hello_cpp11.exe
Hello C++11

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/i-common-method/build
$
ii-cxx-standard
Files
  1. 运行开始菜单的 “MSYS2 MinGW x64”,运行下面命令构建项目目录。
1
2
3
cd /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/
mkdir ii-cxx-standard
cd ii-cxx-standard
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
# Set the minimum version of CMake that can be used
# To find the cmake version run
# $ cmake --version
cmake_minimum_required(VERSION 3.1)

# Set the project name
project(hello_cpp11)

# Set the C++ standard to C++ 11
set(CMAKE_CXX_STANDARD 11)

# Add an executable
add_executable(hello_cpp11 main.cpp)
  1. 创建 main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
#include <iostream>

int main(int argc, char *argv[])
{
auto message = "Hello C++11";
std::cout << message << std::endl;
return 0;
}
Introduction

This example shows how to set the C++ standard using the CMAKE_CXX_STANDARD variable. This is available since CMake v3.1.

The files in this tutorial are below:

1
2
3
4
5
6
7
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard
$ tree
.
├── CMakeLists.txt
└── main.cpp

0 directories, 2 files
  • CMakeLists.txt - Contains the CMake commands you wish to run.

  • main.cpp - A simple “Hello World” cpp file targeting C++11.

Concepts

Using CXX_STANDARD property

Setting the CMAKE_CXX_STANDARD variable causes the CXX_STANDARD property on all targets. This causes CMake to set the appropriate flag at compille time.

The CMAKE_CXX_STANDARD variable falls back to the closest appropriate standard without a failure. For example, if you request -std=gnu11 you may end up with -std=gnu0x.

This can result in an unexpected failure at compile time.

Building the Examples

Below is sample output from building this example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard
$ mkdir build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard
$ cd build/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build
$ cmake .. -G "MSYS Makefiles"
-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build
$ make VERBOSE=1
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -S/F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard -B/F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build --check-build-system CMakeFiles/Makefile.cmake 0
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_progress_start /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build/CMakeFiles /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build//CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build”
make -f CMakeFiles/hello_cpp11.dir/build.make CMakeFiles/hello_cpp11.dir/depend
make[2]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build”
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_depends "MSYS Makefiles" /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build/CMakeFiles/hello_cpp11.dir/DependInfo.cmake --color=
make[2]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build”
make -f CMakeFiles/hello_cpp11.dir/build.make CMakeFiles/hello_cpp11.dir/build
make[2]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build”
[ 50%] Building CXX object CMakeFiles/hello_cpp11.dir/main.cpp.obj
/D/lyf_computer_language/msys64/mingw64/bin/c++.exe -std=gnu++11 -MD -MT CMakeFiles/hello_cpp11.dir/main.cpp.obj -MF CMakeFiles/hello_cpp11.dir/main.cpp.obj.d -o CMakeFiles/hello_cpp11.dir/main.cpp.obj -c /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/main.cpp
[100%] Linking CXX executable hello_cpp11.exe
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E rm -f CMakeFiles/hello_cpp11.dir/objects.a
/D/lyf_computer_language/msys64/mingw64/bin/ar.exe qc CMakeFiles/hello_cpp11.dir/objects.a "CMakeFiles/hello_cpp11.dir/main.cpp.obj"
/D/lyf_computer_language/msys64/mingw64/bin/c++.exe -Wl,--whole-archive CMakeFiles/hello_cpp11.dir/objects.a -Wl,--no-whole-archive -o hello_cpp11.exe -Wl,--out-implib,libhello_cpp11.dll.a -Wl,--major-image-version,0,--minor-image-version,0 -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
make[2]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build”
[100%] Built target hello_cpp11
make[1]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build”
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_progress_start /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build/CMakeFiles 0

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build
$ ls
cmake_install.cmake CMakeCache.txt CMakeFiles hello_cpp11.exe Makefile

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build
$ ./hello_cpp11.exe
Hello C++11

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/ii-cxx-standard/build
$
iii-compile-features
Files
  1. 运行开始菜单的 “MSYS2 MinGW x64”,运行下面命令构建项目目录。
1
2
3
cd /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/
mkdir iii-compile-features
cd iii-compile-features
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Set the minimum version of CMake that can be used
# To find the cmake version run
# $ cmake --version
cmake_minimum_required(VERSION 3.1)

# Set the project name
project(hello_cpp11)

# Add an executable
add_executable(hello_cpp11 main.cpp)

# set the C++ standard to the appropriate standard for using auto
target_compile_features(hello_cpp11 PUBLIC cxx_auto_type)

# Print the list of known compile features for this version of CMake
message("List of compile features: ${CMAKE_CXX_COMPILE_FEATURES}")
  1. 创建 main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
#include <iostream>

int main(int argc, char *argv[])
{
auto message = "Hello C++11";
std::cout << message << std::endl;
return 0;
}
Introduction

This example shows how to set the C++ standard using the target_compile_features function. This is available since CMake v3.1.

The files in this tutorial are below:

1
2
3
4
5
6
7
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features
$ tree
.
├── CMakeLists.txt
└── main.cpp

0 directories, 2 files
  • CMakeLists.txt - Contains the CMake commands you wish to run.

  • main.cpp - A simple “Hello World” cpp file targeting C++11.

Concepts

Using target_compile_features

Calling the target_compile_features function on a target will look at the passed in feature and determine the correct compiler flag to use for your target.

1
target_compile_features(hello_cpp11 PUBLIC cxx_auto_type)

As with other target_* functions, you can specify the scope of the feature for the selected target. This populates the INTERFACE_COMPILE_FEATURES property for the target.

The list of available features can be found from the CMAKE_CXX_COMPILE_FEATURES variable. You can obtain a list of the available features using the following code:

1
message("List of compile features: ${CMAKE_CXX_COMPILE_FEATURES}")
Building the Examples

Below is sample output from building this example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features
$ mkdir build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features
$ cd build/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build
$ cmake .. -G "MSYS Makefiles"
-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
List of compile features: cxx_std_98;cxx_template_template_parameters;cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates;cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates;cxx_std_17;cxx_std_20;cxx_std_23
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build
$ make VERBOSE=1
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -S/F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features -B/F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build --check-build-system CMakeFiles/Makefile.cmake 0
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_progress_start /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build/CMakeFiles /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build//CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build”
make -f CMakeFiles/hello_cpp11.dir/build.make CMakeFiles/hello_cpp11.dir/depend
make[2]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build”
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_depends "MSYS Makefiles" /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build/CMakeFiles/hello_cpp11.dir/DependInfo.cmake --color=
make[2]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build”
make -f CMakeFiles/hello_cpp11.dir/build.make CMakeFiles/hello_cpp11.dir/build
make[2]: 进入目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build”
[ 50%] Building CXX object CMakeFiles/hello_cpp11.dir/main.cpp.obj
/D/lyf_computer_language/msys64/mingw64/bin/c++.exe -MD -MT CMakeFiles/hello_cpp11.dir/main.cpp.obj -MF CMakeFiles/hello_cpp11.dir/main.cpp.obj.d -o CMakeFiles/hello_cpp11.dir/main.cpp.obj -c /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/main.cpp
[100%] Linking CXX executable hello_cpp11.exe
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E rm -f CMakeFiles/hello_cpp11.dir/objects.a
/D/lyf_computer_language/msys64/mingw64/bin/ar.exe qc CMakeFiles/hello_cpp11.dir/objects.a "CMakeFiles/hello_cpp11.dir/main.cpp.obj"
/D/lyf_computer_language/msys64/mingw64/bin/c++.exe -Wl,--whole-archive CMakeFiles/hello_cpp11.dir/objects.a -Wl,--no-whole-archive -o hello_cpp11.exe -Wl,--out-implib,libhello_cpp11.dll.a -Wl,--major-image-version,0,--minor-image-version,0 -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
make[2]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build”
[100%] Built target hello_cpp11
make[1]: 离开目录“/f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build”
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_progress_start /F/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build/CMakeFiles 0

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build
$ ls
cmake_install.cmake CMakeCache.txt CMakeFiles hello_cpp11.exe Makefile

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build
$ ./hello_cpp11.exe
Hello C++11

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/01-basic/L-cpp-standard/iii-compile-features/build
$

02-sub-projects

Many large projects are made up of different libraries and binaries. These can be organised into multiple folders and sub-projects to ease development.

The examples included are

  • basic - This basic example includes a static library, a header only library and an executable.

A-basic

Files
  1. 运行开始菜单的 “MSYS2 MinGW x64”,运行下面命令构建项目目录。
1
2
3
4
5
cd /f/vscode/cpp_projects/cmake-examples/
mkdir 02-sub-projects
cd 02-sub-projects
mkdir A-basic
cd A-basic
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
cmake_minimum_required(VERSION 3.5)

project(subprojects)

# Add sub directories
add_subdirectory(sublibrary1)
add_subdirectory(sublibrary2)
add_subdirectory(subbinary)
  1. 创建 subbinary/CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
project(subbinary)

# Create the executable
add_executable(${PROJECT_NAME} main.cpp)

# Link the static library from subproject1 using its alias sub::lib1
# Link the header only library from subproject2 using its alias sub::lib2
# This will cause the include directories for that target to be added to this project
target_link_libraries(${PROJECT_NAME}
sub::lib1
sub::lib2
)
  1. 创建 subbinary/main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "sublib1/sublib1.h"
#include "sublib2/sublib2.h"

int main(int argc, char *argv[])
{
sublib1 hi;
hi.print();

sublib2 howdy;
howdy.print();

return 0;
}
  1. 创建 sublibrary1/CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
# Set the project name
project(sublibrary1)

# Add a library with the above sources
add_library(${PROJECT_NAME} src/sublib1.cpp)
add_library(sub::lib1 ALIAS ${PROJECT_NAME})

target_include_directories(${PROJECT_NAME}
PUBLIC ${PROJECT_SOURCE_DIR}/include
)
  1. 创建 sublibrary1/include/sublib1/sublib1.h 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
#ifndef __SUBLIB_1_H__
#define __SUBLIB_1_H__

class sublib1
{
public:
void print();
};

#endif
  1. 创建 sublibrary1/src/sublib1.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
#include <iostream>

#include "sublib1/sublib1.h"

void sublib1::print()
{
std::cout << "Hello sub-library 1!" << std::endl;
}
  1. 创建 sublibrary2/CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
# Set the project name
project(sublibrary2)

add_library(${PROJECT_NAME} INTERFACE)
add_library(sub::lib2 ALIAS ${PROJECT_NAME})

target_include_directories(${PROJECT_NAME}
INTERFACE
${PROJECT_SOURCE_DIR}/include
)
  1. 创建 sublibrary2/include/sublib2/sublib2.h 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef __SUBLIB_2_H__
#define __SUBLIB_2_H__

#include <iostream>

class sublib2
{
public:
void print()
{
std::cout << "Hello header only sub-library 2!" << std::endl;
}
};

#endif
Introduction

This example shows how to setup a CMake project that includes sub-projects. The top level CMakeLists.txt calls the CMakeLists.txt in the sub directories to create the following:

  • sublibrary1 - A static library

  • sublibrary2 - A header only library

  • subbinary - An executable

The files included in this example are:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/02-sub-projects/A-basic
$ tree
.
├── CMakeLists.txt
├── subbinary
│   ├── CMakeLists.txt
│   └── main.cpp
├── sublibrary1
│   ├── CMakeLists.txt
│   ├── include
│   │   └── sublib1
│   │   └── sublib1.h
│   └── src
│   └── sublib1.cpp
└── sublibrary2
├── CMakeLists.txt
└── include
└── sublib2
└── sublib2.h

8 directories, 8 files
  • CMakeLists.txt - Top level CMakeLists.txt

  • subbinary/CMakeLists.txt - to make the executable

  • subbinary/main.cpp - source for the executable

  • sublibrary1/CMakeLists.txt - to make a static library

  • sublibrary1/include/sublib1/sublib1.h - The header file of the static library

  • sublibrary1/src/sublib1.cpp - The source file of the static library

  • sublibrary2/CMakeLists.txt - to setup header only library

  • sublibrary2/include/sublib2/sublib2.h - The header file of the header only library

In this example I have moved the header files to a subfolder under each projects include directory, while leaving the target include as the root include folder. This is a good idea to prevent filename clashes because you have to include a file like below:

1
#include "sublib1/sublib1.h"

This also means that if you install your library for other users the default install location would be /usr/local/include/sublib1/sublib1.h.

Concepts
Adding a Sub-Directory

A CMakeLists.txt file can include and call sub-directories which include a CMakeLists.txt files.

1
2
3
add_subdirectory(sublibrary1)
add_subdirectory(sublibrary2)
add_subdirectory(subbinary)
Referencing Sub-Project Directories

When a project is created using the project() command, CMake will automatically create a number of variables which can be used to reference details about the project. These variables can then be used by other sub-projects or the main project. For example, to reference the source directory for a different project you can use.

1
2
${sublibrary1_SOURCE_DIR}
${sublibrary2_SOURCE_DIR}

The variables created by CMake include:

Variable Info
PROJECT_NAME The name of the project set by the current project().
CMAKE_PROJECT_NAME the name of the first project set by the project() command, i.e. the top level project.
PROJECT_SOURCE_DIR The source directory of the current project.
PROJECT_BINARY_DIR The build directory for the current project.
name_SOURCE_DIR The source directory of the project called “name”. In this example the source directories created would be sublibrary1_SOURCE_DIR, sublibrary2_SOURCE_DIR, and subbinary_SOURCE_DIR.
name_BINARY_DIR The binary directory of the project called “name”. In this example the binary directories created would be sublibrary1_BINARY_DIR, sublibrary2_BINARY_DIR, and subbinary_BINARY_DIR.
Header only Libraries

If you have a library that is created as a header only library, cmake supports the INTERFACE target to allow creating a target without any build output.

1
add_library(${PROJECT_NAME} INTERFACE)

When creating the target you can also include directories for that target using the INTERFACE scope. The INTERFACE scope is use to make target requirements that are used in any Libraries that link this target but not in the compilation of the target itself.

1
2
3
4
target_include_directories(${PROJECT_NAME}
INTERFACE
${PROJECT_SOURCE_DIR}/include
)
Referencing Libraries from Sub-Projects

If a sub-project creates a library, it can be referenced by other projects by calling the name of the target in the target_link_libraries() command. This means that you don’t have to reference the full path of the new library and it is added as a dependency.

1
2
3
4
target_link_libraries(subbinary
PUBLIC
sublibrary1
)

Alternatively, you can create an alias target which allows you to reference the target in read only contexts.

To create an alias target run:

1
2
add_library(sublibrary2)
add_library(sub::lib2 ALIAS sublibrary2)

To reference the alias, just it as follows:

1
2
3
target_link_libraries(subbinary
sub::lib2
)
Include directories from sub-projects

When adding the libraries from the sub-projects, starting from cmake v3, there is no need to add the projects include directories in the include directories of the binary using them.

This is controlled by the scope in the target_include_directories() command when creating the libraries. In this example because the subbinary executable links the sublibrary1 and sublibrary2 libraries it will automatically include the ${sublibrary1_SOURCE_DIR}/include and ${sublibrary2_SOURCE_DIR}/include folders as they are exported with the PUBLIC and INTERFACE scopes of the libraries.

Building the example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/02-sub-projects/A-basic
$ mkdir build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/02-sub-projects/A-basic
$ cd build/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/02-sub-projects/A-basic/build
$ cmake .. -G "MSYS Makefiles"
-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/02-sub-projects/A-basic/build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/02-sub-projects/A-basic/build
$ make
[ 25%] Building CXX object sublibrary1/CMakeFiles/sublibrary1.dir/src/sublib1.cpp.obj
[ 50%] Linking CXX static library libsublibrary1.a
[ 50%] Built target sublibrary1
[ 75%] Building CXX object subbinary/CMakeFiles/subbinary.dir/main.cpp.obj
[100%] Linking CXX executable subbinary.exe
[100%] Built target subbinary

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/02-sub-projects/A-basic/build
$ ls
cmake_install.cmake CMakeFiles subbinary sublibrary2
CMakeCache.txt Makefile sublibrary1

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/02-sub-projects/A-basic/build
$ cd subbinary/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/02-sub-projects/A-basic/build/subbinary
$ ls
cmake_install.cmake CMakeFiles Makefile subbinary.exe

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/02-sub-projects/A-basic/build/subbinary
$ ./subbinary.exe
Hello sub-library 1!
Hello header only sub-library 2!

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/02-sub-projects/A-basic/build/subbinary
$

03-code-generation

Code generation can be useful to create source code in different languages from a common description file. This can reduce the amount of manual code to write and increase interoperability.

Examples showing code generation using variables from CMake and also using some common tools.

  • configure-file - Using the CMake configure_file function to inject CMake variables.

  • Protocol Buffers - Using Google Protocol Buffers to generate C++ source.

configure-files

Files
  1. 运行开始菜单的 “MSYS2 MinGW x64”,运行下面命令构建项目目录。
1
2
3
4
5
cd /f/vscode/cpp_projects/cmake-examples/
mkdir 03-code-generation
cd 03-code-generation/
mkdir configure-files
cd configure-files/
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
cmake_minimum_required(VERSION 3.5)

# Set the project name
project(cf_example)

# Set a project version
set(cf_example_VERSION_MAJOR 0)
set(cf_example_VERSION_MINOR 2)
set(cf_example_VERSION_PATCH 1)
set(cf_example_VERSION "${cf_example_VERSION_MAJOR}.${cf_example_VERSION_MINOR}.${cf_example_VERSION_PATCH}")

# Call configure files on ver.h.in to set the version.
# Uses the standard ${VARIABLE} syntax in the file
configure_file(ver.h.in ${PROJECT_BINARY_DIR}/ver.h)

# configure the path.h.in file.
# This file can only use the @VARIABLE@ syntax in the file
configure_file(path.h.in ${PROJECT_BINARY_DIR}/path.h @ONLY)

# Add an executable
add_executable(cf_example
main.cpp
)

# include the directory with the new files
target_include_directories(cf_example
PUBLIC
${CMAKE_BINARY_DIR}
)
  1. 创建 main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include "ver.h"
#include "path.h"

int main(int argc, char *argv[])
{
std::cout << "Hello Version " << ver << "!" << std::endl;
std::cout << "Path is " << path << std::endl;
return 0;
}
  1. 创建 path.h.in 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
#ifndef __PATH_H__
#define __PATH_H__

// version variable that will be substituted by cmake
// This shows an example using the @ variable type
const char* path = "@CMAKE_SOURCE_DIR@";

#endif
  1. 创建 ver.h.in 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
#ifndef __VER_H__
#define __VER_H__

// version variable that will be substituted by cmake
// This shows an example using the $ variable type
const char* ver = "${cf_example_VERSION}";

#endif
Introduction

During the call to cmake it is possible to create files that use variables from the CMakeLists.txt and cmake cache. During CMake generation the file is copied to a new location and any cmake variables are replaced.

The files in this tutorial are below:

1
2
3
4
5
6
7
8
9
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/configure-files
$ tree
.
├── CMakeLists.txt
├── main.cpp
├── path.h.in
└── ver.h.in

0 directories, 4 files
  • CMakeLists.txt - Contains the CMake commands you wish to run

  • main.cpp - The source file with main

  • path.h.in - File to contain a path to the build directory

  • ver.h.in - File to contain the version of the project

Concepts
Configure Files

To do variable substitution in a file you can use the configure_file() function in CMake. This core arguments for this function are source file and destination file.

1
2
3
configure_file(ver.h.in ${PROJECT_BINARY_DIR}/ver.h)

configure_file(path.h.in ${PROJECT_BINARY_DIR}/path.h @ONLY)

The first example above, allows the variable to be defined like a CMake variables using the ${} syntax or an @@ in the ver.h.in file. After generation a new file ver.h will be available in the PROJECT_BINARY_DIR.

1
const char* ver = "${cf_example_VERSION}";

The second example, only allows variables to be defined using the @@ syntax in the path.h.in file. After generation a new file path.h will be available in the PROJECT_BINARY_DIR.

1
const char* path = "@CMAKE_SOURCE_DIR@";
Building the Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/configure-files
$ mkdir build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/configure-files
$ cd build/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/configure-files/build
$ cmake .. -G "MSYS Makefiles"
-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/03-code-generation/configure-files/build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/configure-files/build
$ ls
cmake_install.cmake CMakeCache.txt CMakeFiles Makefile path.h ver.h

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/configure-files/build
$ cat path.h
#ifndef __PATH_H__
#define __PATH_H__

// version variable that will be substituted by cmake
// This shows an example using the @ variable type
const char* path = "F:/vscode/cpp_projects/cmake-examples/03-code-generation/configure-files";

#endif

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/configure-files/build
$ cat ver.h
#ifndef __VER_H__
#define __VER_H__

// version variable that will be substituted by cmake
// This shows an example using the $ variable type
const char* ver = "0.2.1";

#endif

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/configure-files/build
$ make
[ 50%] Building CXX object CMakeFiles/cf_example.dir/main.cpp.obj
[100%] Linking CXX executable cf_example.exe
[100%] Built target cf_example

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/configure-files/build
$ ls
cf_example.exe CMakeCache.txt Makefile ver.h
cmake_install.cmake CMakeFiles path.h

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/configure-files/build
$ ./cf_example.exe
Hello Version 0.2.1!
Path is F:/vscode/cpp_projects/cmake-examples/03-code-generation/configure-files

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/configure-files/build
$

protobuf

Files
  1. 运行开始菜单的 “MSYS2 MinGW x64”,运行下面命令构建项目目录。
1
2
3
cd /f/vscode/cpp_projects/cmake-examples/03-code-generation/
mkdir protobuf
cd protobuf/
  1. 创建 AddressBook.proto 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package tutorial;

message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;

enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}

message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}

repeated PhoneNumber phone = 4;
}

message AddressBook {
repeated Person person = 1;
}
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
cmake_minimum_required(VERSION 3.5)

# Set the project name
project (protobuf_example)

# find the protobuf compiler and libraries
find_package(Protobuf REQUIRED)

# check if protobuf was found
if(PROTOBUF_FOUND)
message ("protobuf found")
else()
message (FATAL_ERROR "Cannot find Protobuf")
endif()

# Generate the .h and .cxx files
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS AddressBook.proto)

# Print path to generated files
message ("PROTO_SRCS = ${PROTO_SRCS}")
message ("PROTO_HDRS = ${PROTO_HDRS}")

# Add an executable
add_executable(protobuf_example
main.cpp
${PROTO_SRCS}
${PROTO_HDRS})

target_include_directories(protobuf_example
PUBLIC
${PROTOBUF_INCLUDE_DIRS}
${CMAKE_CURRENT_BINARY_DIR}
)

# link the exe against the libraries
target_link_libraries(protobuf_example
PUBLIC
${PROTOBUF_LIBRARIES}
)
  1. 创建 main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <iostream>
#include <fstream>
#include <string>
#include "AddressBook.pb.h"
using namespace std;

// This function fills in a Person message based on user input.
void PromptForAddress(tutorial::Person* person) {
cout << "Enter person ID number: ";
int id;
cin >> id;
person->set_id(id);
cin.ignore(256, '\n');

cout << "Enter name: ";
getline(cin, *person->mutable_name());

cout << "Enter email address (blank for none): ";
string email;
getline(cin, email);
if (!email.empty()) {
person->set_email(email);
}

while (true) {
cout << "Enter a phone number (or leave blank to finish): ";
string number;
getline(cin, number);
if (number.empty()) {
break;
}

tutorial::Person::PhoneNumber* phone_number = person->add_phone();
phone_number->set_number(number);

cout << "Is this a mobile, home, or work phone? ";
string type;
getline(cin, type);
if (type == "mobile") {
phone_number->set_type(tutorial::Person::MOBILE);
} else if (type == "home") {
phone_number->set_type(tutorial::Person::HOME);
} else if (type == "work") {
phone_number->set_type(tutorial::Person::WORK);
} else {
cout << "Unknown phone type. Using default." << endl;
}
}
}

// Main function: Reads the entire address book from a file,
// adds one person based on user input, then writes it back out to the same
// file.
int main(int argc, char* argv[]) {
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;

if (argc != 2) {
cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
return -1;
}

tutorial::AddressBook address_book;

{
// Read the existing address book.
fstream input(argv[1], ios::in | ios::binary);
if (!input) {
cout << argv[1] << ": File not found. Creating a new file." << endl;
} else if (!address_book.ParseFromIstream(&input)) {
cerr << "Failed to parse address book." << endl;
return -1;
}
}

// Add an address.
PromptForAddress(address_book.add_person());

{
// Write the new address book back to disk.
fstream output(argv[1], ios::out | ios::trunc | ios::binary);
if (!address_book.SerializeToOstream(&output)) {
cerr << "Failed to write address book." << endl;
return -1;
}
}

// Optional: Delete all global objects allocated by libprotobuf.
google::protobuf::ShutdownProtobufLibrary();

return 0;
}
Introduction

This example shows how to generate source files using protobuf. Protocol Buffers is a data serialization format from Google. A user provides a .proto file with a description of the data. Then using the protobuf compiler, the proto file can be translated into source code in a number of languages including C++.

The files in this tutorial are below:

1
2
3
4
5
6
7
8
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf
$ tree
.
├── AddressBook.proto
├── CMakeLists.txt
└── main.cpp

0 directories, 3 files
  • AddressBook.proto - proto file from main protocol buffer example

  • CMakeLists.txt - Contains the CMake commands you wish to run

  • main.cpp - The source file from the protobuf example.

Requirements

This example requires the protocol buffers binary and libraries to be installed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
lyf@DESKTOP-GV2QHKN MSYS ~
$ pacman -S mingw-w64-x86_64-protobuf mingw-w64-x86_64-protobuf-c protobuf-de
vel
正在解析依赖关系...
正在查找软件包冲突...

软件包 (4) protobuf-3.16.0-1 mingw-w64-x86_64-protobuf-3.16.0-3
mingw-w64-x86_64-protobuf-c-1.3.3-2 protobuf-devel-3.16.0-1

全部安装大小: 58.05 MiB

:: 进行安装吗? [Y/n]
(4/4) 正在检查密钥环里的密钥 [##################] 100%
(4/4) 正在检查软件包完整性 [##################] 100%
(4/4) 正在加载软件包文件 [##################] 100%
(4/4) 正在检查文件冲突 [##################] 100%
(4/4) 正在检查可用存储空间 [##################] 100%
:: 正在处理软件包的变化...
(1/4) 正在安装 mingw-w64-x86_64-protobuf [##################] 100%
(2/4) 正在安装 mingw-w64-x86_64-protobuf-c [##################] 100%
(3/4) 正在安装 protobuf [##################] 100%
(4/4) 正在安装 protobuf-devel [##################] 100%

lyf@DESKTOP-GV2QHKN MSYS ~
$ pacman -Ss protobuf
mingw32/mingw-w64-i686-protobuf 3.16.0-3
Protocol Buffers - Google's data interchange format (mingw-w64)
mingw32/mingw-w64-i686-protobuf-c 1.3.3-2
Protocol Buffers implementation in C (mingw-w64)
mingw32/mingw-w64-i686-python-protobuf 3.16.0-3
Protocol Buffers (mingw-w64)
mingw64/mingw-w64-x86_64-protobuf 3.16.0-3 [已安装]
Protocol Buffers - Google's data interchange format (mingw-w64)
mingw64/mingw-w64-x86_64-protobuf-c 1.3.3-2 [已安装]
Protocol Buffers implementation in C (mingw-w64)
mingw64/mingw-w64-x86_64-python-protobuf 3.16.0-3
Protocol Buffers (mingw-w64)
ucrt64/mingw-w64-ucrt-x86_64-protobuf 3.16.0-3
Protocol Buffers - Google's data interchange format (mingw-w64)
ucrt64/mingw-w64-ucrt-x86_64-protobuf-c 1.3.3-2
Protocol Buffers implementation in C (mingw-w64)
ucrt64/mingw-w64-ucrt-x86_64-python-protobuf 3.16.0-3
Protocol Buffers (mingw-w64)
clang32/mingw-w64-clang-i686-protobuf 3.16.0-3
Protocol Buffers - Google's data interchange format (mingw-w64)
clang32/mingw-w64-clang-i686-protobuf-c 1.3.3-2
Protocol Buffers implementation in C (mingw-w64)
clang32/mingw-w64-clang-i686-python-protobuf 3.16.0-3
Protocol Buffers (mingw-w64)
clang64/mingw-w64-clang-x86_64-protobuf 3.16.0-3
Protocol Buffers - Google's data interchange format (mingw-w64)
clang64/mingw-w64-clang-x86_64-protobuf-c 1.3.3-2
Protocol Buffers implementation in C (mingw-w64)
clang64/mingw-w64-clang-x86_64-python-protobuf 3.16.0-3
Protocol Buffers (mingw-w64)
msys/protobuf 3.16.0-1 (libraries) [已安装]
Protocol Buffers - Google's data interchange format
msys/protobuf-devel 3.16.0-1 (development) [已安装]
Protobuf headers and libraries

lyf@DESKTOP-GV2QHKN MSYS ~
$
Concepts
Exported Variables

The variables exported by the CMake protobuf package and used in this example include:

  • PROTOBUF_FOUND - If Protocol Buffers is installed

  • PROTOBUF_INCLUDE_DIRS - The protobuf header files

  • PROTOBUF_LIBRARIES - The protobuf library

More variables are defined and can be found by examining the documentation at the top of your FindProtobuf.cmake file.

Generating Source

The protobuf CMake package includes a number of helper functions to make the code generation easier. In this example we are generating C++ source and use the following code:

1
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS AddressBook.proto)

The arguments are:

  • PROTO_SRCS - Name of the variable that will store the .pb.cc files.

  • PROTO_HDRS - Name of the variable that will store the .pb.h files.

  • AddressBook.proto - The .proto file to generate code from.

Generated Files

After the PROTOBUF_GENERATE_CPP function is called, you will have the above mentioned variables available. These will be marked as the output to a custom command which calls the protobuf compiler binary to generate them.

To then have the files generated you should add them to a library or executable. For example:

1
2
3
4
add_executable(protobuf_example
main.cpp
${PROTO_SRCS}
${PROTO_HDRS})

This will cause the protobuf compiler to be called when you call make on that executables target.

When changes are made to the .proto file, the associated source files will be autogenerated again. However, if no changes are made to the .proto file and you re-run make, then nothing will be done.

Building the Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf
$ mkdir build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf
$ cd build/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build
$ cmake .. -G "MSYS Makefiles"
-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found Protobuf: D:/lyf_computer_language/msys64/mingw64/lib/libprotobuf.dll.a (found version "3.16.0")
protobuf found
PROTO_SRCS = F:/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build/AddressBook.pb.cc
PROTO_HDRS = F:/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build/AddressBook.pb.h
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build
$ ls
cmake_install.cmake CMakeCache.txt CMakeFiles Makefile

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build
$ make VERBOSE=1
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -S/F/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf -B/F/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build --check-build-system CMakeFiles/Makefile.cmake 0
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_progress_start /F/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build/CMakeFiles /F/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build//CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: 进入目录“/f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build”
make -f CMakeFiles/protobuf_example.dir/build.make CMakeFiles/protobuf_example.dir/depend
make[2]: 进入目录“/f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build”
[ 25%] Running cpp protocol buffer compiler on AddressBook.proto
/D/lyf_computer_language/msys64/mingw64/bin/protoc.exe --cpp_out F:/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build -I F:/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf F:/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/AddressBook.proto
[libprotobuf WARNING C:/_/M/mingw-w64-protobuf/src/build-x86_64-shared/src/google/protobuf/compiler/parser.cc:651] No syntax specified for the proto file: AddressBook.proto. Please use 'syntax = "proto2";' or 'syntax = "proto3";' to specify a syntax version. (Defaulted to proto2 syntax.)
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_depends "MSYS Makefiles" /F/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf /F/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf /F/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build /F/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build /F/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build/CMakeFiles/protobuf_example.dir/DependInfo.cmake --color=
make[2]: 离开目录“/f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build”
make -f CMakeFiles/protobuf_example.dir/build.make CMakeFiles/protobuf_example.dir/build
make[2]: 进入目录“/f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build”
[ 50%] Building CXX object CMakeFiles/protobuf_example.dir/main.cpp.obj
/D/lyf_computer_language/msys64/mingw64/bin/c++.exe -I/F/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build -MD -MT CMakeFiles/protobuf_example.dir/main.cpp.obj -MF CMakeFiles/protobuf_example.dir/main.cpp.obj.d -o CMakeFiles/protobuf_example.dir/main.cpp.obj -c /F/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/main.cpp
[ 75%] Building CXX object CMakeFiles/protobuf_example.dir/AddressBook.pb.cc.obj
/D/lyf_computer_language/msys64/mingw64/bin/c++.exe -I/F/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build -MD -MT CMakeFiles/protobuf_example.dir/AddressBook.pb.cc.obj -MF CMakeFiles/protobuf_example.dir/AddressBook.pb.cc.obj.d -o CMakeFiles/protobuf_example.dir/AddressBook.pb.cc.obj -c /F/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build/AddressBook.pb.cc
[100%] Linking CXX executable protobuf_example.exe
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E rm -f CMakeFiles/protobuf_example.dir/objects.a
/D/lyf_computer_language/msys64/mingw64/bin/ar.exe qc CMakeFiles/protobuf_example.dir/objects.a "CMakeFiles/protobuf_example.dir/main.cpp.obj" "CMakeFiles/protobuf_example.dir/AddressBook.pb.cc.obj"
/D/lyf_computer_language/msys64/mingw64/bin/c++.exe -Wl,--whole-archive CMakeFiles/protobuf_example.dir/objects.a -Wl,--no-whole-archive -o protobuf_example.exe -Wl,--out-implib,libprotobuf_example.dll.a -Wl,--major-image-version,0,--minor-image-version,0 /D/lyf_computer_language/msys64/mingw64/lib/libprotobuf.dll.a -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32
make[2]: 离开目录“/f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build”
[100%] Built target protobuf_example
make[1]: 离开目录“/f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build”
/D/lyf_computer_language/msys64/mingw64/bin/cmake.exe -E cmake_progress_start /F/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build/CMakeFiles 0

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build
$ ls
AddressBook.pb.cc cmake_install.cmake CMakeFiles protobuf_example.exe
AddressBook.pb.h CMakeCache.txt Makefile

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build
$ ./protobuf_example.exe test.db
test.db: File not found. Creating a new file.
Enter person ID number: 1
Enter name: lyf
Enter email address (blank for none): xxx@qq.com
Enter a phone number (or leave blank to finish): 12345678901
Is this a mobile, home, or work phone? home
Enter a phone number (or leave blank to finish):

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build
$ ls
AddressBook.pb.cc cmake_install.cmake CMakeFiles protobuf_example.exe
AddressBook.pb.h CMakeCache.txt Makefile test.db

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build
$ cat test.db

$
lyf
xxx@qq.com"

12345678901
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build
$ ./protobuf_example.exe test.db
Enter person ID number: 2
Enter name: zhy
Enter email address (blank for none): xxx@qq.com
Enter a phone number (or leave blank to finish): 12345678902
Is this a mobile, home, or work phone? mobile
Enter a phone number (or leave blank to finish): 99999999999
Is this a mobile, home, or work phone? work
Enter a phone number (or leave blank to finish):

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build
$ ls
AddressBook.pb.cc cmake_install.cmake CMakeFiles protobuf_example.exe
AddressBook.pb.h CMakeCache.txt Makefile test.db

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build
$ cat test.db

$
lyf
xxx@qq.com"

12345678901
5
zhy
xxx@qq.com"

12345678902"

99999999999
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/03-code-generation/protobuf/build
$

04-static-analysis

Static analysis is the analysis of code without executing it. It can be used to find common programming errors and enforce coding guidelines. Examples of errors that can be found using static analysis tools include:

  • Out of bounds errors

  • Memory leaks

  • Usage of uninitialized variables

  • Use of unsafe functions

Analysis tools can detect errors early and are becoming a standard tool in most build chains. Some build tools such as Clang include a build in static analysis tool. However standalone tools also exist.

The examples here include using the following tools:

  • CppCheck

  • Clang Static Analyzer

  • Clang Format

clang-analyzer

Files
  1. 运行开始菜单的 “MSYS2 MSYS”,安装 Clang toolchain
1
2
pacman -S --needed base-devel mingw-w64-clang-x86_64-toolchain
pacman -S cmake
  1. 运行开始菜单的 “MSYS2 MinGW Clang x64”,运行下面命令构建项目目录。
1
2
3
4
5
cd /f/vscode/cpp_projects/cmake-examples/
mkdir 04-static-analysis
cd 04-static-analysis/
mkdir clang-analyzer
cd clang-analyzer/
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
cmake_minimum_required(VERSION 3.5)

project(cppcheck_analysis)

# Use debug build as recommended
set(CMAKE_BUILD_TYPE Debug)

# Have cmake create a compile database
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# Add sub directories
add_subdirectory(subproject1)
add_subdirectory(subproject2)
  1. 创建 subproject1/CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
# Set the project name
project(subproject1)

# Add an executable with the above sources
add_executable(${PROJECT_NAME} main1.cpp)
  1. 创建 subproject1/main1.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
#include <iostream>

int main(int argc, char *argv[])
{
std::cout << "Hello Main1!" << std::endl;
return 0;
}
  1. 创建 subproject2/CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
# Set the project name
project(subproject2)

# Add an executable with the above sources
add_executable(${PROJECT_NAME} main2.cpp)
  1. 创建 subproject2/main2.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
#include <iostream>

int main(int argc, char *argv[])
{
std::cout << "Hello Main2!" << std::endl;
int* x = NULL;
std::cout << *x << std::endl;
return 0;
}
Introduction

This example shows how to call the Clang Static Analyzer to do static analysis using the scan-build tool.

The files included in this example are:

1
2
3
4
5
6
7
8
9
10
11
12
lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer
$ tree
.
├── CMakeLists.txt
├── subproject1
│   ├── CMakeLists.txt
│   └── main1.cpp
└── subproject2
├── CMakeLists.txt
└── main2.cpp

2 directories, 5 files
  • CMakeLists.txt - Top level CMakeLists.txt

  • subproject1/CMakeLists.txt - CMake commands for subproject 1

  • subproject1/main1.cpp - source for a subproject with no errors

  • subproject2/CMakeLists.txt - CMake commands for subproject 2

  • subproject2/main2.cpp - source for a subproject that includes errors

Requirements

To run this example you must have clang analyzer and the scan-build tool installed.

1
pacman -S --needed base-devel mingw-w64-clang-x86_64-toolchain

It will result in the tool being available as:

1
2
3
lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer
$ which scan-build
/clang64/bin/scan-build
Concepts
scan-build

To run clang static analyzer you can use the tool scan-build to run the analyzer when you also run the compiler. This overrides the CC and CXX environment variables and replaces them with it’s own tools. To run it you can do

1
2
$ scan-build-3.6 cmake ..
$ scan-build-3.6 make

By default this will run the standard compiler for your platform, i.e. gcc on linux. However, if you want to override this you can change the command to:

1
$ scan-build-3.6 --use-cc=clang-3.6 --use-c++=clang++-3.6 -o ./scanbuildout/ make
scan-build output

scan-build will only output warnings during compile time and will also generate a list of HTML files which contain detailed analysis of the error.

1
2
3
4
5
6
7
8
9
10
$ cd scanbuildout/
$ tree
.
└── 2017-07-03-213514-3653-1
├── index.html
├── report-42eba1.html
├── scanview.css
└── sorttable.js

1 directory, 4 files

By default these are output to /tmp/scanbuildout/{run folder}. You can change this using scan-build -o /output/folder.

Building the example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer
$ mkdir build

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer
$ cd build/

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer/build
$ scan-build -o ./scanbuildout cmake ..
scan-build: Using '/clang64/bin/clang' for static analysis
-- The C compiler identification is Clang 14.0.4
-- The CXX compiler identification is Clang 14.0.4
System is unknown to cmake, create:
Platform/MINGW64_NT-10.0-19044 to use this system, please post your config file on discourse.cmake.org so it can be added to cmake
-- Detecting C compiler ABI info
System is unknown to cmake, create:
Platform/MINGW64_NT-10.0-19044 to use this system, please post your config file on discourse.cmake.org so it can be added to cmake
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /clang64/libexec/ccc-analyzer - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
System is unknown to cmake, create:
Platform/MINGW64_NT-10.0-19044 to use this system, please post your config file on discourse.cmake.org so it can be added to cmake
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /clang64/libexec/c++-analyzer - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer/build
scan-build: Analysis run complete.
scan-build: Removing directory '/f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer/build/scanbuildout/2022-08-12-144922-1147-1' because it contains no reports.
scan-build: No bugs found.

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer/build
$ scan-build -o ./scanbuildout make
scan-build: Using '/clang64/bin/clang' for static analysis
[ 25%] Building CXX object subproject1/CMakeFiles/subproject1.dir/main1.cpp.obj
[ 50%] Linking CXX executable subproject1
[ 50%] Built target subproject1
[ 75%] Building CXX object subproject2/CMakeFiles/subproject2.dir/main2.cpp.obj
[100%] Linking CXX executable subproject2
[100%] Built target subproject2
scan-build: Analysis run complete.
scan-build: Removing directory '/f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer/build/scanbuildout/2022-08-12-144942-1200-1' because it contains no reports.
scan-build: No bugs found.

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer/build
$ ls
cmake_install.cmake CMakeFiles Makefile subproject1
CMakeCache.txt compile_commands.json scanbuildout subproject2

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer/build
$ cd scanbuildout/

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer/build/scanbuildout
$ ls

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer/build/scanbuildout
$ cd ../subproject1

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer/build/subproject1
$ ls
cmake_install.cmake CMakeFiles Makefile subproject1.exe

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer/build/subproject1
$ ./subproject1.exe
Hello Main1!

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer/build/subproject1
$ cd ../subproject2

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer/build/subproject2
$ ls
cmake_install.cmake CMakeFiles Makefile subproject2.exe

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer/build/subproject2
$ ./subproject2.exe
Hello Main2!
Segmentation fault

lyf@DESKTOP-GV2QHKN CLANG64 /f/vscode/cpp_projects/cmake-examples/04-static-analysis/clang-analyzer/build/subproject2
$

06-installer

CMake has the ability to create installers for multiple platforms using a program called CPack. CPack includes the ability to create Linux RPM, deb and gzip distributions of both binaries and source code. It also includes the ability to create NSIS files for Microsoft Windows.

deb

Files
  1. 运行开始菜单的 “MSYS2 MinGW x64”,运行下面命令构建项目目录。
1
2
3
4
5
cd /f/vscode/cpp_projects/cmake-examples/
mkdir 06-installer
cd 06-installer/
mkdir deb
cd deb/
  1. 创建 cmake-examples.conf 文件,粘贴下面代码。
1
# Sample configuration file that could be installed
  1. 创建 CMakeLists.txt 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
cmake_minimum_required(VERSION 3.5)

project(cmake_examples_zip)

# set a project version
set(deb_example_VERSION_MAJOR 0)
set(deb_example_VERSION_MINOR 2)
set(deb_example_VERSION_PATCH 2)
set(deb_example_VERSION "${deb_example_VERSION_MAJOR}.${deb_example_VERSION_MINOR}.${deb_example_VERSION_PATCH}")

#######################################
# Create a library
#######################################

# Generate the shared library from the library sources
add_library(cmake_examples_zip SHARED src/Hello.cpp)

target_include_directories(cmake_examples_zip
PUBLIC
${PROJECT_SOURCE_DIR}/include
)

########################################
# Create an executable
########################################

# Add an executable with the above sources
add_executable(cmake_examples_zip_bin src/main.cpp)

# link the new hello_library target with the hello_binary target
target_link_libraries(cmake_examples_zip_bin
PUBLIC
cmake_examples_zip
)

###########################################
# Install
###########################################

# Binaries
install(TARGETS cmake_examples_zip_bin
DESTINATION bin)

# Library
# Note: may not work on windows
install(TARGETS cmake_examples_zip
LIBRARY DESTINATION lib)

# Config
install(FILES cmake-examples.conf
DESTINATION etc)

############################################
# Create DEB
############################################

# Tell CPack to generate a .deb package
set(CPACK_GENERATOR "ZIP")

# Set a Package Maintainer.
# This is required
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "luyanfeng")

# Set a Package Version
set(CPACK_PACKAGE_VERSION ${deb_example_VERSION})

# Include CPack
include(CPack)
  1. 创建 include/Hello.h 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
9
10
#ifndef __HELLO_H__
#define __HELLO_H__

class Hello
{
public:
void print();
};

#endif
  1. 创建 src/Hello.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
#include <iostream>

#include "Hello.h"

void Hello::print()
{
std::cout << "Hello Install!" << std::endl;
}
  1. 创建 src/main.cpp 文件,粘贴下面代码。
1
2
3
4
5
6
7
8
#include "Hello.h"

int main(int argc, char *argv[])
{
Hello hi;
hi.print();
return 0;
}
Introduction

This example shows how to generate a Linux installers using the ZIP format.

The files in this tutorial are below:

1
2
3
4
5
6
7
8
9
10
11
12
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/06-installer/deb
$ tree
.
├── cmake-examples.conf
├── CMakeLists.txt
├── include
│   └── Hello.h
└── src
├── Hello.cpp
└── main.cpp

2 directories, 5 files
  • CMakeLists.txt - Contains the CMake commands you wish to run

  • cmake-examples.conf - An example configuration file

  • include/Hello.h - The header file to include

  • src/Hello.cpp - A source file to compile

  • src/main.cpp - The source file with main

Requirements
1
2
pacman -S zip
pacman -S unzip
Concepts
CPack Generator

A CPack Generator can be used by a make package target to create an installer.

In the case of Debian packages you can tell CMake to create a generator using the following:

1
set(CPACK_GENERATOR "DEB")

After setting various settings to describe the package you must then tell CMake to include the CPack generator using

1
include(CPack)

Once included all files that would typically be installed using a make install target can now be packaged into a Debian package.

Debian Package Settings

Various settings for the package are exposed by CPack. In this example we set the following:

1
2
3
4
5
6
# Set a Package Maintainer.
# This is required
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Thom Troy")

# Set a Package Version
set(CPACK_PACKAGE_VERSION ${deb_example_VERSION})

Which sets the maintainer and version. More debian specific settings are specified below.

Variable Info
CPACK_DEBIAN_PACKAGE_MAINTAINER Maintainer information.
CPACK_PACKAGE_DESCRIPTION_SUMMARY Package short description.
CPACK_PACKAGE_DESCRIPTION Package description.
CPACK_DEBIAN_PACKAGE_DEPENDS For advanced users to add custom scripts.
CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA The build directory you are currently in.
CPACK_DEBIAN_PACKAGE_SECTION Package section (see here).
CPACK_DEBIAN_PACKAGE_VERSION Package version.
Building the Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/06-installer/deb
$ mkdir build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/06-installer/deb
$ cd build/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/06-installer/deb/build
$ cmake .. -G "MSYS Makefiles"
-- The C compiler identification is GNU 12.1.0
-- The CXX compiler identification is GNU 12.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: D:/lyf_computer_language/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/lyf_computer_language/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: F:/vscode/cpp_projects/cmake-examples/06-installer/deb/build

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/06-installer/deb/build
$ make help
The following are some of the valid targets for this Makefile:
... all (the default if no target is provided)
... clean
... depend
... edit_cache
... install
... install/local
... install/strip
... list_install_components
... package
... package_source
... rebuild_cache
... cmake_examples_zip
... cmake_examples_zip_bin
... src/Hello.obj
... src/Hello.i
... src/Hello.s
... src/main.obj
... src/main.i
... src/main.s

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/06-installer/deb/build
$ make package
[ 25%] Building CXX object CMakeFiles/cmake_examples_zip.dir/src/Hello.cpp.obj
[ 50%] Linking CXX shared library libcmake_examples_zip.dll
[ 50%] Built target cmake_examples_zip
[ 75%] Building CXX object CMakeFiles/cmake_examples_zip_bin.dir/src/main.cpp.obj
[100%] Linking CXX executable cmake_examples_zip_bin.exe
[100%] Built target cmake_examples_zip_bin
Run CPack packaging tool...
CPack: Create package using ZIP
CPack: Install projects
CPack: - Run preinstall target for: cmake_examples_zip
CPack: - Install project: cmake_examples_zip []
CPack: Create package
CPack: - package: F:/vscode/cpp_projects/cmake-examples/06-installer/deb/build/cmake_examples_zip-0.2.2-win64.zip generated.

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/06-installer/deb/build
$ ls
_CPack_Packages CPackConfig.cmake
cmake_examples_zip_bin.exe CPackSourceConfig.cmake
cmake_examples_zip-0.2.2-win64.zip install_manifest.txt
cmake_install.cmake libcmake_examples_zip.dll
CMakeCache.txt libcmake_examples_zip.dll.a
CMakeFiles Makefile

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/06-installer/deb/build
$ unzip cmake_examples_zip-0.2.2-win64.zip
Archive: cmake_examples_zip-0.2.2-win64.zip
creating: cmake_examples_zip-0.2.2-win64/bin/
inflating: cmake_examples_zip-0.2.2-win64/bin/cmake_examples_zip_bin.exe
inflating: cmake_examples_zip-0.2.2-win64/bin/libcmake_examples_zip.dll
creating: cmake_examples_zip-0.2.2-win64/etc/
inflating: cmake_examples_zip-0.2.2-win64/etc/cmake-examples.conf
creating: cmake_examples_zip-0.2.2-win64/lib/
inflating: cmake_examples_zip-0.2.2-win64/lib/libcmake_examples_zip.dll.a

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/06-installer/deb/build
$ ls
_CPack_Packages CPackConfig.cmake
cmake_examples_zip_bin.exe CPackSourceConfig.cmake
cmake_examples_zip-0.2.2-win64 install_manifest.txt
cmake_examples_zip-0.2.2-win64.zip libcmake_examples_zip.dll
cmake_install.cmake libcmake_examples_zip.dll.a
CMakeCache.txt Makefile
CMakeFiles

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/06-installer/deb/build
$ cd cmake_examples_zip-0.2.2-win64/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/06-installer/deb/build/cmake_examples_zip-0.2.2-win64
$ ls
bin etc lib

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/06-installer/deb/build/cmake_examples_zip-0.2.2-win64
$ cd bin/

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/06-installer/deb/build/cmake_examples_zip-0.2.2-win64/bin
$ ls
cmake_examples_zip_bin.exe libcmake_examples_zip.dll

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/06-installer/deb/build/cmake_examples_zip-0.2.2-win64/bin
$ ./cmake_examples_zip_bin.exe
Hello Install!

lyf@DESKTOP-GV2QHKN MINGW64 /f/vscode/cpp_projects/cmake-examples/06-installer/deb/build/cmake_examples_zip-0.2.2-win64/bin
$

结语

第二十二篇博文写完,开心!!!!

今天,也是充满希望的一天。