标签:
编译:把高级语言书写的代码转换为机器可识别的机器指令。编译高级语言后生成的指令虽然可被机器识别,但是还不能被执行。编译时,编译器检查高级语言的语法、函数与变量的声明是否正确。只有所有的语法正确、相关变量定义正确编译器就可以编译出中间目标文件。通常,一个高级语言的源文件都可对应一个目标文件。目标文件在Linux中默认后缀为“.o”(如“foo.c”的目标文件为“foo.o”)。
为了和规则的目标文件相区别。本文将编译高级语言后生成的目标文件成为.o文件。
链接:将多.o文件,或者.o文件和库文件链接成为可被操作系统执行的可执行程序(Linux环境下,可执行文件的格式为“ELF”格式)。链接器不检查函数所在的源文件,只检查所有.o文件中的定义的符号。将.o文件中使用的函数和其它.o或者库文件中的相关符号进行合并,对所有文件中的符号进行重新安排(重定位),并链接系统相关文件(程序启动文件等)最终生成可执行程序。链接过程使用GNU 的“ld”工具。
静态库:又称为文档文件(Archive File)。它是多个.o文件的集合。Linux中静态库文件的后缀为“.a”。静态库中的各个成员(.o文件)没有特殊的存在格式,仅仅是一个.o文件的集合。使用“ar”工具维护和管理静态库。
共享库:也是多个.o文件的集合,但是这些.o文件时有编译器按照一种特殊的方式生成(Linux中,共享库文件格式通常为“ELF”格式。共享库已经具备了可执行条件)。模块中各个成员的地址(变量引用和函数调用)都是相对地址。使用此共享库的程序在运行时,共享库被动态加载到内存并和主程序在内存中进行连接。多个可执行程序可共享库文件的代码段(多个程序可以共享的使用库中的某一个模块,共享代码,不共享数据)。另外共享库的成员对象可被执行(由libdl.so提供支持)。
参考 info ld了解更加详细的关于ld的说明和用法。
² 显式规则:它描述了在何种情况下如何更新一个或者多个被称为目标的文件(Makefile的目标文件)。书写Makefile时需要明确地给出目标文件、目标的依赖文件列表以及更新目标文件所需要的命令(有些规则没有命令,这样的规则只是纯粹的描述了文件之间的依赖关系)。
² 隐含规则:它是make根据一类目标文件(典型的是根据文件名的后缀)而自动推导出来的规则。make根据目标文件的名,自动产生目标的依赖文件并使用默认的命令来对目标进行更新(建立一个规则)。
² 变量定义:使用一个字符或字符串代表一段文本串,当定义了一个变量以后,Makefile后续在需要使用此文本串的地方,通过引用这个变量来实现对文本串的使用。第一章的例子中,我们就定义了一个变量“objects”来表示一个.o文件列表。
² Makefile指示符:指示符指明在make程序读取makefile文件过程中所要执行的一个动作。其中包括:
² 注释:Makefile中“#”字符后的内容被作为是注释内容(和shell脚本一样)处理。如果此行的第一个非空字符为“#”,那么此行为注释行。注释行的结尾如果存在反斜线(\),那么下一行也被作为注释行。一般在书写Makefile时推荐将注释作为一个独立的行,而不要和Makefile的有效行放在一行中书写。当在Makefile中需要使用字符“#”时,可以使用反斜线加“#”(\#)来实现(对特殊字符“#”的转义),其表示将“#”作为一字符而不是注释的开始标志。
GUN make的执行过程分为两个阶段。
第一阶段:读取所有的makefile文件(包括“MAKIFILES”变量指定的、指示符“include”指定的、以及命令行选项“-f(--file)”指定的makefile文件),内建所有的变量、明确规则和隐含规则,并建立所有目标和依赖之间的依赖关系结构链表。
在第二阶段:根据第一阶段已经建立的依赖关系结构链表决定哪些目标需要更新,并使用对应的规则来重建这些目标。
理解make执行过程的两个阶段是很重要的。它能帮助我们更深入的了解执行过程中变量以及函数是如何被展开的。变量和函数的展开问题是书写Makefile时容易犯错和引起大家迷惑的地方之一。本节将对这些不同的结构的展开阶段进行简单的总结(明确变量和函数的展开阶段,对正确的使用变量非常有帮助)。首先,明确以下基本的概念;在make执行的第一阶段中如果变量和函数被展开,那么称此展开是“立即”的,此时所有的变量和函数被展开在需要构建的结构链表的对应规则中(此规则在建立链表是需要使用)。其他的展开称之为“延后”的。这些变量和函数不会被“立即”展开,而是直到后续某些规则须要使用时或者在make处理的第二阶段它们才会被展开。
可能现在讲述的这些还不能完全理解。不过没有关系,通过后续章节内容的学习,我们会一步一步的熟悉make的执行过程。学习过程中可以回过头来参考本节的内容。相信在看完本书之后,会对make的整个过程有全面深入的理解
“所有模式匹配规则”
#sample GNUmakefile
foo:
frobnicate > foo
%: force
@$(MAKE) -f Makefile $@
force: ;
变量定义解析的规则如下:
IMMEDIATE = DEFERRED
IMMEDIATE ?= DEFERRED
IMMEDIATE := IMMEDIATE
IMMEDIATE += DEFERRED or IMMEDIATE
define IMMEDIATE
DEFERRED
Endef
当变量使用追加符(+=)时,如果此前这个变量是一个简单变量(使用 :=定义的)则认为它是立即展开的,其它情况时都被认为是“延后”展开的变量。
终极目标的确认:
1、除以点号“.”开始的第一个规则中的第一个目标
2、如果Makefile的第一个规则有多个目标,那么默认的终极目标是多个目标中的第一个。
3、模式规则的目标。目标所在的规则是Makefile的第一个规则时,它们并不会被作为“终极目标”。
4、可以通过命令行将一个Makefile中的目标指定为此次make过程的终极目标,如:make clean
甚至可以指定一个在Makefile中不存在的目标作为终极目标
“order-only”依赖的使用举例:
LIBS = libtest.a
foo : foo.c | $(LIBS)
$(CC) $(CFLAGS) $< -o $@ $(LIBS)
make在执行这个规则时,如果目标文件“foo”已经存在。当“foo.c”被修改以后,目标“foo”将会被重建,但是当“libtest.a”被修改以后。将不执行规则的命令来重建目标“foo”。
通配符使用举例:
print: *.c
lpr -p $?
touch print
通配符缺陷:
objects = *.o
foo : $(objects)
cc -o foo $(CFLAGS) $(objects)
目录搜索:
1、一般目录搜索:VPATH
定义变量“VPATH”时,使用空格或者冒号(:)将多个需要搜索的目录分开
VPATH = src:../headers
2、选择性目录搜索
1、vpath PATTERN DIRECTORIES
为所有符合模式“PATTERN”的文件指定搜索目录“DIRECTORIES”。多个目录使用空格或者冒号(:)分开。类似上一小节的“VPATH”变量。
2、vpath PATTERN
清除之前为符合模式“PATTERN”的文件设置的搜索路径。
3、vpath
清除所有已被设置的文件搜索路径。
举例:
vpath %.h ../headers
vpath %.c foo
vpath % blish
vpath %.c bar
库文件和搜索目录:-lNAME
1. make在执行规则时会在当前目录下搜索一个名字为“libNAME.so”的文件;
2. 如果当前工作目录下不存在这样一个文件,则make会继续搜索使用“VPATH”或者“vpath”指定的搜索目录。
3. 还是不存在,make将搜索系统库文件存在的默认目录,顺序是:“/lib”、“/usr/lib”
伪目标:永远会被执行的目标
1、Makefile中定义的只执行命令的目标,如果工作目录下有一个同名的实际文件,则此目标永远不会执行。
2. 提高执行make时的效率
以将一个较长行使用反斜线(\)来分解为多行,这样可以使我们的Makefile书写清晰、容易阅读理解。但需要注意:反斜线之后不能有空格
模式规则:
模式规则类似于普通规则。只是在模式规则中,目标名中需要包含有模式字符“%”(一个)。要注意的是:模式字符“%”的匹配和替换发生在规则中所有变量和函数引用展开之后,变量和函数的展开一般发生在make读取Makefile时
因此,一个模式规则的格式为:
%.o : %.c ; COMMAND... //这个模式规则指定了如何由文件“N.c”来创建文件“N.o”,
%.o : debug.h //表示所有的.o文件都依赖于头文件“debug.h”)。
标签:
原文地址:http://www.cnblogs.com/jiangzhaowei/p/4273160.html