cmake项目使用递归CmakeLists.txt的方式添加源文件 一般情况下要添加多个源文件用于编译需要手动添加例如add_executable(${PROJECT_NAME}src/main.cpp src/utils/message/message.cpp src/utils/sort/sort_algorithms.cpp)每次添加源文件都得修改根目录的CMakeLists.txt这样很麻烦且不利于多人协作为了解决这个问题可以在每一个源文件目录下添加一个CMakeLists.txt文件来解决1.先准备好源文件1.src/main.cpp#includeiostream#includevector#includealgorithm#includeutils/message/message.h#includeutils/sort/sort_algorithms.hstaticvoidtest_message(){std::string messagebuild_message();std::coutmessagestd::endl;}// 统一打印整型数组供排序和链表测试复用。staticvoidprint_values(conststd::vectorintvalues){std::cout[;for(std::size_t i0;ivalues.size();i){if(i0){std::cout, ;}std::coutvalues[i];}std::cout];}// 执行一个排序函数并用 std::is_sorted 判断排序结果是否正确。staticvoidrun_sort_test(conststd::stringname,std::vectorint(*sort_func)(std::vectorint),conststd::vectorintinput){conststd::vectorintresultsort_func(input);std::coutname: ;print_values(result);std::cout(std::is_sorted(result.begin(),result.end())? PASS: FAIL)std::endl;}staticvoidtest_sort(){// 所有排序算法使用同一份输入便于对比输出结果。conststd::vectorintvalues{9,4,6,2,8,1,5,3,7,0};run_sort_test(bubble_sort,sort_algorithms::bubble_sort,values);run_sort_test(selection_sort,sort_algorithms::selection_sort,values);run_sort_test(insertion_sort,sort_algorithms::insertion_sort,values);run_sort_test(merge_sort,sort_algorithms::merge_sort,values);run_sort_test(quick_sort,sort_algorithms::quick_sort,values);}intmain(){std::coutHello, World!std::endl;test_message();test_sort();return0;}2.src/utils/sort_algorithms.h#ifndefSORT_ALGORITHMS_H#defineSORT_ALGORITHMS_H#includevectornamespace sort_algorithms{// 冒泡排序重复交换相邻逆序元素返回排序后的副本。std::vectorintbubble_sort(std::vectorintvalues);// 选择排序每轮选择未排序区间的最小值返回排序后的副本。std::vectorintselection_sort(std::vectorintvalues);// 插入排序把当前元素插入到前方已排序区间返回排序后的副本。std::vectorintinsertion_sort(std::vectorintvalues);// 归并排序递归拆分并合并有序区间返回排序后的副本。std::vectorintmerge_sort(std::vectorintvalues);// 快速排序基于枢轴分区后递归排序返回排序后的副本。std::vectorintquick_sort(std::vectorintvalues);}// namespace sort_algorithms#endif3.src/utils/sort_algorithms.cpp#includesort_algorithms.h#includealgorithm#includecstddefnamespacesort_algorithms{namespace{// 对 [left, right) 区间做归并排序buffer 用作合并时的临时空间。voidmerge_sort_range(std::vectorintvalues,std::vectorintbuffer,std::size_t left,std::size_t right){if(right-left1){return;}conststd::size_t midleft(right-left)/2;merge_sort_range(values,buffer,left,mid);merge_sort_range(values,buffer,mid,right);// 两个子区间都已经有序把较小元素依次写入 buffer。std::size_t ileft;std::size_t jmid;std::size_t kleft;while(imidjright){buffer[k]values[i]values[j]?values[i]:values[j];}while(imid){buffer[k]values[i];}while(jright){buffer[k]values[j];}// 把合并后的有序结果复制回原数组对应区间。for(std::size_t indexleft;indexright;index){values[index]buffer[index];}}// 对闭区间 [left, right] 做快速排序分区和递归处理。voidquick_sort_range(std::vectorintvalues,intleft,intright){if(leftright){return;}constintpivotvalues[left(right-left)/2];intileft;intjright;// 从两端向中间扫描把小于 pivot 的元素放左侧大于 pivot 的元素放右侧。while(ij){while(values[i]pivot){i;}while(values[j]pivot){--j;}if(ij){std::swap(values[i],values[j]);i;--j;}}if(leftj){quick_sort_range(values,left,j);}if(iright){quick_sort_range(values,i,right);}}}// namespacestd::vectorintbubble_sort(std::vectorintvalues){for(std::size_t endvalues.size();end1;--end){boolswappedfalse;// 每轮把当前未排序区间的最大值“冒泡”到末尾。for(std::size_t i1;iend;i){if(values[i-1]values[i]){std::swap(values[i-1],values[i]);swappedtrue;}}// 如果本轮没有交换说明数组已经有序可以提前结束。if(!swapped){break;}}returnvalues;}std::vectorintselection_sort(std::vectorintvalues){for(std::size_t i0;ivalues.size();i){std::size_t min_indexi;// 在未排序区间中寻找最小值的位置。for(std::size_t ji1;jvalues.size();j){if(values[j]values[min_index]){min_indexj;}}std::swap(values[i],values[min_index]);}returnvalues;}std::vectorintinsertion_sort(std::vectorintvalues){for(std::size_t i1;ivalues.size();i){constintcurrentvalues[i];std::size_t ji;// 将比 current 大的元素右移给 current 腾出插入位置。while(j0values[j-1]current){values[j]values[j-1];--j;}values[j]current;}returnvalues;}std::vectorintmerge_sort(std::vectorintvalues){// buffer 只分配一次递归过程中复用避免每层递归重复分配。std::vectorintbuffer(values.size());merge_sort_range(values,buffer,0,values.size());returnvalues;}std::vectorintquick_sort(std::vectorintvalues){// 空数组不进入递归避免 size_t 到 int 转换时出现下溢。if(!values.empty()){quick_sort_range(values,0,static_castint(values.size()-1));}returnvalues;}}// namespace sort_algorithms4.src\utils\message\message.h#ifndefMESSAGE_H#defineMESSAGE_H#includestring// 构建示例程序启动时显示的提示信息。std::stringbuild_message();#endif5.src\utils\message\message.cpp#includemessage.hstd::stringbuild_message(){// 保持消息独立成函数方便演示静态库被主程序链接和调用。returnHello from a CMake subdirectory project built with MinGW.;}2.修改CMakeLists.txt1.根目录的CMakeLists.txtcmake_minimum_required(VERSION3.16)project(cmake-demo VERSION1.0.0LANGUAGES CXX)#C标准设置set(CMAKE_CXX_STANDARD17)set(CMAKE_CXX_STANDARD_REQUIRED ON)set(CMAKE_CXX_EXTENSIONS OFF)# 可执行文件add_executable(${PROJECT_NAME})add_subdirectory(src)2.src/CMakeLists.txtfile(GLOB CURRENT_SOURCES CONFIGURE_DEPENDS${CMAKE_CURRENT_SOURCE_DIR}/*.cpp${CMAKE_CURRENT_SOURCE_DIR}/*.cc${CMAKE_CURRENT_SOURCE_DIR}/*.cxx${CMAKE_CURRENT_SOURCE_DIR}/*.h${CMAKE_CURRENT_SOURCE_DIR}/*.hpp)target_sources(${PROJECT_NAME}PRIVATE ${CURRENT_SOURCES})target_include_directories(${PROJECT_NAME}PRIVATE${CMAKE_CURRENT_SOURCE_DIR})add_subdirectory(utils)3.src\utils\CMakeLists.txtfile(GLOB CURRENT_SOURCES CONFIGURE_DEPENDS${CMAKE_CURRENT_SOURCE_DIR}/*.cpp${CMAKE_CURRENT_SOURCE_DIR}/*.cc${CMAKE_CURRENT_SOURCE_DIR}/*.cxx${CMAKE_CURRENT_SOURCE_DIR}/*.h${CMAKE_CURRENT_SOURCE_DIR}/*.hpp)target_sources(${PROJECT_NAME}PRIVATE ${CURRENT_SOURCES})target_include_directories(${PROJECT_NAME}PRIVATE${CMAKE_CURRENT_SOURCE_DIR})add_subdirectory(sort)add_subdirectory(message)4.src\utils\message\CMakeLists.txtfile(GLOB CURRENT_SOURCES CONFIGURE_DEPENDS${CMAKE_CURRENT_SOURCE_DIR}/*.cpp${CMAKE_CURRENT_SOURCE_DIR}/*.cc${CMAKE_CURRENT_SOURCE_DIR}/*.cxx${CMAKE_CURRENT_SOURCE_DIR}/*.h${CMAKE_CURRENT_SOURCE_DIR}/*.hpp)target_sources(${PROJECT_NAME}PRIVATE ${CURRENT_SOURCES})target_include_directories(${PROJECT_NAME}PRIVATE${CMAKE_CURRENT_SOURCE_DIR})5.src\utils\sort\CMakeLists.txtfile(GLOB CURRENT_SOURCES CONFIGURE_DEPENDS${CMAKE_CURRENT_SOURCE_DIR}/*.cpp${CMAKE_CURRENT_SOURCE_DIR}/*.cc${CMAKE_CURRENT_SOURCE_DIR}/*.cxx${CMAKE_CURRENT_SOURCE_DIR}/*.h${CMAKE_CURRENT_SOURCE_DIR}/*.hpp)target_sources(${PROJECT_NAME}PRIVATE ${CURRENT_SOURCES})target_include_directories(${PROJECT_NAME}PRIVATE${CMAKE_CURRENT_SOURCE_DIR})3.CMakeLists.txt逐行解释1.file(GLOB ...)— 收集文件列表file(GLOB CURRENT_SOURCES CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/*.cc ${CMAKE_CURRENT_SOURCE_DIR}/*.cxx ${CMAKE_CURRENT_SOURCE_DIR}/*.h ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp )file(GLOB ...)用通配符匹配当前目录下所有指定后缀的文件CURRENT_SOURCES将匹配到的文件列表存入这个变量CONFIGURE_DEPENDS告诉 CMake 当添加/删除文件时自动重新扫描不写的话新增文件后需要手动重新运行 cmake 才会生效匹配的扩展名.cpp、.cc、.cxx、.h、.hpp2.target_sources(...)— 把文件添加到目标target_sources(${PROJECT_NAME} PRIVATE ${CURRENT_SOURCES})把上面收集到的所有源文件添加到名为${PROJECT_NAME}的目标可执行文件或库PRIVATE表示这些源文件只属于这个目标自身不会透传给依赖它的其他目标3.target_include_directories(...)— 添加头文件搜索路径target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})把当前目录CMAKE_CURRENT_SOURCE_DIR添加为头文件搜索路径这样在#include message.h时编译器能在这个子目录里找到头文件整体作用这种模式的目的是让 CMake 自动发现子目录下的源文件不需要每次新增文件都手动修改 CMakeLists.txt。例如在 utils 目录下它会自动匹配src/utils/sort_algorithms.cppsrc/utils/sort_algorithms.h以及sort/和message/子目录中通过add_subdirectory添加的文件⚠️注意虽然GLOB很方便但 CMake 官方更推荐显式列出源文件使用set()或手动列出因为GLOB在文件变更时可能不会自动触发重新配置除非加了CONFIGURE_DEPENDS。不过对于学习项目这样做问题不大。4.优化源文件夹的CMakeLists.txt观察到src/CMakeLists.txt,src\utils\CMakeLists.txt,src\utils\message\CMakeLists.txt,src\utils\sort\CMakeLists.txt四个源文件夹下面的CMakeLists.txt非常相似差别只在于添加子文件夹add_subdirectory这个操作因为需要添加不同名字的子文件夹。可以将手动添加指定子文件夹的操作改为自动扫描并添加所有子文件夹# 自动扫描并添加所有子文件夹file(GLOB ALL_ENTRIES CONFIGURE_DEPENDS${CMAKE_CURRENT_SOURCE_DIR}/*)foreach(ENTRY ${ALL_ENTRIES})if(IS_DIRECTORY ${ENTRY})get_filename_component(DIR_NAME ${ENTRY}NAME)add_subdirectory(${DIR_NAME})endif()endforeach()

相关新闻

最新新闻

Spring Cloud Alibaba 2025.0.0 配置中心踩坑日记

Spring Cloud Alibaba 2025.0.0 配置中心踩坑日记

Spring Cloud Alibaba 2025.0.0 配置中心踩坑日记从 2021.x 升到 2025.0.0 之后,配置中心的写法全变了。bootstrap.yml 默认关掉、spring.config.import 接入方式也换了、Nacos Server 版本还不对齐。踩了一堆坑,整理下来备忘。环境组件版本Spring Boot3…

2026/7/10 7:28:51
同城外卖APP开发技术解析:用户端、商家端、骑手端三端系统如何设计?

同城外卖APP开发技术解析:用户端、商家端、骑手端三端系统如何设计?

随着本地生活服务市场不断发展,同城外卖已经从简单的“线上点餐工具”逐渐升级为连接消费者、商家、配送人员的新型数字化服务平台。无论是餐饮创业者、区域生活服务平台,还是传统实体商家,都希望通过搭建自己的同城外卖APP,实现流…

2026/7/10 7:28:51
不止“联网”:企业网络,才是数字化办公的隐形核心战力

不止“联网”:企业网络,才是数字化办公的隐形核心战力

很多中小企业对企业网络的认知,还停留在“能上网、连WiFi、传文件”的基础层面。但在全员数字化、云端办公、远程协作常态化的今天,企业网络早已不是简单的上网工具,而是支撑业务运转、数据流转、安全防护的数字化基础设施核心。员工卡顿掉线…

2026/7/10 7:28:51
Python接口自动化测试实战:Requests与Unittest构建高效测试框架

Python接口自动化测试实战:Requests与Unittest构建高效测试框架

1. 项目概述:为什么选择 Python3 Requests Unittest 这套组合拳? 如果你正在为项目里那些重复、枯燥的接口测试发愁,或者每次发版前都要手动点点点,那今天聊的这个组合,可能就是你的“解放双手”利器。Python3 Requ…

2026/7/10 7:28:51
YOLO安卓部署实战:ONNX导出、NCNN集成与性能调优全链路

YOLO安卓部署实战:ONNX导出、NCNN集成与性能调优全链路

1. 为什么“YOLO模型部署到安卓设备”不是简单拖个模型文件就完事?YOLO、安卓、Android Studio、ONNX、NCNN——这五个词凑在一起,表面看是条清晰的技术路径:训练好YOLO模型 → 导出ONNX → 用NCNN在Android Studio里加载运行。但我在过去三年…

2026/7/10 7:28:51
51单片机无源蜂鸣器驱动:3种PWM方波生成方案对比与音调控制

51单片机无源蜂鸣器驱动:3种PWM方波生成方案对比与音调控制

51单片机无源蜂鸣器驱动:3种PWM方波生成方案深度解析与实战优化无源蜂鸣器驱动原理与技术选型在嵌入式系统设计中,无源蜂鸣器因其灵活的音调控制和成本优势,成为许多51单片机项目的首选发声器件。与有源蜂鸣器不同,无源蜂鸣器内部…

2026/7/10 7:23:51

月新闻