Linux 应用层开发入门(二)| GCC编译器的使用

在 Linux 环境下,源文件需要经过编译才能生成可执行文件。在 Windows 平台进行应用程序开发时,开发者通常只需通过点击按钮即可完成编译过程,这是因为集成开发环境(IDE)(如 Visual Studio)已经对底层的编译、链接等工具进行了高度封装,屏蔽了编译细节。相比之下,Linux 平台同样提供了功能完善的集成开发环境,但在实际工程开发中,更常见的方式是直接使用命令行编译工具。即便在使用 IDE 的情况下,开发者仍然需要理解并掌握常用的编译流程及关键编译选项,这对于定位编译错误、优化程序性能以及进行交叉编译尤为重要。
在 PC 平台(x86 架构)上,常用的编译工具链主要包括 gcc、ld、objcopy、objdump 等,这些工具生成的可执行程序只能在 x86 平台上运行。而在嵌入式 Linux 开发中,目标运行平台通常为 ARM 架构,此时必须使用交叉编译工具链,例如
xxx-gcc、xxx-ld等。不同工具链的前缀可能有所差异,如arm-linux-gcc、arm-buildroot-linux-gnueabihf-gcc等,但其基本工作原理是一致的。
下面将围绕 GCC 编译器,依次介绍 Linux 下程序的编译流程、常用编译选项以及交叉编译的基本用法,为后续的应用层开发实践奠定基础。
1 GCC编译过程
在 Linux 环境下,C/C++ 源文件并不能直接运行,必须经过编译生成可执行文件。一个完整的 C/C++ 程序,从源代码到最终可执行文件,通常需要经历 四个阶段:
汇编
start.s -------> start.o --| 链接
预处理 编译 汇编 |-------> led.elf
main.c --------> main.i --------> mainn.s -------> main.o --|
- 预处理(Preprocessing)
- 编译(Compilation)
- 汇编(Assembly)
- 链接(Linking)
这四个步骤共同构成了 GCC 的完整编译过程。在日常交流中,我们通常使用“编译”这一术语来统称上述全部过程;如果不是特指其中某一个阶段,本文也遵循这一习惯。
1.1 GCC编译流程概述
GCC 的整体编译流程如下所示:
hello.c
↓ 预处理(-E)
hello.i
↓ 编译(-S)
hello.s
↓ 汇编(-c)
hello.o
↓ 链接
hello(可执行文件)
GCC 通过不同的命令行选项,可以 单独执行某一步,也可以 一次性完成全部步骤。

1.2 使用 GCC 一步完成编译
最常见的用法是直接让 GCC 完成从源文件到可执行文件的全部流程:
gcc hello.c
上述命令会生成一个默认名称为 a.out 的可执行文件:
./a.out
指定输出文件名:
gcc -o hello hello.c
./hello
1.3 GCC 编译过程的详细拆解
为了更清楚地理解 GCC 内部的工作机制,我们可以使用 -v 选项查看编译过程:
gcc -o hello hello.c -v
输出信息较多,其中关键步骤类似如下:

cc1 hello.c -o /tmp/ccxxxx.s
as -o /tmp/ccxxxx.o /tmp/ccxxxx.s
collect2 -o hello /tmp/ccxxxx.o ...
这些命令分别对应 GCC 编译过程中的各个阶段。
1.4 各编译阶段说明
1.4.1 预处理(Preprocessing)
C/C++源文件中,以“#”开头的命令被称为预处理命令,如包含命令 “#include”、宏定义命令“#define”、条件编译命令“#if”、“#ifdef”等。 预处理就是将要包含(include)的文件插入原文件中、将宏定义展开、根据条件 编译命令选择要使用的代码,最后将这些东西输出到一个“.i”文件中等待进一 步处理。预处理阶段主要完成以下工作:
- 展开
#include引入的头文件 - 展开
#define定义的宏 - 处理条件编译指令(
#if、#ifdef等) - 删除注释
可以使用 -E 选项只进行预处理:
gcc -E hello.c -o hello.i

生成的 hello.i 文件中已经不再包含宏和头文件,而是纯 C 代码。
📌 查看所有宏定义:
gcc -E -dM hello.c

1.4.2 编译(Compilation)
编译就是把C/C++代码(比如上述的“.i”文件)“翻译”成汇编代码,所用 到的工具为cc1(它的名字就是cc1,x86有自己的cc1命令,ARM板也有自己的 cc1 命令)。编译阶段会将预处理后的 C 代码翻译成 汇编代码。
gcc -S hello.i -o hello.s

生成的 hello.s 是平台相关的汇编代码。
该阶段由 GCC 内部的 cc1 工具完成,不同架构(x86 / ARM)对应不同的 cc1。
1.4.3 汇编(Assembly)
汇编就是将第二步输出的汇编代码翻译成符合一定格式的机器代码,在 Linux 系统上一般表现为ELF目标文件(OBJ 文件),用到的工具为as。x86有 自己的 as 命令,ARM 版也有自己的 as 命令,也可能是 xxxx-as(比如 arm linux-as)。汇编阶段将汇编代码转换为 目标文件(Object File):
gcc -c hello.s -o hello.o

hello.o 是二进制格式的 ELF 目标文件,但仍不能直接运行;该阶段由汇编器 as 完成。
1.4.4 链接(Linking)
链接就是将上步生成的OBJ文件和系统库的OBJ文件、库文件链接起来,最终生成了可以在特定平台运行的可执行文件,用到的工具为ld或collect2。
gcc -o hello hello.o

链接过程通常由 collect2 调用 ld 完成。上述命令会生成一个默认名称为 hello.out 的可执行文件,即输入>>> ./hello <<<就可以执行文件:

2 GCC 常用编译选项
| 选项 | 说明 |
|---|---|
-E |
只进行预处理 |
-S |
编译生成汇编代码 |
-c |
生成目标文件,不链接 |
-o |
指定输出文件名 |
-I |
指定头文件搜索路径 |
-L |
指定库文件搜索路径 |
-l |
指定链接的库 |
3 x86 GCC 与 ARM 交叉编译说明
本文示例使用的是 x86 平台上的 gcc。在 ARM 嵌入式开发中,只需将 gcc 替换为对应的交叉编译器,例如:
arm-buildroot-linux-gnueabihf-gcc hello.c -o hello
其 编译流程、参数含义和使用方式完全一致,只是目标平台不同。
4 本节小结
本节介绍了 GCC 编译器的基本工作流程:
- 理解 C 程序从源代码到可执行文件的 4 个阶段
- 掌握常见的 GCC 编译选项
- 学会拆解并观察 GCC 的内部编译过程
- 为后续 Makefile、多文件工程和交叉编译打下基础
更多推荐



所有评论(0)