精通GCC编译器ppt课件.ppt
精 通 GCC 编译器,content,GCC 概论GCC 深入探索GCC 的编译选项GCC 的应用技巧,01. GCC 是何物?,Linux系统下的gcc(GNU C Compiler)是GNU推出的功能强大、性能优越的多平台编译器,是GNU的代表作品之一。gcc是可以在多种硬体平台上编译出可执行程序的超级编译器,其执行效率与一般的编译器相比平均效率要高20%30%。 gcc编译器能将C、C+语言源程序、汇程式化序和目标程序编译、连接成可执行文件,如果没有给出可执行文件的名字,gcc将生成一个名为a.out的文件。在Linux系统中,可执行文件没有统一的后缀,系统从文件的属性来区分可执行文件和不可执行文件。而gcc则通过后缀来区别输入文件的类别,下面我们来介绍gcc所遵循的部分约定规则。DEMO,GCC的几个版本,请问GCC 和cc有啥区别?怎样在linux下 查看GCC的版本 信息?,查看版本信息,安装路径:,相关文件类型:,c 为后缀的文件,C语言源代码文件; .a 为后缀的文件,是由目标文件构成的档案库文件; .C,.cc或.cxx 为后缀的文件,是C+源代码文件; .h 为后缀的文件,是程序所包含的头文件; .i 为后缀的文件,是已经预处理过的C源代码文件; .ii 为后缀的文件,是已经预处理过的C+源代码文件; .m 为后缀的文件,是Objective-C源代码文件; .o 为后缀的文件,是编译后的目标文件; .s 为后缀的文件,是汇编语言源代码文件; .S 为后缀的文件,是经过预编译的汇编语言源代码文件。,gcc编译的4个过程:,预处理(也称预编译,Preprocessing):命令gcc首先调用cpp进行预处理,在预处理过程中,对源代码文件中的文件包含(include)、预编译语句(如宏定义define等)进行分析。编译(Compilation):接着调用cc1进行编译,这个阶段根据输入文件生成以.o为后缀的目标文件。汇编(Assembly):汇编过程是针对汇编语言的步骤,调用as进行工作。连接(Linking):当所有的目标文件都生成之后,gcc就调用 ld来完成最后的关键性工作,这个阶段就是连接参考:深入透析,演示:,DEMO基本的用法是gcc options filenames,1、没有任何选项:gcc helloworld.c 结果会在和helloworld.c相同的目录下产生一个a.out的可执行文档。 2、-o选项,指定输出文档名:gcc -o helloworld helloworld.c -o意思是Output即需要指定输出的可执行文档的名称。这里的名称为helloworld。 3、-c选项,只编译,不汇编连接:gcc -c helloworld.c -c意思就是Compile,产生一个叫helloworld.o的目标文档 4、-S选项,产生汇编源文档:gcc -S helloworld.c -S意思就是aSsemble,产生一个叫helloworld.s的汇编源文档 5、-E选项,预处理C源文档:gcc -E helloworld.c -E意思就是prEprocess。输出不是送到一个文档而是标准输出。当然能够对他进行重定向: gcc -E helloworld.c helloworld.txt,优化选项 -O选项,基本优化:gcc -O helloworld.c -O意思就是Optimize,产生一个经过优化的叫作a.out的可执行文档。也能够同时使用-o选项,以指定输出文档名。如: gcc -O -o test helloworld.c 即会产生一个叫test的经过优化的可执行文档。 -O2选项,最大优化:gcc -O2 helloworld.c 产生一个经过最大优化的叫作a.out的可执行文档。,调试选项 -g选项,产生供gdb调试用的可执行文档:gcc -g helloworld.c 产生一个叫作a.out的可执行文档,大小明显比只用-o选项编译汇编连接后的文档大。 -pg选项,产生供gprof剖析用的可执行文档:gcc -pg helloworld.c 产生一个叫作a.out的执行文档,大小明显比用-g选项后产生的文档还大。,02. GCC快速入门,第一个实例 hello!DEMO,GCC 常用编译开关,-w 禁止输出警告消息-Werror 将所有警告转换为错误-Wall 显示所有的警告消息-v 显示编译程序的当前版本号-static 连接器将忽略动态连接库,同时通过将静态目标文件直接包含到结果目标文件完成对所有引用的解析。-shared -fPCI 连接器将生成共享目标代码,-pipe 使用管道而不是临时文件一个阶段到另一个阶段交换输出的方式,可以加快编译速度。建议使用。-o 指定输出文件,对各种输出皆有效。,-I 指定搜索系统头文件的目录,可以重复使用多个该选项指定多个目录-Dmacro:相当于C语言中的#define macro-UMACRO 取消对 MACRO 宏的定义-c/-C:只激活预处理,编译,和汇编,也就是他只把程序做成obj文件-o: 指定目标名称-On(0,1,2,3):-S:只激活预处理和编译,就是指把文件编译成为汇编代码-E:只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面.,-Idir:使用-I制定了目录,先在你所制定的目录查找,然后再按常规的顺序去找头文件.-M:生成文件关联的信息。包含目标文件所依赖的所有源代码。-llibrary:指定编译的时候使用的库-Ldir:指定编译时搜索库的路径-g:指示编译器在编译时产生调试信息。-static:此选项将禁止使用动态库,所以,编译出来的东西,一般都很大,也不需要什么动态连接库,就可以运行.,建立自己的GCC 编译环境,一个系统上如何同时存在并使用多个版本的GCC编译器?建立目标目录:在gcc源代码同一级目录下(与源目录$srcdir是同级目录)% mkdir gcc-build% cd gcc-build配置环境:% ./gcc-3.4.0/configure -prefix=/usr/local/gcc-3.4.0 -enable-threads=posix -disable-checking -enable-long-long -host=i386-redhat-linux -with-system-zlib -enable-languages=c,c+,java将GCC安装在/usr/local/gcc-3.4.0目录下,支持C/C+和JAVA语言,编译安装:% make&make install其它配置:GCC 3.4.0的所有文件,包括命令文件(如gcc、g+)、库文件等都在$destdir目录下分别存放,如命令文件放在bin目录下、库文件在lib下、头文件在include下等。由于命令文件和库文件所在的目录还没有包含在相应的搜索路径内,所以必须要作适当的设置之后编译器才能顺利地找到并使用它们。用符号连接的方式实现,这样做的好处是我仍然可以使用系统上原来的旧版本的GCC编译器。% ln -s $destdir/bin/gcc gcc34库路径的设置:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:destdir/libsetenv LD_LIBRARY_PATH /usr/local/gcc-3.4.0/lib:$LD_LIBRARY_PATH,03. GCC的编译环境,工具: gcc c编译器,它在链接时使用c库 cc1 实际的c编译器 cc1plus 实际的c+编译器 collect2 使用collect2产生特定的全局初始化代码,后台处理是传递参数给ld完成实际的链接工作。 crt0.o 初始化和结束代码 libgcc 平台相关的库,binutils相关工具:as: gnu汇编工具 gprof : 性能分析工具 ld : gnu链接器,链接器可以读写各种目标文件中的信息,通过BFD(binary file descriptor)提供的工具实现,BFD定义了类似a.out, elf, coff等目标文件的格式 make: objcopy: 目标文件从二进制格式翻译或复制到另一种 objdump: 显示目标文件的各种信息 strings: 显示文件的字符串 strip : 去除符合表 readelf : 分析elf并显示信息,gcc预处理相关#define TEST(ARGTERM) printf(“the term “ #ARGTERM “is a stringn”)#define err(.) fprintf(stderr, _VA_ARGS_) err( %s %dn, error code is, 48);/实现可变参数宏的定义.error 和 warning指令if, elif, else, endif指令,gcc预定义宏 _BASE_FILE_ 完整的源文件名路径 _cplusplus 测试c+程序 _DATE_ 日期 _FILE_ 源文件名 _func_ 替代_FUNCTION_,_FUNCTION_以被GNU不推荐使用 _TIME_ 日期 _LINE_ 行数 _VERSION_ gcc版本,gas汇编工具(AT&T的风格)ld:ld把一定量的目标文件跟档案文件连接起来,并重定位它们的数据,连接符号引用.一般在编译一个程序时,最后一步就是运行ld。autoscanf automake等工具运行环境变量路径的问题,makefile make configure 脚本Makefile 包含了所有的规则和目标,而 make 则是为了完成目标而去解释 Makefile 规则的工具。根据源码包中 Makefile.in 文件的指示,configure 脚本检查当前的系统环境和配置选项在当前目录中生成 Makefile 文件(还有其它本文无需关心的文件),然后 make 程序就按照当前目录中的 Makefile 文件的指示将源代码编译为二进制文件,最后将这些二进制文件移动(即安装)到指定的地方(仍然按照 Makefile 文件的指示)。,autoconf主要根据程式员提供的configure.in,生成能够自动检测系统配置的脚本configure。而后再由configure根据各目录下的Makefile.in自动生成Makefile。这样,程式员就能够直接使用具备丰富功能的Makefile了。,autoconf产生makefile的过程:运行autoscan命令将configure.scan 文档重命名为configure.in,并修改configure.in文档在project目录下新建Makefile.am文档,并在core和shell目录下也新建makefile.am文档在project目录下新建NEWS、 README、 ChangeLog 、AUTHORS文档将/usr/share/automake-1.X/目录下的depcomp和complie文档拷贝到本目录下运行aclocal命令运行autoconf命令运行automake -a命令运行./confiugre脚本,automake由于Makefile.in仍然可能比较复杂,automake能够根据程式员编写的 Makefile.am自动生成Makefile.in。 在调用automake时,往往要使用-a选项,该选项将自动建立一些项目需要的文档(以建立符号连接的形式), 他们是:install-sh、missing、mkinstalldirs、doc/mdate-sh 等等。 假如在除了使用 -a 选项外,还使用-c 选项,则不是在项目目录中制作到系统相应文档的连接,而是将文档复制到项目目录中。,03. GCC 编译优化,优化原理:从运行时的依赖关系来看,对性能有较大影响的组件有 kernel 和 glibc ,经过正确的版本选择、合理的配置、优化编译的内核与C库将对提高系统的性能起着基础性的作用。从被编译的软件包来看,每个软件包的 configure 脚本都提供了许多配置选项,其中有许多选项是与性能息息相关的。比如,对于 Apache-2.2.6 而言,你可以使用 -enable-MODULE=static 将模块静态编译进核心,使用 -disable-MODULE 禁用不需要的模块,使用 -with-mpm=MPM 选择一个高效的多路处理模块,在不需要IPv6的情况下使用 -disable-ipv6 禁用IPv6支持,在不使用线程化的MPM时使用 -disable-threads 禁用线程支持等。针对特定的软件包,请在编译前使用 configure -help 查看所有选项,合理的选用。,从编译过程自身来看,将源代码编译为二进制文件是在 Makefile 文件的指导下,由 make 程序调用一条条编译命令完成的。而将源代码编译为二进制文件又需要经过以下四个步骤:预处理(cpp) 编译(gcc或g+) 汇编(as) 连接(ld) ;括号中表示每个阶段所使用的程序,它们分别属于 GCC 和 Binutils 软件包。显然优化应当从编译工具自身的选择以及控制编译工具的行为入手。,常用优化选项gcc默认提供了5级优化选项的集合:-O0:无优化(默认)-O和-O1:使用能减少目标文件大小以及执行时间并且不会使编译时间明显增加的优化.在编译大型程序的时候会显著增加编译时内存的使用.-O2:包含-O1的优化并增加了不需要在目标文件大小和执行速度上进行折衷的优化.编译器不执行循环展开以及函数内联.此选项将增加编译时间和目标文件的执行性能.-Os:专门优化目标文件大小,执行所有的不增加目标文件大小的-O2优化选项.并且执行专门减小目标文件大小的优化选项.-O3:打开所有-O2的优化选项并且增加 -finline-functions, -funswitch-loops,-fpredictive-commoning, -fgcse-after-reload and -ftree-vectorize优化选项.,05. GCC 与GDB,Debug选项:在gcc编译源代码时指定-g选项可以产生带有调试信息的目标代码,gcc可以为多个不同平台上帝不同调试器提供调试信息,默认gcc产生的调试信息是为gdb使用的,可以使用-gformat 指定要生成的调试信息的格式以提供给其他平台的其他调试器使用.常用的格式有-ggdb:生成gdb专用的调试信息,使用最适合的格式(DWARF 2,stabs等)会有一些gdb专用的扩展,可能造成其他调试器无法运行.可以指定调试信息的等级:在指定的调试格式后面加上等级:如: -ggdb2 等,0代表不产生调试信息.在使用-gdwarf-2时因为最早的格式为-gdwarf2会造成混乱,所以要额外使用一个-glevel来指定调试信息的等级,其他格式选项也可以另外指定等级.,GCC 的编译错误类型C语法错误 错误资讯文件source.c中第n行有语法错误(syntex errror)头文件错误 错误资讯找不到头文件head.h(Can not find include file head.h)档案库错误 错误资讯连接程序找不到所需的函数库未定义符号 错误资讯有未定义的符号(Undefined symbol)。,通常可以使用-Wall来开启以下警告: -Waddress -Warray-bounds (only with -O2) -Wc+0 x-compat -Wchar-subscripts -Wimplicit-int -Wimplicit-function-declaration -Wcomment -Wformat -Wmain (only for C/ObjC and unless -ffreestanding) -Wmissing-braces -Wnonnull -Wparentheses -Wpointer-sign -Wreorder -Wreturn-type -Wsequence-point -Wsign-compare (only in C+) -Wstrict-aliasing -Wstrict-overflow=1 -Wswitch -Wtrigraphs -Wuninitialized (only with -O1 and above) -Wunknown-pragmas -Wunused-function -Wunused-label -Wunused-value -Wunused-variable,unused-function: 警告声明但是没有定义的static函数;unused-label: 声明但是未使用的标签;unused-parameter: 警告未使用的函数参数;unused-variable:声明但是未使用的本地变量;unused-value:计算了但是未使用的值;format:printf和scanf这样的函数中的格式字符串的使用不当;implicit-int:未指定类型;implicit-function:函数在声明前使用;char-subscripts:使用char类作为数组下标(因为char可能是有符号数);,missingbraces:大括号不匹配;parentheses:圆括号不匹配;return-type:函数有无返回值以及返回值类型不匹配;sequence-point:违反顺序点的代码,比如ai = ci+;switch:switch语句缺少default或者switch使用枚举变量为索引时缺少某个变量的case;strict-aliasing=n:使用n设置对指针变量指向的对象类型产生警告的限制程度,默认n=3;只有在-fstrict-aliasing设置的情况下有效;unknow-pragmas:使用未知的#pragma指令;uninitialized:使用的变量为初始化,只在-O2时有效;,以下是在-Wall中不会激活的警告选项:cast-align: 当指针进行类型转换后有内存对齐要求更严格时发出警告;sign-compare:当使用signed和unsigned类型比较时;missing-prototypes:当函数在使用前没有函数原型时;packed:packed是gcc的一个扩展,是使结构体各成员之间不留内存对齐所需的空间,有时候会造成内存对齐的问题;padded:也是gcc的扩展,使结构体成员之间进行内存对齐的填充,会造成结构体体积增大.unreachable-code:有不会执行的代码时.inline:当inline函数不再保持inline时(比如对inline函数取地址);disable-optimization:当不能执行指定的优化时.(需要太多时间或系统资源).可以使用 -Werror时所有的警告都变成错误,使出现警告时也停止编译.需要和指定警告的参数一起使用,06. GCC交叉编译器,制作交叉编译器一般分四步:制作交叉的二进制工具制作不带库的gcc交叉编译器用制作好的gcc交叉编译器将所需要的库编译重新编译带库的gcc交叉编译器cross-3.4.1.tar.bz2,07. 小结,为什么选择GCCGCC编译包括那些过程?中间的过程文件类型包括那些?怎样对Gcc的编译过程进行优化?如何打造自己个性化的Gcc编译环境?GCC和GDB的关系?Gcc与arm-linux-gcc的区别?,08. time for questions:,GCC全称是什么?gcc和arm-linux-gcc是什么关系?glibc与gcc的关系?linux 内核与gcc的关系?/etc/ld.so.conf与ldconfig?GCC 与makefile?,09. your question please:,?,content,GCC 概论GCC 深入探索GCC 的编译选项GCC 的应用技巧,GCC 调用动态链接库,动态库的搜索路径搜索的先后顺序,编译目标代码时指定的动态库搜索路径; 环境变量LD_LIBRARY_PATH指定的动态库搜索路径; 配置文件/etc/ld.so.conf中指定的动态库搜索路径; 默认的动态库搜索路径/lib; 默认的动态库搜索路径/usr/lib.,GCC调用静态链接库,库文件与环境变量总结,-D 编译开关的用途,编译时:gcc -DMODULE -c.?文件中:#define MODULEgcc -DDEBUGgcc -DRELEASEgcc -DVERSION_1_2_0_1-DMACRO=DEFN 以字符串“DEFN”定义 MACRO 宏),GCC 的编程环境,GCC编译的幕后信息,GCC在内核中的应用,content,GCC 概论GCC 深入探索GCC 的编译选项GCC 的应用技巧,content,GCC 概论GCC 深入探索GCC 的编译选项GCC 的应用技巧,推荐读物,Using and Porting the GNU Compiler CollectionGCC 中文手册学习使用GCCUsing the GNU Compiler Collection,