CMake Usage

CMake Usage

在我的 C++ 项目中,我更倾向于使用 CMake 而非 Make。这主要是因为 CMake 在整合第三方库时表现出了更高的便捷性,同时在项目维护方面也更为出色。下面简要介绍一下 CMake 的一些常用方法和特点:

  1. 跨平台构建系统:CMake 支持多平台,无论是 Windows、Linux 还是 MacOS,都可以使用相同的 CMake 文件来构建项目。
  2. 更易于管理依赖关系:当涉及到第三方库时,CMake 使得管理和链接这些库变得更加简单。通过简单的指令,可以轻松地将外部库集成到项目中。
  3. 易于维护和扩展:CMake 的脚本语言清晰明了,使得项目的维护和扩展变得更加容易。即便项目规模扩大,使用 CMake 也可以保持构建配置的清晰和简洁。
  4. 生成原生构建环境:CMake 能够为不同的编译器生成原生的构建文件。例如,它可以为 Visual Studio 生成解决方案文件,为 Make 生成 Makefile,这让开发者可以使用自己熟悉的工具进行构建。
  5. 灵活性和可配置性:CMake 允许用户编写复杂的构建脚本,这些脚本可以根据不同的平台和条件进行适当的调整和配置。

总结一下,CMake 由于其跨平台性、易于管理依赖关系、良好的可维护性和灵活性,成为了构建 C++ 项目的优选工具。对于希望简化构建过程并增强项目可维护性的开发者来说,学习并使用 CMake 是非常值得的。

CMake Third Part Library

C++ 生态中有许多功能强大的第三方库,比如 Abseil 和 argparse。然而,对于初学者来说,学习如何在 CMake 项目中正确调用这些库可能会有些挑战。以下是一个简单的指南,帮助您开始使用这些库:

Load Library

使用abseil当作例子来详细的解释一下,首先我们的CMakeLists.txt初始化如下:

1
2
3
4
5
6
cmake_minimum_required(VERSION 3.22)
project(test)

set(CMAKE_CXX_STANDARD 20)

add_executable(test main.cpp)

当我们想添加abseil可以进行一下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cmake_minimum_required(VERSION 3.22)
project(test)

set(CMAKE_CXX_STANDARD 20)

include(FetchContent)
FetchContent_Declare(
abseil
GIT_REPOSITORY https://github.com/abseil/abseil-cpp.git
)

set(ABSL_PROPAGATE_CXX_STD ON CACHE BOOL "Enable C++ standard propagation to Abseil targets" FORCE)

FetchContent_MakeAvailable(abseil)

add_executable(test main.cpp)

#目标链接中添加 absl
target_link_libraries(test absl::flat_hash_map)

FetchContent 是 CMake 3.11 及更高版本中引入的一个模块,旨在简化从外部源获取代码的过程。这个模块允许您在构建时下载或更新外部依赖项,而不需要预先下载这些依赖项或将它们包含在您的项目源代码中。这种方法对于管理外部库非常有用,特别是当这些库频繁更新或者有多个项目共享时。

  1. 声明外部内容:使用 FetchContent_Declare 函数,您可以指定要获取的外部内容。您需要提供一些细节,比如项目名称、源代码的位置(例如 Git 仓库)等。例如:

    1
    2
    3
    4
    FetchContent_Declare(
    abseil
    GIT_REPOSITORY https://github.com/abseil/abseil-cpp.git
    )
  2. 获取内容FetchContent_MakeAvailableFetchContent_GetPropertiesFetchContent_Populate 函数用于下载和更新声明的内容。当这些命令执行时,CMake 会检查是否已经下载了内容,如果没有,则会从指定的源获取它。

    1
    FetchContent_MakeAvailable(abseil)
  3. 集成到项目中:一旦内容被获取,它就可以被集成到您的项目中。通常,这意味着添加对应的子目录或链接库到您的项目中。

    1
    target_link_libraries(test absl::flat_hash_map)

添加完abseil的库之后我们就可以在项目中调用该库,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"

int main(int argc, char *argv[]) {
absl::flat_hash_map<int, int> map;
map[1] = 2;
map[2] = 3;

absl::flat_hash_set<int> set;
set.insert(1);
set.insert(2);
set.insert(1);

std::cout << "map[1] = " << map[1] << std::endl;
std::cout << "map[2] = " << map[2] << std::endl;

std::cout << "set size: " << set.size() << std::endl;

}

在上面的例子中我们调用了absl::flat_hash_mapabsl::flat_hash_set编译顺利通过,说明成功调用了该库。

CMake Subdirectory

在处理大型 C++ 项目时,有效地组织代码和文件夹结构是至关重要的。这不仅有助于保持项目的整洁,还能简化构建和维护过程。在这里,我们将讨论如何在 CMake 中添加子文件夹,并将必要的库链接到这些子文件夹中,以实现更好的项目结构和模块化。

按照上面的例子,我们把absl::flat_hash_map添加到一个单独的文件夹中,我们首先创建一个文件夹srcsrc文件夹下创建hash.cpphash.hCMakeLists.txt三个文件,内容分别如下:

hash.h

1
2
3
4
5
6
7
8
#ifndef TEST_HASH_H
#define TEST_HASH_H

#include "absl/container/flat_hash_map.h"

auto test_hash() -> void;

#endif //TEST_HASH_H

hash.cpp

1
2
3
4
5
6
7
8
9
10
#include "hash.h"

auto test_hash() -> void {
absl::flat_hash_map<int, int> map;
map[1] = 2;
map[2] = 3;

std::cout << "map[1] = " << map[1] << std::endl;
std::cout << "map[2] = " << map[2] << std::endl;
}

CMakeLists.txt

1
2
3
4
5
6
add_library(src
hash.h
hash.cpp
)

target_link_libraries(src PUBLIC absl::flat_hash_map)

这种在根目录下的CMakeLists.txt也需要简单修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
cmake_minimum_required(VERSION 3.22)
project(test)

set(CMAKE_CXX_STANDARD 20)

include(FetchContent)
FetchContent_Declare(
abseil
GIT_REPOSITORY https://github.com/abseil/abseil-cpp.git
)

set(ABSL_PROPAGATE_CXX_STD ON CACHE BOOL "Enable C++ standard propagation to Abseil targets" FORCE)

FetchContent_MakeAvailable(abseil)

add_subdirectory(src)

add_executable(test main.cpp)

target_link_libraries(test absl::flat_hash_map src)
  1. add_subdirectory(src): 这行命令告诉 CMake 在当前项目中添加一个子目录,这里是名为 src 的目录。CMake 会查找 src 目录下的 CMakeLists.txt 文件,并执行其中的命令。这种做法通常用于项目结构中的源代码组织,将不同的代码部分放在不同的目录中,有助于保持项目的整洁和模块化。
  2. add_executable(test main.cpp): 这个命令创建了一个名为 test 的可执行文件。main.cpp 是这个可执行文件的源文件。这行命令告诉 CMake 编译 main.cpp 并将生成的可执行文件命名为 test。通常,main.cpp 包含程序的入口点,即 main 函数。
  3. target_link_libraries(test absl::flat_hash_map src): 这行命令用于将库链接到您的目标可执行文件(这里是 test)上。这意味着它指定了构建 test 时需要使用的库。
    • absl::flat_hash_map:来自于 Abseil 库的组件,这里作为一个链接目标。它表明您的程序使用了 Abseil 中的 flat_hash_map 容器。
    • src:这是指在之前通过 add_subdirectory(src) 添加的子目录。假设 src 目录下的 CMakeLists.txt 中定义了一个库(例如静态库或共享库),则 src 代表该库。这样,test 可执行文件会链接该目录下定义的目标。
----- End Thanks for reading-----