CMake学习


Hello World

1
2
3
4
5
6
7
8
9
10
11
12
#CMakeLists.txt

#指定支持的最低CMake版本
cmake_minimum_required(VERSION 3.5)

#指定项目名称
project (hello_cmake)

#指定应从指定的源文件构建可执行文件
#一个参数是要构建的可执行文件的名称,第二个参数是要编译的源文件列表。
add_executable(hello_cmake main.cpp)
# 简写方式add_executable(${PROJECT_NAME} main.cpp)

使用单独的源文件和头文件

CMake 语法指定了一些可以帮助查找项目或源树中有用目录的变量。其中一些包括:

变量 含义
CMAKE_SOURCE_DIR 根源目录
CMAKE_CURRENT_SOURCE_DIR 当前源目录(如果使用子项目和目录)。
PROJECT_SOURCE_DIR 当前CMake项目的源目录。
CMAKE_BINARY_DIR 根二进制/构建目录。这是您运行cmake命令的目录。
CMAKE_CURRENT_BINARY_DIR 您当前所在的构建目录。
PROJECT_BINARY_DIR 当前项目的构建目录。

在运行make时添加VERBOSE标志,以查看完整的输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 指定支持的最低CMake版本
cmake_minimum_required(VERSION 3.5)

# 指定项目名称
project (hello_headers)

# 创建一个包含源文件的变量
set(SOURCES
src/Hello.cpp
src/main.cpp
)
# 设置 SOURCES变量中特定文件名的另一种替代方法是使用 GLOB 命令,通过通配符模式匹配来查找文件。
# file(GLOB SOURCES "src/*.cpp")

# 添加源文件
add_executable(hello_headers ${SOURCES})

# 设置包含目录
target_include_directories(hello_headers
PRIVATE
${PROJECT_SOURCE_DIR}/include
)

使用静态库

add_library()函数用于从一些源文件中创建一个库。

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

使用target_include_directories函数将目录包含在库中,作用域设置为PUBLIC

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

作用域的含义如下:

  • PRIVATE 该目录仅添加到此目标的包含目录
  • INTERFACE 该目录添加到任何链接此库的目标的包含目录
  • PUBLIC 如下所述,即包含在此库中,也包含在任何链接此库的目标中。
    对于公共头文件target_include_directories的目录将是包含目录树的根,您的C++文件应从该位置开始包含头文件路径。

在这个例子
使用这种方法可以减少项目中使用多个库时,头文件名称冲突的可能性。

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
# 指定支持的最低CMake版本
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
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
cmake_minimum_required(VERSION 3.5)

# 项目名称
project(hello_library)

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

#Generate the shared library from the library sources
# add_library函数用于从一些源文件创建共享库
add_library(hello_library SHARED
src/Hello.cpp
)

# 创建一个别名目标 hello::library,它指向实际的库目标 hello_library。
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_library()` 函数指向你的库。
target_link_libraries( hello_binary
PRIVATE
hello::library
)

make install

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

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
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
# 安装名为cmake_examples_inst_bin的可执行目标到指定的目标目录bin
install (TARGETS cmake_examples_inst_bin
DESTINATION bin)

# Library
# Note: may not work on windows
# 安装名为 cmake_examples_inst 的库目标到 lib 目录
install (TARGETS cmake_examples_inst
LIBRARY DESTINATION lib)

# Header files
# 将 include 目录下的所有头文件拷贝到安装目录的 include 目录中
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/
DESTINATION include)

# Config
# 将名为 cmake-examples.conf 的文件安装到 etc 目录
install (FILES cmake-examples.conf
DESTINATION etc)

设置默认构建和优化标志

CMake 具有多种内置的构建配置,可用于编译您的项目。这些配置指定了优化级别以及是否在二进制文件中包含调试信息。

提供的级别有:

  • Release - 添加 -O3 -DNDEBUG 标志到编译器
  • Debug - 添加 -g 标志
  • MinSizeRel - 添加 -Os -DNDEBUG 标志
  • RelWithDebInfo - 添加 -O2 -g -DNDEBUG 标志
    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
    # Set the minimum version of CMake that can be used
    # To find the cmake version run
    # $ cmake --version
    cmake_minimum_required(VERSION 3.5)

    # 检查是否没有指定构建类型(CMAKE_BUILD_TYPE),并且没有使用多配置生成器(如Visual Studio,使用CMAKE_CONFIGURATION_TYPES)。
    if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)

    # 输出消息,提示用户将构建类型设置为RelWithDebInfo,因为没有指定任何构建类型。
    message("Setting build type to 'RelWithDebInfo' as none was specified.")

    # 将构建类型设置为RelWithDebInfo,并将其缓存为一个字符串类型的变量。FORCE选项确保即使该变量之前被设置,也会被覆盖。
    set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)

    # 为CMake GUI设置构建类型的可能值,允许用户在GUI中选择。这里列出了Debug、Release、MinSizeRel和RelWithDebInfo四个选项。
    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
    "MinSizeRel" "RelWithDebInfo")

    endif()

    # 设置项目名称
    project (build_type)

    # 添加可执行文件
    add_executable(cmake_examples_build_type main.cpp)

设置额外的编译标志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
)

调用clang

CMake 提供选项来控制用于编译和链接代码的程序。这些程序包括:

  • CMAKE_C_COMPILER - 用于编译 C 代码的程序。

  • CMAKE_CXX_COMPILER - 用于编译 C++ 代码的程序。

  • CMAKE_LINKER - 用于链接二进制文件的程序。

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
2
3
4
5
6
7
8
9
10
#pre_test.sh
#!/bin/bash

ROOT_DIR=`pwd`
dir="01-basic/I-compiling-with-clang"

if [ -d "$ROOT_DIR/$dir/build.clang" ]; then
echo "deleting $dir/build.clang"
rm -r $dir/build.clang
fi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#run_tesh.sh
#!/bin/bash
# Ubuntu supports multiple versions of clang to be installed at the same time.
# The tests need to determine the clang binary before calling cmake
clang_bin=`which clang`
clang_xx_bin=`which clang++`

if [ -z $clang_bin ]; then
clang_ver=`dpkg --get-selections | grep clang | grep -v -m1 libclang | cut -f1 | cut -d '-' -f2`
clang_bin="clang-$clang_ver"
clang_xx_bin="clang++-$clang_ver"
fi

echo "Will use clang [$clang_bin] and clang++ [$clang_xx_bin]"


mkdir -p build.clang && cd build.clang && \
cmake .. -DCMAKE_C_COMPILER=$clang_bin -DCMAKE_CXX_COMPILER=$clang_xx_bin && make

生成ninja构建文件

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
2
3
4
5
6
7
8
9
10
#pre_test.sh
#!/bin/bash

ROOT_DIR=`pwd`
dir="01-basic/J-building-with-ninja"

if [ -d "$ROOT_DIR/$dir/build.ninja" ]; then
echo "deleting $dir/build.ninja"
rm -r $dir/build.ninja
fi
1
2
3
4
5
6
7
8
9
10
11
12
#run_tesh.sh
#!/bin/bash
# Travis-ci cmake version doesn't support ninja, so first check if it's supported
ninja_supported=`cmake --help | grep Ninja`

if [ -z $ninja_supported ]; then
echo "Ninja not supported"
exit
fi

mkdir -p build.ninja && cd build.ninja && \
cmake .. -G Ninja && ninja

导入目标链接Boost

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
2
3
4
5
6
7
8
9
10
11
12
13
#run_test.sh
#!/bin/bash
# Make sure we have the minimum cmake version
cmake_version=`cmake --version | grep version | cut -d" " -f3`

[[ "$cmake_version" =~ ([3-9][.][5-9.][.][0-9]) ]] || exit 0

echo "correct version of cmake"
mkdir -p build && cd build && cmake .. && make
if [ $? -ne 0 ]; then
echo "Error running example"
exit 1
fi

设置C++标准

1

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)

2

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)

3

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}")