CMake基础教程:Ubuntu新手必学的安装与初步使用技巧
发布时间: 2025-07-13 06:24:25 阅读量: 42 订阅数: 28 


ubuntu20.04 dpkg无网安装cmake

# 1. CMake简介及其在Ubuntu上的安装
## CMake简介
CMake(Cross Platform Make)是一个跨平台的自动化构建系统,它使用可读的配置文件来生成本地化的构建环境,如 Makefiles 或 Visual Studio 项目文件。CMake 针对 C 和 C++ 程序提供了强大的构建过程管理能力,是现代软件开发中构建复杂项目的标准工具之一。
## 安装 CMake 在 Ubuntu 上
在 Ubuntu 上安装 CMake 是一项简单的工作,可以通过系统的包管理器 `apt` 来完成。以下为安装步骤:
```sh
sudo apt update
sudo apt install cmake
```
安装完成后,你可以通过输入 `cmake --version` 来检查 CMake 是否正确安装,并验证安装的版本。
安装 CMake 后,你就可以开始创建你的第一个 CMake 项目了。CMake 通过一个名为 `CMakeLists.txt` 的配置文件来控制构建过程。这个文件会告诉 CMake 如何配置和生成目标文件,无论是可执行文件还是库文件。在接下来的章节中,我们将深入了解如何编写 `CMakeLists.txt` 文件,并利用 CMake 来构建和管理你的项目。
# 2. CMake的基本命令与构建系统概念
## 2.1 CMake的构建过程
### 2.1.1 CMakeLists.txt文件的基本结构
CMake构建过程的起点是 `CMakeLists.txt` 文件。这个文件包含了用于指定项目构建方式的指令集。一个基础的 `CMakeLists.txt` 包括以下几个部分:
- `cmake_minimum_required`:声明了CMake的最小版本要求。
- `project`:定义了项目的名称及其版本。
- `add_executable` 或 `add_library`:这些指令用于创建可执行文件或库文件。
- `target_link_libraries`:将目标文件链接到必要的库上。
这里是一个简单的 `CMakeLists.txt` 文件示例:
```cmake
cmake_minimum_required(VERSION 3.10)
project(MyExampleProject VERSION 1.0)
add_executable(MyExample main.cpp)
target_link_libraries(MyExample PRIVATE stdc++fs)
```
### 2.1.2 CMake的变量与缓存机制
CMake使用变量来存储信息,类似于其他编程语言。变量可以在命令间传递参数或存储系统路径等信息。例如:
```cmake
set(SOURCE_FILES main.cpp utils.cpp)
add_executable(MyExample ${SOURCE_FILES})
```
在CMake中也可以使用缓存变量(cache variables),这些变量存储在缓存中,具有默认值,并且用户可以在CMake配置过程中覆盖它们。例如:
```cmake
set(SOURCE_FILES main.cpp utils.cpp CACHE STRING "List of source files")
```
## 2.2 CMake的项目管理
### 2.2.1 添加子目录和模块化项目
随着项目规模的增长,模块化成为一种管理大型代码库的有效方式。CMake允许将项目分解为子项目或模块,并在顶层 `CMakeLists.txt` 中包含它们。使用 `add_subdirectory` 指令可以添加子目录:
```cmake
add_subdirectory(src)
```
### 2.2.2 定义和使用宏与函数
CMake中的宏(macro)和函数(function)允许代码复用。它们可以接受参数,并且宏与函数执行时拥有自己的作用域。函数与宏的区别在于返回值和变量作用域。函数有返回值,而宏没有。函数内部定义的变量不会泄漏到外部,而宏内部定义的变量是全局的。
定义一个宏的示例:
```cmake
macro(my_macro)
message("Hello from my_macro")
endmacro()
```
定义一个函数的示例:
```cmake
function(my_function)
message("Hello from my_function")
endfunction()
```
## 2.3 CMake的构建目标和生成器
### 2.3.1 构建目标类型及其配置
CMake支持多种构建目标类型,包括可执行文件和不同类型的库(静态库和共享库)。根据目标类型的不同,可以使用不同的构建配置选项来调整项目的构建特性。以下是一个创建静态库和共享库的例子:
```cmake
# 创建静态库
add_library(MyStaticLib STATIC utils.cpp)
# 创建共享库
add_library(MySharedLib SHARED utils.cpp)
```
### 2.3.2 选择不同的构建系统生成器
构建生成器是指CMake用来创建本地构建环境的工具链。例如,Unix Makefiles生成器用于Linux和Mac OS系统,而Visual Studio生成器用于Windows。通过命令行,开发者可以指定使用哪个生成器:
```shell
cmake -G "Unix Makefiles" .
```
或者在Windows上指定使用特定版本的Visual Studio:
```shell
cmake -G "Visual Studio 16 2019" -A x64 .
```
通过这些不同的生成器,CMake能够为不同的开发环境准备适当的构建脚本和项目文件。
以上是第二章的详细内容。这些部分共同构成对CMake基本命令和构建系统概念的理解,为开发者提供了理解和使用CMake的基础知识。在后续章节中,我们将通过具体的实践应用来加深理解,并进一步探索CMake的进阶技巧和高级功能。
# 3. CMake实践应用:开发一个简单的C++程序
## 3.1 从Hello World开始
### 3.1.1 创建源代码和CMake配置文件
让我们开始创建一个非常基础的C++ "Hello World" 程序来演示如何使用CMake进行项目管理。假设我们已经安装了CMake,并且配置了相应的环境。
首先,在项目根目录下创建一个名为 `main.cpp` 的文件:
```cpp
#include <iostream>
int main() {
std::cout << "Hello, CMake!" << std::endl;
return 0;
}
```
接着,我们创建一个 `CMakeLists.txt` 文件来配置我们的项目。这是CMake项目的配置文件,它指示CMake如何编译我们的代码。
```cmake
# 设置最低CMake版本要求
cmake_minimum_required(VERSION 3.0)
# 设置项目名称
project(HelloWorld)
# 指定C++标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# 添加可执行文件
add_executable(HelloWorld main.cpp)
```
### 3.1.2 配置和构建项目
为了构建项目,我们遵循以下步骤:
1. 打开终端,并导航到包含 `CMakeLists.txt` 文件的目录。
2. 运行 `cmake .` 来生成Makefile。
3. 运行 `make` 命令来编译项目。
4. 运行生成的可执行文件来测试结果。
代码块中的命令逐行解释:
```bash
cmake . # 生成Makefile
```
这个命令会读取当前目录下的 `CMakeLists.txt` 文件,并创建一个Makefile,这个Makefile包含了所有编译源代码所需的规则和指令。
```bash
make # 编译项目
```
这个命令会使用Makefile中指定的规则来编译我们的项目。编译过程中,CMake会调用编译器(如g++)来编译源代码文件 `main.cpp`。
```bash
./HelloWorld # 运行程序
```
最后,这个命令运行编译好的程序,你应该在终端看到输出 "Hello, CMake!"。
## 3.2 添加库和链接依赖
### 3.2.1 添加和构建静态库与共享库
在实际项目中,我们经常需要链接自己的库或者第三方库。下面是添加和构建静态库和共享库的步骤:
1. 创建库文件的源代码。例如,在 `library/` 目录下创建 `lib.cpp` 和 `lib.h`:
```cpp
// library/lib.h
#pragma once
void printMessage();
// library/lib.cpp
#include "lib.h"
#include <iostream>
void printMessage() {
std::cout << "Message from Library!" << std::endl;
}
```
2. 修改 `CMakeLists.txt` 文件以添加库的构建规则:
```cmake
# 添加库
add_library(OurLib STATIC library/lib.cpp)
# 静态库文件的目录
set_target_properties(OurLib PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
# 可执行文件链接到静态库
target_link_libraries(HelloWorld OurLib)
```
代码块中的命令逐行解释:
```cmake
add_library(OurLib STATIC library/lib.cpp)
```
这个命令定义了一个名为 `OurLib` 的静态库,并指定 `lib.cpp` 作为源代码。
```cmake
set_target_properties(OurLib PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
```
这个命令设置静态库 `OurLib` 的输出路径为当前项目源代码目录下的 `lib` 文件夹。
```cmake
target_link_libraries(HelloWorld OurLib)
```
这个命令将 `OurLib` 静态库链接到我们的 `HelloWorld` 可执行文件。
3. 配置和构建项目。遵循前节所述的构建步骤。
### 3.2.2 管理项目依赖关系
随着项目的成长,我们需要更复杂的依赖管理。CMake提供了各种方法来管理项目依赖。一个常见的方法是使用 `find_package()` 命令。
```cmake
find_package(Boost REQUIRED) # 查找Boost库
if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
endif()
```
`find_package()` 命令会根据配置或环境变量来查找库。如果找到,它会设置一些变量,如 `Boost_INCLUDE_DIRS` 和 `Boost_LIBRARIES`,然后你可以使用这些变量在项目中链接和包含所需的库。
## 3.3 实现项目版本控制和自定义安装
### 3.3.1 版本控制和项目信息管理
CMake使得版本控制变得容易,它允许我们在 `CMakeLists.txt` 文件中定义项目版本号。
```cmake
# 设置项目版本信息
set(PROJECT_VERSION_MAJOR 1)
set(PROJECT_VERSION_MINOR 0)
# 将版本号信息写入文件
configure_file(
"${PROJECT_SOURCE_DIR}/project_version.h.in"
"${PROJECT_BINARY_DIR}/project_version.h"
)
```
在这里,我们定义了主版本号和次版本号,然后使用 `configure_file()` 命令将这些信息插入到一个头文件中,使我们的代码可以包含并使用这些版本信息。
### 3.3.2 使用CMake安装项目文件
为了让项目可被安装到系统目录或打包,我们可以使用CMake的安装指令。
```cmake
# 安装规则
install(TARGETS HelloWorld DESTINATION bin)
install(DIRECTORY include/ DESTINATION include)
install(FILES project_version.h DESTINATION include)
```
上面的代码告诉CMake将我们的可执行文件安装到系统的 `bin` 目录,将 `include` 目录下的所有内容安装到系统的 `include` 目录,并将 `project_version.h` 安装到系统的 `include` 目录。
# 4. ```
# 第四章:CMake进阶技巧与高级功能
## 4.1 CMake的条件编译和选项
### 4.1.1 使用条件语句处理不同的编译环境
在复杂的软件项目中,我们经常需要根据不同的编译环境来设置不同的编译选项。CMake提供了强大的条件语句来处理这些需求,例如`if()`, `foreach()`, `while()`等。
#### 代码块展示
```cmake
if(MSVC)
# 在Windows使用MSVC编译器时执行的指令
add_definitions(-DWIN32_LEAN_AND_MEAN)
elseif(UNIX AND NOT APPLE)
# 在Linux系统上执行的指令
add_definitions(-D__LINUX__)
else()
# 默认情况或其他情况
add_definitions(-DDEFAULT_VERSION)
endif()
```
#### 参数说明
- `MSVC`: 检测是否使用了Microsoft Visual C++编译器。
- `UNIX`:检测是否在类Unix操作系统上。
- `APPLE`:检测是否在苹果系统上。
#### 执行逻辑说明
在上述代码块中,根据不同的操作系统和编译器,可以设置不同的预定义宏,这些宏可以在项目的源代码中使用,以实现条件编译。
### 4.1.2 提供用户选项和自定义编译行为
CMake允许开发者提供可配置的选项供用户选择,从而让用户能够控制编译过程或特定功能的开启与关闭。
#### 代码块展示
```cmake
option(USE_OPENSSL "Enable OpenSSL" OFF)
if(USE_OPENSSL)
find_package(OpenSSL REQUIRED)
include_directories(${OPENSSL_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${OPENSSL_LIBRARIES})
endif()
```
#### 参数说明
- `USE_OPENSSL`: 一个可选的CMake变量,用户可以设置为`ON`或`OFF`。
- `find_package(OpenSSL REQUIRED)`: 查找系统中安装的OpenSSL库。
#### 执行逻辑说明
通过`option()`命令提供了一个用户可配置的选项`USE_OPENSSL`。用户可以在命令行中使用`-DUSE_OPENSSL=ON`来控制该选项。如果启用了该选项,CMake会尝试找到OpenSSL库,并将其包含目录添加到项目中,以及链接相应的库文件。
## 4.2 CMake中的测试与质量保证
### 4.2.1 添加和执行单元测试
为了确保项目的质量和稳定性,单元测试是一个不可或缺的部分。CMake通过其测试模块提供了添加和执行单元测试的支持。
#### 代码块展示
```cmake
enable_testing()
add_executable(tests test1.cpp test2.cpp)
add_test(NAME Test1 COMMAND tests test1)
add_test(NAME Test2 COMMAND tests test2)
```
#### 执行逻辑说明
- `enable_testing()`: 开启CMake的测试支持。
- `add_executable(tests test1.cpp test2.cpp)`: 创建一个名为`tests`的可执行文件,它将由两个测试源文件组成。
- `add_test(NAME Test1 COMMAND tests test1)`: 添加一个名为`Test1`的测试,该测试执行`tests`可执行文件的`test1`函数。
### 4.2.2 集成持续集成与代码覆盖率工具
为了适应现代软件开发流程,集成持续集成(CI)和代码覆盖率分析工具是提高代码质量和维护性的关键步骤。
#### 代码块展示
```cmake
# 使用Catch2库作为测试框架
find_package(Catch2 REQUIRED)
include(Catch)
add_executable(myproject main.cpp)
target_link_libraries(myproject Catch2::Catch2)
# 使用Codecov来收集和上传代码覆盖率数据
if(ENABLE_CODECOV)
include(ProcessorCount)
ProcessorCount(N)
set(CMAKE覆盖率_EXE "codecov")
set(CMAKE覆盖率_FLAGS "--gcov --exclude \"src/*,test/*\"")
add_custom_command(
TARGET myproject POST_BUILD
COMMAND ${CMAKE覆盖率_EXE} ${CMAKE覆盖率_FLAGS} -t $ENV{CODECOV_TOKEN}
)
endif()
```
#### 参数说明
- `Catch2`: 一个流行的C++测试框架。
- `Codecov`: 一个流行的代码覆盖率分析服务。
#### 执行逻辑说明
在上面的代码中,我们首先使用`find_package`来查找并包含Catch2测试框架,然后通过定义`ENABLE_CODECOV`选项来决定是否启用代码覆盖率分析。如果启用,使用`add_custom_command`在项目构建后执行Codecov工具来收集覆盖率数据,并上传至服务端。
## 4.3 CMake与其他工具的集成
### 4.3.1 集成Doxygen生成文档
良好的项目文档是软件维护和开发的关键。CMake能够通过简单的配置与Doxygen文档生成工具集成。
#### 代码块展示
```cmake
find_package(Doxygen REQUIRED)
if(DOXYGEN_FOUND)
configure_file(${PROJECT_SOURCE_DIR}/Doxyfile.in Doxyfile @ONLY)
add_custom_target(doc ALL
COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/doc
COMMENT "Generating API documentation with Doxygen"
VERBATIM
)
endif()
```
#### 参数说明
- `Doxygen`: 一个流行的开源文档生成器。
- `Doxyfile.in`: 模板配置文件,由`configure_file()`命令处理。
#### 执行逻辑说明
首先,CMake尝试找到Doxygen工具。如果成功找到,将模板文件`Doxyfile.in`配置为当前项目的具体配置文件`Doxyfile`。然后创建一个自定义目标`doc`,在构建项目时执行Doxygen命令生成文档。
### 4.3.2 使用CPack打包分发项目
为了方便将项目打包分发,CMake提供了CPack工具,可以生成各种格式的安装包。
#### 代码块展示
```cmake
set(CPACK_GENERATOR "TGZ")
include(CPack)
set(CPACK_PACKAGE_NAME "myproject")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_PACKAGE_VENDOR "MyCompany")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A simple C++ project.")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
add_custom_target打包
COMMAND ${CPACK_COMMAND}
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
COMMENT "Creating package"
)
```
#### 参数说明
- `CPACK_GENERATOR "TGZ"`: 指定包生成器,此处为TAR格式。
- `CPACK_PACKAGE_NAME`, `CPACK_PACKAGE_VERSION`, 等: 定义包的元数据。
- `README.md`, `LICENSE`: 项目文档和许可文件。
#### 执行逻辑说明
代码中设置了CPack的参数,指定了项目的名称、版本、描述和许可等信息。然后使用`add_custom_target`定义了一个名为`打包`的目标,执行CPack命令来创建一个压缩包,包内包含了项目的二进制文件、文档和许可证等信息。
```
# 5. 跨平台开发的CMake实践
跨平台开发是现代软件开发中的一项重要技能。CMake作为一种跨平台的构建工具,天然地支持多种操作系统,包括但不限于Windows, Linux, macOS等。本章节将探讨如何利用CMake进行跨平台开发,并展示具体的实践案例。
## 5.1 掌握跨平台编译的基础
跨平台编译意味着一套源代码能够在不同的操作系统上进行编译和运行。为了达到这个目标,开发者需要抽象出平台相关的依赖,并且确保编译脚本(CMakeLists.txt)能够适应不同的系统。
### 5.1.1 平台检测与条件编译
CMake允许开发者通过 `find_package` 命令来检测和导入特定平台的开发包。同时,通过 `if` 和 `elseif` 语句可以实现平台特定的条件编译。
```cmake
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_definitions(-DWIN32_LEAN_AND_MEAN)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_definitions(-DLINUX)
endif()
```
### 5.1.2 编写可移植的CMakeLists.txt
编写CMake脚本时,要考虑到不同平台之间的差异。例如,Windows和Linux在文件路径分隔符、共享库的扩展名等方面有所不同。
```cmake
# 使用CMAKE_INSTALL_PREFIX来设置可移植的安装路径
set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "Install path prefix, prepended onto install directories.")
# 使用if语句处理不同平台下的库和头文件路径
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
include_directories("C:/path/to/windows/headers")
else()
include_directories("/usr/include")
endif()
```
## 5.2 实现平台无关的源代码
为了编写跨平台的源代码,开发者需要遵循一些最佳实践,例如使用条件编译指令处理平台差异,避免硬编码路径和依赖库。
### 5.2.1 使用预处理器宏
跨平台开发常使用预处理器宏来处理不同平台特有的代码。开发者可以在 `CMakeLists.txt` 中定义特定的宏,并在源代码中使用。
```cmake
# CMakeLists.txt
add_definitions(-DPLATFORMSpecificCode)
# source.cpp
#ifdef PLATFORMSpecificCode
// Platform specific code
#endif
```
### 5.2.2 避免平台依赖
避免在代码中直接使用特定于平台的API和数据类型。例如,在处理文件路径时使用C++标准库而不是操作系统的API。
```cpp
#include <iostream>
#include <string>
#include <filesystem>
int main() {
std::filesystem::path p = "/path/to/file.txt";
// 使用C++标准库操作文件路径
}
```
## 5.3 配置CMake以支持多平台
在配置CMake项目时,要考虑到不同平台可能需要不同的配置。CMake提供了强大的工具来检测系统环境并相应地配置项目。
### 5.3.1 使用try_run检测功能
`try_run` 命令可以在编译时检测特定平台的特性,这对于确保代码的可移植性非常有用。
```cmake
try_run(RUN_RESULT COMPILE_RESULT
"${CMAKE_BINARY_DIR}/tmp"
"${PROJECT_SOURCE_DIR}/cmake/try_run"
RUN_OUTPUT_VARIABLE RUN_OUTPUT)
if(COMPILE_RESULT AND NOT RUN_RESULT)
set(FOUND_SOMETHING TRUE CACHE BOOL "Found something")
else()
set(FOUND_SOMETHING FALSE CACHE BOOL "Found something")
endif()
```
### 5.3.2 为不同平台设置特定的构建选项
在某些情况下,开发者可能需要为不同的平台设置特定的构建选项。通过 `option` 命令可以创建用户可配置的CMake选项,并在编译时选择。
```cmake
option(BUILD_FOR_WINDOWS "Build for Windows Platform" OFF)
if(BUILD_FOR_WINDOWS)
add_definitions(-DWINDOWS_BUILD)
endif()
```
通过上述实践,开发者可以确保项目在不同的平台上都能顺利编译和运行,从而大大提高了代码的可移植性和项目的可维护性。跨平台开发不仅限于代码层面,还包括编译配置、环境检测、条件编译等多个方面,而CMake恰恰提供了一套完整的解决方案来简化这一过程。
0
0
相关推荐







