zoukankan      html  css  js  c++  java
  • 嵌入式Linux开发之Makefile

    makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。

    makefile的好处就是:

    • “自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
    • 节约编译时间(没改动的文件不编译)。

    make是一个命令工具,是一个解释makefile中指令的命令工具。

    一、Makefile规则

    1.1 基本规则(注释规范)

    一个简单的Makefile 主要的 5个部分 (显示规则, 隐晦规则, 变量定义, 文件指示, 注释),其样式如下:

    target:prerequisites
        command
        ...
        ...
    =====================
    目标 : 依赖文件
    [tab键] 命令
          ...
          ...

    这是一个文件依赖关系,也就是说target是由一个或多个目标文件依赖于prerequisites中的文件,其生成规则定义在command中,而且只要prerequisites中有一个以上的文件比target文件更新的话,command所定义的命令就会被执行,这是makefile的最基本规则,也是makefile中最核心的内容。

    其中:

    • target: 是目标文件,可以是object file,也可以是执行文件,还可以是一个标签label。如果目标文件的更新时间晚于依赖文件的更新时间,则说明依赖文件没有改动,目标文件不需要重新编译。否则重新编译并更新目标。
    • prerequisites:即目标文件由哪些文件生成。如果依赖条件中存在不存在的依赖条件,则会寻找其它规则是否可以产生依赖条件。例如:规则一是生成目标 hello.elf需要使用到依赖条件 hello.o,但是 hello.o 不存在。则 Makefile 会寻找到一个生成 hello.o 的规则二并执行。
    • command:即通过执行该命令,由依赖文件生成目标文件。注意每条命令前必须有且仅有一个 tab 保持缩进,这是语法要求。

    (1) 显示规则 : 说明如何生成一个或多个目标文件(包括 生成的文件, 文件的依赖文件, 生成的命令);

    (2) 隐晦规则 : make的自动推导功能所执行的规则;

    (3) 变量定义: Makefile中定义的变量;

    (4) 文件指示 : Makefile中引用其他Makefile; 指定Makefile中有效部分; 定义一个多行命令;

    (5) 注释: Makefile只有行注释 "#", 如果要使用或者输出"#"字符, 需要进行转义, "#";

    GNU make 的工作方式:

    1. 读入主Makefile (主Makefile中可以引用其他Makefile);
    2. 读入被include的其他Makefile;
    3. 初始化文件中的变量;
    4. 推导隐晦规则, 并分析所有规则;
    5. 为所有的目标文件创建依赖关系链;
    6. 根据依赖关系, 决定哪些目标要重新生成;
    7. 执行生成命令;

    Makefile文件注释有以下几种方式:

    • 单行注释:makefile 把 # 字符后面的内容作为注释内容处理(shell、perl 脚本也是使用 # 字符作为注释符)
    • 多行注释:如果需要注释多行,在注释行的结尾加行反斜线(),下一行也被注释,可以注释多行。

    1.2 规则中的通配符

    • *   : 表示任意一个或多个字符;
    • ?    : 表示任意一个字符;
    • [...]: ex. [abcd] 表示a,b,c,d中任意一个字符, [^abcd]表示除a,b,c,d以外的字符, [0-9]表示 0~9中任意一个数字;
    • ~   :表示用户的home目录;
    • %:通配符,如%.o:%c,表示所有的目标文件及其依赖文件。

    1.3 路径搜索

    当一个Makefile中涉及到大量源文件时(这些源文件和Makefile极有可能不在同一个目录中),这时, 最好将源文件的路径明确在Makefile中, 便于编译时查找. Makefile中有个特殊的变量 VPATH 就是完成这个功能的。指定了 VPATH 之后, 如果当前目录中没有找到相应文件或依赖的文件, Makefile 回到 VPATH 指定的路径中再去查找。

    VPATH 使用方法:

    • vpath <directories>: 当前目录中找不到文件时, 就从<directories>中搜索;
    • vpath <pattern> <directories>:符合<pattern>格式的文件, 就从<directories>中搜索;
    • vpath <pattern>:清除符合<pattern>格式的文件搜索路径;
    • vpath:清除所有已经设置好的文件路径;
    # 示例1 - 当前目录中找不到文件时, 按顺序从 src目录 ../parent-dir目录中查找文件
    VPATH src:../parent-dir   
    
    # 示例2 - .h结尾的文件都从 ./header 目录中查找
    VPATH %.h ./header
    
    # 示例3 - 清除示例2中设置的规则
    VPATH %.h
    
    # 示例4 - 清除所有VPATH的设置
    VPATH

    1.4 示例

    我们以hello.c文件为例:

    #include <stdio.h>
    int main(int argc,char *argv[])
    {
      printf("Hello World!
    ");
      return 0;
    }

    然后编写Makefile(这里使用的是gcc、而不是arm-linux-gcc):

    ALL: hello.o
    
    hello.o: hello.c
            gcc hello.c -o hello.o

    命令格式:

    • make   (目标,省略的话默认执行第一个目标):

    编译并执行:

    make
    ./hello.o

    把hello.c文件复制一份,重命名为hello_copy.c。修改Makefile的内容如下:

    ALL: $(obj)
    $(obj):%.o: %.c
        gcc $< -o $@
    .PHONY: clean
    clean:
        rm -f $(obj)
    • 第一个target是ALL,而ALL由两个.o文件构成,对应的两个.c文件可以同时编译;
    • target可以是变量,例子中的obj是一个变量;
    • 这里加上了一个.PHONY、$<、$@,究竟是啥呢?这个后面我们会介绍。

    二、Makefile函数 

    Makefile 中自带了一些函数, 利用这些函数可以简化 Makefile 的编写。

    函数调用语法如下:

    $(<function> <arguments>)
    # 或者
    ${<function> <arguments>}
    • <function> 是函数名;
    • <arguments> 是函数参数;

    2.1 获取匹配模式文件名函数wildcard

    • 语法:$(wildcard PATTERN)
    • 函数功能:列出当前目录下所有符合模式“ PATTERN”格式的文件名。“PATTERN”使用 shell可识别的通配符,包括“ ?”(单字符)、“*”(多字符)等。
    • 返回值:空格分割的、存在当前目录下的所有符合模式“ PATTERN”的文件名。

    例如:

    SRC = $(wildcard  ./*.c)

    匹配目录下所有的 .c 文件,并将其赋值给 SRC 变量。

    2.2 模式替换函数patsubst

    pat 是 pattern 的缩写,subst 是 substring 的缩写。

    • 语法:$(patsubst PATTERN,REPLACEMENT,TEXT)
    • 函数功能:搜索“ TEXT”中以空格分开的单词,将否符合模式“ TATTERN ”替换为“REPLACEMENT ”。参数“PATTERN”中可以使用模式通配符 “%”来代表一个单词中的若干字符。 如果参数“REPLACEMENT ”中也包含一个“%”,那么“ REPLACEMENT ”中的“ %”将是“ TATTERN”中的那个“ %”所代表的字符串。在“ TATTERN ”和“REPLACEMENT ”中,只有第一个“ %”被作为模式字符来处理,之后出现的不再作模式字符(作为一个字符)。在参数中如果需要将第一个出现的“ %”作为字符本身而不作为模式字符时,可使用反斜杠“ ”进行转义处理(转义处理的机制和使用静态模式的转义一致,
    • 返回值:替换后的新字符串。

    参数 “TEXT ”单词之间的多个空格在处理时被合并为一个空格,并忽略前导和结尾空格。

    例如:

    OBJ = $(patsubst %.c, %.o, $(SRC))

    这个函数有三个参数,意思是取出 SRC 中所有的值,然后将 “.c” 替换为 “.o”,最后赋值给 OBJ 变量。

    示例:

    SRC = $(wildcard *.c)
    OBJ = $(patsubst %.c, %.o, $(SRC))
    
    ALL: hello.out
    
    hello.out: $(OBJ)
            gcc $(OBJ) -o hello.out
    
    $(OBJ): $(SRC)
            gcc -c  $(SRC) -o $(OBJ)

    这里我们先将所有的 “.c” 文件编译为 “.o” 文件,这样后面更改某个 “.c” 文件时,其它的 “.c” 文件将不再编译,而只是编译有更改的 “.c” 文件,可以大大节约大项目中的编译速度。

    需要注意的是:

    • .o文件一般是通过编译的但还未链接的。
    • .out文件一般都是经过相应的链接产生的可执行文件(linux下)。

    2.3 foreach 函数

    函数“foreach ”不同于其它函数。它是一个循环函数。类似于 Linux 的 shell 中的for 语句:

    • 语法:$(foreach VAR,LIST,TEXT)
    • 函数功能: 这个函数的工作过程是这样的:如果需要(存在变量或者函数的引用),首先展开变量“ VAR”和“ LIST”的引用;而表达式“ TEXT”中的变量引用不展开。执行时把“ LIST”中使用空格分割的单词依次取出赋值给变量“VAR”,然后执行“ TEXT”表达式。重复直到“ LIST”的最后一个单词(为空时结束)。“TEXT ”中的变量或者函数引用在执行时才被展开,因此如果在“TEXT”中存在对“ VAR”的引用,那么“ VAR”的值在每一次展开式将会到的不同的值。
    • 返回值: 空格分割的多次表达式“ TEXT ”的计算的结果。

    2.4 过滤函数 filter

    1).找出符合PATTERN 格式的值

    • 语法:$(filter PATTERN... ,TEXT)
    • 函数功能:过滤掉字串“ TEXT”中所有不符合模式“ PATTERN ”的单词,保留所有符合此模式的单词。可以使用多个模式。模式中一般需要包含模式字符“%”。存在多个模式时,模式表达式之间使用空格分割。
    • 返回值:空格分割的“ TEXT”字串中所有符合模式“ PATTERN ”的字串。

    示例:

    # Makefile 内容
    all:
        @echo $(filter %.o %.a,program.c program.o program.a)

    执行命令:

    # bash 中执行 make
    $ make
    program.o program.a

    2).找出不符合PATTERN 格式的值

    • 语法:$(filter-out PATTERN... ,TEXT)
    • 函数功能:过滤掉字串“ TEXT”中所有符合模式“ PATTERN ”的单词,保留所有不符合此模式的单词。可以使用多个模式。模式中一般需要包含模式字符“%”。存在多个模式时,模式表达式之间使用空格分割。
    • 返回值:空格分割的“ TEXT”字串中所有不符合模式“ PATTERN ”的字串。

    示例:

    # Makefile 内容
    all:
        @echo $(filter-out %.o %.a,program.c program.o program.a)

    执行命令:

    # bash 中执行 make
    $ make
    program.c

    2.5 if函数

    这里的if是个函数,它用于判断条件是否存在或者为true。 和后面将会介绍的条件判断不一样, 后面介绍的条件判断属于Makefile的关键字。

    • 语法:$(if <condition>,<then-part>)$(if <condition>,<then-part>,<else-part>)
    • 函数功能:用于条件判断。
    • 返回值:返回符合条件的部分的值。

    示例:

    # Makefile 内容
    val := a
    objects := $(if $(val),$(val).o,nothing)
    no-objects := $(if $(no-val),$(val).o,nothing)
    
    all:
        @echo $(objects)
        @echo $(no-objects)

    执行命令:

    # bash 中执行 make
    $ make
    a.o
    nothing

    2.6 创建新的参数化函数call

    • 语法:$(call <expression>,<parm1>,<parm2>,<parm3>...)
    • 函数功能:函数调用。
    • 返回值:返回调用的函数的执行结果。

    示例:

    # Makefile 内容
    log = "====debug====" $(1) "====end===="
    
    all:
        @echo $(call log,"正在 Make")

    执行命令:

    # bash 中执行 make
    $ make
    ====debug==== 正在 Make ====end====

    2.7 判断变量的来源函数orgin

    • 语法:$(origin <variable>)
    • 函数功能:判断变量的来源,返回值有以下类型:

    类型

    含义

    undefined <variable> 没有定义过
    default <variable> 是个默认的定义, 比如 CC 变量
    environment <variable> 是个环境变量, 并且 make时没有使用 -e 参数
    file <variable> 定义在Makefile中
    command line <variable> 定义在命令行中
    override <variable> 被 override 重新定义过
    automatic <variable> 是自动化变量

     示例:

    # Makefile 内容
    val-in-file := test-file
    override val-override := test-override
    
    all:
        @echo $(origin not-define)    # not-define 没有定义
        @echo $(origin CC)            # CC 是Makefile默认定义的变量
        @echo $(origin PATH)         # PATH 是 bash 环境变量
        @echo $(origin val-in-file)    # 此Makefile中定义的变量
        @echo $(origin val-in-cmd)    # 这个变量会加在 make 的参数中
        @echo $(origin val-override) # 此Makefile中定义的override变量
        @echo $(origin @)             # 自动变量, 具体前面的介绍

    执行命令:

    # bash 中执行 make
    $ make val-in-cmd=val-cmd
    undefined
    default
    environment
    file
    command line
    override
    automatic

    2.8 shell

    • 语法:$(shell <shell command>)
    • 函数功能:执行一个shell命令,作用和 `<shell command>` 一样, 是反引号。
    • 返回值:将shell命令的结果作为函数的返回。

    2.9 去空格函数strip

    • 语法:$(strip <string>)
    • 函数功能:去掉 <string> 字符串中开头和结尾的空字符。
    • 返回值:被去掉空格的字符串值。

    示例:

    # Makefile 内容
    VAL := "       aa  bb  cc "
    
    all:
        @echo "去除空格前: " $(VAL)
        @echo "去除空格后: " $(strip $(VAL))

    执行命令:

    # bash 中执行 make
    $ make
    去除空格前:         aa  bb  cc 
    去除空格后: aa bb cc

    2.10 查找字符串函数findstring 

    • 语法 $(findstring <find>,<in>)、
    • 函数功能: 在字符串 <in> 中查找 <find> 字符串。
    • 返回值: 如果找到, 返回 <find> 字符串,  否则返回空字符串。

    示例:

    # Makefile 内容
    VAL := "       aa  bb  cc "
    
    all:
        @echo $(findstring aa,$(VAL))
        @echo $(findstring ab,$(VAL))

    执行命令:

    # bash 中执行 make
    $ make
    aa

    2.11 更多函数

    由于Makefile函数过多,就不一一介绍了,更多函数信息请移步此处

    三、makefile内置变量

    3.1 shell变量(CXX、CC等)

    下面只列出一些C相关的:

    变量名

    含义

    RM rm -f
    AR ar
    CC cc
    CXX g++

    示例:

    # Makefile 内容
    all:
        @echo $(RM)
        @echo $(AR)
        @echo $(CC)
        @echo $(CXX)
    
    # bash 中执行make, 显示各个变量的值
    $ make
    rm -f
    ar
    cc
    g++

    3.2 自动变量($@、%<等)

    Makefile 中很多时候通过自动变量来简化书写, 各个自动变量的含义如下:

    自动变量

    含义

    $@ 目标集合
    $% 当目标是函数库文件时, 表示其中的目标文件名
    $< 第一个依赖目标. 如果依赖目标是多个, 逐个表示依赖目标
    $? 比目标新的依赖目标的集合
    $^ 所有依赖目标的集合, 会去除重复的依赖目标
    $+ 所有依赖目标的集合, 不会去除重复的依赖目标
    $* 这个是GNU make特有的, 其它的make不一定支持

    示例:

    SRC = $(wildcard *.c)
    OBJ = $(patsubst %.c, %.o, $(SRC))
     
    ALL: hello.out
     
    hello.out: $(OBJ)
            gcc -o $@ $<
     
    $(OBJ): $(SRC)
            gcc -c -o $@ $<

    四、其它常用功能

    4.1 代码清理clean

    我们可以编译一条属于自己的 clean 语句,来清理 make 命令所产生的所有文件。例如

    SRC = $(wildcard *.c)
    OBJ = $(patsubst %.c, %.o, $(SRC))
    
    ALL: hello.out
    
    hello.out: $(OBJ)
            gcc -o $@ $<
    
    $(OBJ): $(SRC)
            gcc -c -o $@ $<
    clean:
            rm -rf $(OBJ) *.out

    这样我们就可以使用make clean 命令来清理生成的文件了:

    提示:make命令是可以带上目标名的,如果make后面不跟目标名字的话,默认生成第一个目标,当带上目标名的话,生成指定的目标。

    4.2 伪目标 .PHONY

    上面我们写了一个 clean 语句,使得我们执行 “make clean” 命令的时候,可以清理我们生成的文件。

    但是假如还存在一个文件名就是 clean 文件,那么我们再执行 “make clean” 命令的时候就只是显示:

    make clean
    make: `clean' is up to date.

    为什么?我们看一看Makefile的核心规则:

    • 目标文件不存在;
    • 某个依赖文件比目标文件新;

    但是现在目录中有名为clean的文件,那目标文件存在,那就取决于依赖,但是在Makefile中clean目标没有依赖,所以没有办法通过判断依赖的的时间去更新clean目标,所以clean目标文件一直都是目录中那么clean文件。所以说,如果目录中有和clean同名文件时就没有办法执行clean操作了。

    解决方法就是我们使用伪目标,把这个目标定义为假想目标这样就可以避免出现上面的问题了,例如:

    SRC = $(wildcard *.c)
    OBJ = $(patsubst %.c, %.o, $(SRC))
     
    ALL: hello.out
     
    hello.out: $(OBJ)
            gcc -o $@ $<
     
    $(OBJ): $(SRC)
            gcc -c -o $@ $<
     
    clean:
            -rm -rf $(OBJ) hello.out
     
    .PHONY: clean ALL

    通常,我们也会把 ALL 也设置为伪目标。 

    4.3 Makefile命令前缀

    我们知道在Makefile文件中是可以编写shell命令的,Makefile 中书写shell命令时可以加2种前缀 @ 和 -, 或者不用前缀。

    3种格式的shell命令区别如下:

    • 不用前缀:输出执行的命令以及命令执行的结果, 出错的话停止执行;
    • 前缀 @ :关闭命令回显,只输出命令执行的结果, 出错的话停止执行;
    • 前缀 - :命令执行有错的话, 忽略错误, 继续执行;

    不用前缀示例:

    # Makefile 内容 (不用前缀)
    all:
        echo "没有前缀"
        cat this_file_not_exist
        echo "错误之后的命令"       <-- 这条命令不会被执行

    执行命令:

    # bash中执行 make
    $ make
    echo "没有前缀"             <-- 命令本身显示出来
    没有前缀                    <-- 命令执行结果显示出来
    cat this_file_not_exist
    cat: this_file_not_exist: No such file or directory
    make: *** [all] Error 1

    前缀 @ 示例:

    # Makefile 内容 (前缀 @)
    all:
        @echo "没有前缀"
        @cat this_file_not_exist
        @echo "错误之后的命令"       <-- 这条命令不会被执行

    执行命令:

    # bash中执行 make
    $ make
    没有前缀                         <-- 只有命令执行的结果, 不显示命令本身
    cat: this_file_not_exist: No such file or directory
    make: *** [all] Error 1

    前缀 - 示例:

    # Makefile 内容 (前缀 -)
    all:
        -echo "没有前缀"
        -cat this_file_not_exist
        -echo "错误之后的命令"       <-- 这条命令会被执行

    执行命令:

    # bash中执行 make
    $ make
    echo "没有前缀"             <-- 命令本身显示出来
    没有前缀                    <-- 命令执行结果显示出来
    cat this_file_not_exist
    cat: this_file_not_exist: No such file or directory
    make: [all] Error 1 (ignored)
    echo "错误之后的命令"       <-- 出错之后的命令也会显示
    错误之后的命令              <-- 出错之后的命令也会执行

    4.4 引用其它的Makefile

    语法: include <filename>  (filename 可以包含通配符和路径)。

    示例:

    # Makefile 内容
    all:
        @echo "主 Makefile begin"
        @make other-all
        @echo "主 Makefile end"
    
    include ./other/Makefile
    
    # ./other/Makefile 内容
    other-all:
        @echo "other makefile begin"
        @echo "other makefile end"

    执行命令:

    # bash中执行 make
    $ make
    主 Makefile begin
    make[1]: Entering directory `/path/to/makefile/other'
    other makefile begin
    other makefile end
    make[1]: Leaving directory `/path/to/makefile/other'
    主 Makefile end

    如果我们想向other/Makefile传递参数怎么办?可以使用export:

     export 语法格式如下:

    • export variable = value;
    • export variable := value;
    • export variable += value;
    # Makefile 内容
    export VALUE1 := export.c    <-- 用了 export, 此变量能够传递到 ./other/Makefile 中
    VALUE2 := no-export.c        <-- 此变量不能传递到 ./other/Makefile 中
    
    all:
        @echo "主 Makefile begin"
        @cd ./other && make
        @echo "主 Makefile end"
    
    
    # ./other/Makefile 内容
    other-all:
        @echo "other makefile begin"
        @echo "VALUE1: " $(VALUE1)
        @echo "VALUE2: " $(VALUE2)
        @echo "other makefile end"

    执行命令:

    # bash中执行 make
    $ make
    主 Makefile begin
    make[1]: Entering directory `/path/to/makefile/other'
    other makefile begin
    VALUE1:  export.c        <-- VALUE1 传递成功
    VALUE2:                  <-- VALUE2 传递失败
    other makefile end
    make[1]: Leaving directory `/path/to/makefile/other'
    主 Makefile end

    4.5 定义命令包

    命令包有点像是个函数, 将连续的相同的命令合成一条, 减少 Makefile 中的代码量, 便于以后维护。语法:

    define <command-name>
    command
    ...
    endef

    示例:

    # Makefile 内容
    define run-hello-makefile
    @echo -n "Hello"
    @echo " Makefile!"
    @echo "这里可以执行多条 Shell 命令!"
    endef
    
    all:
        $(run-hello-makefile)

    执行命令:

    # bash 中运行make
    $ make
    Hello Makefile!
    这里可以执行多条 Shell 命令!

    4.6 条件判断

    条件判断的关键字主要有 ifeq ifneq ifdef ifndef。语法:

    <conditional-directive>
        <text-if-true>
    endif
    
    # 或者
    <conditional-directive>
        <text-if-true>
    else
        <text-if-false>
    endif

    ifeq的例子, ifneq和ifeq的使用方法类似, 就是取反。示例: 

    # Makefile 内容
    all:
    ifeq ("aa", "bb")
        @echo "equal"
    else
        @echo "not equal"
    endif

    执行命令:

    # bash 中执行 make
    $ make
    not equal

    ifdef的例子, ifndef和ifdef的使用方法类似, 就是取反。示例: 

    # Makefile 内容
    SRCS := program.c
    
    all:
    ifdef SRCS
        @echo $(SRCS)
    else
        @echo "no SRCS"
    endif

    执行命令:

    # bash 中执行 make
    $ make
    program.c

    五、Makefile变量

    5.1 变量定义

    变量的种类分为:

    • 既时变量(简单变量):例子: 赋值方式: A := xxx    #A的值在定义就可以确定,即刻赋值;
    • 延时变量:例子:赋值方式:A =xxx      #A的值在使用到的时候才会确定;

    • ?= : 延时变量,第一次定义才有效,如果这个变量在前面已经定义过,那么不执行这句赋值;
    • +=  : 可以是即时变量也可以是延时变量,取决于这个变量的定义;

    比如我们编写Makefile文件:

    A:=$(C)
    
    B=$(C)
    
    C=123
    
    ALL:
            @echo A=$(A)
            @echo B=$(B)

    C赋值给A、但是C现在的值为空,B是延时变量,等到用到时才确定,所以执行到C=123才会显示B的值,也就是123。@表示关闭命令回显。

    5.2 变量替换 $(var:%.c=%.o)

    # Makefile内容
    SRCS := programA.c programB.c programC.c
    OBJS := $(SRCS:%.c=%.o)
    
    all:
        @echo "SRCS: " $(SRCS)
        @echo "OBJS: " $(OBJS)

    $(SRCS:%.c=%.o)表示将SRCS变量中以.c结尾的字符串替换为.o结尾。运行结果:

    # bash中运行make
    $ make
    SRCS:  programA.c programB.c programC.c
    OBJS:  programA.o programB.o programC.o

    5.3 变量追加值 +=

    # Makefile内容
    SRCS := programA.c programB.c programC.c
    SRCS += programD.c
    
    all:
        @echo "SRCS: " $(SRCS)

    运行结果:

    # bash中运行make
    $ make
    SRCS:  programA.c programB.c programC.c programD.c

    5.4 变量覆盖 override

    作用是使 Makefile中定义的变量能够覆盖 make 命令参数中指定的变量:

    • override <variable> = <value>
    • override <variable> := <value>
    • override <variable> += <value>

    下面通过一个例子体会 override 的作用:

    # Makefile内容 (没有用override)
    SRCS := programA.c programB.c programC.c
    
    all:
        @echo "SRCS: " $(SRCS)
    
    # bash中运行make
    $ make SRCS=nothing
    SRCS:  nothing

    使用override:

    # Makefile内容 (用override)
    override SRCS := programA.c programB.c programC.c
    
    all:
        @echo "SRCS: " $(SRCS)
    
    # bash中运行make
    $ make SRCS=nothing
    SRCS:  programA.c programB.c programC.c

    5.5 目标变量

    作用是使变量的作用域仅限于这个目标(target), 而不像之前例子中定义的变量, 对整个Makefile都有效.

    语法:

    • <target> : <variable-assignment>
    • <target> : override <variable-assignment> (override作用参见 变量覆盖的介绍)
    # Makefile 内容
    SRCS := programA.c programB.c programC.c
    
    target1: TARGET1-SRCS := programD.c     #目标变量定义
    target1:
        @echo "SRCS: " $(SRCS)
        @echo "SRCS: " $(TARGET1-SRCS)
    
    target2:
        @echo "SRCS: " $(SRCS)
        @echo "SRCS: " $(TARGET1-SRCS)

    执行命令:

    # bash中执行make
    $ make target1
    SRCS:  programA.c programB.c programC.c
    SRCS:  programD.c
    
    $ make target2     <-- target2中显示不了 $(TARGET1-SRCS)
    SRCS:  programA.c programB.c programC.c
    SRCS:

    六、Makefile中一些GNU约定俗成的伪目标

    如果有过在Linux上, 从源码安装软件的经历的话, 就会对 make clean, make install 比较熟悉。

    像 clean, install 这些伪目标, 广为人知, 不用解释就大家知道是什么意思了。

    下面列举一些常用的伪目标, 如果在自己项目的Makefile合理使用这些伪目标的话, 可以让我们自己的Makefile看起来更专业。

    伪目标

    含义

    all 所有目标的目标,其功能一般是编译所有的目标
    clean 删除所有被make创建的文件
    install 安装已编译好的程序,其实就是把目标可执行文件拷贝到指定的目录中去
    print 列出改变过的源文件
    tar 把源程序打包备份. 也就是一个tar文件
    dist 创建一个压缩文件, 一般是把tar文件压成Z文件. 或是gz文件
    TAGS 更新所有的目标, 以备完整地重编译使用
    check 或 test 一般用来测试makefile的流程

    参考文章

    [1] Makefile简单使用实例

    [2] Makefile 语法入门

    [3]Makefile 使用总结

    [4]快速的理解MakeFile+读懂一个MakeFile

  • 相关阅读:
    DHCP服务搭建
    JumpServer跳板机
    PXE
    DNS
    MySQL
    企业级LNMP分离式部署
    MHA-Atlas-MySQL高可用集群2
    MHA-Atlas-MySQL高可用集群
    备份全网服务器数据
    FTP
  • 原文地址:https://www.cnblogs.com/zyly/p/14827987.html
Copyright © 2011-2022 走看看