(一)CMake构建C++项目

前言

照例先说一下环境,和使用工具版本。不同环境和工具不同的版本情况是不一样的,有的甚至差别非常大。

  • 操作系统:Microsoft Windows 11
  • 编译器:gcc/g++ 13.2.0
  • 构建工具:CMake 4.0.2
  • 编辑器:Visual Studio Code 1.100.3

说一下编译器的安装:

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
验证

同样 CMake 也是去官网下载然后解压并设置环境变量,方法同 gcc 一样,不再赘述。提一下,在编写好第一个 CMakeLists.txt 文件之后 vscode 会自动识,并在左侧工具栏显示 cmake 构建按钮,如果没有显示出来,说明没有安装 camke 相关插件,或安装的插件不对。下面列出该项目安装的插件以供参考:
插件
C/C++插件应该只需要安装第二个就行,另外两个是它附带安装的;同样 cmake 只需安装 CMake Tools 即可,另外一个是附带的,如果不对可手动安装一下。

工程结构

工具都安装之后,新建文件夹 example-cmake-demo 作为我们的项目目录,在该目录下新建以下文件夹:
在这里插入图片描述

  • bin:最终可执行文件目录;
  • build:cmake 构建目录,里面是 cmake 构建过程中生成的文件;
  • docs(可选):存放项目相关文档的地方;
  • lib:项目用到的第三方库;
  • src:源文件(.h,.hpp,.c,.cpp)存放位置;
  • test(可选):单元测试文件位置。

另外本示例项目为多模块工程,所以在 src 目录下新建了 pnc_map 和 process 两个文件夹,名称随意,根据自己项目需要更改。

CMakeLists

分别在项目、src、pnc_map、process 根目录新建 CMakeLists.txt 文件,注意文件名和大小写要一字不差,否则 CMake 无法识别。

项目根目录 CMakeLists.txt:

# 指定 cmake 版本
cmake_minimum_required(VERSION 4.0.2)
# 项目信息
project(
    Planning  # 项目名称
    VERSION 0.0.1 # 项目版本
    DESCRIPTION "a demo of cmake" # 项目描述
    HOMEPAGE_URL "https://gitee.com/scarypie/example-cmake-demo" # 项目地址
    LANGUAGES CXX # 语言
)

# 语言版本 C++ 17
set(CMAKE_CXX_STANDARD 17)

# 变量设置:输出目录、pnc_map模块路径、process模块路径
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
set(PNC_MAP_DIR ${CMAKE_SOURCE_DIR}/src/pnc_map)
set(PROCESS_DIR ${CMAKE_SOURCE_DIR}/src/process)

# 添加子模块
add_subdirectory(src)

作为最外层项目没有源文件,也没有输出内容,只是定义相关变量。可以理解为项目的整体配置,包含项目描述,用到的工具及版本信息,和一些构建过程中用到的变量,与主项目模块是包含关系。

src 根目录 CMakeLists.txt:

# 定义主项目
project(planning_main)
# 包含哪些子模块
add_subdirectory(pnc_map)
add_subdirectory(process)
# 可执行程序名称及源文件
add_executable(${PROJECT_NAME} planning_main.cpp)
# 主程引用的头文件
target_include_directories(
    ${PROJECT_NAME}
    PUBLIC
    ${PROCESS_DIR}
)
# 链接主程用到的第三方库
target_link_libraries(
    ${PROJECT_NAME}
    PUBLIC
    process
)

planning_main 才是真正的项目,定义了项目结构(包含哪些子模块),主程序名称、源文件、头文件和第三方库。

process 根目录 CMakeLists.txt:

# 模块名称
project(process)
# 模块类型,即该模块最终会生成一个动态链接库
add_library(
    ${PROJECT_NAME}
    SHARED
    process.cpp
)
# 相关头文件
target_include_directories(
    ${PROJECT_NAME}
    PUBLIC
    ${PNC_MAP_DIR}
)
# 链接 pnc_map 库
target_link_libraries(
    ${PROJECT_NAME}
    PUBLIC
    pnc_map
)

pnc_map 根目录 CMakeLists.txt:

# 模块名称
project(pnc_map)
# 模块类型
add_library(
    ${PROJECT_NAME}
    SHARED
    pnc_map.cpp
)

从 CMakeLists.txt 的结构可以看出该项目为 planning_main,包含两个子模块 process、pnc_map,子模块生成动态链接库,被主程序使用,其中 process 模块又依赖于 pnc_map。最终会在项目目录下的 bin 文件夹中生成三个文件:planning_main.exe、libprocess.dll、libpnc_map.dll。注:gcc/g++ 生成的库文件都是以 lib 开头,.dll 或 .a 结尾,中间是项目(模块)名称,.dll 表示是动态库,.a 表示 静态库。

编译和运行

项目目标是在控制台输出文字,本身没有实际意义,只是作为 windows 环境下在 vscode 中开发 c/c++ 项目开端教程。关于 cmake 的命令可以去官网或百度查阅,篇幅问题不再展开说明。项目文件可以去我的仓库下载。

如果上面各文件内容跟我的一致,点击 vscode 左下角进行 build 会在终端提示 “Build finished with exit code 0”:
build
同样再点击左下角的运行按钮,就会在控制台看到输出内容:
运行结果

单元测试

讲一下如何在 cmake 项目中进行单元测试。单元测试的目的是为了解决在复杂项目结构情况下,对其中某一子模块单独进行测试的需求,避免为了测试单一模块而对整个项目进行编译和调试。

上面在项目结构中提到的 test 目录就是用来进行单元测试而创建,比如我们要单独对 pnc_map 进行测试,则只需要在 test 目录下创建 map_test(名称随意)目录,然后在该目录下创建 map_test.cpp 文件,用来写单元测试代码,和 CMakeLists.txt 用来管理该单元测试模块。

目录结构:
在这里插入图片描述

map_test.cpp 代码:

#include <iostream>
#include "pnc_map.hpp"

using namespace std;

void mapTest() {
    cout << "This is a map test" << endl;
    Pnc_Map pncMap;
    pncMap.map_info();
}

int main(int argc, char* argv[]) {
    mapTest();
    return EXIT_SUCCESS;
}

这里会发现在第二行引用 pnc_map.hpp 时会有错误提示,先不用管。

test/map_test 目录下的 CMakeLists.txt:

# 定义测试模块名称
project(map_test)
# 测试模块执行程序定义
add_executable(${PROJECT_NAME} map_test.cpp)
# 测试模块引用 pnc_map 头文件
target_include_directories(
    ${PROJECT_NAME}
    PUBLIC
    ${PNC_MAP_DIR}
)
# 链接 pnc_map 库
target_link_libraries(
    ${PROJECT_NAME}
    PUBLIC
    pnc_map
)
# 添加模块,告诉 cmake 这是一个测试模块, NAME 为测试模块名称(要与 project 定义一致),COMMMAND 即执行命令
add_test(
    NAME map_test
    COMMAND ${PROJECT_NAME}
)

到这里再到 map_test.cpp 文件中,会发现引用 pnc_map.hpp 的地方已经正常。上面 command 定义测试时要执行的程序,直接用该模块名称,并在 add_executable 中指定生成的可执行程序,与项目名称一致,也是 PROJECT_NAME,即 command 要与 add_executable 定义的名称一致。

最外层 CMakeLists.txt 修改:
在这里插入图片描述
关键代码已在上图中标出,即启动测试,并加入单元测试模块(路径),cmake 会在其所在目录下查找该模块位置。

上述工作完成后,会在 map_test 文件中显示可执行按钮,我这里显示是对勾,是因为已经执行过且结果为 Passed,未执行过的应该是三角形执行按钮:
在这里插入图片描述

直接点击该按钮就可以执行单元测试,或者在左侧工具栏中点击 Testing 按钮,然后点击相应项的执行按钮即可,测试结果如下:
在这里插入图片描述
测试结果中给出了测试结果和总用时。或者左侧工具栏中 CMake 中将启动项改为 map_test,则只会在控制台打印出 pnc_map 和 map_test 两个模块要打印的信息:
在这里插入图片描述

posted @ 2025-06-07 23:59  凉皮也是菜  阅读(127)  评论(0)    收藏  举报  来源