当前位置: 首页 > news >正文

CMake 多目录项目构建

CMake 多目录项目构建

CMake 多目录项目构建完整笔记


一、项目目录结构

cc/
├── CMakeLists.txt        # 顶层构建文件
├── include/              # 公共头文件目录
│   ├── calc.h            # 四则运算头文件
│   └── sort.h            # 排序算法头文件
├── calc/                 # 四则运算静态库目录
│   ├── add.cpp
│   ├── sub.cpp
│   ├── mul.cpp
│   ├── div.cpp
│   └── CMakeLists.txt
├── lib/                  # 静态库输出目录(自动生成)
│   └── libcalc.a
│   └── libsort.a
├── sort/                 # 排序算法静态库目录
│   ├── insert.cpp        # 插入排序
│   ├── select.cpp        # 选择排序
│   └── CMakeLists.txt
├── test1/                # 四则运算测试程序
│   ├── calc.cpp          # 测试主文件
│   └── CMakeLists.txt
├── test2/                # 排序算法测试程序
│   ├── sort.cpp          # 测试主文件
│   └── CMakeLists.txt
├── bin/                  # 可执行文件输出目录(自动生成)
│   ├── app1              # 四则运算测试程序
│   └── app2              # 排序算法测试程序
└── build/                # 外部构建目录(推荐方式)

二、顶层 CMakeLists.txt(项目入口)

cmake_minimum_required(VERSION 3.15)
project(test)# 定义项目根目录路径
set(PROJECT_ROOT ${CMAKE_CURRENT_SOURCE_DIR})# 定义静态库生成路径
set(LIBPATH ${PROJECT_ROOT}/lib)# 定义可执行文件的存储目录
set(EXECPATH ${PROJECT_ROOT}/bin)# 定义头文件路径
set(HEADPATH ${PROJECT_ROOT}/include)# 定义库文件的名字
set(CALCLIB calc)
set(SORTLIB sort)# 定义可执行文件的名字
set(APPNAME1 app1)
set(APPNAME2 app2)# 给当前节点添加子目录
add_subdirectory(calc)
add_subdirectory(sort)
add_subdirectory(test1)
add_subdirectory(test2)

三、子目录 CMakeLists.txt 详解

1. calc/CMakeLists.txt(四则运算静态库)

cmake_minimum_required(VERSION 3.15)
project(calc)# 搜索当前目录下所有源文件
aux_source_directory(./ SRC)# 加载公共头文件路径
include_directories(${HEADPATH})# 设置静态库生成路径
set(LIBRARY_OUTPUT_PATH ${LIBPATH})# 生成静态库 calc
add_library(${CALCLIB} STATIC ${SRC})

2. sort/CMakeLists.txt(排序算法静态库)

cmake_minimum_required(VERSION 3.15)
project(sort)# 搜索当前目录下所有源文件
aux_source_directory(./ SRC)# 加载公共头文件路径
include_directories(${HEADPATH})# 设置静态库生成路径
set(LIBRARY_OUTPUT_PATH ${LIBPATH})# 生成静态库 sort
add_library(${SORTLIB} STATIC ${SRC})

3. test1/CMakeLists.txt(四则运算测试程序)

cmake_minimum_required(VERSION 3.15)
project(test1)# 搜索当前目录下所有源文件
aux_source_directory(./ SRC)# 加载公共头文件路径
include_directories(${HEADPATH})# 链接的库路径(告诉编译器去哪找静态库)
link_directories(${LIBPATH})# 设置可执行文件输出到 bin 文件夹
set(EXECUTABLE_OUTPUT_PATH ${EXECPATH})# 生成可执行文件 app1
add_executable(${APPNAME1} ${SRC})# 现代 CMake 链接方式(推荐)
target_link_libraries(${APPNAME1} PRIVATE ${CALCLIB})

4. test2/CMakeLists.txt(排序算法测试程序)

cmake_minimum_required(VERSION 3.15)
project(test2)# 搜索当前目录下所有源文件
aux_source_directory(./ SRC)# 加载公共头文件路径
include_directories(${HEADPATH})# 链接的库路径(告诉编译器去哪找静态库)
link_directories(${LIBPATH})# 设置可执行文件输出到 bin 文件夹
set(EXECUTABLE_OUTPUT_PATH ${EXECPATH})# 生成可执行文件 app2
add_executable(${APPNAME2} ${SRC})# 现代 CMake 链接方式(推荐)
target_link_libraries(${APPNAME2} PRIVATE ${SORTLIB})

四、关键配置解析

1. 变量定义(顶层文件)

变量 作用 示例值
PROJECT_ROOT 项目根目录路径 ${CMAKE_CURRENT_SOURCE_DIR}
LIBPATH 静态库输出路径 ${PROJECT_ROOT}/lib
EXECPATH 可执行文件输出路径 ${PROJECT_ROOT}/bin
HEADPATH 公共头文件路径 ${PROJECT_ROOT}/include
CALCLIB/SORTLIB 静态库目标名 calc / sort
APPNAME1/APPNAME2 可执行文件目标名 app1 / app2

2. add_subdirectory 命令

  • 作用:添加子目录,构建子项目
  • 示例:add_subdirectory(calc) → 进入 calc/ 目录执行其 CMakeLists.txt
  • 执行顺序:按添加顺序构建,先构建库,再构建可执行文件

3. aux_source_directory 命令

  • 作用:自动扫描指定目录下的所有 .cpp 文件,存入变量
  • 示例:aux_source_directory(./ SRC) → 当前目录下所有源文件存入 SRC
  • 注意:仅扫描当前目录,不递归子目录
  • 作用:将可执行文件与静态库链接
  • 语法:target_link_libraries(目标名 PRIVATE 库名)
  • 特点:现代 CMake 推荐方式,自动处理依赖关系

五、编译与运行步骤

1. 清空并进入构建目录

cd build
rm -rf *

2. 生成构建文件

cmake ..

3. 编译项目

make

4. 运行测试程序

# 四则运算测试
./bin/app1# 排序算法测试
./bin/app2

六、常见问题与解决

1. 头文件找不到

  • 原因:未设置 include_directories(${HEADPATH})
  • 解决:确保子目录 CMakeLists.txt 中包含该命令

2. 静态库找不到

  • 原因:未设置 link_directories(${LIBPATH}) 或静态库未生成
  • 解决:
    • 检查 lib/ 目录下是否生成 libcalc.alibsort.a
    • 确保 test1/test2/ 中包含 link_directories(${LIBPATH})

3. 链接错误 undefined reference

  • 原因:未使用 target_link_libraries 链接静态库
  • 解决:确保可执行文件的 CMakeLists.txt 中包含链接命令

七、总结

  1. 项目结构规范:公共头文件统一放在 include/,库文件放在 lib/,可执行文件放在 bin/
  2. 模块化构建:使用 add_subdirectory 管理子项目,实现库与可执行文件分离
  3. 现代 CMake 实践:优先使用 target_link_libraries 链接库,避免旧版 link_libraries
  4. 路径管理:通过顶层变量统一管理路径,避免硬编码
http://www.gsyq.cn/news/1369303.html

相关文章:

  • 机器学习非确定性对法律决策的挑战:从代码即法律到过程治理
  • 日志分析卡在Kibana?DeepSeek轻量级替代方案来了:单节点部署、<50ms延迟、支持PB级日志回溯,限时开放API密钥申请通道
  • ArcaNN框架:自动化构建机器学习原子间势,高效模拟化学反应
  • 如何用79万中文医疗对话数据集构建专业的医疗AI助手:完整指南
  • 影刀RPA浏览器自动化系统:多账号环境隔离与资源调度实战
  • 如何快速掌握抖音批量下载工具:面向初学者的完整指南
  • ComfyUI-Impact-Pack:3步实现AI图像智能修复与细节增强
  • 中兴光猫超级权限解锁:5分钟掌握zteOnu的完整使用指南
  • DeepSeek v3升级后成本激增41%?紧急发布:兼容性迁移成本对冲清单(含6个可立即执行的config开关)
  • 【DeepSeek R1-VL流式优化白皮书】:基于127个真实生产案例的RTT压缩公式与chunk_size黄金阈值表
  • 小白也能秒懂的B站视频下载神器:BilibiliDown完全指南
  • 5分钟搞定!Windows电脑安装安卓应用的终极指南
  • 企业内部分享如何通过Taotoken实现大模型API调用审计
  • 英雄联盟本地化效率工具:League Akari 完全使用指南
  • Windows苹果设备驱动一键安装:告别连接烦恼的终极解决方案
  • Python 开发者如何快速接入 Taotoken 并调用多模型 API
  • 微信网页版解锁方案:wechat-need-web浏览器插件完整指南
  • Node.js 服务如何快速集成 Taotoken 提供的多模型能力
  • 为什么你的微调模型总在loss plateau?DeepSeek官方未公开的训练数据准备5大隐性标准(附自动化验证脚本)
  • SMUDebugTool:深度驾驭AMD Ryzen处理器的终极硬件调试指南
  • 电动汽车充电桩可靠性监控:超越传统运行时间指标
  • 面板数据因果推断:双重机器学习与相关随机效应CRE的稳健性实践
  • 3分钟掌握R3nzSkin:英雄联盟国服免费换肤完全指南
  • 让Windows资源管理器完美显示iPhone照片缩略图的5个关键步骤
  • SMUDebugTool深度解析:AMD Ryzen硬件调试与性能调优终极指南
  • 泉盛UV-K5/K6固件深度改造:4大核心技术突破与完全实战指南
  • 如何利用taotoken为claude code配置可靠的备用api通道防止中断
  • java问题之`Map.of` does not allow null values
  • 【紧急避坑】ChatGPT安卓端权限滥用警告:3类高危行为已致23万账号异常(附检测+修复脚本)
  • GetQzonehistory:3分钟学会永久保存QQ空间记忆的终极免费方案