添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

.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.自动化变量

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>)

真正的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>)

注意: 这个函数会新生成一个Shell程序来执行命令,所以你要注意其运行性能,如果你的Makefile中有一些比较复杂的规则,并大量使用了这个函数,那么对于你的系统性能是有害的。特别是Makefile的隐晦的规则可能会让你的shell函数执行的次数比你想像的多得多。

五、通配符   *   %

* 是去 系统 中匹配, % 是仅在 makefile 中匹配的:

凡是要到系统中去匹配的,就得用 * ;%通配符仅限在makefile文件中用来匹配规则而已,也就是%匹配的东西(可以看成字符串)在makefile(可以看成普通文档)中是可以找到的,而 * 匹配的东西,就需要跳出makefile去系统中匹配对应的文件之类的东西。

1.在shell命令中可以使用*,因为shell命令是连接系统的,shell中使用*,就是匹配系统中的文件

2.在依赖的时候可以使用*,如:

这时候,我们已经人为规定了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嵌套执行的时候,可以使用:

这样 clean 就被声明成一个伪目标,无论当前目录下是否存在 clean 这个文件,当我们执行 make clean 后 rm 都会被执行。而且当一个目标被声明为伪目标之后,make 在执行此规则时不会去试图去查找隐含的关系去创建它。这样同样提高了 make 的执行效率,同时也不用担心目标和文件名重名而使我们的编译失败。

十、隐含规则

隐含规则简要理解就是:正常的规则是三要素一个都不能少,就是目标、依赖、命令一个都少不了,如果少了,就不能正确运行,但是由于隐含规则的存在,可以自动补全,自动利用隐含规则推导,补充上缺失的部分。

注:隐含条件只能省略中间目标文件重建的命令和规则,但是最终目标的命令和规则不能省略。

可以联想到,如果没有显式指出命令的话,会推导命令,但是命令就真的凭空产生吗?不是的,还记得说变量的时候,第一个就说的是默认得隐含变量,这些推到出来的就会用这些默认变量来生成命令。

这里我们没有写生成main.o和common.o的规则,但是照样可以正常编译链接,然后运行。这就是隐含规则的作用。

隐含规则的具体的工作流程:make 执行过程中遇到没有提供显式规则的中间目标文件,则根据其后缀 .o 找到隐含规则,隐含规则提供了此中间目标的基本依赖关系。确定中间目标的依赖文件和重建中间目标需要使用的命令行。隐含规则所提供的依赖文件只是一个基本的依赖关系(在C语言中,通常他们之间的对应关系是:test.o 对应的是 test.c 文件)。如果需要增加其他的自定义的文件作为依赖,则需要 在Makefile 中使用没有命令行的规则给出。

十一、其他技巧

1.不输出回显指令:@

2.定义string类型为空:先定义一个空变量,然后后面采用“#”注释符来表示变量定义的终止,这样,我们可以定义出其值是一个空格的变量。

最后三行应该总是相同的。在这个文件的前面部分,你要对变量赋值或者增加自定义的make规则。

设置这三个变量之一来指定要构建什么:

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 编译。下面是做法:

mkdir build_dir

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打断点