1、g+编译选项与makefile文件的编写,- cosmozhang,课程大纲,g+编译选项 概述,gcc 认为预处理后的文件(.i)是C文件,并且设定C形式的连接. g+ 认为预处理后的文件(.i)是C+文件,并且设定C+形式的连接.选项必须分立给出,如:-dr与-d -r完全不是一回事选项区分大小写大多数-f和-W选项有两个相反的格式: -fname和 -fno-name (或-Wname和-Wno-name),g+编译选项 选项分类及常用选项,1、总体选项 -c -s -E -o -v 2、语言选项 -ansi3、警告选项 -Wall -pedantic-errors -werror4、调
2、试选项 -g (默认为g2)5、优化选项 -O 一般宁可优化代码也不用这个选项6、预处理选项 -Dmacro -Dmacro=defn -Umacro 7、汇编选项8、连接器选项 -l -static -shared -symbolic9、目录选项 -I -I- -L -B (.)10、目标机选项 -V11、配置相关选项 -G12、代码生成选项 -fpic -fPIC,g+编译选项 总体选项,一、gcc/g+在执行编译,总共需要4步 1、预处理,生成.i的文件 预处理器cpp2、将预处理后的文件不转换成汇编语言,生成文件.s 编译器egcs3、有汇编变为目标代码(机器代码)生成.o的文件 汇编
3、器as4、连接目标代码,生成可执行程序 链接器ld注:除非使用了-c, -S,或-E选项(或者编译错误阻止了完整的过程),否则连接总是 最后的步骤。要生成以上4种文件,编译选项是什么?,g+编译选项 总体选项,对应的编译选项是:-E 激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面. g+ -E hello.cpp precompile.txt-S 激活预处理、编译,就是指把文件编译成为汇编代码。 g+ -S hello.cpp-c 激活预处理、编译、汇编 g+ -c hello.cpp生成目标代码,根据要生成文件类型有所差异(执行文件、.a、.so文件)。g+默认生成的是可执行
4、文件。,g+编译选项 目录选项,二、编译、链接目录及文件选项-IDIRNAME 指定头文件路径-i 相当于#include-LDIRNAME 指定库文件路径-lFOO 链接库名 lib*.a 编译及链接器会根据-I, -L指定的目录依次进行匹配,相当于连字符编译及链接查询目录顺序是怎样的?,g+编译选项 目录选项,匹配顺序是:1、当前路径2、用户指定的路径,写在specs内的,后来用-D -I -L指定的3、环境变量(PATH及LD_LIBRARY_PATH.)指定的路径4、系统内定的默认路径5、ld.so的环境变量(这是run time的时候)当初在编译时指定的(在gcc/gcc/colle
5、ct2.c:locatelib()?更具体的匹配顺序见附件:,编译、链接、执行查询路径,g+编译选项 调试选项,三、调试选项-g 以操作系统的本地格式.产生调试信息. GDB能够使用这些调试信息.-ggdb 以本地格式(如果支持)输出调试信息,尽可能包括GDB扩展-glevel 请求生成调试信息,同时用level指出需要多少信息.默认的level值是2.,g+编译选项 链接选项,四、链接方式选项:-static 此选项将禁止使用动态库。 优点:程序运行不依赖于其他库 缺点:文件比较大-shared (-G) 此选项将尽量使用动态库,为默认选项 优点:生成文件比较小 缺点:运行时需要系统提供动态
6、库-symbolic 建立共享目标文件的时候,把引用绑定到全局符号上.对所有无法解析的引用作出警告(除非用连接编辑选项 -Xlinker -z -Xlinker defs取代)。 注:只有部分系统支持该选项.,g+编译选项 警告选项,五、错误与告警选项-Wall 一般使用该选项,允许发出GCC能够提供的所有有用的警告。也可以用-Wwarning来标记指定的警告。-pedantic 允许发出ANSI/ISO C标准所列出的所有警告-pedantic-errors 允许发出ANSI/ISO C标准所列出的错误-werror 把所有警告转换为错误,以在警告发生时中止编译过程-w 关闭所有警告,建议不
7、要使用此项,g+编译选项 预处理选项,六、预处理选项-Dmacro 相当于C语言中的#define macro -Dmacro=defn 相当于C语言中的#define macro=defn -Umacro 相当于C语言中的#undef macro -undef 取消对任何非标准宏的定义,g+编译选项 其他选项,-O 优化选项,一般不建议使用。代码优化比使用该选项要更好。-fpic 编译器就生成位置无关目标码.适用于共享库(shared library). -fPIC 编译器就输出位置无关目标码.适用于动态连接(dynamic linking),即使分支需要大范围转移.,第二章 g+常见问题及
8、处理,g+常见问题,一、如何减小发布的可执行文件的大小:1、使用动态链接方式2、不使用-g编译选项 (正式发布前将-g选项却除,但为了跟踪问题,会结合记录可配置级别的log)3、发布前使用strip命令对可执行文件进行处理。二、-D选项的妙用1、发布debug, release版本时定义不同的宏2、作为不同操作系统、软件环境的开关。三、显示详细的编译、汇编、连接命令1、在g+中带上选项 -v,g+常见问题,四、undefined reference问题引起此类问题的原因主要有:1. 缺少某个源文件,或源文件中缺少某个函数2. 源文件中的宏,未正确开启3. 链接时,多个库的顺序未根据依赖关系安排
9、4. 编译时的先后顺序未按依赖关系安排1-2处理:一般把未添加的函数,源文件或者库添加到编译环境中。 Linux下使用grep命令也可以快速的找到,如可以在项目(库)目录下,使用 grep -n something *3-4处理:主要是解决链接顺序。 如果liba依赖于libb,在Makefile的LD选项中,libb应出现在liba的左侧。如下图:,g+常见问题,原因:libSamebarRecommendPublic.a依赖于libqqact.a,但-lqqact选项在-lSamebarRecommendPublic前面,所以发生连接错误。解决方法:将-lSamebarRecommendP
10、ublic选项移至-lqqact前,五、如何查看libnetbar_public.a(或执行文件、动态库)中的符号1、readelf -s libnetbar_public.a,g+常见问题,g+常见问题,2、objdump -t libnetbar_public.a,g+常见问题,3、ldd libnetbar_public.a (只能对.so及可执行文件) ,只显示会调用到的动态链接库,g+常见问题,五、日志使用_FILE_, _LINE_, _FUNCTION_宏,以方便问题的定位。六、编译提示:/usr/lib/gcc/i586-suse-linux/4.1.0/././././i58
11、6-suse-linux/bin/ld: cannot find -lidn方法:使用-v选项,并查看连接的各个路径下是否存在libidn.a的文件,第三章 Makefile文件的编写,Makefile文件的编写 总述,一、简介 make是Linux下的一款程序自动维护工具,配合makefile的使用,就能够根据程序中模块的修改情况,自动判断应该对那些模块重新编译,从而保证软件是由最新的模块构成。二、make的作用(或者说为什么要用make)1、避免重复输入烦琐的编译命令。2、加快编译速度3、建立手册页4、将应用程序安装至指定目录,makefile文件编写,三、make命令调用格式:make
12、-f makefile文件名选项宏定义目标常用选项有:-Idirname 指定被包含的makefile所在目录-w 如果make在执行时改变目录,打印当前目录名-d 打印调试信息-k 用该选项,即使make程序遇到错误也会继续向下运行,makefile文件编写 总述,四、makefile文件主要包含了5部分内容1、显示规则2、隐式规则:又称预定义规则。隐式规则简化了makefile的编写和维护。(make命令带-p选项),比如: 后缀规则,可以指定:.SUFFIXES: .cpp3、模式规则提供的一种扩展make隐式规则的方法,规则与普通规则一样,主要是目标必定含有%号,比如: %.o : %
13、.c$(CC) -c $(CFLAGS) $(CPPFLAGS) $ -o $4、变量定义(自动变量/预定义变量/自定义变量)5、文件指示(include, make -I, #if include)6、特殊字符:注释# 转义 通配符* 宿主目录,makefile编写 总述,五、makefile文件是被make命令调用的,用于描述系统中模块之间的相互依赖关系,以及产生目标文件所要执行的命令(规则)。编写规则通用形式:target : dependency depenency . commandcommand.注:command前是tab键,而非空格,makefile文件编写 关系依赖,六、ma
14、kefile关系依赖:规定了最终得到的应用程序跟生成它的各个源文件之间的关系,如下图:,main: main.o f1.o f2.omain.o:main.c def1.hf1.o: f1.c def1.h def2.hf2.o: f2.c def2.h def3.h,makefile文件编写 规则,七、规则:描述如何生成目标,或者说使用哪些命令来根据依赖模块产生目标。这就是command,这里的command即可以是gcc/g+编译命令,也可以是shell命令或是其他可执行文件。,main : main.o f1.o f2.ogcc -o main main.o f1.o f2.omain.
15、o : main.c def1.hgcc -c main.cf1.o : f1.c def1.h def2.hgcc -c f1.cf2.o : f2.c def2.h def3.hgcc -c f2.c,makefile文件编写 变量,八、变量(或者说宏)1、定义方法: VARNAME=some_text . 如: OBJS := howdy.o helper.o2、变量引用:$(VARNAME)或 $VARNAME)3、变量扩展:VARNAME += $(VARNAME) some_textn. 注:在使用变量时要注意库的连接左右问题 建议使用:VARNAME := some_textn
16、$(VARNAME)4、作用:用代表某些多处使用而又可能发生变化的内容,节省重复修改的工作,避免遗漏。一般用来代表一些文件名或选项。,makefile编写 变量,5、自动变量$ 规则的目标所对应的文件名$ 规则中的第一个相关文件名$ 规则中所有相关文件的列表,以空格为分隔符$? 规则中日期新于目标的所有相关文件的列表$(D) 目标文件的目录部分$(F) 目标文件的文件名部分$* 这个变量表示目标模式中“%”及其之前的部分。,makefile文件编写 变量,6、预定义变量CC C编译程序,默认值=ccCFLAGS 传给C编译器的标志CPP C+编译程序,默认值=cppCPPFLAGSLDFLAG
17、S 传给链接程序(ld)的标志,默认值=AR 归档维护程序,默认值=arARFLAGS 默认值=rvAS 汇编程序,默认值=asASFLAGS,makefile文件编写 总结,GNU的make工作时的执行步骤如下: (1) 读入所有的makefile文件。(2) 读入被include包括的其他makefile文件。(3) 初始化文件中的变量。(4) 推导隐式规则,并分析所有规则。(5) 为所有的目标文件创建依赖关系链。(6) 根据依赖关系,决定哪些目标要重新生成。(7) 执行生成命令。,第四章 Makefile常见实例,makefile实例,1、通过g+的MM选项显示各文件间依赖关系gcc -
18、MM main.c f1.c f2.cmain.o: main.c def1.hf1.o: f1.c def1.h def2.hf2.o: f2.c def2.h def3.h2、多目标$(OBJ_DIR)%.o:$(SRC_DIR)%.cpp echo Compiling $ $. $(CXX) $(INC) $(C_FLAGS) -c $ -o $3、静态模式objects = foo.o bar.oall: $(objects)$(objects): %.o: %.c$(gcc) -c $(CFLAGS) $ -o $,makefile实例,4、大项目makefile的处理给源文件分类,
19、并存放在不同的目录中,给各个目录定义变量。按层定义makefile.pub文件,该文件主要定义一些变量(如INC, SRC)、函数、本层会生成的lib文件。子层文件include上层及相关makefile.pub文件。并根据情况对变量进行扩展。生成库文件提供给下一级makefile进行链接。嵌套调用make在makefile文件中定义VPATH = src:./headers使用环境变量,makefile使用实例,5、程序包(函数的定义)定义程序包:define run-yaccyacc $(firstword $)mv y.tab.c $endef程序包的使用%.c : %.y $(run-
20、yacc),makefile使用实例,6、函数使用$( )或是: i := $ 示例:INC = $(patsubst %,-I%,$(ALLINC)make支持的函数有:$(subst ,) $(patsubst ,) $(filter ,) .,7、分支语法endif以及:elseendif注:conditional-directive可以是:ifeq(), ifneq(), ifdef, ifndef,makefile使用实例,分支语法示例:libs_for_gcc = -lgnunormal_libs =foo: $(objects)ifeq ($(CC),gcc)$(CC) -o f
21、oo $(objects) $(libs_for_gcc)else$(CC) -o foo $(objects) $(normal_libs)endif注:上面示例的这个规则中,目标foo可以根据变量$(CC)的值选取不同的函数库来编译程序,makefile使用实例,make的妙用同步文件至远端服务器:cmdscp:scp -P3600 exe user_00172.25.32.162:/usr/local/.make使用注意事项:如果只是更改了.h文件,make是不会重新编译的。在.h文件有函数定义时要注意。因为make是比较文件时间判断是否要生成文件的,所以因为两台机器的时间不一致,在两台文件间同步文件make后的程序并未使用实际最新的代码。,g+编译选项及makefile编写,Thanks,