GCC编译器详解
概述
GCC(GNU Compiler Collection)是最流行的编译器套件,支持C、C++、Fortran等多种语言。
GCC编译流程
| Text Only |
|---|
| 源代码(.c) -> 预处理(.i) -> 编译(.s) -> 汇编(.o) -> 链接(可执行文件)
|
基本编译
单文件编译
| Bash |
|---|
| # 编译并运行
gcc hello.c -o hello
./hello
# 分步编译
gcc -E hello.c -o hello.i # 预处理
gcc -S hello.i -o hello.s # 编译为汇编
gcc -c hello.s -o hello.o # 汇编为目标文件
gcc hello.o -o hello # 链接
# C++编译
g++ hello.cpp -o hello
|
多文件编译
| Bash |
|---|
| # 一起编译
gcc main.c func.c -o program
# 分别编译后链接
gcc -c main.c -o main.o
gcc -c func.c -o func.o
gcc main.o func.o -o program
|
编译选项
优化选项
| Bash |
|---|
| -O0 # 不优化(默认)
-O1 # 基本优化
-O2 # 标准优化(推荐)
-O3 # 激进优化
-Os # 优化代码大小
-Ofast # 最快执行(不严格遵守标准)
# 示例
gcc -O2 program.c -o program
|
调试选项
| Bash |
|---|
| -g # 生成调试信息
-ggdb # GDB专用调试信息
-g3 # 最大化调试信息
# 示例
gcc -g program.c -o program
|
警告选项
| Bash |
|---|
| -Wall # 启用所有常见警告
-Wextra # 额外警告
-Werror # 警告当作错误
-Wpedantic # 严格遵循标准
-Wno-unused # 禁用特定警告
# 示例
gcc -Wall -Wextra program.c -o program
|
标准选项
| Bash |
|---|
| # C标准
-std=c89 # C89/C90
-std=c99 # C99
-std=c11 # C11
-std=c17 # C17
-std=gnu11 # C11 + GNU扩展
# C++标准
-std=c++11 # C++11
-std=c++14 # C++14
-std=c++17 # C++17
-std=c++20 # C++20
|
预处理器选项
| Bash |
|---|
| -DMACRO # 定义宏
-DDEBUG=1 # 定义宏并赋值
-UMACRO # 取消宏定义
-I/path/to/include # 添加头文件路径
-include file.h # 强制包含文件
# 示例
gcc -DDEBUG -I./include program.c -o program
|
链接选项
| Bash |
|---|
| -L/path/to/lib # 添加库路径
-lm # 链接数学库
-lpthread # 链接pthread库
-static # 静态链接
-shared # 生成共享库
-rdynamic # 导出符号给动态链接器
# 示例
gcc program.c -L./lib -lmylib -lm -o program
|
创建库文件
静态库
| Bash |
|---|
| # 编译目标文件
gcc -c func1.c -o func1.o
gcc -c func2.c -o func2.o
# 创建静态库
ar rcs libmylib.a func1.o func2.o
# 使用静态库
gcc main.c -L. -lmylib -o program
|
共享库
| Bash |
|---|
| # 创建共享库
gcc -shared -fPIC -o libmylib.so func1.c func2.c
# 使用共享库
gcc main.c -L. -lmylib -o program
# 运行时指定库路径
LD_LIBRARY_PATH=. ./program
# 或编译时指定
gcc main.c -L. -lmylib -Wl,-rpath,. -o program
|
交叉编译
ARM交叉编译
| Bash |
|---|
| # 安装交叉编译器
apt install gcc-arm-linux-gnueabihf
# 交叉编译
arm-linux-gnueabihf-gcc program.c -o program_arm
# 指定sysroot
arm-linux-gnueabihf-gcc --sysroot=/path/to/sysroot program.c -o program
|
常用架构
| Bash |
|---|
| # ARM 32位
arm-linux-gnueabihf-gcc
# ARM 64位
aarch64-linux-gnu-gcc
# RISC-V
riscv64-linux-gnu-gcc
# MIPS
mips-linux-gnu-gcc
|
链接器控制
链接脚本
| Text Only |
|---|
| /* linker.ld */
ENTRY(_start)
SECTIONS
{
. = 0x40000000;
.text : { *(.text) }
. = 0x40010000;
.data : { *(.data) }
.bss : { *(.bss) }
}
|
| Bash |
|---|
| # 使用链接脚本
gcc -T linker.ld program.c -o program
|
属性和内联汇编
函数属性
| C |
|---|
| // 对齐
__attribute__((aligned(16))) int var;
// 打包结构
struct __attribute__((packed)) {
char a;
int b;
};
// 不返回
__attribute__((noreturn)) void exit_program(void);
// 内联
static inline __attribute__((always_inline)) int add(int a, int b);
// 弱符号
__attribute__((weak)) void handler(void);
|
内联汇编
| C |
|---|
| // 基本内联汇编
asm("movl $1, %eax");
// 扩展内联汇编
int a = 10, b;
asm("movl %1, %0"
: "=r"(b)
: "r"(a));
// 带clobber列表
asm("movl %1, %0\n\t"
"addl $1, %0"
: "=r"(b)
: "r"(a)
: "cc");
|
编译器内置函数
| C |
|---|
| // 位操作
int clz = __builtin_clz(x); // 前导零计数
int ctz = __builtin_ctz(x); // 尾随零计数
int pop = __builtin_popcount(x); // 置位计数
// 分支预测
if (__builtin_expect(x, 0)) { // x大概率是0
// ...
}
// 内存屏障
__sync_synchronize();
// 原子操作
__sync_add_and_fetch(&var, 1);
__sync_bool_compare_and_swap(&var, old, new);
|
Makefile集成
| Makefile |
|---|
| CC = gcc
CFLAGS = -Wall -O2
LDFLAGS = -lm
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
program: $(OBJS)
$(CC) $(OBJS) $(LDFLAGS) -o $@
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(OBJS) program
|
调试和分析
生成预处理文件
| Bash |
|---|
| gcc -E program.c > program.i
|
生成汇编文件
| Bash |
|---|
| gcc -S program.c -o program.s
|
查看依赖
| Bash |
|---|
| gcc -M program.c # 所有依赖
gcc -MM program.c # 忽略系统依赖
|
参考资料