C 语言广为人知,编译深受新老程序员的程序好评。使用 C 语言编写的员入源文件代码,使用了标准的编译英语术语,因而人们可以方便阅读。程序然而,员入计算机只能理解二进制代码。编译为将代码转换为机器语言,程序你需要使用一种被称为编译器的员入工具。 最常见的编译编译器是 GCC(GNU 编译器集)。编译过程涉及到一系列的程序中间步骤及相关工具。 为验证在你的员入系统上是否已经安装了 GCC,使用 gcc 命令: 如有必要,编译使用你的程序软件包管理器来安装 GCC。在基于 Fedora 的员入系统上,使用 dnf : 在基于 Debian 的系统上,使用 apt : 在安装后,如果你想查看 GCC 的安装位置,那么使用: 这里有一个简单的 C 程序,站群服务器用于演示如何使用 GCC 来编译。打开你最喜欢的文本编辑器,并在其中粘贴这段代码: // hellogcc.c #include int main() { printf("Hello, GCC!\n"); return 0; 保存文件为 hellogcc.c ,接下来编译它: $ ls hellogcc.c $ gcc hellogcc.c $ ls -1 a.out 如你所见,a.out 是编译后默认生成的二进制文件。为查看你所新编译的应用程序的输出,只需要运行它,就像你运行任意本地二进制文件一样: $ ./a.out 文件名称 a.out 是非常莫名其妙的,所以,如果你想具体指定可执行文件的名称,你可以使用 -o 选项: (LCTT 译注:注意这和最近 Linux 内核废弃的 a.out 格式无关,只是名字相同,这里生成的 a.out 是 ELF 格式的 —— 也不知道谁给起了个 a.out 这破名字,在我看来,默认输出文件名就应该是去掉了 .c 扩展名后的名字。by wxy) $ gcc -o hellogcc hellogcc.c $ ls a.out hellogcc hellogcc.c $ ./hellogcc 当开发一个需要编译多个 C 源文件文件的大型应用程序时,亿华云这种选项是很有用的。 编译实际上有四个步骤,即使在简单的用例中 GCC 自动执行了这些步骤。 预处理:GNU 的 C 预处理器(cpp)解析头文件(#include 语句),展开 宏macros 定义(#define 语句),并使用展开的源文件代码来生成一个中间文件,如 hellogcc.i。编译:在这个期间中,编译器将预处理的源文件代码转换为指定 CPU 架构的汇编代码。由此生成是汇编文件使用一个 .s 扩展名来命名,如在这个示例中的 hellogcc.s 。 在运行 GCC 时,可以使用 -v 选项来查看每一步的细节: Compiler flowchart 体验编译的每个步骤可能是很有用的,因此在一些情况下,服务器租用你不需要 GCC 完成所有的步骤。 首先,除源文件文件以外,删除在当前文件夹下生成的文件。 $ rm a.out hellogcc.o $ ls 首先,启动预处理器,将其输出重定向为 hellogcc.i : $ cpp hellogcc.c > hellogcc.i $ ls 查看输出文件,并注意一下预处理器是如何包含头文件和扩展宏中的源文件代码的。 现在,你可以编译代码为汇编代码。使用 -S 选项来设置 GCC 只生成汇编代码: $ gcc -S hellogcc.i $ ls hellogcc.c hellogcc.i hellogcc.s 查看汇编代码,来看看生成了什么。 使用你刚刚所生成的汇编代码来创建一个目标文件: $ as -o hellogcc.o hellogcc.s $ ls 要生成一个可执行文件,你必须将对象文件链接到它所依赖的库。这并不像前面的步骤那么简单,但它却是有教育意义的: $ ld -o hellogcc hellogcc.o ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000 ld: hellogcc.o: in function `main`: 在链接器查找完 libc.so 库后,出现一个引用 undefined puts 错误。你必须找出适合的链接器选项来链接必要的库以解决这个问题。这不是一个小技巧,它取决于你的系统的布局。 在链接时,你必须链接代码到核心运行时(CRT)目标,这是一组帮助二进制可执行文件启动的子例程。链接器也需要知道在哪里可以找到重要的系统库,包括 libc 和 libgcc,尤其是其中的特殊的开始和结束指令。这些指令可以通过 --start-group 和 --end-group 选项来分隔,或者使用指向 crtbegin.o 和 crtend.o 的路径。 这个示例使用了 RHEL 8 上的路径,因此你可能需要依据你的系统调整路径。 $ ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 \ -o hello \ /usr/lib64/crt1.o /usr/lib64/crti.o \ --start-group \ -L/usr/lib/gcc/x86_64-redhat-linux/8 \ -L/usr/lib64 -L/lib64 hello.o \ -lgcc \ --as-needed -lgcc_s \ --no-as-needed -lc -lgcc \ --end-group \ 在 Slackware 上,同样的链接过程会使用一组不同的路径,但是,你可以看到这其中的相似之处: $ ld -static -o hello \ -L/usr/lib64/gcc/x86_64-slackware-linux/11.2.0/ \ /usr/lib64/crt1.o /usr/lib64/crti.o hello.o /usr/lib64/crtn.o \ --start-group \ -lc -lgcc -lgcc_eh \ 现在,运行由此生成的可执行文件: $ ./hello 下面是一些帮助检查文件类型、符号表symbol tables 和链接到可执行文件的库的实用程序。 使用 file 实用程序可以确定文件的类型: $ file hellogcc.c hellogcc.c: C source, ASCII text $ file hellogcc.o hellogcc.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped $ file hellogcc 对目标文件使用 nm 实用程序可以列出 符号表 : $ nm hellogcc.o 0000000000000000 T main 使用 ldd 实用程序来列出动态链接库: $ ldd hellogcc linux-vdso.so.1 (0x00007ffe3bdd7000) libc.so.6 => /lib64/libc.so.6 (0x00007f223395e000) 在这篇文章中,你了解到了 GCC 编译中的各种中间步骤,和检查文件类型、符号表symbol tables 和链接到可执行文件的库的实用程序。在你下次使用 安装 GCC
演示使用 GCC 来编译一个简单的 C 程序
命名输出的文件
在 GCC 编译中的中间步骤
手动编译代码
一些有用的实用程序
总结