GCC(GNU Compiler Collection)和 G++ 是 GNU 项目的一部分。GCC 是一个多语言支持的编译器,可以处理 C、C++、Fortran 等语言,而 G++ 是 GCC 的 C++ 前端,用于专门处理 C++ 源代码。
GCC/G++ 的编译过程分为四个主要阶段:
预处理是编译的第一个阶段,主要完成以下任务:
#define
定义的宏。#ifdef
)选择性地编译代码。#include
指定的文件插入到源代码中。命令示例:
gcc -E hello.c -o hello.i
-E
:执行预处理并停止。.i
:预处理后的代码。在此阶段,编译器会:
命令示例:
gcc -S hello.i -o hello.s
-S
:仅执行编译,生成汇编代码。.s
:包含汇编代码。汇编阶段将汇编代码转换为机器可识别的目标代码(二进制格式)。
命令示例:
gcc -c hello.s -o hello.o
-c
:仅执行汇编,生成目标文件。.o
:二进制目标文件。连接阶段将多个目标文件和库文件链接在一起,生成可执行文件或库文件。连接过程中可能会调用外部的动态或静态库。
命令示例:
gcc hello.o -o hello
hello
:最终生成的可执行文件。GCC 和 G++ 提供了多种选项,支持不同的编译需求。以下是一些常见选项及其功能:
选项 | 功能描述 |
---|---|
-E | 只执行预处理,生成 .i 文件 |
-S | 只执行编译,生成 .s 汇编文件 |
-c | 只执行汇编,生成 .o 二进制目标文件 |
-o | 指定输出文件名 |
-g | 生成调试信息,供调试器(如 GDB)使用 |
-Wall | 打开所有常见的警告信息 |
-O0 | 不进行优化 |
-O1 | 启用基本优化 |
-O2 | 启用进一步优化 |
-O3 | 启用最高级别优化,可能导致代码体积增大 |
-static | 使用静态链接,生成不依赖动态库的可执行文件 |
-shared | 生成动态库 |
程序开发中,链接是将目标文件与库文件结合的过程,链接方式主要分为静态链接和动态链接。
静态链接是在编译阶段将库文件的代码直接嵌入到可执行文件中。
命令示例:
gcc hello.o -o hello -static
动态链接是在程序运行时加载所需的库文件,而非将其嵌入到可执行文件中。
查看动态链接依赖库:
ldd hello
示例输出:
linux-vdso.so.1 => (0x00007fffeb1ab000)
libc.so.6 => /lib64/libc.so.6 (0x00007ff776af5000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff776ec3000)
静态库是在编译时被直接打包到可执行文件中的库文件,通常后缀为 .a
。
ar rcs libhello.a hello.o
gcc main.o -o main -L. -lhello
动态库在程序运行时加载,通常后缀为 .so
。
gcc -shared -o libhello.so hello.o
gcc main.o -o main -L. -lhello
注意: 动态库默认存储路径为 /usr/lib
或 /usr/local/lib
,若库文件不在默认路径中,可以通过环境变量 LD_LIBRARY_PATH
指定动态库路径。
GCC 和 G++ 提供了多种优化选项,开发者可以根据项目需求选择合适的优化级别:
优化级别 | 描述 |
---|---|
-O0 | 无优化(默认) |
-O1 | 基本优化 |
-O2 | 在不显著增加编译时间的前提下进行进一步优化 |
-O3 | 启用所有优化选项,可能导致代码体积增加 |
-Os | 优化代码体积,适用于存储受限的设备 |
GCC 和 G++ 是 C 和 C++ 开发中不可或缺的工具,它们提供了从预处理到最终链接的完整编译支持。理解编译的每个阶段及其常用选项,可以帮助开发者更高效地开发、调试和优化程序。同时,动态链接和静态链接各有优劣,开发者需要根据项目需求合理选择。