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

从微观到宏观了解C++项目的编译 - 教程

微观层面

在 C++ 中,每一个 .cpp 源文件都是独立编译的。这个过程通常分为四个步骤:

  1. 预处理 (Preprocessing)

    • 做什么:处理所有以 # 开头的指令。

    • 具体:把 #include "header.h" 的内容原封不动地复制粘贴到 .cpp 文件里;把 #define 定义的宏进行文本替换。

    • 产物:一个巨大的、纯 C++ 代码的文本流(不再包含 # 指令)。

  2. 编译 (Compilation)

    • 做什么:把 C++ 代码翻译成汇编语言

    • 具体:是否开启优化-O2 / -O3;是否打开调试信息:-g;是否启用某些指令集:-march=native, -mavx2 等;检查语法错误,将高级语言逻辑转换为 CPU 指令的助记符。

    • 产物:汇编文件(.s)。

  3. 汇编 (Assembly)

    • 做什么:把汇编语言翻译成机器能读懂的二进制机器码

    • 产物目标文件 (Object File),在 Linux 下通常是 .o 文件,Windows 下是 .obj。

    • 注意:此时,每个 .o 文件只包含自己那部分代码的机器码,如果代码里调用了别的文件的函数,这里只留了一个“坑”(占位符),并不知道具体地址。

  4. 链接 (Linking)

    • 做什么:把成百上千个 .o 文件和各种库文件(.a, .so)打包在一起,生成最终的可执行文件或库。

    • 具体:链接器会扫描所有 .o 文件,填上第3步留下的那些“坑”。比如 A 文件调用了 B 文件的函数,链接器负责把 A 中调用的地址指向 B 中函数的实际地址。

    • 产物:最终的可执行程序(Executable)或 库(Library)。

    • 静态链接 / 动态链接:两者都是 先编译好库,区别在于:

      • 静态链接:把库的代码拷贝一份进可执行文件里 → 可执行文件大,但独立性强。

      • 动态链接运行时去加载 .so/.dll → 文件小,但依赖运行环境要有对应的库。

宏观层面

对一个大型项目,往往会有:

  • 若干静态库 / 动态库

  • 若干可执行文件工具

  • 单元测试、benchmark、demo

假如一个大一点的项目如下:

project/src/main.cppdetector.cpputils.cppinclude/detector.hutils.hthird_party/libsome_cv.a    # 一个静态库

如果不构建系统的话就要写一堆命令:

# 编译每个 cpp 为 .o
g++ -Iinclude -c src/detector.cpp -o build/detector.o
g++ -Iinclude -c src/utils.cpp    -o build/utils.o
g++ -Iinclude -c src/main.cpp     -o build/main.o
# 链接,生成最终可执行文件
g++ build/main.o build/detector.o build/utils.o \third_party/libsome_cv.a \-o build/seatbelt_demo
再加上:
Debug/Release 两套配置
不同平台(Linux/Windows)
不同编译选项(开不开 O3、开不开 AVX)
单元测试、示例、工具程序…

这些东西的依赖关系一复杂,手写脚本就会很容易爆炸。

所以引入CMake只需要写工程描述就可以

来源于菜鸟教程的CMake解释

实际上的层面划分

源码 →(CMake)→ 构建系统(Ninja/Makefile/VS 工程)→ 调用编译器 → 可执行文件

  • CMake 干的事:

    • 读取 CMakeLists.txt,理解“这个项目有哪些源文件、要生成什么可执行文件、需要哪些库、用什么编译选项”

    • 生成对应平台的“构建脚本”,比如:

      • Linux/macOS:Makefile 或 Ninja 的 build.ninja

      • Windows:Visual Studio 的 .sln.vcxproj

  • 真正编译 C++ 的还是编译器g++ / clang / cl.exe
    CMake 只是在帮你把一长串编译命令自动拼出来,并且增量编译、跨平台都帮你处理好了。

流程其实是两步:

  1. 配置(configure)

    • CMakeLists.txt

    • 生成构建文件(Makefile / build.ninja / VS 工程等)

  2. 构建(build)

    • 用上一步生成的构建文件

    • 实际调用 g++/clang/cl 去编译和链接

cmake -S . -B build      # 第一步:配置 -> 在 build/ 里生成构建脚本
cmake --build build      # 第二步:构建 -> 真正编译
  • cmake:运行 CMake 程序。

  • -S .Source,源码目录在当前目录 .(里面要有 CMakeLists.txt)。

  • -B buildBinary / Build,生成的构建文件放到 build/ 目录里(推荐的 out-of-source build)。

“cmake --build build”只是 “cmake(程序) ——build(子命令) build(目录)”

还可以指定生成器

因为 CMake 只是“中间人”,得适配不同平台 / 工具链:

  • Unix Makefiles → 生成 Makefile,然后用 make

  • Ninja → 生成 build.ninja,然后用 ninja

  • Visual Studio 17 2022 → 生成 .sln.vcxproj

  • 还有 Xcode 等等

一般自己用的话,可以简单粗暴地记:

  • Linux/macOS:随便用默认,或者一直用 Ninja

    cmake -S . -B build -G "Ninja"
  • Unix Makefiles(默认的 Make)

生成器选择建议:

  • 如果你没啥特别需求 → 用 Ninja,爽一点

  • 如果 Ninja 没装 / 老项目都用 Make → 用默认的也没问题

简单对比:

  • Ninja

    • 编译速度通常更快(增量编译调度做得好)

    • 输出信息更干净

    • 配合 CMake 官方也推荐

  • Make (Unix Makefiles)

    • 到哪基本都有

    • 工具链、老项目兼容性好

    • 但大项目下依赖计算、并行效率可能不如 Ninja

构建类型(Debug / Release)怎么选?谁好谁坏

这里分两类生成器看:

单配置生成器(Make / Ninja)

它们一次 build 只能是一个配置,所以要在 configure 阶段告诉 CMake:

常用的几种:

  • Debug

    • 几乎不开优化,保留完整调试信息

    • 开发调试时用

  • Release

    • 开优化(-O3 等),可能不带调试信息

    • 最终发布 / 跑性能时用

  • RelWithDebInfo(Release with Debug Info)

    • 开优化 + 保留调试信息

    • 想兼顾“能调试 + 不至于太慢”时用

配置方式(Ninja/Make 常用):

# Debug版本
cmake -S . -B build -G "Ninja" -DCMAKE_BUILD_TYPE=Debug
# Release版本
cmake -S . -B build-release -G "Ninja" -DCMAKE_BUILD_TYPE=Release
cmake --build build           # 编译 Debug
cmake --build build-release   # 编译 Release

    可以给不同配置用不同 build 目录:build-debug, build-release,互不干扰

    多配置生成器(VS / Xcode)

    这类生成器一次可以包含多个配置(Debug/Release 都在工程里),所以

    cmake -S . -B build -G "Visual Studio 17 2022"
    #配置时不写 CMAKE_BUILD_TYPE
    cmake --build build --config Debug
    cmake --build build --config Release
    #构建时再选

    最后 因为我是偏命令行编译C++  就固定这样

    # 第一次 / 改配置时:
    cmake -S . -B build -G "Ninja" -DCMAKE_BUILD_TYPE=Debug
    # 之后每次改完代码只要:
    cmake --build build -j$(nproc)

    -j = jobs,意思是:同时开多少个编译任务并行跑

    $(nproc) 是啥?这一段是 shell 语法,叫“命令替换”:意思是:先执行括号里的命令,把输出结果当作字符串塞回来= 先执行 nproc 这个命令,它会输出当前 CPU 有多少个逻辑核心

    所以cmake --build build -j$(nproc)即为build 目录里编译,并行任务数 = CPU 的核心数

    终极版总结三种角色

    • CMake

      • ✅ 看 CMakeLists.txt

      • ✅ 根据你选的“生成器”(Ninja / Make / VS)生成对应的构建脚本

        • 比如:Makefile / build.ninja / .sln

      • ❌ 不负责决定“什么时候重编什么文件”

    • 构建系统(Make / Ninja / VS 等)

      • ✅ 读取 CMake 生成的构建脚本

      • ✅ 进行 增量编译判断

        • 哪些 .cpp 改了 → 只编这些

        • 哪些没改 → 直接复用上次的 .o

      • ✅ 调用编译器去干活(编译、链接)

    • 编译器(g++ / clang / cl)

      • ✅ 负责把 .cpp.o(+ 汇编这些细节)

      • ✅ 把一堆 .o + 库 → 可执行文件 / 动态库

    CMakeCMakeLists.txt,根据选的生成器生成对应构建脚本;
    构建系统 读这些脚本,做增量编译判断,然后调用 编译器 进行编译/链接生成可执行文件。

    暂且算是把最基本的捋明白了 maybe 未完待续。。。

    http://www.jsqmd.com/news/362318/

    相关文章:

  • 当漏洞未爆发时:预测型防御如何改写容器安全攻防战——致软件测试工程师的前沿防御指南
  • 2026年济南公司搬家服务评测推荐:告别搬迁烦恼,高效省心之选排行榜 - 品牌推荐
  • 2026年进口无线表面肌电代理商推荐:国际知名品牌选购与国内优质代理渠道全解析 - 品牌推荐大师1
  • 2026年济南管道疏通服务评测排名:专业疏通服务选择指南与避坑要点 - 品牌推荐
  • 面向对象程序设计-寒假学习
  • 翘曲晶圆传输易损坏,哪种末端效应器的晶圆机器人适配性更好?
  • 银行展厅智能化服务:金融消保科普场景下的迎宾机器人技术解析与主流产品应用 - 智造出海
  • 2026国内最新月嫂会所top10推荐!服务深度覆盖广州、天河、黄埔、海珠等地,优质月子中心权威榜单发布,专业护理助力新生家庭安心休养 - 品牌推荐2026
  • 一周时间搭建企业级Agent开发平台!完整技术方案+代码实现,建议收藏
  • 产品拆解到底怎么做?8步框架,新手产品经理必学干货!
  • (9)UPlayer 与 APawn 与 AController 的区别,
  • 服务器如何配置SSH密钥登录提高安全性
  • 一文看懂重庆艺考文化课:核心要素、Top5机构推荐与选课逻辑 - 深度智识库
  • 【收藏必看】Agent评测体系实战指南:3大评分器+2大框架,建立可量化的信任机制
  • 2026年全国路灯/玉兰灯/太阳能路灯/高杆灯厂家权威榜单 智能化节能化全覆盖 - 深度智识库
  • 一元羊肉粉月赚30万:揭秘餐饮秘籍
  • 【SCI投稿全流程】新手小白第一次投稿必读,包你少走弯路!
  • 如何在生产环境中部署Java调用淘宝商品详情API的项目?
  • vmare workstatition下载
  • 【公共管理方向可投稿】第六届公共管理与智能社会国际学术会议(PMIS 2026)
  • 2026年济南电脑售后维修点评测推荐:当电脑突发故障,如何选择靠谱服务商 - 品牌推荐
  • 基于DWS构建RAG框架生成行业调研报告
  • 【多所研究所知名高校办会】第三届光电信息与光学工程国际学术会议(OIOE 2026)
  • 2026年香港留学申请攻略:深圳优选中介助力港前三本科录取 - 品牌2025
  • AI元人文:多元共生与价值原语
  • 2026年济南钢琴搬运公司评测推荐:告别搬运烦恼,专业服务安心之选 - 品牌推荐
  • 2026年尤斯灌流室厂家直供推荐榜:国内斯灌流室行业标杆企业/质量可靠的生产企业全方位评测 - 品牌推荐大师1
  • 白帽视角下的安全事故1.19亿罚单:一场本可避免的网络安全风暴
  • 2026副主任护师备考资料推荐:优选适配,准确助力备考通关 - 医考机构品牌测评专家
  • 2026SAT备考不踩坑指南:SAT一对一、小班、线下怎么选才高效? - 品牌2025