460 likes | 665 Views
GCC/G++ Tutorial. C/C++ Preprocessing, Compiling, Assembly & Linking http://blog.csdn.net/kendiv/archive/2004/12/28/231711.aspx 吴茂瑛 ricket@sjtu.edu.cn 200 7 年 06 月 07 日. What is GCC. GNU Compiler Collector 支持多种高级语言 c, c++, fortran, java, ada
E N D
GCC/G++ Tutorial C/C++ Preprocessing, Compiling, Assembly & Linking http://blog.csdn.net/kendiv/archive/2004/12/28/231711.aspx 吴茂瑛ricket@sjtu.edu.cn 2007年06月07日 机群系统并行程序调试环境 DENNET
What is GCC • GNU Compiler Collector • 支持多种高级语言c, c++, fortran, java, ada • 支持多种处理器(alpha,arm,avr,IA-64,intel 386, AMD, mips, mmix, powerpc, sparc, pdp-11…) 机群系统并行程序调试环境 DENNET
Include syntax • 头文件中包含函数与变量的声明 • #include <headfile.h> • #include “headfile.h” • 源文件首先会生成(COMPILE)中间目标文件,再由中间目标文件连接(LINK)生成执行文件 • 在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成Object File 机群系统并行程序调试环境 DENNET
总览(SYNOPSIS) • gcc[option|filename ]... • 认为预处理后的文件(.i)是C文件,并且设定C形式的连接. • g++[option|filename ]... • 认为预处理后的文件(.i)是C++文件,并且设定C++形式的连接. 机群系统并行程序调试环境 DENNET
源文件后缀名与处理 • .c —— C源程序;预处理,编译,汇编 • .C —— C++源程序;预处理,编译,汇编 • .cc —— C++源程序;预处理,编译,汇编 • .cxx —— C++源程序;预处理,编译,汇编 • .m —— Objective-C源程序;预处理,编译,汇编 • .i ——预处理后的C文件;编译,汇编 • .ii ——预处理后的C++文件;编译,汇编 • .s ——汇编语言源程序;汇编 • .S ——汇编语言源程序;预处理,汇编 • .h ——预处理器文件;通常不出现在命令行上 机群系统并行程序调试环境 DENNET
GCC使用的一些环境变量 C_INCLUDE_PATH编译C程序时使用的环境变量,用于查找头文件,默认为/usr/include。CPLUS_INCLUDE_PATH编译C++程序时使用的环境变量,用于查找头文件,默认为/usr/include。OBJC_INCLUDE_PATH编译Obj-C程序时使用的环境变量,用于查找头文件。CPATH 编译C/C++/Obj-C程序时使用的环境变量,用于查找头文件。COMPILER_PATH如果没有用GCC_EXEC_PREFIX定位子程序,编译程序将会在此查找它的子程序。LIBRARY_PATH连接程序将在这些目录中寻找特殊的连接程序文件/lib, /lib64, /usr/lib, /usr/lib64, /usr/local/lib。LD_LIBRARY_PATH该环境变量不影响编译程序,但是程序运行的时候会有影响:程序会查找该目录列表以寻找共享库。当不能够在编译程序的目录中找到共享库的时候,执行程序必须设置该环境变量。LD_RUN_PATH该环境变量不影响编译程序,但是程序运行的时候会有影响:它在运行时指出了文件的名字,运行的程序可以由此得到它的符号名字和地址。由于地址不会重新载入,因而可能符号应用其他文件中的绝对地址。这个和ld工具使用的"-R"选项完全一样。GCC_EXEC_PREFIX编译程序执行所有子程序的名字的前缀,默认值是"<prefix>/lib/gcc-lib/",其中的<prefix>是安装时configure脚本指定的前缀。LANG指定编译程序使用的字符集,可用于创建宽字符文件、串文字、注释;默认为英文。[目前只支持日文"C-JIS,C-SJIS,C-EUCJP",不支持中文]LC_ALL指定多字节字符的字符分类,主要用于确定字符串的字符边界以及编译程序使用何种语言发出诊断消息;默认设置与LANG相同。中文相关的几项:"zh_CN.GB2312 , zh_CN.GB18030 , zh_CN.GBK , zh_CN.UTF-8 , zh_TW.BIG5"TMPDIR编译程序存放临时工作文件的临时目录,这些临时文件通常在编译结束时被删除。 机群系统并行程序调试环境 DENNET
选项(OPTIONS) • 总体选项(Overall Option) • -c -S -E -o file -pipe -v -x language • 语言选项(Language Option) • -ansi -fall-virtual -fcond-mismatch -fdollars-in-identifiers -fenum-int-equiv -fexternal-templates -fno-asm -fno-builtin -fhosted -fno-hosted -ffreestanding -fno-freestanding -fno-strict-prototype -fsigned-bitfields -fsigned-char -fthis-is-variable -funsigned-bitfields -funsigned-char -fwritable-strings -traditional -traditional-cpp -trigraphs • 警告选项(Warning Option) • -fsyntax-only -pedantic -pedantic-errors -w -W -Wall -Waggregate-return -Wcast-align -Wcast-qual -Wchar-subscript -Wcomment -Wconversion -Wenum-clash -Werror -Wformat -Wid-clash-len -Wimplicit -Wimplicit-int -Wimplicit-function-declaration -Winline -Wlong-long -Wmain -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Wno-import -Wparentheses -Wpointer-arith -Wredundant-decls -Wreturn-type -Wshadow -Wstrict-prototypes -Wswitch -Wtemplate-debugging -Wtraditional -Wtrigraphs -Wuninitialized -Wunused -Wwrite-strings • 调试选项(Debugging Option) • -a -dletters -fpretend-float -g -glevel -gcoff -gxcoff -gxcoff+ -gdwarf -gdwarf+ -gstabs -gstabs+ -ggdb -p -pg -save-temps -print-file-name=library -print-libgcc-file-name -print-prog-name=program • 优化选项(Optimization Option) • -fcaller-saves -fcse-follow-jumps -fcse-skip-blocks -fdelayed-branch -felide-constructors -fexpensive-optimizations -ffast-math -ffloat-store -fforce-addr -fforce-mem -finline-functions -fkeep-inline-functions -fmemoize-lookups -fno-default-inline -fno-defer-pop -fno-function-cse -fno-inline -fno-peephole -fomit-frame-pointer -frerun-cse-after-loop -fschedule-insns -fschedule-insns2 -fstrength-reduce -fthread-jumps -funroll-all-loops -funroll-loops -O -O2 -O3 • 预处理器选项(Preprocessor Option) • -Aassertion -C -dD -dM -dN -Dmacro[=defn] -E -H -idirafter dir -include file -imacros file -iprefix file -iwithprefix dir -M -MD -MM -MMD -nostdinc -P -Umacro -undef • 汇编器选项(Assembler Option) • -Wa,option • 连接器选项(Linker Option) • -llibrary -nostartfiles -nostdlib -static -shared -symbolic -Xlinker option -Wl,option -u symbol • 目录选项(Directory Option) • -Bprefix -Idir -I- -Ldir • 目标机选项(Target Option) • -b machine -V version • 配置相关选项(Configuration Dependent Option) 机群系统并行程序调试环境 DENNET
总体选项(Overall Option) 机群系统并行程序调试环境 DENNET
-x language • 明确指出后面输入文件的语言为language (而不是从文件名后缀得到的默认选择); • 这个选项应用于后面 所有的输入文件,直到遇着下一个`-x‘选项; • language的可选值有`c‘, `objective-c’, `c-header‘, `c++’, `cpp-output‘, `assembler’,和`assembler-with-cpp‘, ‘none’ -c output • 编译或汇编源文件,但是不作连接; • 编译器输出对应于源文件的目标文件; • 缺省情况下, GCC通过用`.o‘替换源文件名后缀`.c’, `.i‘, `.s’,等等,产生目标文件名.可以使用-o选项选择其他名字; • GCC忽略-c选项后面任何无法识别的输入文件 机群系统并行程序调试环境 DENNET
-S • 编译后即停止,不进行汇编; • 对于每个输入的非汇编语言文件,输出文件是汇编语言文件; • 缺省情况下, GCC通过用`.o‘替换源文件名后缀`.c’, `.i‘,等等,产生 目标文件名; • 可以使用-o选项选择其他名字; • GCC忽略任何不需要编译的输入文件 -E • 预处理后即停止,不进行编译; • 对于每个输入的非汇编语言文件,输出文件是标准化输出; • GCC忽略任何不需要预处理的输入文件 机群系统并行程序调试环境 DENNET
-o file • 指定输出文件为file • 选项不在乎GCC产生什么输出,无论是可执行文件,目标文件,汇编文件还是 预处理后的C代码. • 由于只能指定一个输出文件,因此编译多个输入文件时,使用`-o'选项没有意义,除非输出一个可执行文件. • 如果没有使用`-o'选项,默认的输出结果是: • 可执行文件为`a.out‘; • `source.suffix ‘的目标文件是`source.o’; • 汇编文件是 `source.s‘; • 预处理后的C源代码送往标准输出。 -v • (在标准错误)显示执行编译阶段的命令; • 同时显示编译器驱动程序,预处理器,编译器的版本号 机群系统并行程序调试环境 DENNET
语言选项(Language Option) 机群系统并行程序调试环境 DENNET
-ansi • 支持符合ANSI标准的C程序 • 关闭GNU C中某些不兼容ANSI C的特性,例如asm, inline和 typeof关键字,以及诸如unix和vax这些预定义宏 • 开启不受欢迎和极少使用的ANSI trigraph特性,以及禁止`$'成为标识符的一部分. • 可选的关键字 __asm__, __extension__, __inline__和__typeof__仍然有效; • 预定义宏,如__unix__和__vax__,无论有没有使用 `-ansi'选项,始终有效。 -fno-asm • 不把asm, inline或typeof当作关键字;用 __asm__, __inline__和__typeof__替代; • `-ansi' 隐含声明了`-fno-asm'. 机群系统并行程序调试环境 DENNET
-fno-builtin • 不支持以双下划线开始的内建函数(built-in function); • 目前受影响的函数主要有_exit, abort, abs, alloca, cos, exit, fabs, labs, memcmp, memcpy, sin, sqrt, strcmp, strcpy,和strlen; • -ansi可以避免exit和alloca成为内建函数 -fhosted • 按宿主环境进行编译; • 隐含声明了fbuiltin • 警告不正确的main函数声明. 机群系统并行程序调试环境 DENNET
-ffreestanding • 按独立环境编译; • 隐含声明了fno-builtin选项; • 对于main函数没有特别要求 -fno-strictprototype • 对于没有参数的函数声明,例如 `int foo (); ‘: • 按C风格处理---即不说明参数个数或类型. (仅针对C++) • 正常情况下,这样的函数foo在C++中意味着参数为空. 机群系统并行程序调试环境 DENNET
预处理器选项(Preprocessor Option) 机群系统并行程序调试环境 DENNET
-include file • 在处理常规输入文件之前,首先处理文件file • 结果是,文件file的内容先得到编译; • 命令行上任何`-D‘和`-U’选项永远在`-include file‘之前处理, 无论他们在命令行上的顺序如何. • `-include'和`-imacros'选项按书写顺序处理 -undef • 不要预定义任何非标准宏; • 包括系统结构标志 机群系统并行程序调试环境 DENNET
汇编器选项(Assembler Option) 机群系统并行程序调试环境 DENNET
-Wa,option • 把选项option传递给汇编器 • 如果option含有逗号,就在逗号处分割成多个选项 机群系统并行程序调试环境 DENNET
连接器选项(Linker Option) 机群系统并行程序调试环境 DENNET
-llibrary • 连接名为library的库文件; • 连接器在标准搜索目录中寻找名字为`liblibrary.a‘的库文件; • 搜索目录除了一些系统标准目录外,还包括用户以`-L‘选项指定的路径; • 一般说来用这个方法找到的文件是库文件组成的归档文件(archive file); • 连接器处理归档文件的 方法是:扫描归档文件,寻找某些成员,这些成员的符号目前已被引用,不过还没有被定义.但是,如果连接器找到普通的目标文件,而不是库文件,就把这个目标文件按平常方式连接进来; • 指定`-l‘选项和指定文件名的唯一区别是, `-l选项用`lib’和`.a‘把library包裹起来,而且搜索一些目录; • -lobjc这个-l选项的特殊形式用于连接Objective C程序; • -Ldir在`-l'选项的搜索路径列表中添加dir目录 机群系统并行程序调试环境 DENNET
GNU库(共享 &静态) • linux系统中可用的库都存放在/usr/lib和/lib目录中; • 库文件名由前缀lib和库名以及后缀组成。共享库的后缀名由.so和版本号组成,静态库的后缀名为.a; 静态库:ar rsv ~/lib/libtest.a myfunc.o (压缩命令, 从.o 到 .a) 动态库:gcc -fPIC -shared -o $HOME/lib/libtest.so myfunc.c • 数学共享库的库名为libm.so.5,这里的标识字符为m,版本号为5;libm.a则是静态数学库;X-Windows库名为libX11.so.6,使用X11作为库的标识,版本为6; • 在默认情况下,Linux将首先搜索指定库的共享版本,如果找不到,才会去搜索静态版本; • 在/usr/lib和/lib目录中可以找到绝大多数的共享库。连接时将首先搜索这两个目录。有一些库也可能存放在特定的目录中,在/etc/ld.conf配置文件中给出了这些目录的列表(ldconfig命令); • 静态库是指编译连接时,把库文件的代码全部加入到可执行文件中,所以生成的文件较大,但运行时,就不再需要库文件了。动态库正好相反,在编译连接时,没有把库文件的代码加入到可执行文件中,所以生成的文件较小,但运行时,仍需要加载库文件 机群系统并行程序调试环境 DENNET
常用库文件 • gcc编译器中引用可搜索到的目录中的库文件时,需要使用-l选项和库名; -lname将首先使用libname.so进行搜索 • 在gcc命令行上输入-lm可以在程序中连接标准算术库,是libm.so$ gcc main.c io.c -o bookrecs –lm • 系统中还有一些其它可用的库,常用的是libncurses.a库,包含了一些简单的鼠标移动例程;在命令行中使用-lncurses选项引用libncurses.so库。下面的例子同时调用了数学和光标库。$ gcc mian.c io.c -o bookrecs -lm –lncurses • 在引用其它目录中的库时,需要使用-ldir选项指定该目录。该选项指定了搜索库函数时其它路径。在下面的例子中,用户在连接时使用了mydir目录中的myio.so库文件。 $ gcc main.c -o bookrecs -lmydir -lmyio 机群系统并行程序调试环境 DENNET
-static • 在支持动态连接(dynamic linking)的系统上,阻止连接共享库; • 该选项在其他系统上无效 -Wl,option • 把选项option传递给连接器; • 如果option中含有逗号,就在逗号处分割成多个选项 机群系统并行程序调试环境 DENNET
目录选项(Directory Option) 指定搜索路径,用于查找头文件,库文件,或编译器的某些成员 机群系统并行程序调试环境 DENNET
-Idir • 在头文件’#include<file>’或者’#include”file”’的搜索路径列表中添加dir 目录; • 任何在`-I-‘前面用`-I’选项指定的搜索路径只适用于`#include “file”‘这种情况;他们不能用来搜索`#include <file>’包含的头文件; • 如果用`-I'选项指定的搜索路径位于`-I-'选项后面,就可以在这些路径中搜索所有的 `#include'指令. (一般说来-I选项就是这么用的.) • `-I-‘选项能够阻止当前目录(存放当前输入文件的地方)成为搜索`#include “file”’的第一选择; • `-I-'不影响使用系统标准目录,因此, `-I-'和`-nostdinc'是不同的选项. 机群系统并行程序调试环境 DENNET
-Bprefix • 这个选项指出在何处寻找可执行文件,库文件,以及编译器自己的数据文件. 编译器驱动程序需要执行某些下面的子程序: `cpp', `cc1' (或C++的 `cc1plus'), `as'和`ld'.他把prefix当作欲执行的程序的 前缀,既可以包括也可以不包括`machine/version/'. • 对于要运行的子程序,编译器驱动程序首先试着加上`-B'前缀(如果存在).如果没有找到文件,或没有指定 `-B'选项,编译器接着会试验两个标准前缀`/usr/lib/gcc/'和 `/usr/local/lib/gcc-lib/'.如果仍然没能够找到所需文件,编译器就在`PATH'环境变量 指定的路径中寻找没加任何前缀的文件名. • 如果有需要,运行时(run-time)支持文件`libgcc.a'也在`-B'前缀的搜索范围之内. 如果这里没有找到,就在上面提到的两个标准前缀中寻找,仅此而已.如果上述方法没有找到这个文件,就不连接他了.多数 情况的多数机器上, `libgcc.a'并非必不可少. • 你可以通过环境变量GCC_EXEC_PREFIX获得近似的效果;如果定义了这个变量,其值就和上面说的 一样用做前缀.如果同时指定了`-B'选项和GCC_EXEC_PREFIX变量,编译器首先使用 `-B'选项,然后才尝试环境变量值. . 机群系统并行程序调试环境 DENNET
警告选项(WARNING OPTION) 针对程序结构的诊断信息,程序不一定有错误,而是存在风险,或者可能存在错误 机群系统并行程序调试环境 DENNET
-fsyntax-only检查程序中的语法错误,但是不产生输出信息;-fsyntax-only检查程序中的语法错误,但是不产生输出信息; • -w禁止所有警告信息; • -Wimplicit-int警告没有指定类型的声明; • -Wuninitialized在初始化之前就使用自动变量; • -Wno-import禁止所有关于#import的警告信息; • -W对下列事件显示额外的警告信息: • 非易变自动变量(nonvolatile automatic variable)可能在调用longjmp时发生改变. • 既可以返回值,也可以不返回值的函数. (缺少结尾的函数体被看作不返回函数值) • 表达式语句或逗号表达式的左侧没有产生作用(side effect).如果要防止这种警告,应该把未使用的表达式强制转换 为void类型. • 无符号数用`>'或`<='和零做比较 机群系统并行程序调试环境 DENNET
调试选项(DEBUGGING OPTION) 这些选项控制多种优化措施 机群系统并行程序调试环境 DENNET
-O • -O1 • 优化.对于大函数,优化编译占用稍微多的时间和相当大的内存; • 不使用`-O'选项时,只有声明了register的变量才分配使用寄存器.编译结果比不用 `-O'选项的PCC要略逊一筹. • 使用了`-O'选项,编译器会试图减少目标码的大小和执行时间. • 如果指定了`-O'选项, `-fthread-jumps'和`-fdefer-pop'选项将被 打开.在有delay slot的机器上, `-fdelayed-branch'选项将被打开.在即使没有帧指针 (frame pointer)也支持调试的机器上, `-fomit-frame-pointer'选项将被打开 • -O2多优化一些.除了涉及空间和速度交换的优化选项,执行几乎所有的优化工作.例如不进行循环展开(loop unrolling)和函数内嵌(inlining).和-O选项比较,这个选项既增加了编译时间,也提高了生成代码的 运行效果. • -O3优化的更多.除了打开-O2所做的一切,它还打开了-finline-functions选项 • -O0不优化 如果指定了多个-O选项,不管带不带数字,最后一个选项才是生效的选项. 机群系统并行程序调试环境 DENNET
file.c C源文件 file.h C头文件(预处理文件) file.i预处理后的C源文件 file.CC/file.cc/file.cxx C++源文件 file.m Objective-C源文件 file.s汇编语言文件 file.o目标文件 a.out连接的输出文件 $TMPDIR/cc*临时文件 $LIBDIR/cpp预处理器 $LIBDIR/cc1 C编译器 $LIBDIR/cc1plus C++编译器 $LIBDIR/collect某些机器需要的连接器前端(front end)程序 $LIBDIR/libgcc.a GCC子例程(subroutine)库 /lib/crt[01n].o启动例程(start-up) $LIBDIR/ccrt0 C++的附加启动例程 /lib/libc.a标准C库 /usr/include #include文件的标准目录 $LIBDIR/include #include文件的标准gcc目录 $LIBDIR/g++-include #include文件的附加g++目录 LIBDIR通常为/usr/local/lib/machine/version. TMPDIR来自环境变量TMPDIR (如果存在,缺省为/usr/tmp ,否则为 /tmp). 机群系统并行程序调试环境 DENNET
如何写makefile 或许很多Windows的程序员都不知道makefile这个东西,因为那些Windows的IDE(Integrated Development Environment,集成开发环境)都为你做了这个工作,但要成为一个好的、professional的程序员,makefile还是必须要了解的。 机群系统并行程序调试环境 DENNET
什么是Makefile • Makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作; • Makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令; • make是一个命令工具,是一个解释Makefile文件中指令的命令工具,一般来说,大多数的IDE都有这个命令; • makefile带来的好处就是——“自动化编译”,一旦写好Makefile,只需要一个make命令,整个工程完全自动编译 机群系统并行程序调试环境 DENNET
configure • 系统配置程序configure的作用 1. 接受用户的安装参数和选项;设置系统缺省配置 2. 处理配置参数 • 建立目标系统后端文件与逻辑文件名之间的链接,使编译系统能正确地在目标平台上生成 • 在模板文件Makefile.in中插入和修改与配置参数有关的信息,生成目标平台上的Makefile文件 • 生成config.status文件,记录本次安装的配置信息 机群系统并行程序调试环境 DENNET
Makefile的简单例子 通常的格式为 target : requisitive command 从8个c源文件和3个头文件 编译连接为目标文件edit 一般来说,默认的操作都放 最开头(edit),也就是说 ,输入“make”默认为“make edit”;而正常把“clean”放在 最前面。 某些时候可能还有“make install” edit : main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o cc -o edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o main.o : main.c defs.h cc -c main.ckbd.o : kbd.c defs.h command.h cc -c kbd.ccommand.o : command.c defs.h command.h cc -c command.cdisplay.o : display.c defs.h buffer.h cc -c display.cinsert.o : insert.c defs.h buffer.h cc -c insert.csearch.o : search.c defs.h buffer.h cc -c search.cfiles.o : files.c defs.h buffer.h command.h cc -c files.cutils.o : utils.c defs.h cc -c utils.cclean : rm edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o 机群系统并行程序调试环境 DENNET
如何简化前面的例子 (1) 只要make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中; (2) 如果要加入其他的目标 .o文件,只要修改objects变量就可以了; (3) “.PHONY”表示,clean是个伪目标文件; (4) 自动生成依赖性:可以利用c/c++编译使用的-M(对于cc)或者-MM选项(对于gcc) objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) main.o : defs.h kbd.o : defs.h command.h command.o : defs.h command.h display.o : defs.h buffer.h insert.o : defs.h buffer.h search.o : defs.h buffer.h files.o : defs.h buffer.h command.h utils.o : defs.h .PHONY : clean clean : rm edit $(objects) objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) $(objects) : defs.h kbd.o command.o files.o : command.h display.o insert.o search.o files.o : buffer.h .PHONY : clean clean : rm edit $(objects) files = foo.elc bar.o lose.o $(filter %.o,$(files)): %.o: %.c $(CC) -c $(CFLAGS) $< -o $@ $(filter %.elc,$(files)): %.elc: %.el emacs -f batch-byte-compile $< 机群系统并行程序调试环境 DENNET
Makefile里有什么? Makefile里主要包含了五个东西: • 显式规则:要生成的文件,文件的依赖文件,生成的命令 • 隐晦规则:自动推导目标文件和依赖文件名的关系 • 变量定义:运行make时,变量都会被扩展到相应的引用位置上 • 文件指示: (1)在一个Makefile中引用另一个Makefile,与c语言中的#include一样,使用“include foo.make”这种方式(如果是“-include foo.make”,则表示忽略foo.make中的错误);(2)根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;(3)定义一个多行的命令 • 注释:# Makefile中的命令,必须要以[Tab]键开始 机群系统并行程序调试环境 DENNET
Makefile的文件名 Makefile的一般命名规则为: • 常规命名顺序:GNUmakefile 〉makefile 〉Makefile • 特定名称:Makefile.linux • make –f Make.linux • make –file Make.linux Makefile最常用,一方面因为显目,另一方面符合大多数人的习惯 机群系统并行程序调试环境 DENNET
make的工作方式 • 读入所有的Makefile; • 读入被include的其它Makefile; • 初始化文件中的变量; • 推导隐晦规则,并分析所有规则; • 为所有的目标文件创建依赖关系链; • 根据依赖关系,决定哪些目标要重新生成; • 执行生成命令。 机群系统并行程序调试环境 DENNET
使用过渡文件.d生成Makefile %.d: %.c @set -e; rm -f $@; \ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \ sed 's/\($*\)\.o[ :]*/\1.o $@ :/g' < $@.$$$$ > $@; \ rm -f $@.$$$$ 这个模式要做的事把依赖关系: main.o : main.c defs.h 转成:main.o main.d : main.c defs.h • 规则的意思是,所有的[.d]文件依赖于[.c]文件 • 第一行“rm -f $@”的意思是删除所有的目标,也就是[.d]文件; • 第二行的意思是,为每个依赖文件“$<”,也就是[.c]文件生成依赖文件; • “$@”表示模式“%.d”文件,如果有一个C文件是name.c,那么“%”就是“name”; • “$$$$”意为一个随机编号,第二行生成的文件有可能是“name.d.12345”; • 第三行使用sed命令做了一个替换; • 第四行就是删除临时文件。 机群系统并行程序调试环境 DENNET
Makefile的书写规则 • Makefile文件中的命令必须以\t(TABLE键)开头; • make的命令默认是被“/bin/sh”——UNIX的标准Shell解释执行的。除非你特别指定一个其它的Shell; • 对于@echo 正在编译XXX模块......,运行make将不显示”echo正在编译XXX模块......”,而只是显示这一行命令的运行结果“正在编译XXX模块......”; • 需要注意的是,如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。 exec: cd /home/hchen; pwd 机群系统并行程序调试环境 DENNET
使用条件判断 libs_for_gcc = -lgnu normal_libs = ifeq ($(CC),gcc) libs=$(libs_for_gcc) else libs=$(normal_libs) endif foo: $(objects) $(CC) -o foo $(objects) $(libs) libs_for_gcc = -lgnu normal_libs = foo: $(objects) ifeq ($(CC),gcc) $(CC) -o foo $(objects) $(libs_for_gcc) else $(CC) -o foo $(objects) $(normal_libs) endif 除了ifeq(‘’,’’)外,还有ifneq、ifdef和ifneq 机群系统并行程序调试环境 DENNET
自动化变量 $@表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。 $%仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar.o)",那么,"$%"就是"bar.o","$@"就是"foo.a"。如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。 $<依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。 $?所有比目标新的依赖目标的集合。以空格分隔。 $^所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。 $+这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。 $* 这个变量表示目标模式中"%"及其之前的部分。如果目标是"dir/a.foo.b",并且目标的模式是"a.%.b",那么,"$*"的值就是"dir/a.foo"。这个变量对于构造有关联的文件名是比较有较。如果目标中没有模式的定义,那么"$*"也就不能被推导出,但是,如果目标文件的后缀是make所识别的,那么"$*"就是除了后缀的那一部分。例如:如果目标是"foo.c",因为".c"是make所能识别的后缀名,所以,"$*"的值就是"foo"。: 机群系统并行程序调试环境 DENNET
$(@D) 表示"$@"的目录部分(不以斜杠作为结尾),如果"$@"值是"dir/foo.o",那么"$(@D)"就是"dir",而如果"$@"中没有包含斜杠的话,其值就是"."(当前目录)。 $(@F)表示"$@"的文件部分,如果"$@"值是"dir/foo.o",那么"$(@F)"就是"foo.o","$(@F)"相当于函数"$(notdir $@)"。 "$(*D)""$(*F)"和上面所述的同理,也是取文件的目录部分和文件部分。对于上面的那个例子,"$(*D)"返回"dir",而"$(*F)"返回"foo" "$(%D)""$(%F)"分别表示了函数包文件成员的目录部分和文件部分。这对于形同"archive(member)"形式的目标中的"member"中包含了不同的目录很有用。 "$(<D)""$(<F)"分别表示依赖文件的目录部分和文件部分。 "$(^D)""$(^F)"分别表示所有依赖文件的目录部分和文件部分。(无相同的) "$(+D)""$(+F)"分别表示所有依赖文件的目录部分和文件部分。(可以有相同的) "$(?D)""$(?F)"分别表示被更新的依赖文件的目录部分和文件部分。 机群系统并行程序调试环境 DENNET
用 gdb 调试 GCC 程序 在shell终端输入“gdb”:,前提是在编译时必须加入-g • kill 终止正在调试的程序 • list 列出产生执行文件的源代码的一部分 • next 执行一行源代码但不进入函数内部 • step 执行一行源代码而且进入函数内部 • run 执行当前被调试的程序 • quit 终止 gdb • watch 使你能监视一个变量的值而不管它何时被改变 • print 显示表达式的值 • break 26在代码26行设置断点, 这将使程序执行到这里时被挂起 • make 使你能不退出 gdb 就可以重新产生可执行文件 • shell 使你能不离开 gdb 就执行 UNIX shell 命令 机群系统并行程序调试环境 DENNET