linux makefile
跟我一起学习makefile
编译链接
在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即 Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)。 编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ文件)。链接时,主要是链接函数和全局变量,所以,我们可以使用这些中间目标文件(O文件或是OBJ文件)来链接我们的应用程序。链接器并不管函数所在的源文件,只管函数的中间目标文件(Object File),在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给中间目标文件打个包,在Windows下这种包叫“库文件”(Library File),也就是 .lib 文件,在UNIX下,是Archive File,也就是 .a 文件。
总结一下,源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error),在VC下,这种错误一般是:Link 2001错误,意思说是说,链接器未能找到函数的实现。你需要指定函数的Object File.
makefile的规则
1)如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。
2)如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程。
3)如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。
target … : prerequisites …
command
变量的定义和使用
target=main
objects=main.o fun.o
(objects)
gcc -o $(target) $(objects)
make自动推导
只要make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中。
edit : $(objects)
cc -o edit $(objects)
main.o : defs.h
kbd.o : defs.h command.h
头文件引用
$(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)
前面说过,.PHONY意思表示clean是一个“伪目标”,。而在rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。当然,clean的规则不要放在文件的开头,不然,这就会变成make的默认目标,相信谁也不愿意这样。不成文的规矩是——“clean从来都是放在文件的最后”。
引用其他的makefile
include foo.make *.mk $(bar)
make的工作方式
GNU的make工作时的执行步骤入下:(想来其它的make也是类似)
1、读入所有的Makefile。
2、读入被include的其它Makefile。
3、初始化文件中的变量。
4、推导隐晦规则,并分析所有规则。
5、为所有的目标文件创建依赖关系链。
6、根据依赖关系,决定哪些目标要重新生成。
7、执行生成命令。
函数
1、objects := $(wildcard *.o)
这种用法由关键字“wildcard”指出,关于Makefile的关键字,我们将在后面讨论。
2、patsubst
$(patsubst ,,
名称:模式字符串替换函数——patsubst。
功能:查找
返回:函数返回被替换过后的字符串。
自动化变量
@“就是匹配于
目标中模式定义的集合。
%“就是"bar.o”,”[email protected]“就是"foo.a”。如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。
<“将是符合模式的一系列的文件集。注意,其是一个一个取出来的。
$?
所有比目标新的依赖目标的集合。以空格分隔。
$^
所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。
^”,也是所有依赖目标的集合。只是它不去除重复的依赖目标。
“的值就是"dir/a.foo”。这个变量对于构造有关联的文件名是比较有较。如果目标中没有模式的定义,那么"“就是除了后缀的那一部分。例如:如果目标是"foo.c”,因为".c"是make所能识别的后缀名,所以,"",除非是在隐含规则或是静态模式中。如果目标中的后缀是make所不能识别的,那么"$"就是空值。
@“的目录部分(不以斜杠作为结尾),如果”(@D)“就是"dir”,而如果"[email protected]“中没有包含斜杠的话,其值就是”."(当前目录)。
@“的文件部分,如果”(@F)“就是"foo.o”,"(notdir (*D)"
“(*D)“返回"dir”,而”(%D)"
“(<D)”
“(^D)”
“(+D)”
“(?D)”
“$(?F)”
分别表示被更新的依赖文件的目录部分和文件部分。
模式的匹配
一般来说,一个目标的模式有一个有前缀或是后缀的"%",或是没有前后缀,直接就是一个"%"。因为"%“代表一个或多个字符,所以在定义好了的模式中,我们把”%“所匹配的内容叫做"茎”,例如"%.c"所匹配的文件"test.c"中"test"就是"茎"。因为在目标和依赖目标中同时有"%“时,依赖目标的"茎"会传给目标,当做目标中的"茎”。
当一个模式匹配包含有斜杠(实际也不经常包含)的文件时,那么在进行模式匹配时,目录部分会首先被移开,然后进行匹配,成功后,再把目录加回去。在进行"茎"的传递时,我们需要知道这个步骤。例如有一个模式"e%t",文件"src/eat"匹配于该模式,于是"src/a"就是其"茎",如果这个模式定义在依赖目标中,而被依赖于这个模式的目标中又有个模式"c%r",那么,目标就是"src/car"。("茎"被传递)
上一篇: CentOS源码编译安装Python3
下一篇: 搜狐开源镜像上线