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

软件构建工具生态

系统框架

┌───────────────────────────────┐
│ 配置层 (Configuration)         │
│   • Kconfig (Linux, Zephyr)   │
│   • Kconfig-frontends (menu)  │
│   → 决定编译哪些功能模块         │
│   → 生成 .config 文件          │
└───────────────────────────────┘│▼
┌───────────────────────────────┐
│ 构建系统生成层 (Meta-Build)     │
│   • CMake                     │
│   • Meson                     │
│   • Autotools (configure)     │
│   • GN, Bazel, Buck           │
│   → 解析工程结构 & 配置          │
│   → 生成规则文件                │
│     (Makefile / build.ninja)  │
└───────────────────────────────┘│▼
┌───────────────────────────────┐
│ 构建执行层 (Build Executor)     │
│   • Make                      │
│   • Ninja                     │
│   • MSBuild (Windows)         │
│   • Gradle (Java/Android)     │
│   → 执行具体编译命令             │
│   → 调用编译器                  │
└───────────────────────────────┘│▼
┌───────────────────────────────┐
│ 编译器 (Compiler Toolchain)    │
│   • GCC / Clang / MSVC        │
│   • Emscripten (WebAssembly)  │
│   • arm-none-eabi-gcc (嵌入式) │
│   → 把源码编译成目标文件/库/可执行 │
└───────────────────────────────┘│▼
┌───────────────────────────────┐
│ 产物 (Artifacts)               │
│   • 可执行文件 (ELF, EXE)       │
│   • 静态库 (.a, .lib)          │
│   • 动态库 (.so, .dll)         │
│   • WebAssembly (.wasm)       │
└───────────────────────────────┘

比喻:

  • 生成器 (CMake / Meson / Bazel) = 建筑师,负责出图纸(规则文件)。
  • 执行器 (Make / Ninja / MSBuild) = 工地工头,照图纸分配任务。
  • 编译器 (GCC / Clang / MSVC) = 工人,真正把砖(源码)砌成房子(可执行文件)。
  • 辅助工具 = 供应链和加速器,让工地运转更快更稳。

生成器 / 元构建工具(高层):这些工具和 CMake 属于同类,都不直接编译,而是生成规则文件。

  • 这些工具负责 描述工程结构,然后生成底层构建文件。CMake 就在这一层。
  • CMake → 跨平台通用的生成器。
  • Meson → 类似 CMake,搭配 Ninja,语法更现代。
  • Autotools (GNU Autoconf/Automake) → 传统 Unix 世界,写 configure 脚本。
  • Bazel (Google 出品) → 强调可重现、分布式构建。
  • Buck (Meta 出品) → 针对大规模 C++/Java 工程。
  • GN (Generate Ninja, Chromium 用) → 专门为生成 Ninja 构建文件设计,取代 GYP。

构建执行器(中层):这些和 Make/Ninja 是同类,主要区别在生态和性能。

  • 这些是真正的 构建工具,读规则文件去调用编译器。
  • Make → 经典,执行 Makefile。
  • Ninja → 新一代,快,执行 build.ninja。
  • MSBuild → Windows/.NET 世界,执行 .csproj/.sln。
  • Gradle → Java/Android 生态常用。
  • Ant (老 Java 工具) → 逐渐被 Gradle/Maven 替代。

编译器(底层)执行器最终调用的就是编译器:

  • GCC(GNU Compiler Collection)
  • Clang/LLVM
  • MSVC (Microsoft Visual C++)
  • ICC (Intel C Compiler, 已转向 oneAPI DPC++)
  • Emscripten (emcc) → 把 C/C++ 转为 WebAssembly

相关工具(辅助层)在构建生态里,还有一些配套工具:

  • Pkg-config → 帮助查找依赖库的头文件路径、链接参数。
  • Conan / vcpkg → C/C++ 包管理器,类似 npm/pip。
  • ccache → 编译缓存,加速二次构建。
  • distcc / icecc → 分布式编译,把任务分发到多台机器。
  • Docker → 提供一致的编译环境,避免“在我机子上能跑”。
场景生成器 (高层)执行器 (中层)编译器 (底层)说明
Linux 桌面应用CMake / Meson / AutotoolsMake / NinjaGCC / Clang经典组合:CMake + Ninja + GCC,性能好、兼容性强
Windows 桌面应用CMake / MSBuild / QMakeMSBuild (VS) / NinjaMSVC / ClangVS 开发常用 MSBuild;跨平台项目偏好 CMake + Ninja
macOS/iOS 应用CMake / XcodeXcode (xcodebuild) / NinjaClang (Apple LLVM)苹果生态强绑定 Clang/Xcode;跨平台可用 CMake
Android (NDK, JNI)CMake / GradleNinja (NDK) / GradleClang (NDK)上层 APK 构建靠 Gradle,底层 native 用 CMake + Ninja
WebAssembly (Emscripten)CMake / MesonNinjaEmscripten (emcc, em++)Qt WASM、游戏引擎常用组合
嵌入式 ARM (裸机/RTOS)CMakeNinja / MakeGCC (arm-none-eabi) / LLVM常见 STM32、nRF、ESP32 SDK 都支持 CMake
大型项目 (Chromium, TensorFlow)GN / Bazel / BuckNinjaClang / GCCNinja 的速度优势在大项目里特别明显
Java/Android 应用 (非 NDK)GradleGradlejavac / kotlinc完全 Java/Kotlin 生态,不涉及 C/C++
老派 Unix 项目Autotools (configure)MakeGCC很多历史项目依旧在用 ./configure && make

CPU 架构与编译器

                ┌───────────────┐│   源代码 (C/C++) │└───────────────┘│▼┌───────────────────────────────────────────┐│              编译器前端 (Front-end)       ││   解析语法、检查语义、支持 C/C++ 标准     ││   ───────────────────────────────────     ││   GCC   |   Clang/LLVM   |   MSVC         │└───────────────────────────────────────────┘│▼┌───────────────────────────────────────────┐│            编译器后端 (Back-end)           ││   不同 CPU 架构的代码生成 (Codegen)        ││                                           ││   x86 / x86_64 → PC, 服务器               ││   ARM-M (裸机) → MCU, IoT                 ││   ARM-A (Linux) → 树莓派, 手机            ││   RISC-V → 嵌入式, Linux SBC              ││   MIPS → 路由器, 机顶盒                   ││   PowerPC → 工控, 游戏机                  ││   SPARC → 服务器                          │└───────────────────────────────────────────┘│▼┌───────────────────────────────────────────┐│            目标文件 / 可执行文件            ││   .o / .elf / .bin / .exe / .so / .dll    │└───────────────────────────────────────────┘

一个典型的 GCC 工具链名字形如:

<arch>-<vendor>-<os>-<abi>
  • arch → CPU 架构 (x86, arm, riscv…)
  • vendor → 厂商/发行版 (gnu, w64, unknown…),vendor 字段经常被省略,特别是 pc、unknown 这种没太大意义的值。
  • os → 目标操作系统 (linux, none, mingw32…)
  • abi → 应用二进制接口 (eabi, gnu, musl, hardfp…)
    • 光从 gcc 工具链的名字,并不能具体区分 ABI。
    • x86\_64-linux-gnu-gccaarch64-linux-gnu-gcc,这两个从名字上看他们的 ABI 都是 GNU,其实差异很大
工具链名架构 (arch)操作系统 (os)ABI/用途输出文件格式典型应用
x86_64-linux-gnu-gccx86_64LinuxGNU libcELF常见 Linux 程序
i686-linux-gnu-gccx86 (32-bit)LinuxGNU libcELF老 32 位 Linux 程序
arm-none-eabi-gccARM Cortex-MNone (裸机)EABI (无 OS)ELF / BINSTM32, nRF52, RTOS
arm-linux-gnueabihf-gccARMv7 (32-bit)LinuxGNU libc, 硬浮点ELF树莓派 32-bit Linux
aarch64-linux-gnu-gccARMv8 (64-bit)LinuxGNU libcELF树莓派 64-bit Linux, Android
riscv64-unknown-elf-gccRISC-VNone (裸机)ELFELF / BINRISC-V MCU
riscv64-unknown-linux-gnu-gccRISC-VLinuxGNU libcELFRISC-V Linux SBC
x86_64-w64-mingw32-gccx86_64Windows (MinGW)Win32 APIPE (.exe/.dll)交叉编 Windows 程序
i686-w64-mingw32-gccx86 (32-bit)Windows (MinGW)Win32 APIPE老 Windows 程序
powerpc-linux-gnu-gccPowerPCLinuxGNU libcELF工控机, 老游戏机
mipsel-linux-gnu-gccMIPS (小端)LinuxGNU libcELF路由器, 机顶盒

ABI 是什么?

  • 如果说 API(应用编程接口)是“源代码层面的约定”(比如 printf() 怎么调用),
  • 那 ABI(应用二进制接口)就是“编译后机器码层面的约定”:函数参数怎么传递(寄存器还是栈?顺序?)
    • 返回值怎么传递
    • 数据类型的大小和对齐方式(int 是 32 位还是 64 位?)
    • 调用系统调用的方式(Linux syscall、Windows syscall 不一样)
    • 动态库的符号如何导出/解析
    • 只要 ABI 不兼容,就算源代码一样,编译出来的二进制也跑不通。
工具链名ABI 字段含义
x86_64-linux-gnugnu使用 GNU libc (glibc) 的 Linux ABI
x86_64-linux-muslmusl使用 musl libc 的 Linux ABI(常见于 Alpine Linux)
arm-none-eabieabiEmbedded ABI,ARM 裸机/RTOS,不依赖操作系统
arm-linux-gnueabihfgnueabihfLinux + glibc + 硬件浮点 (hard-float ABI)
arm-linux-gnueabignueabiLinux + glibc + 软件浮点 (soft-float ABI)
riscv64-unknown-elfelf没有 OS,用 ELF 作为目标文件格式

ABI 与编程语言的关系

          ┌───────────────────────────────┐│            ABI                 ││  (应用二进制接口, EABI/gnu…)   │└───────────────────────────────┘│┌───────────────────┼───────────────────┐▼                   ▼                   ▼直接编译型语言      依赖运行时语言       虚拟机语言(遵循 ABI)           (解释器遵循 ABI)     (VM 遵循 ABI)─────────────        ─────────────        ─────────────• C                 • Python             • Java• C++               • Lua                • Kotlin/JVM• Rust              • Ruby               • Scala• Go (部分实现)     • MicroPython*       • .NET/Mono• Fortran           • PHP                • C#  ─────────────        ─────────────        ─────────────

直接编译型语言:

  • 编译器直接输出目标机器码 (ELF/PE/Mach-O)。
  • 必须严格遵循 ABI 的函数调用、数据布局、异常规则。
  • 例子:C, C++, Rust, Fortran。
  • 在 ARM EABI、Linux glibc、Windows PE 下都能直接跑。

依赖运行时语言:

  • 自身不能直接编译成裸机机器码。
  • 需要一个 解释器 (interpreter) 或 运行时 (runtime),而这个解释器是用 C/C++ 写的
  • 所以它们是 间接遵循 ABI
  • 例子:Python (CPython), Lua, Ruby, PHP。
  • 在嵌入式 MCU 里 → 可以跑 MicroPython (因为解释器本身是 C 写的,遵循 EABI)。

虚拟机语言

  • 语言本身运行在 虚拟机 (JVM, CLR) 上,不能直接映射到裸机 ABI。
  • VM 是用 C/C++ 写的,所以 VM 遵循 ABI,而语言通过 VM 间接遵循
  • 例子:Java, Kotlin, Scala (JVM),C#/.NET。
  • 在 ARM Linux 上跑 Java 程序,其实是 JVM 遵循 Linux ABI。

C 库与系统调用

常见 C 库及适用平台

C 库特点适用平台
glibc (GNU C Library)功能最全,POSIX 标准实现,支持多线程、locale、动态加载。体积大。Linux 桌面、服务器
musl轻量化,静态链接友好,二进制小。Alpine Linux、容器、嵌入式 Linux
uClibc比 glibc 小,适合路由器等小型 Linux。OpenWrt、嵌入式 Linux
newlib面向裸机/RTOS,只有最基本的 C 标准库,没有系统调用,需要用户自己实现 write() 等。ARM Cortex-M、RISC-V MCU (arm-none-eabi-gcc)
picolibcnewlib 的轻量化现代替代品,适合极小 MCU。STM32, nRF52, Zephyr RTOS
bionicGoogle 为 Android 写的 C 库,轻量,兼容 Linux 内核。Android (ARM/x86)
dietlibc极简 C 库,超小,功能不全。超小嵌入式 Linux
MSVCRT / UCRTWindows 的 C 运行时库(CRT),提供 C API + WinAPI 绑定。Windows
Darwin libcmacOS/iOS 的 C 库,基于 BSD libc。Apple 系统
【用户态 User Space】
──────────────────────────────────────────────应用程序 (App)││  1. 调用标准库函数│     printf("hi"); fopen("file.txt", "r");▼C 库 (glibc / musl / newlib …)││  2. 解析参数,准备系统调用号│     比如 write(fd=1, buf="hi", len=3)││  3. 调用封装好的 syscall 接口▼系统调用接口 (syscall wrapper)││  4. 触发特权指令│     x86: int 0x80 / syscall│     ARM: svc #0│
───────────────────────[ 用户态 → 内核态 切换 ]───────────────────────
【内核态 Kernel Space】│▼内核系统调用分发 (syscall table)││  5. 根据系统调用号跳转到对应内核函数│     sys_write(), sys_open(), sys_fork()│▼内核子系统├─ 进程管理 (fork, exec, wait)├─ 内存管理 (mmap, brk, page fault)├─ 文件系统 (open, read, write)├─ 网络协议栈 (socket, send, recv)└─ 驱动程序 (控制硬件 IO)││  6. 执行完毕,返回结果 (返回值 / errno)▼
───────────────────────[ 内核态 → 用户态 切换 ]───────────────────────
【用户态 User Space】│▼C 库 (处理返回值)││  7. 封装返回值,转换为用户能理解的形式│     如果失败 → 设置 errno▼应用程序││  8. 得到最终结果│     (比如 printf 成功返回字符数)
──────────────────────────────────────────────
【硬件 Hardware】受内核驱动控制的设备 (CPU/内存/磁盘/网卡/显示器 …)

在 MCU(裸机/RTOS)平台上,到底有没有“系统调用”?newlib 里是怎么实现的?

系统调用的本质

  • 在 Linux/Windows 这类操作系统里:
  • 系统调用 (syscall) 是进入内核的“入口函数”,例如 read()、write()、open()。
  • 在 MCU(裸机/RTOS) 平台上:
    • 没有真正的“内核”,所以严格意义上 没有系统调用。
    • 但为了兼容标准 C 库(如 printf、malloc),C 库还是需要某种“底层实现”。

newlib 是一款专为嵌入式系统设计的 C 标准库,它提供了 C 标准 API (printf, malloc, time …),但底层功能必须由用户自己实现。

它采用了一种 “半系统调用 (syscall stubs)” 的机制:

  • newlib 里有一组 弱符号函数(weak functions),例如: _write _read _sbrk(堆空间扩展,malloc 用)_open, _close, _lseek _exit
  • 这些函数默认是空壳(weak implementation)。
  • 用户必须自己实现这些函数,把它们映射到 MCU 的外设或 RTOS API 上。
  • 这样 printf("hi") 在 newlib 里会调用 _write(fd, buf, len),而 _write 由你来实现(比如写到 UART)。

文章转载自:

http://eO8CYM6Y.xmxbm.cn
http://8wev5H7B.xmxbm.cn
http://TMRuR2nk.xmxbm.cn
http://Nz7YeVvW.xmxbm.cn
http://kbV3obKF.xmxbm.cn
http://FuQErOK8.xmxbm.cn
http://7Rlj77Bw.xmxbm.cn
http://53XAMZ3W.xmxbm.cn
http://E9g7Jc7I.xmxbm.cn
http://y6YKyy7h.xmxbm.cn
http://1SgMuJWd.xmxbm.cn
http://kR4Ca0JQ.xmxbm.cn
http://ri7oDkZp.xmxbm.cn
http://zl8NYuZB.xmxbm.cn
http://l2AcHtnA.xmxbm.cn
http://dREiZZB6.xmxbm.cn
http://ls8nODKG.xmxbm.cn
http://gWRRWvIL.xmxbm.cn
http://IV32lGia.xmxbm.cn
http://f4RDWzu0.xmxbm.cn
http://XGA69h8Z.xmxbm.cn
http://ZDpUhh1T.xmxbm.cn
http://HbD82sQ8.xmxbm.cn
http://oyvqThk0.xmxbm.cn
http://KCQtnJGq.xmxbm.cn
http://YZKfm9yk.xmxbm.cn
http://vzVmG5Pf.xmxbm.cn
http://CIiz8kxK.xmxbm.cn
http://8l4cACHc.xmxbm.cn
http://o1INv4xK.xmxbm.cn
http://www.dtcms.com/a/368138.html

相关文章:

  • 无人机RTK模块技术要点与难点
  • 微信开发小程序开发授权获取 access_token
  • Spring Boot+Nacos+MySQL微服务问题排查指南
  • LeetCode 2749.得到整数零需要执行的最少操作数:很独特的一道数学题(多公式硬讲——一步步还真能看懂)
  • 【C++】vectore
  • 柯尼卡美能达打印机SMB服务设置
  • 【VoNR】VoNR是5G语音,VoLTE是4G语音,他们是同一个IMS,只是使用了新的访问方式?
  • Android/Java 泛型全面详解
  • 国产化PDF处理控件Spire.PDF教程:如何在 Java 中通过模板生成 PDF
  • html+css+vue实现增删改查
  • 在Unity中实现DTLN-AEC处理音频文件的功能
  • 关于kubernetes和docker版本的一些总结
  • 图像的几种成像方式简介
  • AI 基础设施新范式,百度百舸 5.0 技术深度解析
  • 中创中间件适配HGDB
  • 没 iCloud, 如何数据从iPhone转移到iPhone
  • 【技术教程】如何将文档编辑器集成至基于Java的Web应用程序
  • 基于华为云平台的STM32F103C8T6工业生产线温湿度监控系统
  • js设计模式-状态模式
  • 一文从零部署vLLM+qwen0.5b(mac本地版,不可以实操GPU单元)
  • Python核心基础:运算符、流程控制与字符串操作详解
  • Follow 幂如何刷屏?拆解淘宝闪购×杨幂的情绪共振品牌营销
  • 嵌入式学习4——硬件
  • 数据标注:人工智能视觉感知的基石
  • 【Linux系统】POSIX信号量
  • 【Python - 类库 - requests】(02)使用“requests“发起GET请求的详细教程
  • XSCT/Vitis 裸机 JTAG 调试与常用命令
  • 【GitHub每日速递】不止 TeamViewer 替代!RustDesk 与 PowerToys,Windows 效率神器
  • 使用海康机器人相机SDK实现基本参数配置(C语言示例)
  • Go 服务注册 Nacos 的坑与解决方案——从 404 到连接成功的排查之路