前言

本文用于记录我在学习和工作中遇到的各种GCC选项,虽然这些选项可以在GNU的手册上查到,不过这里做个总结,可以避免每次都去查手册,算是一个备忘吧。本文的内容会不断更新扩充。

1 常用的编译选项

选项作用

-o指定输出文件名称

-E只进行预处理

-S只进行预处理、编译

-c只预处理、编译、汇编,但不链接

-D使用-D name[=definition]预定义名为name的宏,

若不指定值则默认宏的内容为1

-l(小写的L)使用-l libname或者-llibname,使链接器在链接时搜索名为libname.a/libname.so(静态/动态)的库文件

-L使用-Ldir添加搜索目录,即链接器在搜索-l选项指定的库文件时,除了系统的库目录还会(优先)在-L指定的目录下搜索

-I(大写的i)使用-I dir,将目录dir添加为头文件搜索目录

-include使用-include file,等效于在被编译的源文件开头添加#include "file"

-static指定静态链接(默认是动态链接)

-O0~3开启编译器优化,-O0为不优化,-O3为最高级别的优化

-Os优化生成代码的尺寸,使能所有-O2的优化选项,除了那些让代码体积变大的

-Og优化调试体验,在保留调试信息的同时保持快速的编译,对于生成可调试代码,比-O0更合适,不会禁用调试信息。

-Wall使编译器输出所有的警告信息

-march指定目标平台的体系结构,如-march=armv4t,常用于交叉编译

-mtune指定目标平台的CPU以便GCC优化,如-mtune=arm9tdmi,常用于交叉编译


2 其他编译选项

2.1 -x language

通常gcc通过源文件的后缀来判断该源文件是由什么语言编写的(虽然Linux中后缀没有意义),换句话说,如果我们的文件名不带后缀,那么gcc就无法判断源文件的语言类型了,也就无法完成编译。举例来说:

例1

我用c语言编写了一段代码,将其保存在文件名为main.lll中,执行gcc main.lll会报错:

main.lll: file not recognized: File format not recognized collect2: error : ld returned 1 exit status 12

例2

在u-boot中,生成链接脚本的命令为

arm-linux-gcc -E -Wp,-MD,./.u-boot.lds.d ...... -x assembler-with-cpp -std=c99 -P -o u-boot.lds arch/arm/cpu/u-boot.lds

,如果把其中的

-x assembler-with-cpp

去掉,则编译器给出如下信息(且不会生成链接脚本):

linker input file unused because linking not done 1

至此,

-x language

的作用就很好理解了,当我们的源文件不添加常规的后缀时,使用该选项来告诉gcc源文件使用了哪种编程语言,其中的language

表明的就是语言类型,其可取的值有(不是全部):

c c-header cpp-output c++ c+±header c+±cpp-output objective-c objective-c-header objective-c-cpp-output objective-c++ objective-c+±header objective-c+±cpp-output assembler assembler-with-cpp

2.2 -fno-xxx

-fno-common

遇到多个弱定义的全局符号时输出一条警告信息。

-fno-ident

忽略

#ident

命令。

-fno-builtin

遇到与内建函数同名的函数时不去链接内建函数,除非函数名以

__builtin_

开头,也可以使用

-fno-builtin-function

来针对特定的函数。

2.3 -fxxx

-ffreestanding

告诉编译器要编译的目标处于独立的环境。在独立的环境中,标准库可能不存在,程序的入口也不一定是main。使用该选项的典型例子有bootloader、OS kernel等,这些程序不依赖标准库,也不需要编译器给它们添加.init段。

-fomit-frame-pointer

在不需要帧指针的函数中省略掉帧指针。所谓帧指针,指的是指向一个函数的栈帧的底部的指针(栈顶指针是没办法省的)。比如x86平台就使用ebp作为帧指针。省略掉帧指针的好处是可以多出一个可用的寄存器,坏处是不利于栈回溯。

值得注意的是,有些平台的过程调用规范指定必须使用帧指针,此时该选项无效;同时,与该选项对应的-fno-omit-frame-pointer也不保证帧指针一定会被使用。

2.4 -Wxxx

-W/-Wextra

-W是-Wextra的旧称。显然,-Wextra更具有可读性,顾名思义,该选项可以使能一些额外的警告标志。所谓额外,是针对-Wall而言的,-Wall并没有使能所有的警告,尽管它有个all。

-Wshadow

使用该选项时,如果本地的变量或类型声明遮蔽了另一个变量、参数、类型、类成员(C++)、实例变量(Objective-C)或内建函数,则gcc会报警告。

-Wconversion

当使用该选项时,如果隐式类型转换会更改变量的值,则gcc会给出警告。这样的隐式转换有实数与整数的转换、有符号数与无符号数的转换、转向更小类型的转换等。当然,上述转换中,如果最终没有改变变量的值,那么就不会产生警告,如abs(2.0)。

2.5 -Wno-xxx

-Wno-sign-conversion

关闭有符号数和无符号数之间进行类型转换时产生的警告,即使用了该选项,那么有符号数和无符号数之间转换时gcc就不报警告了。

2.6 给链接器使用的选项:-Wl,options

这里所说的链接器是指集成在可执行文件gcc中的链接器,而不是单独使用的ld。当我们通过gcc间接使用链接器时,需要在链接器的编译选项前面加上-Wl,,然后跟着编译选项,即标题中的options。GCC手册中的相应介绍如下:

forum.jpg

那么,为什么需要-Wl,前缀呢?GNU的链接器手册中是这样解释的(很好懂,就不翻译了):

forum.jpg

接下来就介绍一些用于链接器的选项:

-Wl,-rpath=dir在编译链接时,链接器会在dir目录下搜索动态库。同时,把动态库搜索路径dir添加到可执行文件中,以便可执行文件加载运行时使用。要注意该选项与-L选项的区别,-L选项用于编译链接时添加库文件的搜索路径;而该选项仅限于动态库,并且既可以在编译链接时添加搜索路径,同时也能将搜索路径添加到可执行文件中。

3 ARM架构专有的编译选项

-mthumb

使编译器生成THUMB指令

-marm

使编译器生成ARM指令

-mthumb-interwork

使编译器生成支持ARM和Thumb指令集之间相互调用的代码,默认是

-mno-thumb-interwork