GCC 是 GNU Compiler Collection 的简称,GCC 原本称为 GNU C Compiler,随着时代演进,陆续支援 Fortran 、 Pascal 、 Objective-C 、 Java 、 Ada 、 Go 等程序语言,才改称 GNU Compiler Collection。
本篇文章只会探讨 C 语言的部分,不会对其他程序语言多做介绍。
关於 GNU 计画,可参考未来几天会发出的 UNIX、BSD 与 Linux 的爱恨情仇一文。
要将 C 语言编译成可执行档,需要经过多个流程:
预处理
将 include 、 macro 扩展成真正的内容,经过这一步骤後,档案会变大许多。
使用 GCC 进行预处理的方式如下:
gcc -E -I./src main.c -o main.i
-E
会让 gcc 仅对 c 程序做预处理-I
用来指定自定义标头档的优先搜寻目录,若你定义的标头档与程序码同目录,就可以忽略该参数。-o
指定输出档案的档名与格式编译
将预处理过的程序码编译成组合语言,而组合语言又会因为不同的处理器架构出现差异,如果要在 x86 平台编译出 ARM 平台能执行的程序码,就会需要做交叉编译。
使用 GCC 进行编译的方法:
gcc -S -I./src main.c -o main.s
-S
仅输出 C 程序对应的组合语言组译
经过编译後,我们会得到组合语言档案,也就是 *.s
档案。不过,若要让电脑能够执行我们的程序码,我们仍需要将其转换成机器码。
gcc -c main.s -o main.o
-c
仅编译 C 程序,但不连结,即输出对应的目标码连结
连结会将多个目标文件或是 library 连结成可执行档。
gcc -o main main.o
得到可执行档後,可以在 shell command 输入以下命令执行程序:
./main
如果有多个机器码最後会被连结成一个可执行档案,也可以这麽做:
gcc -o main a.o b.o c.o
这样一来,如果开发者更动了其中一个档案,我们只需对有更动的档案进行编译再连结起来。可以大幅节省编译的时间。
除了最基本的编译,当然还要学习其他 GCC 内建的强大功能!
GCC 可以针对不同的处理器架构对程序进行最佳化:
gcc -O2 -o main main.c
考虑以下程序码:
#include <stdio.h>
int main(){
int n;
printf("number is %d\n", n);
return 0;
}
该程序中,n
并没有被正确初始化,不过 GCC 预设是不会有错误提示的,若开发者有需要,可以使用 -Wall
参数:
gcc -Wall -o main main.c
若我们需要使用 GDB 进行除错,在编译之前,我们需要添加 -g
参数告知 GCC 要尽可能的提供资讯给 GDB :
gcc -Wall -g -o main main.c
我们可以使用 -v
参数启用 verbose mode,获得详细的编译讯息:
gcc -v main.c
假设开发者在程序中埋了一段程序码,该程序码只被用於除错:
#include <stdio.h>
int main(){
int n = 0;
for(int i =0;i<1000;i++){
n += i;
#ifdef DEBUG
printf("n is %d\n", n)
#endif
}
return 0;
}
我们除了可以在程序码中加入 #define DEBUG
外,还可以直接对 GCC 下 -D
参数:
gcc -DDEBUG -o main main.c
除了可以用 -D
定义 Macro,GCC 还允许开发者使用 -U
参数取消定义:
gcc -UDEBUG -o main main.c
刚刚已经在预处理的部分提到 -I
的用途。此外,GCC 在编译程序时只预设引入一部份的标头档,如果程序需要使用特别的 Library 进行编译,可以使用 -l
与 -L
参数:
-l
告知 GCC 编译程序时需要使用这个 Library :
以 POSIX Thread 为例:
gcc -lpthread -o main.out main.c
需要注意的是,这里的 Library name 不等於档案名称,在 Linux 下的函式库都要使用 lib 开头,其中 *.so
是动态连结函式库,*.a
是静态连结函式库。
由此可知,把 File name 的 lib
和 .so
去掉就是 Library name 了。
-L
只要函式库的存放路径为:
都可以直接使用 -l
进行连结,换句话说,如果 Library 的位置并非上述的目录,我们就需要用 -L
告知 GCC Library File 所在的目录位置:
gcc -lsum -L/home/gtwang/lib -o main.out main.c
Makefile 可以让开发者省略复杂的编译选项及参数,考虑以下专案结构:
|-- project
|-- src/
| |-- main.c
| |-- linked-list.c
| |-- linked-list.h
| |-- node.c
| |-- node.h
并且,在 main.c
中引用了 linked-list.h
,当我们使用下面命令,就可以查找出 main.c
的依赖关系:
gcc -MM main.c
输出:
main.o: main.c linked-list.h
再假设 linked-list.h
中有使用到 node.h
,输出就会是:
main.o: main.c linked-list.h node.h
如果希望将标准库的依赖关系也列出来,使用 -M
即可:
gcc -M main.c
关於依赖关系,还有相当多种参数可以玩,详细资讯可以参考 Reference 的最後一项。
小的时候,曾有个做科学家的梦想,但不得其门而入,直到上了研究所,才慢慢了解科学家的由来。 在台湾,国...
BOM (Browser Object Model) 浏览器物件模型 JavaScript 与浏览器...
故事从 127.0.0.1这个网址用於localhost,表示为本机端,也会被用来测试网路状况......
计算属性(Computed) 无传入值 具回传值(return) 对来源属性进行操作-> 触发...
-API 闸道器和服务网格(来源:Liran Katz) 实施 API 闸道器以促进跨境通信;他们...