美文网首页
Makefile 规范整理

Makefile 规范整理

作者: G风 | 来源:发表于2018-05-16 09:24 被阅读0次

    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 <variable ...>
    

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

        unexport <variable ...>
    

    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 <variable> = <value>
          override <variable> := <value>
    

    当然,你还可以追加:

          override <variable> += <more text>
        例如:
          @echo ARCH  #x86  
          override ARCH = arm
    

    9.环境变量

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

    KBUILD_AFLAGS_MODULE  := -DMODULE
    export KBUILD_AFLAGS_MODULE
    

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

      其语法是:

    <target ...> : <variable-assignment>
    <target ...> : overide <variable-assignment>
    

      <variable-assignment>可以是前面讲过的各种赋值表达式,如“=”、“:=”、“+=”或是“?=”。第二个语法是针对于 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
    

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

    <pattern ...> : <variable-assignment>
    <pattern ...> : override <variable-assignment>
    

      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.使用函数

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

    $(<function> <arguments>)
    或是
    ${<function> <arguments>}
    

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

    字符串处理函数
        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 <from>,<to>,<text>)

    名称:字符串替换函数——subst。
    功能:把字串<text>中的<from>字符串替换成<to>。

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

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

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

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

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

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

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

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

    $(strip <string>)

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

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

    $(strip a b c )
    

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

    $(findstring <find>,<in>)

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

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

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

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

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

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

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

    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 <pattern...>,<text>)

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

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

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

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

    $(sort <list>)

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

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

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

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

    $(word <n>,<text>)

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

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

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

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

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

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

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

    $(notdir <names...>)

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

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

    $(notdir src/foo.c hacks)
    

    返回值是“foo.c hacks”。

    $(suffix <names...>)

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

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

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

      返回值是“.c .c”

    $(basename <names...>)

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

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

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

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

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

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

    $(addsuffix .c,foo bar)
    

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

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

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

    $(addprefix src/,foo bar)
    

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

    $(join <list1>,<list2>)

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

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

     $(join aaa bbb , 111 222 333)
    

      返回值是“aaa111 bbb222 333”。

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

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

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

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

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

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

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

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

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

    $(origin <variable>)

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

    “undefined”  
    

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

    “default”  
    

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

    “environment”  
    

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

    “file”
    

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

    “command line”
    

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

    “override”
    

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

    “automatic”
    

      如果<variable>是一个命令运行中的自动化变量。关于自动化变量将在后面讲述。
      例如,假设我们有一个 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 <text ...>)

      产生一个致命的错误, <text ...>是错误信息。

    $(warning <text ...>)

      这个函数很像 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 <dir>
    --directory=<dir>
    

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

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

      输出 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>
    --file=<file>
    --makefile=<file>
    

      指定需要执行的 makefile。

    -h
    --help
    

      显示帮助信息。

    --ignore-errors
    

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

    -I <dir>
    --include-dir=<dir>
    

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

    -j [<jobsnum>]
    --jobs[=<jobsnum>]
    

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

    -k
    --keep-going
    

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

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

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

    -o <file>
    --old-file=<file>
    --assume-old=<file>
    

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

    -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 <file>
    --what-if=<file>
    --new-file=<file>
    --assume-file=<file>
    

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

    --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 程序的隐含规则。

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

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

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

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

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

    链接 Object 文件的隐含规则。

      “<n>”目标依赖于“<n>.o”,通过运行 C 的编译器来运行链接程序生成(一般是“ld”),其生成命令是:
    “$(CC) $(LDFLAGS) <n>.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 ; <command ......>
    

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

    相关文章

      网友评论

          本文标题:Makefile 规范整理

          本文链接:https://www.haomeiwen.com/subject/hswudftx.html