## gcc编译选项 虽然这些选项在GNU手册中可以查到,但是还是要做一个总结。 ## 1、常用的编译选项 | 选项 | 作用 | | -------- | ------------------------------------------------------------ | | -o | 指定输出文件名称 | | -E | 只进行预处理 | | -S | 只进行预处理、编译 | | -c | 只预处理、编译、汇编,但不链接 | | -D | 使用-D name[=definition]预定义名为name的宏,若不指定值则默认宏为1 | | -l (小L) | 使用-l libname 或者 -llibname,是链接器在链接时搜索名称为libname.a/libname.so的库文件 | | -L | 使用-L dir添加搜索库文件的目录,除了系统目录外优先搜索的目录 | | -I (大i) | 使用-I dir,将dir目录添加为头文件搜索目录 | | -include | 使用-include file,等效于开头添加`#include "file"` | | -static | 指定静态链接,默认为动态链接 | | -O0~3 | 开启编译器优化,-O0为不优化,-O3为最高优化 | | -Os | 优化生成代码尺寸 | | -Og | 优化调试体验,不会禁用调试信息 | | -Wall | 使编译器输出所有警告信息 | | -march | 指定目标平台的体系结构,如-march=arm4t,常用于交叉编译 | | -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 1 2 例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。 接下来就介绍一些用于链接器的选项: -Wl,-rpath=dir 在编译链接时,链接器会在dir目录下搜索动态库。同时,把动态库搜索路径dir添加到可执行文件中,以便可执行文件加载运行时使用。要注意该选项与-L选项的区别,-L选项用于编译链接时添加库文件的搜索路径;而该选项仅限于动态库,并且既可以在编译链接时添加搜索路径,同时也能将搜索路径添加到可执行文件中。 3 ARM架构专有的编译选项 -mthumb 使编译器生成THUMB指令 -marm 使编译器生成ARM指令 -mthumb-interwork 使编译器生成支持ARM和Thumb指令集之间相互调用的代码,默认是-mno-thumb-interwork