【嵌入式常识篇】一个C项目工程在IDE中是怎么一步步编译成一个固件包的 ...

宁睿  论坛元老 | 2025-1-14 20:43:32 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1084|帖子 1084|积分 3262

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
媒介:初学C语言的时候是在Linux环境下,那时候只知道需要通过GCC工具编译成可执行文件才可以在运行,厥后进入到了嵌入式行业发现需要IDE将一个C项目工程编译成一个固件包,那时候经常会产生一个疑问:一个C项目工程在IDE中是怎么一步步编译成一个固件包的呢?下面就解答一下这个疑问。时光荏苒,也算是给当年刚入行的本身一个答案。

1️⃣,流程简述

将一个 C 项目工程源代码 编译成 固件包(hex、bin、elf 等) 的过程,涉及 编译工具链IDE 的工作原理。一样寻常来说,固件编译流程分为以下关键步骤:
   这个过程通常由 编译工具链(如 GCC、IAR、Keil、Clang 等)完成,而 IDE(如 Keil、STM32CubeIDE、IAR 等)负责调用这些工具链,并提供一个图形化的界面来简化开辟流程
  1. 源码 (C/ASM/头文件)
  2.     ↓
  3. 预处理器 (Preprocessor)
  4.     ↓
  5. 编译器 (Compiler)
  6.     ↓
  7. 汇编器 (Assembler)
  8.     ↓
  9. 链接器 (Linker)
  10.     ↓
  11. 固件包 (HEX/BIN/ELF 文件)
复制代码
对应的执行流程框图如下: 


2️⃣,预处理(Preprocessing)

   预处理器会在编译前对源代码举行 文本更换和展开,重要包括:
  

  • 处理 #include 头文件的引用。
  • 更换宏定义(#define)。
  • 处理条件编译指令(#ifdef、#ifndef、#endif 等)。
  • 移除注释。
  举个例子:下面的这个是源代码
  1. #include "my_header.h"
  2. #define LED_PIN 13
  3. void main() {
  4.     int pin = LED_PIN;
  5. }
复制代码
当预处理之后:
  1. void main() {
  2.     int pin = 13;
  3. }
复制代码
  对应的预处理工具与命令:(最经典的就是GCC,当然如果是其他的芯片环境平台大概就需要用到交叉编译工具了)
  GCC: gcc -E main.c -o main.i
  
3️⃣,编译(Compilation)

   预处理完成的 .i 文件(纯文本 C 代码)会被编译器转换成 汇编代码
  

  • 编译器的任务

    • 语法分析,检查代码的语法和语义。
    • 天生对应的汇编代码(.s 文件)

  同样是上面的例子:编译后的汇编代码:
  1. mov r0, #13
  2. str r0, [sp, #4]
复制代码
   编译工具:
  

  • GCC: gcc -S main.i -o main.s
  
4️⃣,链接(Linking)

   链接器的任务是将多个 目标文件(.o 文件)库文件(.a 或 .lib 文件)启动文件(startup 文件) 合并成一个 可执行的固件文件(.elf/.bin/.hex)
  

  • 链接的工作内容

    • 解析和解决函数、变量的外部引用。
    • 合并不同模块的目标文件。
    • 分配内存地址(根据链接脚本 linker script)。
    • 天生可执行文件(如 .elf、.bin、.hex)。

  链接工具:
  

  • GCC: gcc main.o -o main.elf
    -T linker_script.ld
  示例:
如果有多个文件:
  1. main.o      // 主程序
  2. startup.o   // 启动代码
  3. libc.a      // 标准库
复制代码
链接后的 ELF 文件:
  1. main.elf
复制代码
  
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

宁睿

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表