shell[编译C]gcc的基本用法

(一) gcc的基本用法

(二) 警告提示功能选项

(三) 库操作选项

(四) 调试选项

(五) 交叉编译选项

(一) gcc的基本用法

使用gcc编译器时,必须给出一系列必要的调用参数和文件名称。不同参数的先后顺序对执行结果没有影响,只有在使用同类参数时的先后顺序才需要考虑。如果使用了多个 -L 的参数来定义库目录,gcc会根据多个 -L 参数的先后顺序来执行相应的库目录。

因为很多gcc参数都由多个字母组成,所以gcc参数不支持单字母的组合,Linux中常被叫短参数(short options),如 -dr 与 -d -r 的含义不一样。gcc编译器的调用参数大约有100多个,其中多数参数我们可能根本就用不到,这里只介绍其中最基本、最常用的参数。

gcc最基本的用法是:gcc [options] [filenames]

其中,options就是编译器所需要的参数,filenames给出相关的文件名称,最常用的有以下参数:

-c    

只编译,不链接成为可执行文件。编译器只是由输入的 .c 等源代码文件生成 .o 为后缀的目标文件,通常用于编译不包含主程序的子程序文件。

-o output_filename    

确定输出文件的名称为output_filename。同时这个名称不能和源文件同名。如果不给出这个选项,gcc就给出默认的可执行文件 a.out 。

-g

产生符号调试工具(GNU的 gdb)所必要的符号信息。想要对源代码进行调试,就必须加入这个选项。

-O

对程序进行优化编译、链接。采用这个选项,整个源代码会在编译、链接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是编译、链接的速度就相应地要慢一些,而且对执行文件的调试会产生一定的影响,造成一些执行效果与对应源文件代码不一致等一些令人“困惑”的情况。因此,一般在编译输出软件发行版时使用此选项

-O2

比 -O 更好的优化编译、链接。当然整个编译链接过程会更慢。

-Idirname

将 dirname 所指出的目录加入到程序头文件目录列表中,是在预编译过程中使用的参数。

说明:

C程序中的头文件包含两种情况:

#include

#include "stdio.h"

其中,使用尖括号(<>),预处理程序 cpp 在系统默认包含文件目录(如/usr/include)中搜索相应的文件;使用双引号,预处理程序 cpp 首先在当前目录中搜寻头文件,如果没有找到,就到指定的 dirname 目录中去寻找。

在程序设计中,如果需要的这种包含文件分别分布在不同的目录中,就需要逐个使用 -I 选项给出搜索路径

-Ldirname

将dirname所指出的目录加入到程序函数库文件的目录列表中,是在链接过程中使用的参数。在默认状态下,链接程序 ld 在系统默认路径中(如 /usr/lib)寻找所需要的库文件。这个选项告诉链接程序,首先到 -L 指定的目录中去寻找,然后到系统默认路径中寻找;如果函数库存放在多个目录下,就需要依次使用这个选项,给出相应的存放目录。

-lname

链接时装载名为 libname.a 的函数库。该函数库位于系统默认的目录或者由 -L 选项确定的目录下。例如,-lm 表示链接名为 libm.a 的数学函数库。

例子:假定有一个程序名为 test.c 的C语言源代码文件,要生成一个可执行文件。

#include

int main(void)

{

printf("Hello world/n");

return 0;

}

最简单的办法:gcc test.c -o test

首先,gcc需要调用预处理程序 cpp,由它负责展开在源文件中定义的宏,并向其中插入“#include”语句所包含的内容;接着,gcc调用ccl 和 as,将处理后的源代码编译成目标代码;最后,gcc调用链接程序 ld,把生成的目标代码链接成一个可执行程序。因此,默认情况下,预编译、编译链接一次完成。

编译过程的分步执行:

为了更好地理解gcc的工作过程,我们可以让在gcc工作的4个阶段中的任何一个阶段中停止下来。相关的参数有:

-E

预编译后停下来,生成后缀为 .i 的预编译文件

-c

编译后停下来,生成后缀为 .o 的目标文件

-S

汇编后停下来,生成后缀为 .s 的汇编源文件

第一步:进行预编译,使用 -E 参数

gcc-Etest.c-o test.i

查看 test.i 文件中的内容,会发现 stdio.h 的内容确实都插到文件里去了,而其他应当被预处理的宏定义也都做了相应的处理。

第二步:将 test.i 编译为目标代码,使用 -c 参数

gcc-ctest.c-o test.o

第三步:生成汇编源文件

gcc-Stest.c-o test.s

第四步:将生成的目标文件链接成可执行文件

gcctest.o- otest

对于稍微复杂的情况,比如有多个源代码文件、需要链接库或有其他比较特别的要求,就要给定适当的调用选项参数。

例子:整个源代码程序由两个文件 testmain.c 和 testsub.c 组成,程序中使用了系统提供的数学库(所有与浮点相关的数学运算都必须使用数学库)。

gcc testmain.c testsub.c-lm-o test

其中,-lm 表示链接系统的数学库 libm.a 

说明:

在编译一个包含许多源文件的工程时,若只用一条gcc命令来完成编译是非常浪费时间的。假如项目中有100个源文件需要编译,并且每个源文件中都包含一万行代码,如果像上面那样仅用一条gcc命令来完成编译工作,那么gcc需要将每个源文件都重新编译一遍,然后再全部链接起来。很显然,这样浪费的时间相当多,尤其是当用户只是修改了其中某个文件的时候,完全没有必要将每个文件都重新编译一遍,因为很多已经生成的目标文件是不会发生改变的。要解决这个问题,需要借助像make这样的工具。

(二) 警告提示功能选项

gcc包含完整的出错检查和警告提示功能,它们可以帮助Linux程序员写出更加专业的代码。

(1) -pedantic 选项

当gcc在编译不符合ANSI/ISO C 语言标准的源代码时,将产生相应的警告信息。



[cpp]view plaincopy


print?

#include <stdio.h>  


void main(void)  

 {  

longlongint var = 1;  

printf("It is not standard C code!/n");  

 }  



它有以下问题:

> main 函数的返回值被声明为 void,但实际上应该是 int。

> 使用了 GNU 语法扩展,即使用 long long 来声明64位整数,不符合 ANSI/ISO C 语言标准。

> main 函数在终止前没有调用 return 语句。

(2) -Wall 选项

除了 -pedantic 之外,gcc 还有一些其他编译选项,也能够产生有用的警告信息。这些选项大多以 -W 开头。其中最有价值的当数 -Wall 了,使用它能够使 gcc 产生尽可能多的警告信息。


gcc 给出的警告信息虽然从严格意义上说不能算作错误,但却和可能成为错误来源。一个优秀的程序员应该尽量避免产生警告信息,使自己的代码始终保持简洁、优美和健壮的特性。

建议:gcc 给出的警告信息是很有价值的,它们不仅可以帮助程序员写出更加健壮的程序,而且还是跟踪和调试程序的有力工具。建议在用 gcc 编译源代码时始终带上 -Wall 选项,并把它逐渐培养成一种习惯,这对找出常见的隐式编程错误很有帮助。

(3) -Werror 选项

在处理警告方面,另一个常用的编译选项是 -Werror。它要求 gcc 将所有的警告当成错误进行处理,这在使用自动编译工具(如 Make 等)时非常有用。如果编译时带上 -Werror 选项,那么 gcc 会在所有产生警告的地方停止编译,迫使程序员对自己的代码进行修改。只有当相应的警告信息消除时,才可能将编译过程继续朝前推进。


(4) -Wcast-align 选项

当源程序中地址不需要对齐的指针指向一个地址需要对齐的变量地址时,则产生一个警告。例如,char * 指向一个 int * 地址,而通常在机器中 int 变量类型是需要地址能被2或4整除的对齐地址。

(5) 其他常用选项

-v                            输出 gcc 工作的详细过程

--target-help       显示目前所用的gcc支持CPU类型

-Q                           显示编译过程的统计数据和每一个函数名

(三) 库操作选项

Linux下开发软件时,完全不使用第三方函数库的情况是比较少见的,通常来讲都需要借助一个或多个函数库的支持才能够完成相应的功能。

从程序员的角度看,函数库实际上就是一些头文件(.h)和库文件(.so 或 .a)的集合。虽然Linux下的大多数函数都默认将头文件放到 /usr/include/ 目录下,而库文件则放到 /usr/lib/ 目录下,但并不是所有的情况都是这样。正因如此,gcc 在编译时必须有自己的办法来查找所需要的头文件和库文件。常用的方法有:

(1) -I 

可以向 gcc 的头文件搜索路径中添加新的目录。

(2) -L 

如果使用了不在标准位置的库文件,那么可以通过 -L 选项向 gcc 的库文件搜索路径中添加新的目录。

(3) -l 

Linux下的库文件在命名时有一个约定,就是应该以 lib 这3个字母开头,由于所有的库文件都遵循了同样的规范,因此在用 -l 选项指定链接的库文件名时可以省去 lib 这3个字母。例如,gcc 在对 -lfoo 进行处理时,会自动去链接名为 libfoo.so 的文件。

(4) -static

Linux下的库文件分为两大类,分别是:动态链接库(通常以 .so 结尾)和静态链接库(通常以 .a 结尾)。

两者的差别仅在程序执行时所需的代码是在运行时动态加载的,还是在编译时静态加载的。

默认情况下,gcc 在链接时优先使用动态链接库,只有当动态链接库不存在时才考虑使用静态链接库。

如果需要的话,可以在编译时加上 -static 选项,强制使用静态链接库。

(5) -shared

生成一个共享的目标文件,它能够与其他的目标一起链接生成一个可执行的文件。

(四) 调试选项

对于Linux程序员来讲,gdb(GNU Debugger)通过与 gcc 的配合使用,为基于Linux的软件开发提供了一个完善的调试环境。常用的有:

(1) -g 和 -ggdb

默认情况下,gcc 在编译时不会将调试符号插入到生成的二进制代码中,因为这样会增加可执行文件的大小。如果需要在编译时生成调试符号信息,可以使用 gcc 的 -g 或 -ggdb 选项。

gcc 在产生调试符号时,同样采用了分级的思路,开发人员可以通过在 -g 选项后附加数字1、2、3指定在代码中加入调试信息的多少。默认的级别是2(-g2),此时产生的调试信息包括:扩展的符号表、行号、局部或外部变量信息。

级别3(-g3)包含级别2中的所有调试信息以及源代码中定义的宏。

级别1(-g1)不包含局部变量和与行号有关的调试信息,因此只能够用于回溯跟踪和堆栈转储。

回溯追踪:指的是监视程序在运行过程中函数调用历史。

堆栈转储:则是一种以原始的十六进制格式保存程序执行环境的方法。

注意:使用任何一个调试选项都会使最终生成的二进制文件的大小急剧增加,同时增加程序在执行时的开销,因此,调试选项通常仅在软件的开发和调试阶段使用。

(2) -p 和 -pg

会将剖析(Profiling)信息加入到最终生成的二进制代码中。剖析信息对于找出程序的性能瓶颈很有帮助,是协助Linux程序员开发出高性能程序的有力工具。

(3) -save-temps

保存编译过程中生成的一些列中间文件。

# gcc test.c -o test-save-temps

除了生成执行文件test之外,还保存了test.i 和 test.s 中间文件,供用户查询调试。

(五) 交叉编译选项

通常情况下使用 gcc 编译的目标代码都与使用的机器是一致的,但 gcc 也支持交叉编译的功能,能够编译其他不同CPU的目标代码

使用 gcc 开发嵌入式系统,我们几乎都是以通用的PC机(X86)平台来做宿主机,通过 gcc 的交叉编译功能对其他嵌入式CPU的开发任务。

(具体的选项设置,此处省略)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容

  • 一、温故而知新 1. 内存不够怎么办 内存简单分配策略的问题地址空间不隔离内存使用效率低程序运行的地址不确定 关于...
    SeanCST阅读 7,774评论 0 27
  • GCC编译器 GCC是一个交叉平台的编译器,我想大家并不会觉得陌生。C/C++开发的时候很多时候都会用到GCC来进...
    故事狗阅读 9,106评论 0 25
  • 今天家里气氛有点凝重,刚开始还不知道发生了什么。后来听他们讲,好像是爸爸做担保人,然后那人没交利息没还钱,就得我家...
    大头www阅读 202评论 0 0
  • 2017投资半年总结 先上这半年的成绩,下面那个是打新账户,二月份左右建仓,上面那个是主账户,参加了雪球的实盘比赛...
    橡皮泥7阅读 519评论 1 1
  • 1 圣诞节来临了,小动物们的袜子里收到各种礼物,小松鼠收到坚果酸奶,小熊收到旅游的车票,小狐狸收到电动玩具,大灰狼...
    霷揚阅读 1,024评论 0 8