Makefile 规范整理

1.Makefile规范

target ... : prerequisites ...
   command
   ...
   ...

  target 这 一 个 或 多 个 的 目 标 文 件 依 赖 于prerequisites 中 的 文 件 , 其 生 成 规 则 定 义 在 command (任意的Shell命令)中 。command 是命令行,如果其不与“target:prerequisites”在一行,那么,必须以[Tab键]开头。
一个示例

 foo.o: foo.c defs.h       # foo模块
 cc -c -g foo.c

  a. 文件的依赖关系,foo.o依赖于foo.c和defs.h的文件,如果foo.c
和defs.h的文件日期要比foo.o文件日期要新,或是foo.o不存在,
那么依赖关系发生。

  b. 如果生成(或更新)foo.o文件。也就是那个cc命令,其说明了,
如何生成foo.o这个文件。(当然foo.c文件include了defs.h文件)

2.书写命令

  每条规则中的命令和操作系统 Shell 的命令行是一致的。 make 会一按顺序一条一条的执行命令,每条命令的开头必须以[Tab]键开头,从上下,从左到右,依次执行。
   如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。比如你的第一条命令是 cd 命令,你希望第二条命令得在 cd 之后的基础上运行,那么你就不能把这两条命令写在两行上,而应该把这两条命令写在一行上,用分号分隔。

     exec:
    cd /home/hchen; pwd

  当我们执行“make exec”时, pwd 会打印出“/home/hchen”。“#”是注释符,很像 C/C++中的“//”,其后的本行字符都被注释。

3.命令出错

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

clean:
    -rm -f *.o

  例如 mkdir 命令,我们一定需要建立一个目录,如果目录不存在,那么 mkdir 就成功执行,万事大吉,如果目录存在,那么就出错了。我们之所以使用 mkdir 的意思就是一定要有这样的一个目录,于是我们就不希望 mkdir 出错而终止规则的运行。

4.嵌套执行 make

  我们有一个子目录叫 subdir,这个目录下有个 Makefile 文件,来指明了这个目录下文件的编译规则。那么我们总控的 Makefile 可以这样书写:

 subsystem:
         cd subdir && $(MAKE)

其等价于:

subsystem:
    $(MAKE) -C subdir     (-C是大写的C,小写的c编译出目标文件)

  定义$(MAKE)宏变量的意思是,也许我们的 make 需要一些参数,所以定义成一个变量比较利于维护。这两个例子的意思都是先进入“subdir”目录,然后执行 make 命令。

        MAKE=make  XXXX

  如果你要传递变量到下级 Makefile 中,那么你可以使用这样的声明:

       export 

  如果你不想让某些变量传递到下级 Makefile 中,那么你可以这样声明:

    unexport 

5.定义命令包

  如果 Makefile 中出现一些相同命令序列,那么我们可以为这些相同的命令序列定义一个变量。定义这种命令序列的语法以“define”开始,以“endef”结束,如:

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

  把这个命令包放到一个示例中来看看吧。

foo.c : foo.y
    $(run-yacc)

  make 在执行命令包时,命令包中的每个命令会被依次独立执行。

6.使用变量

  a.使用“=”号,在“=”左侧是变量,右侧是变量的值

    foo = $(ugh)
    ugh = Huh?

  变量$(foo)的值是“Huh?”($(foo)的值是$(bar),变量是可以使用后面的变量来定义的。
  b.使用“:=”操作符
  前面的变量不能使用后面的变量,只能使用前面已定义好了的变量。如果是这样:

    y := $(x) bar
    x := foo

  那么, y 的值是“bar”,而不是“foo bar”
  c.使用“?=”操作符

        FOO ?= bar

  如果 FOO 没有被定义过,那么变量 FOO 的值就是“bar”,如果 FOO 先前被定义过,那么这条语将什么也不做,在使用时,需要给在变量名前加上“$”符号

7.变量高级用法

  第一种是变量值的替换可以替换变量中的共有的部分,其格式是“$(var:a=b)”或是“${var:a=b}”,其意思是,把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串。这里的“结尾”意思是“空格”或是“结束符”。
还是看一个示例吧:

    foo := a.o b.o c.o
    bar := $(foo:.o=.c)  或者 bar := $(foo:%.o=%.c)

  这个示例中,我们先定义了一个“$(foo)”变量,而第二行的意思是把“$(foo)”中所有以“.o”字串“结尾”全部替换成“.c”,所以我们的“$(bar)”的值就是“a.c b.c c.c”。
  把变量的值再当成变量

x = y
y = z
a := $($(x))

  在这个例子中, $(x)的值是“y”,所以$($(x))就是$(y),于是$(a)的值就是“z”。(注意,是“x=y”,而不是“x=$(y)”)
  追加变量值,我们可以使用“+=”操作符给变量追加值,如:

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

  于是,我们的$(objects)值变成: “main.o foo.o bar.o utils.o another.o”,如果变量之前没有定义过,那么,“+=”会自动变成“=”

8.override 指示符

  有变量是通常 make 的命令行参数设置的,那么 Makefile 中对这个变量的赋值会被忽略。如果你想在 Makefile 中设置这类参数的值,那么,你可以使用“override”指示符。
其语法是:

      override  = 
      override  := 

当然,你还可以追加:

      override  += 
    例如:
      @echo ARCH  #x86  
      override ARCH = arm

9.环境变量

  如果我们在环境变量中设置了“CFLAGS”环境变量,那么我们就可以在所有的Makefile 中使用这个变量了。
  当 make 嵌套调用时,上层 Makefile 中定义的变量会以系统环境变量的方式传递到下层的 Makefile 中。当然,默认情况下,只有通过命令行设置的变量会被传递。而定义在文件中的变量,如果要向下层 Makefile 传递,则需要使用export关键字来声明。

KBUILD_AFLAGS_MODULE  := -DMODULE
export KBUILD_AFLAGS_MODULE

10.目标变量或者局部变量

  其语法是:

 : 
 : overide 

  可以是前面讲过的各种赋值表达式,如“=”、“:=”、“+=”或是“?=”。第二个语法是针对于 make 命令行带入的变量,或是系统环境变量。

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

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

11.模式变量

  make 的“模式”一般是至少含有一个“%”的,所以,我们可以以如下方式给所有以[.o]结尾的目标定义目标变量:

          %.o : CFLAGS = -O

  同样,模式变量的语法和“目标变量”一样:

 : 
 : override 

  override 同样是针对于系统环境传入的变量,或是 make 命令行指定的变量.

12.自动变量 含义

  $* 不包含扩展名的目标文件名称
  这个变量表示目标模式中“%”及其之前的部分。如果目标是“dir/a.foo.b”,并且目标的模式是“a.%.b”,那么,“$”的值就是“dir/a.foo”。 如果目标是“foo.c”,因为“.c”是 make 所能识别的后缀名,所以,“$”的值就是“foo”。

  $+ 所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件。

  $< 第一个依赖文件的名称,依赖目标中的第一个目标名字。如果依赖目标是以模式
(即“%”)定义的,那么“$<”将是符合模式的一系列的文件集。注意,其是一个一个取出来的。

  $? 所有时间戳比目标文件晚的依赖文件,并以空格分开

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

  $^ 所有不重复的依赖文件,以空格分开

  $% 仅当 目 标是函数库 文件中,表 示规则中的 目标成员名 。例如,如 果一个目标 是“foo.a(bar.o)”,那么,“$%”就是“bar.o”,“$@”就是“foo.a”。如果目标不是函数库文件(Unix 下是[.a], Windows 下是[.lib]),那么,其值为空。

objects = foo.o bar.o
  all: $(objects)
  $(objects): %.o: %.c
  $(CC) -c $(CFLAGS) $< -o $@

  “%.o”表明要所有以“.o”结尾的目标,也就是“foo.o bar.o”,“%.c”则取模式“%.o”的“%”,也就是“foo bar”,并为其加下“.c”的后缀,所以依赖目标就是“foo.c bar.c”。
  “$<”表示所有的依赖目标集(也就是“foo.c bar.c”),“$@”表示目标集(也就是“foo.o bar.o”)

OBJS = kang.o yul.o
CC = gcc
CFLAGS =-Wall -O -g
david : $ (OBJS)
$(CC) $^ -o $@
kang.o : kang.c kang.h
$(CC) $(CFLAGS) -c $< -o $@
yul.o : yul.c yul.h
$(CC) $(CFLAGS) -c $< -o $@ 

$^:为$ (OBJS) ,既kang.o yul.o
$<: kang.c

% 与 * 区别

   “%”的意思是匹配零或若干字符,例如,“%.h”表示所有以“.h”结尾的文件.
它是在GUNmake的语法层次上的,例如 vpath %.h ../headers ,该语句表示,要求make在“../headers”目录下搜索所有以“.h”结尾的文件.
是Shell所支持的通配符,是在shell的语法层次上,.c,一般用在shell命令里面,如:

clean:
rm -f *.o

make 自己的变量

  环境变量, 比较重要的是PATH, PWD
cc 是 /usr/bin/cc -> /usr/bin/gcc
CXX 是 g++
INCLUDE_DIRS = /usr/include /usr/local/include /usr/include
MAKE_VERSION #make 版本
CURDIR #make 执行时的所在目录
MAKEFILE_LIST #make 用到的文件
MAKECMDGOALS #make的目标

13.使用条件判断

  下面的例子,判断$(CC)变量是否“gcc”,如果是的话,则使用 GNU 函数编译目标

 ifeq ($(CC),gcc)
    $(CC) -o foo $(objects) $(libs_for_gcc)
else
    $(CC) -o foo $(objects) $(normal_libs)
endif

其他条件关键字是ifneq。ifdef。ifndef

14.使用函数

  函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:

$( )
或是
${ }

  就是函数名, make 支持的函数不多。 是函数的参数,参数间以逗号“,”分隔,而函数名和参数之间以“空格”分隔。

字符串处理函数
    subst  patsubst strip findstring filter  filter-out sort  word wordlist 
words firstword
文件名操作函数
    dir notdir suffix basename addsuffix addprefix join
其他
    foreach  if  call  origin  shell  error
$(subst ,,)

名称:字符串替换函数——subst。
功能:把字串中的字符串替换成

返回:函数返回被替换过后的字符串。
示例:

$(subst ee,EE,feet on the street)

   把“feet on the street”中的“ee”替换成“EE”,返回结果是“fEEt on the strEEt”。

$(patsubst ,,)

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

返回:函数返回被替换过后的字符串。
示例:

$(patsubst %.c,%.o,x.c.c bar.c)

  把字串“x.c.c bar.c”符合模式[%.c]的单词替换成[%.o],返回结果是“x.c.obar.o”

$(strip )

名称:去空格函数——strip。
功能:去掉字串中开头和结尾的空字符。

返回:返回被去掉空格的字符串值。
示例:

$(strip a b c )

  把字串“a b c ”去掉开头和结尾的空格,结果是“a b c”。

$(findstring ,)

名称:查找字符串函数——findstring。
功能:在字串中查找字串。

返回:如果找到,那么返回,否则返回空字符串。
示例:

        $(findstring a,a b c)
        $(findstring a,b c)

  第一个函数返回“a”字符串,第二个返回“”字符串(空字符串)

$(filter ,)

名称:过滤函数——filter。
功能:以模式过滤字符串中的单词,保留符合模式的单
词。可以有多个模式。

返回:返回符合模式的字串。
示例:

sources := foo.c bar.c baz.s ugh.h
      foo: $(sources)
      cc $(filter %.c %.s,$(sources)) -o foo

  $(filter %.c %.s,$(sources))返回的值是“foo.c bar.c baz.s”。

$(filter-out ,)

名称:反过滤函数——filter-out。
功能:以模式过滤字符串中的单词,去除符合模式的单词。可以有多个模式。

返回:返回不符合模式的字串。
示例:

    objects=main1.o foo.o main2.o bar.o
    mains=main1.o main2.o
    $(filter-out $(mains),$(objects))

  返回值是“foo.o bar.o”。

$(sort )

名称:排序函数——sort。
功能:给字符串中的单词排序(升序)。

返回:返回排序后的字符串。
示例:

 $(sort foo bar lose)返回“bar foo lose” 。

  备注: sort 函数会去掉中相同的单词。

$(word ,)

名称:取单词函数——word。
功能:取字符串中第个单词。(从一开始)

返回:返回字符串中第个单词。如果中的单词数要大,那么返回空字符串。
示例:

 $(word 2, foo bar baz)返回值是“bar”。
$(firstword )

名称:首单词函数——firstword。
功能:取字符串中的第一个单词。

返回:返回字符串的第一个单词。
示例: $(firstword foo bar)返回值是“foo”。
备注:这个函数可以用 word 函数来实现: $(word 1,)。
  以上,是所有的字符串操作函数,如果搭配混合使用,可以完成比较复杂的功能。这里,举一个现实中应用的例子。我们知道, make 使用“VPATH”变量来指定“依赖文件”的搜索路径。于是,我们可以利用这个搜索路径来指定编译器对头文件的搜索路径参数 CFLAGS,如:

override CFLAGS += $(patsubst %,-I%,$(subst :, ,$(VPATH)))  #VPATH

  指定make命令查找的路径如 果 我 们 的 “$(VPATH) ” 值 是 “src:../headers ”, 那 么 “$(patsubst%,-I%,$(subst :, ,$(VPATH)))”将返回“-Isrc -I../headers”,这正是 cc 或gcc 搜索头文件路径的参数。

$(notdir )

名称:取文件函数——notdir。
功能:从文件名序列中取出非目录部分。非目录部分是
指最后一个反斜杠(“/”)之后的部分。

返回:返回文件名序列的非目录部分。
示例:

$(notdir src/foo.c hacks)

返回值是“foo.c hacks”。

$(suffix )

名称:取后缀函数——suffix。
功能:从文件名序列中取出各个文件名的后缀。

返回:返回文件名序列的后缀序列,如果文件没有后缀,则返回空字串。
示例:

 $(suffix src/foo.c src-1.0/bar.c hacks)

  返回值是“.c .c”

$(basename )

名称:取前缀函数——basename。
功能:从文件名序列中取出各个文件名的前缀部分。

返回:返回文件名序列的前缀序列,如果文件没有前缀,则返回空字串。
示例:

 $(basename src/foo.c src-1.0/bar.c hacks)

  返回值是“src/foo src-1.0/bar hacks”。

$(addsuffix ,)

名称:加后缀函数——addsuffix。
功能:把后缀加到中的每个单词后面。
返回:返回加过后缀的文件名序列。
示例:

$(addsuffix .c,foo bar)

  返回值是“foo.c bar.c”

$(addprefix ,)

名称:加前缀函数——addprefix。
功能:把前缀加到中的每个单词后面。
返回:返回加过前缀的文件名序列。
示例:

$(addprefix src/,foo bar)

  返回值是“src/foo src/bar”

$(join ,)

名称:连接函数——join。
功能:把中的单词对应地加到的单词后面。如果的单词个数要比的多,那么, 中的多出来的单词将保持原样。如果的单词个数要比多,那么, 多出来的单词将被复制到中。

返回:返回连接过后的字符串。
示例:

 $(join aaa bbb , 111 222 333)

  返回值是“aaa111 bbb222 333”。

$(foreach ,,)

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

     names := a b c d
        files := $(foreach n,$(names),$(n).o)

  上面的例子中, $(name)中的单词会被挨个取出,并存到变量“n”中,“$(n).o”每次根据“$(n)”计算出一个值,这些值以空格分隔,最后作为 foreach 函数的返回,所以,$(files)的值是“a.o b.o c.o d.o”。

$(if ,)
$(if ,,)

  if 函数可以包含“else”部分,或是不含。即 if 函数的参数可以是两个,也可以是三个。 参数是 if 的表达式,如果其返回的为非空字符串,那么这个表达式就相当于返回真,于是, 会被计算,否则会被计算。
  而 if 函数的返回值是,如果为真(非空字符串),那个会是整个函数的返回值,如果为假(空字符串),那么会是整个函数的返回值,此时如果没有被定义,那么,整个函数返回空字串。

$(call ,,,...)

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

  reverse = $(1) $(2)
  foo = $(call reverse,a,b)

  那么, foo 的值就是“a b”。当然,参数的次序是可以自定义的,不一定是顺序的,如:

     reverse = $(2) $(1)foo = $(call reverse,a,b)。

此时的 foo 的值就是“b a”

$(origin )

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

“undefined”  

  如果从来没有定义过, origin 函数返回这值“undefined”。

“default”  

  如果是一个默认的定义,比如“CC”这个变量,这种变量我们将在后面讲述。

“environment”  

  如果是一个环境变量,并且当 Makefile 被执行时,“-e”参数没有被打开。

“file”

  如果这个变量被定义在 Makefile 中。

“command line”

  如果这个变量是被命令行定义的。

“override”

  如果是被 override 指示符重新定义的。

“automatic”

  如果是一个命令运行中的自动化变量。关于自动化变量将在后面讲述。
  例如,假设我们有一个 Makefile 其包了一个定义文件 Make.def,在 Make.def 中定义了一个变量“bletch”,而我们的环境中也有一个环境变量“bletch”,此时,我们想判断一下,如果变量来源于环境。

    ifdef bletch
        ifeq "$(origin bletch)" "environment"
            bletch = barf, gag, etc.
        endif
    endif
shell 函数

  shell 函数也不像其它的函数。顾名思义,它的参数应该就是操作系统 Shell 的命令。它和反引号“`”是相同的功能。这就是说, shell 函数把执行操作系统命令后的输出作为函数返回。于是,我们可以用操作系统命令以及字符串处理命令 awk, sed 等等命令来生成一个变量,如:

    files := $(shell echo *.c)
$(error )

  产生一个致命的错误, 是错误信息。

$(warning )

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

15.指定 Makefile

  我们也可以给 make 命令指定一个特殊名字的 Makefile。要达到这个功能,我们要使用 make 的“-f”或是“--file”参数(“--makefile”参数也行)。例

            make -f huang.mk

16.指定目标

  一般来说, make 的最终目标是 makefile 中的第一个目标,而其它目标一般是由这个目标连带出来的。这是 make 的默认行为。当然,一般来说,你的 makefile 中的第一个目标是由许多个目标组成,你可以指示 make,让其完成你所指定的目标。要达到这一目的很简单,需在 make 命令后直接跟目标的名字就可以完成(如前面提到的“make clean”形式)。
   任何在 makefile 中的目标都可以被指定成终极目标,但是除了以“-”打头,或是包含了“=”的目标,因为有这些字符的目标,会被解析成命令行参数或是变量。甚至没有被我们明确写出来的目标也可以成为 make 的终极目标,也就是说,只要 make 可以找到其隐含规则推导规则,那么这个隐含目标同样可以被指定成终极目标。
例如下面这个例子:

    .PHONY: all
    all: prog1 prog2 prog3 prog4

  从这个例子中,我们可以看到,这个 makefile 中有四个需要编译的程序——“prog1”,“prog2”, “prog3”和 “prog4”,我们可以使用“make all”命令来编译所有的目标(如果把 all 置成第一个目标,那么只需执行“make”),我们也可以使用“make prog2”来单独编译目标“prog2”。

17.检查规则

-B
--always-make

  认为所有的目标都需要更新(重编译)。

-C 
--directory=

  指定读取 makefile 的目录。如果有多个“-C”参数, make 的解释是后面的路径以前面的作为相对路径,并以最后的目录作为被指定目录。如:

make –C ~hchen/test –C prog
-debug[=]

  输出 make 的调试信息。

-a

  也就是 all,输出所有的调试信息。(会非常的多)

-b 

  也就是 basic,只输出简单的调试信息。即输出不需要重编译的目标。

-v 

  也就是 verbose,在 b 选项的级别之上。输出的信息包括哪个 makefile 被解析,不需要被重编译的依赖文件(或是依赖目标)等。

-i 

  也就是 implicit,输出所以的隐含规则。

-m 

  也就是 makefile,输出 make 读取 makefile,更新 makefile,执行makefile 的信息。

-d

  相当于“--debug=a”。

-e
--environment-overrides

  指明环境变量的值覆盖 makefile 中定义的变量的值。

-f=
--file=
--makefile=

  指定需要执行的 makefile。

-h
--help

  显示帮助信息。

--ignore-errors

  在执行时忽略所有的错误。

-I 
--include-dir=

  指定一个被包含 makefile 的搜索目标。可以使用多个“-I”参数来指定多个目录。

-j []
--jobs[=]

  指同时运行命令的个数。如果没有这个参数, make 运行命令时能运行多少就运行多少。如果有一个以上的“-j”参数,那么仅最后一个“-j”才是有效的。(注意这个参数在 MS-DOS中是无用的)

-k
--keep-going

  出错也不停止运行。如果生成一个目标失败了,那么依赖于其上的目标就不会被执行。

-n
--just-print
--dry-run
--recon

  仅输出执行过程中的命令序列,但并不执行。

-o 
--old-file=
--assume-old=

  不重新生成的指定的,即使这个目标的依赖文件新于它。

-q
--question

  不运行命令,也不输出。仅仅是检查所指定的目标是否需要更新。如果是 0 则说明要更新,如果是 2 则说明有错误发生。

-p
--print-data-base

  输出makefile 中的所有数据,包括所有的规则和变量。这个参数会让一个简单的makefile都会输出一堆信息。如果你只是想输出信息而不想执行 makefile,你可以使用“make -qp”命令。如果你想查看执行 makefile 前的预设变量和规则,
  你可以使用“make –p –f/dev/null”。这个参数输出的信息会包含着你的 makefile 文件的文件名和行号,所以,用这个参数来调试你的 makefile 会是很有用的,特别是当你的环境变量很复杂的时候。

-r
--no-builtin-rules

  禁止 make 使用任何隐含规则。

-R
--no-builtin-variabes

  禁止 make 使用任何作用于变量上的隐含规则。

-s
--silent
--quiet

  在命令运行时不输出命令的输出。

-S
--no-keep-going
--stop

  取消“-k”选项的作用。因为有些时候, make 的选项是从环境变量“MAKEFLAGS”中继承下来的。所以你可以在命令行中使用这个参数来让环境变量中的“-k”选项失效。

-t
--touch

  相当于 UNIX 的 touch 命令,只是把目标的修改日期变成最新的,也就是阻止生成目标的命令运行。

-v
--version

  输出 make 程序的版本、版权等关于 make 的信息。

-w
--print-directory

  输出运行 makefile 之前和之后的信息。这个参数对于跟踪嵌套式调用 make 时很有用。

--no-print-directory
    禁止“-w”选项。
-W 
--what-if=
--new-file=
--assume-file=

  假定目标需要更新,如果和“-n”选项使用,那么这个参数会输出该目标更新时的运行动作。如果没有“-n”那么就像运行 UNIX 的“touch”命令一样,使得的修改时间为当前时间。

--warn-undefined-variables

  只要 make 发现有未定义的变量,那么就输出警告信息

18.隐含规则

  “隐含规则”也就是一种惯例, make 会按照这种“惯例”心照不喧地来运行,那怕我们的Makefile 中没有书写这样的规则。例如,把[.c]文件编译成[.o]文件这一规则,你根本就不用写出来, make 会自动推导出这种规则,并生成我们需要的[.o]文件。
  我们还可以通过“模式规则”的方式写下自己的隐含规则。用“后缀规则”来定义隐含规则会有许多的限制。
例如,我们有下面的一个 Makefile:

foo : foo.o bar.o
    cc –o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)

  因为 make 的“隐含规则”功能会自动为我们自动去推导这两个目标的依赖目标和生成命令。如果找不到,那么就会报错。
  完全没有必要写下下面的两条规则:

foo.o : foo.c
cc –c foo.c $(CFLAGS)
bar.o : bar.c
cc –c bar.c $(CFLAGS)
编译 C 程序的隐含规则。

   “.o”的目标的依赖目标会自动推导为“.c”,并且其生成命令是“$(CC) –c $(CPPFLAGS) $(CFLAGS)”

编译 C++程序的隐含规则。

   “.o”的目标的依赖目标会自动推导为“.cc”或是“.C”,并且其生成命令是“$(CXX) –c $(CPPFLAGS) $(CFLAGS)”。(建议使用“.cc”作为 C++源文件的后缀,而不是“.C”)

汇编和汇编预处理的隐含规则。

  “.o” 的目标的依赖目标会自动推导为“.s”,默认使用编译品“as”,并且其生成命令是:“$(AS) $(ASFLAGS)”。“.s” 的目标的依赖目标会自动推导为“.S”,默认使用 C 预编译器“cpp”,并且其生成命令是:“$(AS) $(ASFLAGS)”。

链接 Object 文件的隐含规则。

  “”目标依赖于“.o”,通过运行 C 的编译器来运行链接程序生成(一般是“ld”),其生成命令是:
“$(CC) $(LDFLAGS) .o $(LOADLIBES) $(LDLIBS)”。这个规则对于只有一个源文件的工程有效,同时也对多个 Object 文件(由不同的源文件生成)的也有效。例如如下规则:
x : y.o z.o并且“x.c”、“y.c”和“z.c”都存在时,隐含规则将执行如下命令:

    cc -c x.c -o x.o
    cc -c y.c -o y.o
    cc -c z.c -o z.o
    cc x.o y.o z.o -o x
    rm -f x.o
    rm -f y.o
    rm -f z.o

  如果没有一个源文件(如上例中的 x.c)和你的目标名字(如上例中的 x)相关联,那么,你最好写出自己的生成规则,不然,隐含规则会报错的。

19.关于命令参数的变量

ARFLAGS 函数库打包程序 AR 命令的参数。默认值是“rv”。
ASFLAGS 汇编语言编译器参数。(当明显地调用“.s”或“.S”文件时)。
CFLAGS C 语言编译器参数。
CXXFLAGS C++语言编译器参数。
CPPFLAGS C 预处理器参数。(C 和 Fortran 编译器也会用到)。

LDFLAGS 连接器参数(如“ld”)

20.模式规则介绍

   模式规则中,至少在规则的目标定义中要包含“%”,否则,就是一般的规则。目标中的“%”定义表示对文件名的匹配,“%”表示长度任意的非空字符串。例如:“%.c”表示以“.c”结尾的文件名(文件名的长度至少为 3),而“s.%.c”则表示以“s.”开头,“.c”结尾的文件名(文件名的长度至少为 5)。
如果“%”定义在目标中,那么,目标中的“%”的值决定了依赖目标中的“%”的值,也就是说,目标中的模式的“%”决定了依赖目标中“%”的样子。例如有一个模式规则如下:

                   %.o : %.c ; 

  其含义是,指出了怎么从所有的[.c]文件生成相应的[.o]文件的规则。如果要生成的目标是“a.o b.o”,那么“%c”就是“a.c b.c”。

你可能感兴趣的:(Makefile 规范整理)