Makefile 文件描述了整个工程的编译、链接等规则。其中包括:工程中的哪些源文件需要编译以及如何编译、需要创建那些库文件以及如何创建这些库文件、如何最后产生想要得可执行文件。
makefile带来的好处是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。而且在 Makefile 中可以使用系统 shell 所提供的任何命令来完成想要的工作。make是一个命令工具,是一个解释makefile中指令的命令工具。当我们输入make命令的时候,make命令会在当前目录下找寻名字是Makefile的文件。
准备知识
编译:高级语言-->机器指令。编译时,编译器检查高级语言的语法、函数与变量的声明是否正确。只有所有的语法正确、相关变量定义正确编译器就可以编译出中间目标文件。通常,一个高级语言的源文件都可对应一个目标文件。目标文件在Linux 中默认后缀为“.o”(如“foo.c”的目标文件为“foo.o”)
链接:将.o 文件和库文件链接成为可被操作系统执行的可执行程序(Linux 环境下,可执行文件的格式为“ELF”格式)。链接器不检查函数所在的源文件,只检查所有.o 文件中的定义的符号。将.o 文件中使用的函数和其它.o 或者库文件中的相关符号进行合并,对所有文件中的符号进行重新安排(重定位),并链接系统相关文件(程序启动文件等)最终生成可执行程序。链接过程使用 GNU 的“ld”工具。
静态库:又称为文档文件(Archive File)。它是多个.o 文件的集合。Linux 中静态库文件的后缀为“.a”。静态库中的各个成员(.o 文件)没有特殊的存在格式,仅仅是一个.o 文件的集合。使用“ar”工具维护和管理静态库。
共享库:也是多个.o 文件的集合,但是这些.o 文件时有编译器按照一种特殊的方式生成(Linux 中,共享库文件格式通常为“ELF”格式。共享库已经具备了可执行条件)。模块中各个成员的地址(变量引用和函数调用)都是相对地址。使用此共享库的程序在运行时,共享库被动态加载到内存并和主程序在内存中进行连接。多个可执行程序可共享库文件的代码段(多个程序可以共享的使用库中的某一个模块,共享代码,不共享数据)。另外共享库的成员对象可被执行(由 libdl.so 提供支持)
GNU make
在 shell 下执行“make”。make 会自动根据修改情况完成源文件的对应.o 文件的更新、库文件的更新、最终的可执行程序的更新。make 通过比较对应文件(规则的目标和依赖)的最后修改时间,来决定哪些文件需要更新、那些文件不需要更新。对需要更新的文件 make 就执行数据库中所记录的相应命令(在 make 读取 Makefile 以后会建立一个编译过程的描述数据库。此数据库中记录了所有各个文件之间的相互关系,以及它们的关系描述)来重建它,对于不需要重建的文件 make 什么也不做。而且可以通过make的命令行选项来指定需要重新编译的文件。
当使用 make 工具进行编译时,工程中以下几种文件在执行 make 时将会被编译(重新编译):
1. 所有的源文件没有被编译过,则对各个 C 源文件进行编译并进行链接,生成最后的可执行程序;
2. 每一个在上次执行 make 之后修改过的 C 源代码文件在本次执行 make 时将会被重新编译;
3. 头文件在上一次执行 make 之后被修改。则所有包含此头文件的 C 源文件在本次执行 make 时将会被重新编译。
一、makefile文件格式
目标:指的是生成的目标文件名称,可以意取;
依赖:生成目标所需要的文件列表;通常一个目标依赖于一个或者多个文件
命令:通过执行命令对依赖项操作生成目标(命令前必须加 Tab,四个空格将会报错 )。一个目标可以没有依赖而只有动作(指定的命令)。比如 Makefile 中的目标“clean”,此目标没有依赖,只有命令。它所定义的命令用来删除 make 过程产生的中间文件(进行清理工作)。
假设当前文件夹中有hello.c和Makefile两个文件,当我们在终端输入make指令的时候,就会自动编译出hello.o,hello.S,hello.i及目标可执行文件hello
当不想要这些不相关的文件,想对这些文件做一些操作,我们把这样的操作叫做伪目标,标志位.PHONY:
.PHONY:这是固定格式,不能变的,但是下面的clean是自己取的名字,你随便取什么名字都可以,但是clean比较直观。
二、变量
1、内置环境变量
这里的变量其实就是一个类似宏的概念,它是替换的意思,本质上就是一个字符串,字符串如果表示一个列表的话,每一个元素以空格隔开。在makefile执行的时候,会被扩展到对应的位置。
与命令相关的变量(就是这些变量可以当作命令使用):
AR 函数库打包程序。默认命令是“ar”。
AS 汇编语言编译程序。默认命令是“as”。
CC C语言编译程序。默认命令是“cc”。
CXX C++语言编译程序。默认命令是“g++”。
CPP C程序的预处理器(输出是标准输出设备)。默认命令是“$(CC) –E”。
GET 从SCCS文件中扩展文件的程序。默认命令是“get”。
RM 删除文件命令。默认命令是“rm –f”。
关于命令参数可以使用的变量:
ARFLAGS 函数库打包程序AR命令的参数。默认值是“rv”。
ASFLAGS 汇编语言编译器参数。(当明显地调用“.s”或“.S”文件时)。
CFLAGS C语言编译器参数。-g -O0
CXXFLAGS C++语言编译器参数。
COFLAGS RCS命令参数。
CPPFLAGS C预处理器参数。( C 和 Fortran 编译器也会用到)。
FFLAGS Fortran语言编译器参数。
GFLAGS SCCS “get”程序参数。
LDFLAGS 链接器参数。(如:“ld”)
LFLAGS Lex文法分析器参数。
PFLAGS Pascal语言编译器参数。
RFLAGS Ratfor 程序的Fortran 编译器参数。
YFLAGS Yacc文法分析器参数。
2.自动化变量
3、普通变量
“objects”、“OBJECTS”、“objs”、“OBJS”、“obj”或者“OBJ”:
所有的.o 文件的列表的替代,在使用到这些文件列表的地方,使用$(objects)来代替。
4.命名包变量:多行定义一个命令块
5.变量的赋值:
= 看完了所有变量,然后根据变量的最终的值,来进行赋值
6.变量的引用
(1)通过$()
(2)通过$$var
因为在makefile中 $ 的意思是引用,如果想要在命令执行的时候就打印出 $ ,那么就需要$$,就像C语言中的 \ \ 输出 \ 一样
$(var:%.c=%.o) 将var中的所有元素,如果是以 .c结尾的,则换成 .o形式,返回转换后的结果
打印变量:
①通过warning:$(warning 提示性语句 $(变量名))
②通过error:$(error 提示性语句 $(变量名))
三、语句
ifeq( a , b ) - else - endif 或 ifeq 'a' 'b' - else - endif
ifneq( a , b ) - else - endif
ifdef(a) - else - endif
ifndef(a)- else - endif
在格式上,这四个关键字书写的时候前面不能有【tab】键,要顶格书写,如果有【tab】的话,会被make解析成shell命令来执行。
四、函数
这里说的都是makefile内置函数,可以直接调用执行的。
函数调用格式如下:
$( <function> <arguments> ) 或者是 ${<function> <arguments>}
function 是函数名,arguments 是函数的参数,参数之间要用逗号分隔开。而参数和函数名之间使用空格分开。调用函数的时候要使用字符“$”,后面可以跟小括号也可以使用花括号。
1.字符串处理函数
字符串替代函数:函数功能是查找 text 中的单词是否符合模式 pattern,如果匹配的话,则用 replacement 替换。返回值为替换后的新字符串。
$(patsubst<pattern>,<replacement>,<text>)
例: $(subst <from>,<to>,<text>)
函数说明:函数的功能是把字符串中的 form 替换成 to,返回值为替换后的新字符串。
对于上面这俩函数,可以看到都有substitute string,即替代字符串,不同的是,有一个加了pattern ,也就是上一个函数可以使用通配符匹配,比较高端。
去空格函数:函数的功能是去掉字符串的开头和结尾的字符串,并且将其中的多个连续的空格合并成为一个空格。返回值为去掉空格后的字符串。
$(strip<string>)
查找字符串函数:函数的功能是查找 in 中的 find ,如果我们查找的目标字符串存在。返回值为目标字符串,如果不存在就返回空。
$(findstring<find>,<in>)
过滤函数:函数的功能是过滤出 text 中符合模式 pattern 的字符串,可以有多个 pattern (用空格隔开)。返回值为滤到的字符串。
$(filter<pattern>,<text>)
反过滤函数:函数的功能是功能和 filter 函数正好相反,但是用法相同。去除符合模式 pattern 的字符串,保留符合的字符串。返回值是保留的字符串。
$(filter-out <pattern>,<text>)
排序函数:函数的功能是将 <list> 中的单词按首字母排序(升序)。返回值为排列后的字符串。【注:sort会去除重复的字符串】
$(sort <list>)
去单词函数:函数的功能是取出函数 <text> 中的第n个单词。返回值为我们取出的第 n 个单词
$(word <n>,<text>)
2.文件名操作函数
取目录函数:函数的功能是从文件名序列 names 中取出目录部分,如果 names 中没有 “/” ,取出的值为 “./” 。返回值为目录部分,指的是最后一个反斜杠之前的部分。如果没有反斜杠将返回“./”。
$(dir <names>)
取文件函数:函数的功能是从文件名序列 names 中取出非目录的部分。非目录的部分是最后一个反斜杠之后的部分。返回值为文件非目录的部分。
$(notdir<names>)
取后缀名函数:函数的功能是从文件名序列中 names 中取出各个文件的后缀名。返回值为文件名序列 names 中的后缀序列,如果文件没有后缀名,则返回空字符串。
$(suffix<names>)
取前缀函数:函数的功能是从文件名序列 names 中取出各个文件名的前缀部分。返回值为被取出来的文件的前缀名,如果文件没有前缀名则返回空的字符串。
$(basename<names>)
添加后缀名函数:函数的功能是把后缀 suffix 加到 names 中的每个单词后面。返回值为添加上后缀的文件名序列
$(addsuffix<suffix>,<names>)
添加前缀名函数:函数的功能是把前缀 prefix 加到 names 中的每个单词的前面。返回值为添加上前缀的文件名序列。
$(addprefix <prefix>,<names>)
链接函数:函数功能是把 list2 中的单词对应的拼接到 list1 的后面。如果 list1 的单词要比 list2的多,那么,list1 中多出来的单词将保持原样,如果 list1 中的单词要比 list2 中的单词少,那么 list2 中多出来的单词将保持原样。返回值为拼接好的字符串。
$(join <list1>,<list2>)
获取匹配模式文件名函数:函数的功能是列出当前目录下所有符合模式的 PATTERN 格式的文件名。返回值为空格分隔并且存在当前目录下的所有符合模式 PATTERN 的文件名。
$(wildcard PATTERN)
真正的makefile其实很少涉及到具体的名字啥的,一般都是从wildcard入手,获取当前目录下的文件,然后再用其他的文件名操作函数,可以看到,上面的8个函数,说是文件名操作函数,其实就是本质上处理字符串而已,只有wildcard函数是真正的去当前目录下去获取当前目录下符合pattern的文件名。
3.其他常用函数
foreach函数:把参数<list>中的单词逐一取出放到参数 <var> 所指定的变量中,然后再执行<text>所包含的表达式。每一次 <text> 会返回一个字符串,循环过程中,<text> 所返回的每个字符串会以空格分割,最后当整个循环结束的时候,<text> 所返回的每个字符串所组成的整个字符串(以空格分隔)将会是 foreach 函数的返回值。所以<var>最好是一个变量名,<list> 可以是一个表达式,而<text>中一般会只用 <var>这个参数来一次枚举<list>中的单词。【注意:这里的var是一个局部变量,函数结束之后,var变量会消失】
$(foreach <var>,<list>,<text>)
if函数:if 函数可以包含else部分,或者是不包含,即if函数的参数可以是两个,也可以是三个。
$(if <condition>,<then-part>)或(if<condition>,<then-part>,<else-part>)
call函数:call 函数是唯一 一个可以调用参数化表达式的函数。我们可以用来写一个非常复杂的表达式,这个表达式中,我们可以定义很多的参数,然后你可以用 call 函数来向这个表达式传递参数。当 make 执行这个函数的时候,expression参数中的变量$(1)、$(2)、$(3)等,会被参数parm1,parm2,parm3依次取代。而expression的返回值就是 call 函数的返回值。
$(call <expression>,<parm1>,<parm2>,<parm3>,...)
origin函数:origin 函数不像其他的函数,它并不操作变量的值,它只是告诉你这个变量是哪里来的。【注意: variable 是变量的名字,不应该是引用,所以最好不要在 variable 中使用“$”字符。origin 函数会员其返回值来告诉你这个变量的“出生情况”。】
$(origin <variable>)
shell函数:shell函数把执行操作系统命令后的输出作为函数返回。
$(shell <command>)
注意: 这个函数会新生成一个Shell程序来执行命令,所以你要注意其运行性能,如果你的Makefile中有一些比较复杂的规则,并大量使用了这个函数,那么对于你的系统性能是有害的。特别是Makefile的隐晦的规则可能会让你的shell函数执行的次数比你想像的多得多。
五、通配符 * %
*是去系统中匹配,%是仅在makefile中匹配的:
凡是要到系统中去匹配的,就得用 * ;%通配符仅限在makefile文件中用来匹配规则而已,也就是%匹配的东西(可以看成字符串)在makefile(可以看成普通文档)中是可以找到的,而 * 匹配的东西,就需要跳出makefile去系统中匹配对应的文件之类的东西。
1.在shell命令中可以使用*,因为shell命令是连接系统的,shell中使用*,就是匹配系统中的文件
2.在依赖的时候可以使用*,如:
因为,test,作为target,需要找它的依赖,这个找依赖的过程,makefile是做不到的,makefile只能说去决定如何编译依赖,找依赖,需要到系统中去找,所以需要用*。
3.如果依赖存在,那么在makefile中决定如何编译依赖,就可以使用%通配符
这时候,我们已经人为规定了test需要这两个依赖,但是这两个依赖,如何编译,需要在makefile中进行寻找,所以就需要%通配符,来匹配下面的规则。
4.在wildcard中使用*,因为wildcard需要连接系统,获取当前目录下的文件名字,所以需要使用shell中的通配符*
六、源文件搜索路径
源文件搜索路径,是我们在编译的时候,如果工程量巨大,源文件不都在当前目录下,存放于其他目录下,那么VPATH或者vpath就派上了用场,用来指定找寻不在当前目录下的源文件的目录。
VPATH 和 vpath 的区别:VPATH 是变量,更具体的说是环境变量,Makefile 中的一种特殊变量,使用时需要指定文件的路径;vpath 是关键字,按照模式搜索,也可以说成是选择搜索。搜索的时候不仅需要加上文件的路径,还需要加上相应限制的条件。
通俗点说,就是VPATH是一个不具有筛选条件的指定路径方法,如果缺失了一个文件,makefile会去VPATH中的所有目录中挨个寻找对比,效率低。而vpath带了模式搜索,可以选择性的指定哪种类型的文件去哪个目录下寻找,比较方便。
注意:无论定义了多少路径,make 执行的时候会先搜索当前路径下的文件,当前目录下没有我们要找的文件,才去 VPATH 的路径中去寻找。如果当前目录下有我们要使用的文件,那么 make 就会使用我们当前目录下的文件。
七、包含makefile文件include
include就相当于C语言中的#include,当make读取到当前makefile中的include关键字的时候,会暂停读取当前的makefile,进而转去读取include中包含的makefile文件,读取包含的makefile文件之后,再回来继续读取当前的makefile文件。
注意:“include” 关键字所在的行首可以包含一个或者是多个的空格(读取的时候空格会被自动的忽略),但是不能使用 Tab 开始,否则会把 “include” 当作式命令来处理。包含的多个文件之间要使用空格分隔开。使用 “include” 包含进来的 Makefile 文件中,如果存在函数或者是变量的引用,它们会在包含的 Makefile 中展开。
说白了,就是原封不动的将被包含的makefile文件展开在当前makefile文件中包含被包含文件的位置。
八、调用其他makefile
当生成target目标对象时,会执行$(MAKE) -C $(SUBDIR)这条命令,进入目录SUBDIR,该目录下有一个Makefile,并执行。其中,$(MAKE) 指make预定义的变量,一般指的就是make,无需修改,可通过make -p查看make所有的预定义的变量。当然,也可直接指明为make,即make -C $(SUBDIR)。其中-C表示改变当前目录,make的命令选项可通过make -h查看。(make维护了一个变量CURDIR,代表make的工作目录,当使用-C选项修改工作目录的时候,此变量会被重新赋值)
注意: 当Makefile内嵌shell脚本时,Makefile中每一行的shell脚本需要一个shell进程来执行,不同行之间变量值不能传递。所以,Makefile中的shell不管多长也要写在一行。因此,多行的shell需要在Makefile使用反斜杠“\”连接为一行。此时,shell脚本中的一条语句后需要添加分号分隔。
注意: Makefile中对一些简单变量的引用,可以不使用”()”和”{}”来标记变量名,而直接使用$x的格式来实现,此种用法仅限于变量名为单字符的情况。另外自动化变量也使用这种格式。对于一般多字符变量的引用必须使用括号,否则make将把变量名的首字母作为作为变量而不是整个字符串($PATH在Makefile中实际上是$(P)ATH)。
1.变量传递
makefile中的变量传递,当makefile嵌套执行的时候,可以使用:
将指定变量传递给下层makefile,如果不需要传了,可以使用:
九、伪目标
所谓的伪目标可以这样来理解,它并不会创建目标文件,只是想去执行这个目标下面的命令。伪目标的存在可以帮助我们找到命令并执行。
先来看下面指令:
规则中 rm 命令不是创建target目标 clean 的命令,而是执行删除任务,删除当前目录下的所有的 .o 结尾和文件名为 ftp的文件。当工作目录下不存在以 clean 为名字的文件时,在 shell 中输入 make clean 命令,命令 rm 总会被执行 ,这也是我们期望的结果。
如果当前目录下存在文件名为 clean 的文件时情况就会不一样了,当我们在 shell 中执行命令 make clean,由于这个规则没有依赖文件,所以目标被认为是最新的而不去执行规则所定义的命令,因此命令 rm 将不会被执行。
将一个目标声明称伪目标的方法是将它作为特殊的目标.PHONY的依赖:
这样 clean 就被声明成一个伪目标,无论当前目录下是否存在 clean 这个文件,当我们执行 make clean 后 rm 都会被执行。而且当一个目标被声明为伪目标之后,make 在执行此规则时不会去试图去查找隐含的关系去创建它。这样同样提高了 make 的执行效率,同时也不用担心目标和文件名重名而使我们的编译失败。
十、隐含规则
隐含规则简要理解就是:正常的规则是三要素一个都不能少,就是目标、依赖、命令一个都少不了,如果少了,就不能正确运行,但是由于隐含规则的存在,可以自动补全,自动利用隐含规则推导,补充上缺失的部分。
注:隐含条件只能省略中间目标文件重建的命令和规则,但是最终目标的命令和规则不能省略。
可以联想到,如果没有显式指出命令的话,会推导命令,但是命令就真的凭空产生吗?不是的,还记得说变量的时候,第一个就说的是默认得隐含变量,这些推到出来的就会用这些默认变量来生成命令。
隐含规则的具体的工作流程:make 执行过程中遇到没有提供显式规则的中间目标文件,则根据其后缀 .o 找到隐含规则,隐含规则提供了此中间目标的基本依赖关系。确定中间目标的依赖文件和重建中间目标需要使用的命令行。隐含规则所提供的依赖文件只是一个基本的依赖关系(在C语言中,通常他们之间的对应关系是:test.o 对应的是 test.c 文件)。如果需要增加其他的自定义的文件作为依赖,则需要 在Makefile 中使用没有命令行的规则给出。
十一、其他技巧
1.不输出回显指令:@
2.定义string类型为空:先定义一个空变量,然后后面采用“#”注释符来表示变量定义的终止,这样,我们可以定义出其值是一个空格的变量。
注释符”#“才是一个变量定义的结束。如果注释符之前有空格的话,那些空格也会算到所定义的变量之中。
扩展 SQL
一、扩展的构建基础设施
PGXS构建基础设施:简单的扩展模块能够在一个已经安装的服务器上简单地编译。PGXS主要是为了包括 C 代码的扩展而设计,不过它也能用于纯 SQL 的扩展。注意PGXS并不想成为一种用于构建任何与PostgreSQL交互的软件的通用构建系统框架。它只是简单地把简单服务器扩展模块的公共构建规则自动化。对于更复杂的包,你可能需要编写你自己的构建系统。
要把PGXS基础设施用于扩展,必须编写一个简单的 makefile。在这个 makefile 中,你需要设置一些变量并且把它们包括在全局的PGXS makefile 中。
设置这三个变量之一来指定要构建什么:
1.MODULES:要从源文件构建的具有相同词干的共享库对象的列表(不要在这个列表中包括库后缀)
2.MODULE_big:一个要从多个源文件中构建的共享库(在OBJS中列出对象文件)
3.PROGRAM:一个要构建的可执行程序(在OBJS中列出对象文件)
还可以设置以下变量:
EXTENSION:扩展名称;你必须为每一个名称提供一个extension.control文件,它将被安装到prefix/share/extension中
MODULEDIR:subdirectory of prefix/share的子目录,DATA 和 DOCS 文件会被安装到其中(如果没有设置,设置了EXTENSION时默认为extension,没有设置EXTENSION时默认为contrib)
DATA:要安装到prefix/share/$MODULEDIR中的随机文件
DATA_built:要安装到prefix/share/$MODULEDIR中的随机文件,它们需要先被构建
DATA_TSEARCH:要安装到prefix/share/tsearch_data中的随机文件
DOCS:要安装到prefix/doc/$MODULEDIR中的随机文件
HEADERS:要(构建并且)安装在prefix/include/server/$MODULEDIR/$MODULE_big下面的文件
HEADERS_built:和DATA_built不同,HEADERS_built中的文件不会被clean目标移除,如果想要移除它们,把它们也加入到EXTRA_CLEAN或者增加自己的规则来做这件事。
HEADERS_$MODULE:要安装(如果指定了构建则在构建之后安装)在prefix/include/server/$MODULEDIR/$MODULE之下的文件,这里$MODULE必须是一个在MODULES or MODULE_big中用到的模块名。
HEADERS_built_$MODULE:和DATA_built不同,HEADERS_built_$MODULE中的文件不会被clean目标移除,如果想要移除它们,把它们也加入到EXTRA_CLEAN或者增加自己的规则来做这件事。可以为同一个模块同时使用这两个变量或者两者的任意组合,除非你在MODULES列表中有两个模块名称仅有前缀built_上的区别,因为那样会导致歧义。在那种情况下(还好不太可能),应该仅使用HEADERS_built_$MODULE变量。
SCRIPTS:要安装到prefix/bin中的脚本文件(非二进制)
SCRIPTS_built:要安装到prefix/bin中的脚本文件(非二进制),它们需要先被构建
REGRESS:回归测试案例(不带后缀)的列表,见下文
REGRESS_OPTS:要传递给pg_regress的附加开关
ISOLATION:隔离测试用例列表,请参阅下文了解更多详细信息。
ISOLATION_OPTS:要传递给pg_isolation_regress的附加开关
TAP_TESTS:是否需要运行 TAP 测试的开关定义,请参阅下文
NO_INSTALLCHECK:不定义installcheck目标,如果测试要求特殊的配置就会很有用,或者不使用pg_regress
EXTRA_CLEAN:要在make clean中移除的额外文件
PG_CPPFLAGS:将被加到CPPFLAGS前面
PG_CFLAGS:将被加到CFLAGS后面
PG_CXXFLAGS:将被加到CXXFLAGS后面
PG_LDFLAGS:将被加到LDFLAGS前面
PG_LIBS:将被加到PROGRAM链接行
SHLIB_LINK:将被加到MODULE_big链接行
PG_CONFIG:要在其中构建的PostgreSQL安装的pg_config程序的路径(通常只用在你的PATH中的第一个pg_config)
把这个 makefile 作为Makefile放在保存你扩展的目录中。然后你可以执行make进行编译,并且接着make install来安装你的模块。默认情况下,该模块会为在你的PATH中找到的第一个pg_config程序所对应的PostgreSQL安装编译和安装。你可以通过在 makefile 中或者make命令行中设置PG_CONFIG指向另一个pg_config程序来使用一个不同的安装。
如果你想保持编译目录独立,你也可以在你的扩展所属的源代码树之外的目录中运行 make。 这个过程也被称为一个 VPATH 编译。下面是做法:
cd build_dir
make -f /path/to/extension/source/tree/Makefile
make -f /path/to/extension/source/tree/Makefile install
此外,你可以以对核心代码所作的方式一样为 VPATH 设置一个目录。一种方式是使用核心脚本 config/prep_buildtree。一旦这样做,你可以这样设置 make变量VPATH:
make VPATH=/path/to/extension/source/tree
make VPATH=/path/to/extension/source/tree install
这个过程可以在很多种目录布局下工作。
列举在REGRESS变量中的脚本会被用来对你的扩展进行回归测试,回归测试可以在做完make install之后用make installcheck调用。要让这能够工作,你必须已经有一个运行着的PostgreSQL服务器。列举在REGRESS中的脚本文件必须在你扩展目录的名为sql/的子目录中出现。这些文件必须带有扩展.sql,但扩展不能被包括在 makefile 的REGRESS列表中。对每一个测试还应该在名为expected/的子目录中有一个包含预期输出的文件,它具有和脚本文件相同的词干并带有扩展.out。make installcheck会用psql执行每一个测试脚本,并且将得到结果输出与相应的预期输出比较。任何区别都将以diff -c格式写入到文件regression.diffs中。注意尝试运行一个不带预期文件的测试将被报告为“故障”,因此确保你拥有所有的预期文件。
ISOLATION变量中列出的脚本用于测试强调与模块并发会话的行为,可以在make install之后通过make installcheck 调用。 要实现这个工作,你必须有一个正在运行的PostgreSQL服务器。 ISOLATION中列出的脚本文件必须显示在扩展名目录中名为 specs/的子目录中。 这些文件必须具备扩展名.spec,并且不得包含在 makefile 中的ISOLATION列表中。 对于每个测试,在名为expected/的子目录中还应该有一个包含预期输出的文件,并且具有相同的词干和扩展名 .out。 make installcheck执行每个测试脚本,并将结果输出与匹配的预期文件进行比较。 任何差异都将以diff -c的格式写入到output_iso/regression.diffs文件中。 请注意,尝试运行缺少其预期文件的测试将会报告“trouble”,因此请确保你具有全部的预期文件。
TAP_TESTS 启用TAP测试. 每个运行中的数据都存在于名为 tmp_check/的子目录中。
无法给orafce打断点
ifeq($(strip $(foreach v,clean check,$(findstring $(v),$(MAKECMDGOALS)))),)
不等于make clean|check的进入判断