GCC/G++ Tutorial
description
Transcript of GCC/G++ Tutorial
DE机群系统并行程序调试环境NNET
1
GCC/G++ TutorialGCC/G++ Tutorial
C/C++ Preprocessing, Compiling, C/C++ Preprocessing, Compiling, Assembly & LinkingAssembly & Linking
http://blog.csdn.net/kendiv/archive/2004/12/28/231711.aspx
吴茂瑛吴茂瑛 [email protected] [email protected]
20020077 年年 0606 月月 0707 日日
DE机群系统并行程序调试环境NNET
2
What is GCCWhat is GCC
GNU Compiler Collector支持多种高级语言 c, c++, fortran, java, ada支持多种处理器( alpha,arm,avr,IA-64,intel 386, AMD, mips, mmix, powerpc, sparc, pdp-11… )
DE机群系统并行程序调试环境NNET
3
Include syntaxInclude syntax
头文件中包含函数与变量的声明#include <headfile.h>#include “headfile.h”源文件首先会生成( COMPILE )中间目标文件,再由中间目标文件连接( LINK )生成执行文件在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成 Object File
DE机群系统并行程序调试环境NNET
4
总览总览 (SYNOPSIS) (SYNOPSIS)
gcc[option|filename ]...
认为预处理后的文件 (.i) 是 C 文件 , 并且设定 C 形式的连接 .
g++[option|filename ]...
认为预处理后的文件 (.i) 是 C++ 文件 , 并且设定 C++ 形式的连接 .
DE机群系统并行程序调试环境NNET
5
源文件后缀名与处理源文件后缀名与处理.c —— C 源程序 ; 预处理 , 编译 , 汇编.C —— C++ 源程序 ; 预处理 , 编译 , 汇编.cc —— C++ 源程序 ; 预处理 , 编译 , 汇编.cxx —— C++ 源程序 ; 预处理 , 编译 , 汇编.m —— Objective-C 源程序 ; 预处理 , 编译 , 汇编.i —— 预处理后的 C 文件 ; 编译 , 汇编.ii —— 预处理后的 C++ 文件 ; 编译 , 汇编.s —— 汇编语言源程序 ; 汇编.S —— 汇编语言源程序 ; 预处理 , 汇编.h —— 预处理器文件 ; 通常不出现在命令行上
DE机群系统并行程序调试环境NNET
6
GCCGCC 使用的一些环境变量使用的一些环境变量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 编译程序存放临时工作文件的临时目录,这些临时文件通常在编译结束时被删除。
DE机群系统并行程序调试环境NNET
7
选项选项 (OPTIONS) (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)
DE机群系统并行程序调试环境NNET
8
总体选项总体选项(Overall Option)(Overall Option)
DE机群系统并行程序调试环境NNET
9
-x language-x language明确指出后面输入文件的语言为 language ( 而不是从文件名后缀得到的默认选择 ) ;这个选项应用于后面 所有的输入文件 , 直到遇着下一个 `-x‘ 选项;language 的可选值有 `c‘, `objective-c’, `c-header‘, `c++’, `cpp-output‘, `assembler’, 和 `assembler-with-cpp‘, ‘none’
-c output-c output编译或汇编源文件 , 但是不作连接;编译器输出对应于源文件的目标文件; 缺省情况下 , GCC 通过用 `.o‘ 替换源文件名后缀 `.c’, `.i‘, `.s’, 等等 , 产生目标文件名 . 可以使用 -o 选项选择其他名字;GCC 忽略 -c 选项后面任何无法识别的输入文件
DE机群系统并行程序调试环境NNET
10
-S-S编译后即停止 , 不进行汇编;对于每个输入的非汇编语言文件 , 输出文件是汇编语言文件;缺省情况下 , GCC 通过用 `.o‘ 替换源文件名后缀 `.c’, `.i‘, 等等 ,产生 目标文件名;可以使用 -o 选项选择其他名字;GCC 忽略任何不需要编译的输入文件
-E-E
预处理后即停止 , 不进行编译;对于每个输入的非汇编语言文件 , 输出文件是标准化输出;GCC 忽略任何不需要预处理的输入文件
DE机群系统并行程序调试环境NNET
11
-o file-o file指定输出文件为 file选项不在乎 GCC 产生什么输出 , 无论是可执行文件 , 目标文件 ,汇编文件还是 预处理后的 C 代码 .由于只能指定一个输出文件 , 因此编译多个输入文件时 , 使用 `-o' 选项没有意义 , 除非输出一个可执行文件 . 如果没有使用 `-o' 选项 , 默认的输出结果是 :
可执行文件为 `a.out‘ ; `source.suffix ‘ 的目标文件是 `source.o’ ; 汇编文件是 `source.s‘ ; 预处理后的 C 源代码送往标准输出。
-v-v( 在标准错误 ) 显示执行编译阶段的命令;同时显示编译器驱动程序 , 预处理器 , 编译器的版本号
DE机群系统并行程序调试环境NNET
12
语言选项语言选项(Language Option)(Language Option)
DE机群系统并行程序调试环境NNET
13
-ansi-ansi支持符合 ANSI 标准的 C 程序关闭 GNU C 中某些不兼容 ANSI C 的特性 , 例如 asm, inline 和 typeof 关键字 , 以及诸如 unix 和 vax 这些预定义宏开启不受欢迎和极少使用的 ANSI trigraph 特性 , 以及禁止 `$' 成为标识符的一部分 . 可选的关键字 __asm__, __extension__, __inline__ 和__typeof__ 仍然有效;预定义宏 , 如 __unix__ 和 __vax__, 无论有没有使用 `-ansi' 选项 , 始终有效。
-fno-asm-fno-asm不把 asm, inline 或 typeof 当作关键字;用 __asm__, __inline__和 __typeof__ 替代;
`-ansi' 隐含声明了 `-fno-asm'.
DE机群系统并行程序调试环境NNET
14
-fno-builtin-fno-builtin不支持以双下划线开始的内建函数( built-in function );目前受影响的函数主要有 _exit, abort, abs, alloca, cos, exit, fabs, labs, memcmp, memcpy, sin, sqrt, strcmp, strcpy, 和 strlen ;-ansi 可以避免 exit 和 alloca 成为内建函数
-fhosted-fhosted按宿主环境进行编译;隐含声明了 fbuiltin 警告不正确的 main 函数声明 .
DE机群系统并行程序调试环境NNET
15
-ffreestanding-ffreestanding按独立环境编译;隐含声明了 fno-builtin 选项;对于 main 函数没有特别要求
-fno-strictprototype-fno-strictprototype对于没有参数的函数声明 , 例如 `int foo (); ‘ :按 C 风格处理 --- 即不说明参数个数或类型 . ( 仅针对 C++)正常情况下 , 这样的函数 foo 在 C++ 中意味着参数为空 .
DE机群系统并行程序调试环境NNET
16
预处理器选项(Preprocessor Option)
DE机群系统并行程序调试环境NNET
17
-include file-include file在处理常规输入文件之前 , 首先处理文件 file结果是 , 文件 file 的内容先得到编译;命令行上任何 `-D‘ 和 `-U’ 选项永远在 `-include file‘ 之前处理 , 无论他们在命令行上的顺序如何 .`-include' 和 `-imacros' 选项按书写顺序处理
-undef-undef不要预定义任何非标准宏;包括系统结构标志
DE机群系统并行程序调试环境NNET
18
汇编器选项(Assembler Option)
DE机群系统并行程序调试环境NNET
19
-Wa,option-Wa,option
把选项 option 传递给汇编器
如果 option 含有逗号 , 就在逗号处分割成多个选项
DE机群系统并行程序调试环境NNET
20
连接器选项(Linker Option)
DE机群系统并行程序调试环境NNET
21
-l-llibrarylibrary连接名为 library 的库文件;连接器在标准搜索目录中寻找名字为 `liblibrary.a‘ 的库文件;搜索目录除了一些系统标准目录外 , 还包括用户以 `-L‘ 选项指定的路径; 一般说来用这个方法找到的文件是库文件组成的归档文件(archive file) ;连接器处理归档文件的 方法是 :扫描归档文件 ,寻找某些成员 ,这些成员的符号目前已被引用 , 不过还没有被定义 . 但是 , 如果连接器找到普通的目标文件 , 而不是库文件 , 就把这个目标文件按平常方式连接进来;指定 `-l‘ 选项和指定文件名的唯一区别是 , `-l 选项用 `lib’ 和 `.a‘ 把 library 包裹起来 , 而且搜索一些目录;-lobjc 这个 -l 选项的特殊形式用于连接 Objective C 程序;-Ldir 在 `-l' 选项的搜索路径列表中添加 dir 目录
DE机群系统并行程序调试环境NNET
22
GNUGNU 库(共享 库(共享 && 静态)静态)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 命令);静态库是指编译连接时,把库文件的代码全部加入到可执行文件中,所以生成的文件较大,但运行时,就不再需要库文件了。动态库正好相反,在编译连接时,没有把库文件的代码加入到可执行文件中,所以生成的文件较小,但运行时,仍需要加载库文件
DE机群系统并行程序调试环境NNET
23
常用库文件常用库文件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
DE机群系统并行程序调试环境NNET
24
-static-static在支持动态连接 (dynamic linking) 的系统上 ,阻止连接共享库;
该选项在其他系统上无效
-Wl,option-Wl,option把选项 option 传递给连接器;
如果 option 中含有逗号 , 就在逗号处分割成多个选项
DE机群系统并行程序调试环境NNET
25
目录选项(Directory Option)
指定搜索路径 , 用于查找头文件 ,库文件 , 或编译器的某些成员
DE机群系统并行程序调试环境NNET
26
-Idir-Idir
在头文件’ #include<file>’ 或者’ #include”file”’ 的搜索路径列表中添加 dir 目录;任何在 `-I-‘ 前面用 `-I’ 选项指定的搜索路径只适用于 `#include “file”‘ 这种情况 ; 他们不能用来搜索 `#include <file>’ 包含的头文件; 如果用 `-I' 选项指定的搜索路径位于 `-I-' 选项后面 , 就可以在这些路径中搜索所有的 `#include' 指令 . ( 一般说来 -I 选项就是这么用的 .) `-I-‘ 选项能够阻止当前目录 (存放当前输入文件的地方 ) 成为搜索 `#include “file”’ 的第一选择; `-I-' 不影响使用系统标准目录 , 因此 , `-I-' 和 `-nostdinc' 是不同的选项 .
DE机群系统并行程序调试环境NNET
27
-Bprefix-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' 选项 , 然后才尝试环境变量值 . .
DE机群系统并行程序调试环境NNET
28
警告选项警告选项(WARNING OPTION) (WARNING OPTION)
针对程序结构的诊断信息 , 程序不一定有错误 , 而是存在风险 , 或者可能存在错误
DE机群系统并行程序调试环境NNET
29
-fsyntax-only 检查程序中的语法错误 , 但是不产生输出信息;-w 禁止所有警告信息;-Wimplicit-int 警告没有指定类型的声明;-Wuninitialized 在初始化之前就使用自动变量;-Wno-import 禁止所有关于 #import 的警告信息;-W 对下列事件显示额外的警告信息 :
非易变自动变量 (nonvolatile automatic variable) 可能在调用longjmp 时发生改变 .
既可以返回值 ,也可以不返回值的函数 . ( 缺少结尾的函数体被看作不返回函数值 )
表达式语句或逗号表达式的左侧没有产生作用 (side effect).如果要防止这种警告 , 应该把未使用的表达式强制转换 为void 类型 .
无符号数用 `>' 或 `<=' 和零做比较
DE机群系统并行程序调试环境NNET
30
调试选项调试选项(DEBUGGING OPTION)(DEBUGGING OPTION)
这些选项控制多种优化措施
DE机群系统并行程序调试环境NNET
31
-O-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 选项 , 不管带不带数字 , 最后一个选项才是生效的选项 .
DE机群系统并行程序调试环境NNET
32
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).
DE机群系统并行程序调试环境NNET
33
如何写如何写 makefilemakefile
或许很多 Windows 的程序员都不知道makefile 这个东西,因为那些 Windows 的 IDE ( Integrated Development Environment ,集成开发环境)都为你做了这个工作,但要成为一个好的、 professional 的程序员, makefile 还是必须要了解的。
DE机群系统并行程序调试环境NNET
34
什么是什么是 MakefileMakefileMakefile 定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作;Makefile 就像一个 Shell脚本一样,其中也可以执行操作系统的命令; make 是一个命令工具,是一个解释Makefile 文件中指令的命令工具,一般来说,大多数的 IDE都有这个命令;makefile带来的好处就是——“自动化编译”,一旦写好Makefile ,只需要一个 make 命令,整个工程完全自动编译
DE机群系统并行程序调试环境NNET
35
configureconfigure
系统配置程序 configure 的作用1. 接受用户的安装参数和选项 ;设置系统缺省
配置2. 处理配置参数
建立目标系统后端文件与逻辑文件名之间的链接,使编译系统能正确地在目标平台上生成
在模板文件 Makefile.in 中插入和修改与配置参数有关的信息,生成目标平台上的 Makefile 文件
生成 config.status 文件,记录本次安装的配置信息
DE机群系统并行程序调试环境NNET
36
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.omain.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
Makefile 的简单例子
通常的格式为 target : requisitive
command从 8 个 c 源文件和 3 个头文件编译连接为目标文件 edit
一般来说,默认的操作都放最开头( edit ),也就是说,输入“make” 默认为“make edit” ;而正常把“ clean”放在最前面。
某些时候可能还有“makeinstall”
DE机群系统并行程序调试环境NNET
37
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)
如何简化前面的例子如何简化前面的例子(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) $(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 $<
DE机群系统并行程序调试环境NNET
38
MakefileMakefile 里有什么? 里有什么? Makefile 里主要包含了五个东西:
显式规则:要生成的文件,文件的依赖文件,生成的命令 隐晦规则:自动推导目标文件和依赖文件名的关系变量定义:运行 make 时,变量都会被扩展到相应的引用位置上文件指示: (1) 在一个 Makefile 中引用另一个 Makefile ,与 c 语言中的 #include 一样,使用“ include foo.make” 这种方式(如果是“ -include foo.make”,则表示忽略 foo.make 中的错误); (2) 根据某些情况指定 Makefile 中的有效部分,就像 C 语言中的预编译 #if 一样; (3) 定义一个多行的命令注释: #
Makefile 中的命令,必须要以 [Tab] 键开始
DE机群系统并行程序调试环境NNET
39
MakefileMakefile 的文件名的文件名
Makefile 的一般命名规则为:常规命名顺序: GNUmakefile 〉 makefile 〉 Makefile
特定名称: Makefile.linux
make –f Make.linux
make –file Make.linux
Makefile 最常用,一方面因为显目,另一方面符合大多数人的习惯
DE机群系统并行程序调试环境NNET
40
makemake 的工作方式的工作方式
读入所有的 Makefile ; 读入被 include 的其它 Makefile ; 初始化文件中的变量; 推导隐晦规则,并分析所有规则; 为所有的目标文件创建依赖关系链; 根据依赖关系,决定哪些目标要重新生成; 执行生成命令。
DE机群系统并行程序调试环境NNET
41
使用过渡文件使用过渡文件 .d.d 生成生成 MakefileMakefile %.d: %.c @set -e; rm -f $@; \ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \ sed 's/\($*\)\.o[ :]*/\1.o $@ :/g' < $@.$$$$ > $@; \ rm -f $@.$$$$
规则的意思是,所有的 [.d] 文件依赖于 [.c] 文件a) 第一行“ rm -f $@” 的意思是删除所有的目标,也就是 [.d] 文件;b) 第二行的意思是,为每个依赖文件“ $<” ,也就是 [.c] 文件生成依
赖文件;c) “$@” 表示模式“%.d” 文件,如果有一个 C 文件是 name.c ,那么“%” 就是“ name” ;
d) “$$$$”意为一个随机编号,第二行生成的文件有可能是“ name.d.12345” ;
e) 第三行使用 sed 命令做了一个替换;f) 第四行就是删除临时文件。
这个模式要做的事把依赖关系:main.o : main.c defs.h转成: main.o main.d : main.c defs.h
DE机群系统并行程序调试环境NNET
42
MakefileMakefile 的书写规则的书写规则
Makefile 文件中的命令必须以 \t ( TABLE 键)开头; make 的命令默认是被“ /bin/sh”——UNIX 的标准
Shell解释执行的。除非你特别指定一个其它的 Shell ; 对于 @echo 正在编译 XXX模块 ...... ,运行 make 将
不显示” echo正在编译 XXX模块 ......”, 而只是显示这一行命令的运行结果“正在编译 XXX模块 ......” ;
需要注意的是,如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。
exec: cd /home/hchen; pwd
DE机群系统并行程序调试环境NNET
43
使用条件判断使用条件判断 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
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)
除了 ifeq(‘’,’’) 外,还有 ifneq 、 ifdef 和 ifneq
DE机群系统并行程序调试环境NNET
44
自动化变量 自动化变量 $@ 表示规则中的目标文件集。在模式规则中,如果有多个目标,那么, "$@" 就是匹配于目标中模式定义的集合。$% 仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是 "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" 。:
DE机群系统并行程序调试环境NNET
45
$(@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)" 分别表示被更新的依赖文件的目录部分和文件部分。
DE机群系统并行程序调试环境NNET
46
用 用 gdb gdb 调试 调试 GCC GCC 程序 程序 在 shell终端输入“ gdb” :,前提是在编译时必须加
入 -gkill 终止正在调试的程序list 列出产生执行文件的源代码的一部分next 执行一行源代码但不进入函数内部step 执行一行源代码而且进入函数内部run 执行当前被调试的程序quit 终止 gdbwatch 使你能监视一个变量的值而不管它何时被改变print 显示表达式的值break 26 在代码 26 行设置断点 , 这将使程序执行到这里时被挂起make 使你能不退出 gdb 就可以重新产生可执行文件shell 使你能不离开 gdb 就执行 UNIX shell 命令