makeFile

target ... : prerequisites ... 

 

  command

    target为目标文件,可是.o文件,可是执行文件,还可是标签(Label)。prerequisites是生成target所需要的文件或目标。<TAB>command就是make需要执行的命令(任意的shell命令)

 

objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o

    将需要编译的文件赋值给变量objects,在makefile中用$(objects)来调用。

 

xx.o  : test.h 

    xx.o依赖的xx.c不用写,如果有xx.c 那么make会自动推到加上。只需要写额外的其他依赖即可。

 

.PHONY : clean
clean :
-rm edit $(objects)

    为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”(也可不加)。.PHONY 意思表示clean 是一个“伪目标”,而在rm 命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。

 

include foo.make *.mk $(bar)

    包含别的Makefile。

 

*  ?  [...]   

    通配符

 

VPATH = src:../headers

    “src”和“../headers”,make会按照这个顺序进行搜索源文件。目录由“冒号”分隔。(当然,当前目录永远是最高优先搜索的地方)

    

vpath %.h ../headers

    vpath <pattern> <directories>

    为符合模式<pattern>的文件指定搜索目录<directories>。

    vpath <pattern>
    清除符合模式<pattern>的文件的搜索目录。
    vpath
    清除所有已被设置好了的文件搜索目录。

    vapth使用方法中的<pattern>需要包含“%”字符。“%”的意思是匹配零或若干字符,例如,“%.h”表示所有以“.h”结尾的文件。<pattern>指定了要搜索的文件集,而<directories>则指定了<pattern>的文件集的搜索的目录

 

gcc -MM main.c 

    自动找寻源文件中包含的头文件,并生成一个依赖关系。-M会把标准库的头文件包含进来。-MM只包含defs.h这种自定义的头文件

 

-rm -f *.o

    命令行前加一个减号“-”(在Tab键之后),标记为不管命令出不出错都认为是成功的.

 

cd /home/hchen; pwd

    cd如果起作用了,pwd会打印出“/home/hchen”

 

cd subdir && $(MAKE) 等价 $(MAKE) -C subdir

    有一个子目录叫subdir,这个目录下有个Makefile文件,来指明了这个目录下文件的编译规则。定义$(MAKE)宏变量的意思是,也许我们的make需要一些参数,所以定义成一个变量比较利于维护。

 

define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef

    如果Makefile中出现一些相同命令序列,那么我们可以为这些相同的命令序列定义一个变量. 使用的时候就用$(run-yacc)

 

objects = program.o foo.o utils.o
program : $(objects)
cc -o program $(objects)
$(objects) : defs.h

    在Makefile中的定义的变量,就像是C/C++语言中的宏一样,他代表了一个文本字串,在Makefile中执行的时候其会自动原模原样地展开在所使用的地方。其与C/C++所不同的是,你可以在Makefile中改变其值。

 

x := foo
y := $(x) bar
x := later
其等价于:
y := foo bar
x := later

    这种方法,前面的变量不能使用后面的变量,只能使用前面已定义好了的变量

 

FOO ?= bar

    如果FOO没有被定义过,那么变量FOO的值就是“bar”,如果FOO先前被定义过,那么这条语将什么也不做

 

$(var:a=b)

    把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串

 

objects = main.o foo.o bar.o utils.o
objects += another.o

    追加变量值

 

define two-lines
echo foo
echo $(bar)
endef

    define指示符后面跟的是变量的名字,而重起一行定义变量的值,定义是以endef关键字结束。其工作方式和“=”操作符一样。变量的值可以包含函数、命令、文字,或是其它变量。因为命令需要以[Tab]键开头,所以如果你用define定义的命令变量中没有以[Tab]键开头,那么make就不会把其认为是命令。

 

prog : CFLAGS = -g
prog : prog.o foo.o bar.o
$(CC) $(CFLAGS) prog.o foo.o bar.o
prog.o : prog.c
$(CC) $(CFLAGS) prog.c

    不管全局的$(CFLAGS)的值是什么,在prog目标,以及其所引发的所有规则中(prog.o foo.o bar.o的规则),$(CFLAGS)的值都是“-g”

 

<conditional-directive>-------------------------- ifeq (<arg1>, <arg2>)---------------反义词ifneq  以及   ifdef <variable-name>如果变量<variable-name>的值非空,那到表达式为真
<text-if-true>
endif
以及:
<conditional-directive>
<text-if-true>
else
<text-if-false>
endif

 

    比较参数“arg1”和“arg2”的值是否相同,执行不同逻辑

 

$(<function> <arguments>)

    函数调用,很像变量的使用,也是以“$”来标识的。

 

$(subst <from>,<to>,<text>)

    把字串<text>中的<from>字符串替换成<to>

 

$(patsubst <pattern>,<replacement>,<text>)

    查找<text>中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式<pattern>,如果匹配的话,则以<replacement>替换。这里,<pattern>可以包括通配符“%”,表示任意长度的字串。如果<replacement>中也包含“%”,那么,<replacement>中的这个“%”将是<pattern>中的那个“%”所代表的字串。(可以用“\”来转义,以“\%”来表示真实含义的“%”字符)

 

$(strip <string>)

    去掉<string>字串中开头和结尾的空字符。

 

$(findstring <find>,<in>)

    在字串<in>中查找<find>字串。如果找到,那么返回<find>,否则返回空字符串

 

$(filter <pattern...>,<text>)

    以<pattern>模式过滤<text>字符串中的单词,保留符合模式<pattern>的单词。可以有多个模式。返回符合模式<pattern>的字串。

 

$(filter-out <pattern...>,<text>)

    以<pattern>模式过滤<text>字符串中的单词,去除符合模式<pattern>的单词。可以有多个模式。返回不符合模式<pattern>的字串。

 

$(sort <list>)

    给字符串<list>中的单词排序(升序)。返回排序后的字符串。

 

$(word <n>,<text>)

    取字符串<text>中第<n>个单词。(从一开始)。返回字符串<text>中第<n>个单词。如果<n>比<text>中的单词数要大,那么返回空字符串。

 

$(wordlist <s>,<e>,<text>)

    从字符串<text>中取从<s>开始到<e>的单词串。<s>和<e>是一个数字。返回字符串<text>中从<s>到<e>的单词字串。如果<s>比<text>中的单词数要大,那么返回空字符串。如果<e>大于<text>的单词数,那么返回从<s>开始,到<text>结束的单词串。

 

$(words <text>)

    统计<text>中字符串中的单词个数。返回<text>中的单词数。

 

$(firstword <text>)

    取字符串<text>中的第一个单词。返回字符串<text>的第一个单词。

 

$(dir <names...>)

    从文件名序列<names>中取出目录部分。目录部分是指最后一个反斜杠(“/”)之前的部分。如果没有反斜杠,那么返回“./”。返回文件名序列<names>的目录部分。

 

$(notdir <names...>)

    从文件名序列<names>中取出非目录部分。非目录部分是指最后一个反斜杠(“ /”)之后的部分。返回文件名序列<names>的非目录部分。

 

$(suffix <names...>)

    从文件名序列<names>中取出各个文件名的后缀。返回文件名序列<names>的后缀序列,如果文件没有后缀,则返回空字串。

 

$(basename <names...>)

    从文件名序列<names>中取出各个文件名的前缀部分。返回文件名序列<names>的前缀序列,如果文件没有前缀,则返回空字串。

 

$(addsuffix <suffix>,<names...>)

    把后缀<suffix>加到<names>中的每个单词后面。返回加过后缀的文件名序列。

 

$(addprefix <prefix>,<names...>)

    把前缀<prefix>加到<names>中的每个单词后面。返回加过前缀的文件名序列。

 

$(join <list1>,<list2>)

    把<list2>中的单词对应地加到<list1>的单词后面。如果<list1>的单词个数要比<list2>的多,那么,<list1>中的多出来的单词将保持原样。如果<list2>的单词个数要比<list1>多,那么,<list2>多出来的单词将被复制到<list2>中。返回连接过后的字符串。

 

$(foreach <var>,<list>,<text>)

    把参数<list>中的单词逐一取出放到参数<var>所指定的变量中,然后再执行<text>所包含的表达式。每一次<text>会返回一个字符串,循环过程中,<text>的所返回的每个字符串会以空格分隔,最后当整个循环结束时,<text>所返回的每个字符串所组成的整个字符串(以空格分隔)将会是foreach函数的返回值。

 

$(if <condition>,<then-part>)或$(if <condition>,<then-part>,<else-part>)

    

$(call <expression>,<parm1>,<parm2>,<parm3>...)

    当make执行这个函数时,<expression>参数中的变量,如$(1),$(2),$(3)等,会被参数<parm1>,<parm2>,<parm3>依次取代。而<expression>的返回值就是call函数的返回值

 

$(origin <variable>)

    <variable>是变量的名字,不应该是引用。所以你最好不要在<variable>中使用“$”字符。Origin函数会以其返回值来告诉你这个变量的“出生情况”.

 

contents := $(shell cat foo)
files := $(shell echo *.c)

    这个函数会新生成一个Shell程序来执行命令

 

$(error <text ...>)

    产生一个致命的错误,<text ...>是错误信息。注意,error函数不会在一被使用就会产生错误信息,所以如果你把其定义在某个变量中,并在后续的脚本中使用这个变量,那么也是可以的

 

$(warning <text ...>)

    这个函数很像error函数,只是它并不会让make退出,只是输出一段警告信息,而make继续执行。

 

.PHONY: all
all: prog1 prog2 prog3 prog4

    我们可以使用“make all”命令来编译所有的目标(如果把all置成第一个目标,那么只需执行“make”)

 

自动化变量及其说明

$@

    表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。

 

$%

    仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"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"。这个特性是GNU make的,很有可能不兼容于其它版本的make,所以,你应该尽量避免使用"$*",除非是在隐含规则或是静态模式中。如果目标中的后缀是make所不能识别的,那么"$*"就是空值。

 

你可以重载内建的隐含规则(或是定义一个全新的),例如你可以重新构造和内建隐含规则不同的命令,如:

%.o : %.c
$(CC) -c $(CPPFLAGS) $(CFLAGS) -D$(date)

    你可以取消内建的隐含规则,只要不在后面写命令就行。

 

 

posted @ 2018-02-07 15:10  愚智  阅读(388)  评论(0编辑  收藏  举报