拓冰建站拓冰建站
首页 / 资讯中心 / 正文

CMake学习总结

一、CMake和在IDE点击【编译并运行】对比答:IDE 点击【编译并运行】,底层是做了三件事情,①生成编译脚本 (Makefile/Ninja) ②调用 gcc/g++ 编译链接③运行可执行程序。IDE 把这三步全部封装成一个按钮,你点一下全部自动跑完。下来我们看一下使用CMake等操作要怎么实现相同的目标:操作对应命令做什么步骤①cmake ..解析 CMakeLists.txt,输出构建脚本 Makefile步骤②make根据 Makefile,调用 gcc编译源码、链接库,产出.a/.so/可执行程序步骤③./xxx运行二进制程序,和 CMake、gcc 完全无关,交给操作系统执行补充一下,步骤③中可执行程序不是一定带.exe后缀,在windows中可执行程序是一定带.exe后缀的,但是在linux中是要看文件是否有可执行权限,不是看后缀的,使用ls之后绿色的文件夹具有可执行权限。可见CMake学习问题中第10和第12个问题。另外,也可以直接用原生的gcc/g++,直接调用编译器本体,不经过 CMake、Make、IDE 这些中间工具包装。以Windows中gcc为例:#只编译不链接,生成目标文件main.o gcc -c main.c #多个文件编译链接 gcc main.c func.c -o app.execmake指令读取CMakeLists.txt,输出Makefile,Makefile 只是一份文本,记录了:要调用哪些 gcc 命令、哪些文件要编译。编译阶段:把 .c/.cpp 源代码 → 目标文件 .o(Windows 下.obj)。只做语法翻译,不处理库、函数跨文件调用。gcc -c main.c # -c 只编译,不链接,输出 main.o gcc -c func.c # .o:一堆机器码片段,也就是中间程序,但还不能直接运行。链接阶段:把一堆 .o 目标文件 + 系统库 / 第三方库拼在一起 → 可执行文件 exe 。解决:函数调用、库依赖,把零散机器码拼成完整可运行程序。gcc main.o func.o -o app.exe # 输入是.o文件,链接输出exe #输入一堆.o,合并+解析函数符号,生成可执行程序运行阶段.\app.exe二、CMakeLists.txt 中具有分析工程依赖、源码、库、头文件等功能,请问CMakeLists.txt 具体是怎么实现这些功能的,高度抽象总结出来这些知识点。答:CMakeLists.txt 高度抽象总结:它到底靠哪些命令完成「分析源码、头文件、依赖库」CMakeLists 本质就是一套描述工程的声明式脚本:告诉 CMake:我的源码在哪、头文件在哪、要造什么目标(库 / 程序)、目标之间有什么依赖关系。 可以把全部命令归为六大模块,网课里面所有 1‑18 课全部逃不出这 6大类。模块 1:工程基础配置(打底,课程 1、2、3‑4 set)作用:规定版本、项目名字、定义各种路径 / 变量,给后面所有模块用。cmake_minimum_required() # 最低CMake版本要求 project() # 定义项目名称 set() # 定义变量:路径名、源码列表,替代硬编码字符串👉 对应能力:定义工程整体信息,统一管理路径,避免到处写死绝对路径。模块 2:搜集源码文件(课程 5 搜索文件)作用:告诉 CMake,哪些 cpp 文件需要参与编译。两种写法:手动:set(SRC a.cpp b.cpp)手动列举源文件(工业项目首选)自动搜索:aux_source_directory()自动搜目录下全部 cpp(网课示例常用,小工程)👉 对应能力:收集参与编译的源代码,没有源码,CMake 不知道编译什么。模块 3:头文件搜索配置(课程 6 指定头文件路径)作用:告诉 gcc,去哪里找.h头文件。include_directories() # 全局头文件路径(老写法) target_include_directories() # 现代CMake:给某一个目标单独设置头文件路径(推荐)👉 对应能力:解决#include "xxx.h"找不到头文件的编译报错。⚠️这一步只解决编译阶段找头文件,不会处理库文件。模块 4:定义编译目标 —— 告诉 CMake 要产出什么东西(课程 7)目标 (target) 是 CMake 的核心概念:每一个库、每一个可执行程序都叫一个 target。add_library(名字 STATIC 源码) # 目标:生成静态库 .a add_library(名字 SHARED 源码) # 目标:生成动态库 .so add_executable(名字 源码) # 目标:生成可执行程序👉 对应能力:声明你最终要产出的产物,CMake 会为每一个目标生成对应的编译规则。模块 5:处理依赖 链接(重中之重:课程 8、9‑10、17、18)作用:描述目标和目标之间的依赖关系:A 目标需要用到 B 库。target_link_libraries(目标名 PRIVATE/PUBLIC/INTERFACE 依赖库)这一条命令包揽全部链接场景:可执行程序链接静态库可执行程序链接动态库静态库链接另一个静态库(课 17)静态库链接动态库(课 18)补充两个辅助命令link_directories():告诉链接器去哪里找现成的.a/.so库文件add_subdirectory():嵌套 CMake(课 15‑16):加载另外一个子目录的 CMakeLists,引入别的 target。模块 6:CMake 脚本工具函数(脚本语言能力,课 11‑14)CMake 本身是一门脚本语言,可以做打印、字符串处理、列表、宏替换,不参与编译,是辅助调试和配置。message() # 打印日志调试 string() # 字符串操作 list() # 列表操作 configure_file() # 自定义宏,生成配置头文件补充一、完整逻辑链条(脑子里跑一遍 CMake 工作流程)读取顶层CMakeLists.txt,执行基础配置:cmake_minimum_required、project、set定义路径变量。遇到add_subdirectory(),跳转解析子目录的CMakeLists.txt,优先编译被依赖的库。在子库 CMakeLists:搜集源码;设置头文件目录;add_library()创建库目标;target_link_libraries()填写库之间的依赖(课 17/18 就在这里)。解析应用程序目录:add_executable()创建可执行程序目标,再用target_link_libraries链接上面编译好的库。CMake 全部解析完毕,根据所有 target、源码、头文件、依赖关系,生成 Makefile(cmake .. 结束)。执行make:读取 Makefile,调用 gcc/g++,编译每个.cpp,按照依赖完成链接,输出库和可执行程序。./程序操作系统运行产物,CMake 彻底退出。补充二、关键区分(极易混淆)include_directories / target_include_directories编译期:找.h 头文件,只用于代码编译阶段。target_link_libraries链接期:找.a/.so 库二进制,编译完 cpp 之后,把库代码合并进程序。❗头文件路径 ≠ 库路径;包含头文件≠链接库。 你#include xxx.h只是让编译器认识函数声明,还必须链接对应的库文件,否则报 undefined reference 未定义引用错误。补充三、PRIVATE / PUBLIC / INTERFACE 极简记忆表格修饰符含义PRIVATE
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门