• make命令语法学习


    基本概念

    • 需要得到什么就make什么,比如 make abc.txt 得到一个文本文件,make image 得到一个docker 镜像 , 等等。
    • 一般来说使用 make命令的目录下应该一个名为 Makefile的文件。 make -f <makefile> 使用自定义的文件名。
    • Makefile 是一组规则的集合,他们给出了得到目标(target)所需的所有步骤,好比做一道菜需要的所有原料和工艺流程。
    • 规则的基本语法为:
     <target>: <prerequisites...>
        <commands>
    

    其中 target 是必须的,prerequisites和commands非必需,但二者必有其一。

    • 如果只打 make,默认构建第一个目标。
    • make 默认会输出其将要执行的命令,如果不想看到这些输出,可以在命令前加@。
    • make命令列表中的每一行命令,都会在一个独立的shell中执行,因此上一行命令中设置的变量在下一行中不可用。
    • make 的赋值符号是 := 而不是 =

    make中的特殊变量,美元符号

    1. $@ 表示当前正在制作(make)的目标文件。比如 make foo, 那么 $@ 就是 foo。 助记:@表示argument。
    2. $< 表示一个输入文件(先决条件中的第一个)。 助记:< 是bash中的文件输入符。
    3. $^ 所有输入文件, 多次出现的文件在其中仅出现一次。 助记:< 竖起来就是 ^。
    4. $? 所有比target新的输入文件。 助记:? 好比一个问题:“你为什么做这个? 更改了哪些文件以使其必需?”。
    5. $$ 真正的美元符号。
    6. $* 规则中百分号%匹配的东西。 助记: 在make中,百分号%相当于shell中的星号*。
    7. $(@D) 和 $(@F) 分别匹配$@ 的路径部分和文件部分。以上其他变量同理,比如$(<D) 和 $(<F)。
    8. 使用make特殊变量的例子:
      之前:
    result.txt: source.txt
    	@echo "building result.txt from source.txt"
    	cp source.txt result.txt
    source.txt:
    	@echo "building source.txt"
    	echo "this is the source" > source.txt
    

    终端输出:

    building source.txt
    echo "this is the source" > source.txt
    building result.txt from source.txt
    cp source.txt result.txt
    

    现在:

    result-using-var.txt: source.txt
    	@echo "buildling result-using-var.txt using the $$< and $$@ vars"
    	cp $< $@
    

    终端输出:

    buildling result-using-var.txt using the $< and  vars
    cp source.txt result-using-var.txt
    

    使用通配符%批量生成文件

    src/%.txt:
    	@# First things first, create the dir if it doesn't exist.
    	@# Prepend with @ because srsly who cares about dir creation
    	@[ -d src ] || mkdir src
    	@# then, we just echo some data into the file
    	@# The $* expands to the "stem" bit matched by %
    	@# So, we get a bunch of files with numeric names, containing their number
    	echo $* > $@
    

    在终端输入: make src/01.txt 终端输出: echo 01 > src/01.txt 。 src目录下生成 01.txt 文件, 内容为:01。
    这样只能一个个文件依次生成。现在添加下面几行:

    srcfiles := $(shell echo src/{00..99}.txt)
    source: $(srcfiles)
    

    在终端输入: make source , 此时批量生成了100个文件。

    echo 0 > src/0.txt
    echo 1 > src/1.txt
    echo 2 > src/2.txt
    echo 3 > src/3.txt
    echo 4 > src/4.txt
    echo 5 > src/5.txt
    echo 6 > src/6.txt
    echo 7 > src/7.txt
    echo 8 > src/8.txt
    echo 9 > src/9.txt
    echo 10 > src/10.txt
    echo 11 > src/11.txt
    echo 12 > src/12.txt
    echo 13 > src/13.txt
    echo 14 > src/14.txt
    echo 15 > src/15.txt
    echo 16 > src/16.txt
    echo 17 > src/17.txt
    echo 18 > src/18.txt
    echo 19 > src/19.txt
    echo 20 > src/20.txt
    echo 21 > src/21.txt
    echo 22 > src/22.txt
    echo 23 > src/23.txt
    echo 24 > src/24.txt
    echo 25 > src/25.txt
    echo 26 > src/26.txt
    echo 27 > src/27.txt
    echo 28 > src/28.txt
    echo 29 > src/29.txt
    echo 30 > src/30.txt
    echo 31 > src/31.txt
    echo 32 > src/32.txt
    echo 33 > src/33.txt
    echo 34 > src/34.txt
    echo 35 > src/35.txt
    echo 36 > src/36.txt
    echo 37 > src/37.txt
    echo 38 > src/38.txt
    echo 39 > src/39.txt
    echo 40 > src/40.txt
    echo 41 > src/41.txt
    echo 42 > src/42.txt
    echo 43 > src/43.txt
    echo 44 > src/44.txt
    echo 45 > src/45.txt
    echo 46 > src/46.txt
    echo 47 > src/47.txt
    echo 48 > src/48.txt
    echo 49 > src/49.txt
    echo 50 > src/50.txt
    echo 51 > src/51.txt
    echo 52 > src/52.txt
    echo 53 > src/53.txt
    echo 54 > src/54.txt
    echo 55 > src/55.txt
    echo 56 > src/56.txt
    echo 57 > src/57.txt
    echo 58 > src/58.txt
    echo 59 > src/59.txt
    echo 60 > src/60.txt
    echo 61 > src/61.txt
    echo 62 > src/62.txt
    echo 63 > src/63.txt
    echo 64 > src/64.txt
    echo 65 > src/65.txt
    echo 66 > src/66.txt
    echo 67 > src/67.txt
    echo 68 > src/68.txt
    echo 69 > src/69.txt
    echo 70 > src/70.txt
    echo 71 > src/71.txt
    echo 72 > src/72.txt
    echo 73 > src/73.txt
    echo 74 > src/74.txt
    echo 75 > src/75.txt
    echo 76 > src/76.txt
    echo 77 > src/77.txt
    echo 78 > src/78.txt
    echo 79 > src/79.txt
    echo 80 > src/80.txt
    echo 81 > src/81.txt
    echo 82 > src/82.txt
    echo 83 > src/83.txt
    echo 84 > src/84.txt
    echo 85 > src/85.txt
    echo 86 > src/86.txt
    echo 87 > src/87.txt
    echo 88 > src/88.txt
    echo 89 > src/89.txt
    echo 90 > src/90.txt
    echo 91 > src/91.txt
    echo 92 > src/92.txt
    echo 93 > src/93.txt
    echo 94 > src/94.txt
    echo 95 > src/95.txt
    echo 96 > src/96.txt
    echo 97 > src/97.txt
    echo 98 > src/98.txt
    echo 99 > src/99.txt
    

    养成添加伪目标(phony)的好习惯

    伪目标是为了防止这样一种情况出现: 比如上文出现的source,其本身并不是为了生成什么文件,只是执行一条命令或操作,此时假设当前目录下恰好有一个文件名为source,那么这条make命令就不会被执行,因为make认为需要生成的目标已经存在。
    添加伪目标: .PHONY: source, 使得无论什么情况下输入 make source, make都会执行source下的操作。

    生成目标文件

    添加以下内容:

    dest/%.txt: src/%.txt
    	@[ -d dest ] || mkdir dest
    	cp $< $@
    

    此时输入 make dest/02.txt, 终端输出:

    echo 02 > src/02.txt
    cp src/02.txt dest/02.txt
    rm src/02.txt
    

    src目录下无文件, dest目录下有一个文件 02.txt
    但是现在这样只能一次生成一个目标文件,如何批量生成呢?
    加入以下内容:

    .PHONY: destination
    destfiles := $(patsubst src/%.txt,dest/%.txt,$(srcfiles))
    destination: $(destfiles)
    

    输入 make destination, 终端输出

    echo 0 > src/0.txt
    cp src/0.txt dest/0.txt
    echo 1 > src/1.txt
    cp src/1.txt dest/1.txt
    echo 2 > src/2.txt
    cp src/2.txt dest/2.txt
    echo 3 > src/3.txt
    cp src/3.txt dest/3.txt
    echo 4 > src/4.txt
    cp src/4.txt dest/4.txt
    echo 5 > src/5.txt
    cp src/5.txt dest/5.txt
    echo 6 > src/6.txt
    cp src/6.txt dest/6.txt
    echo 7 > src/7.txt
    cp src/7.txt dest/7.txt
    echo 8 > src/8.txt
    cp src/8.txt dest/8.txt
    echo 9 > src/9.txt
    cp src/9.txt dest/9.txt
    echo 10 > src/10.txt
    cp src/10.txt dest/10.txt
    echo 11 > src/11.txt
    cp src/11.txt dest/11.txt
    echo 12 > src/12.txt
    cp src/12.txt dest/12.txt
    echo 13 > src/13.txt
    cp src/13.txt dest/13.txt
    echo 14 > src/14.txt
    cp src/14.txt dest/14.txt
    echo 15 > src/15.txt
    cp src/15.txt dest/15.txt
    echo 16 > src/16.txt
    cp src/16.txt dest/16.txt
    echo 17 > src/17.txt
    cp src/17.txt dest/17.txt
    echo 18 > src/18.txt
    cp src/18.txt dest/18.txt
    echo 19 > src/19.txt
    cp src/19.txt dest/19.txt
    echo 20 > src/20.txt
    cp src/20.txt dest/20.txt
    echo 21 > src/21.txt
    cp src/21.txt dest/21.txt
    echo 22 > src/22.txt
    cp src/22.txt dest/22.txt
    echo 23 > src/23.txt
    cp src/23.txt dest/23.txt
    echo 24 > src/24.txt
    cp src/24.txt dest/24.txt
    echo 25 > src/25.txt
    cp src/25.txt dest/25.txt
    echo 26 > src/26.txt
    cp src/26.txt dest/26.txt
    echo 27 > src/27.txt
    cp src/27.txt dest/27.txt
    echo 28 > src/28.txt
    cp src/28.txt dest/28.txt
    echo 29 > src/29.txt
    cp src/29.txt dest/29.txt
    echo 30 > src/30.txt
    cp src/30.txt dest/30.txt
    echo 31 > src/31.txt
    cp src/31.txt dest/31.txt
    echo 32 > src/32.txt
    cp src/32.txt dest/32.txt
    echo 33 > src/33.txt
    cp src/33.txt dest/33.txt
    echo 34 > src/34.txt
    cp src/34.txt dest/34.txt
    echo 35 > src/35.txt
    cp src/35.txt dest/35.txt
    echo 36 > src/36.txt
    cp src/36.txt dest/36.txt
    echo 37 > src/37.txt
    cp src/37.txt dest/37.txt
    echo 38 > src/38.txt
    cp src/38.txt dest/38.txt
    echo 39 > src/39.txt
    cp src/39.txt dest/39.txt
    echo 40 > src/40.txt
    cp src/40.txt dest/40.txt
    echo 41 > src/41.txt
    cp src/41.txt dest/41.txt
    echo 42 > src/42.txt
    cp src/42.txt dest/42.txt
    echo 43 > src/43.txt
    cp src/43.txt dest/43.txt
    echo 44 > src/44.txt
    cp src/44.txt dest/44.txt
    echo 45 > src/45.txt
    cp src/45.txt dest/45.txt
    echo 46 > src/46.txt
    cp src/46.txt dest/46.txt
    echo 47 > src/47.txt
    cp src/47.txt dest/47.txt
    echo 48 > src/48.txt
    cp src/48.txt dest/48.txt
    echo 49 > src/49.txt
    cp src/49.txt dest/49.txt
    echo 50 > src/50.txt
    cp src/50.txt dest/50.txt
    echo 51 > src/51.txt
    cp src/51.txt dest/51.txt
    echo 52 > src/52.txt
    cp src/52.txt dest/52.txt
    echo 53 > src/53.txt
    cp src/53.txt dest/53.txt
    echo 54 > src/54.txt
    cp src/54.txt dest/54.txt
    echo 55 > src/55.txt
    cp src/55.txt dest/55.txt
    echo 56 > src/56.txt
    cp src/56.txt dest/56.txt
    echo 57 > src/57.txt
    cp src/57.txt dest/57.txt
    echo 58 > src/58.txt
    cp src/58.txt dest/58.txt
    echo 59 > src/59.txt
    cp src/59.txt dest/59.txt
    echo 60 > src/60.txt
    cp src/60.txt dest/60.txt
    echo 61 > src/61.txt
    cp src/61.txt dest/61.txt
    echo 62 > src/62.txt
    cp src/62.txt dest/62.txt
    echo 63 > src/63.txt
    cp src/63.txt dest/63.txt
    echo 64 > src/64.txt
    cp src/64.txt dest/64.txt
    echo 65 > src/65.txt
    cp src/65.txt dest/65.txt
    echo 66 > src/66.txt
    cp src/66.txt dest/66.txt
    echo 67 > src/67.txt
    cp src/67.txt dest/67.txt
    echo 68 > src/68.txt
    cp src/68.txt dest/68.txt
    echo 69 > src/69.txt
    cp src/69.txt dest/69.txt
    echo 70 > src/70.txt
    cp src/70.txt dest/70.txt
    echo 71 > src/71.txt
    cp src/71.txt dest/71.txt
    echo 72 > src/72.txt
    cp src/72.txt dest/72.txt
    echo 73 > src/73.txt
    cp src/73.txt dest/73.txt
    echo 74 > src/74.txt
    cp src/74.txt dest/74.txt
    echo 75 > src/75.txt
    cp src/75.txt dest/75.txt
    echo 76 > src/76.txt
    cp src/76.txt dest/76.txt
    echo 77 > src/77.txt
    cp src/77.txt dest/77.txt
    echo 78 > src/78.txt
    cp src/78.txt dest/78.txt
    echo 79 > src/79.txt
    cp src/79.txt dest/79.txt
    echo 80 > src/80.txt
    cp src/80.txt dest/80.txt
    echo 81 > src/81.txt
    cp src/81.txt dest/81.txt
    echo 82 > src/82.txt
    cp src/82.txt dest/82.txt
    echo 83 > src/83.txt
    cp src/83.txt dest/83.txt
    echo 84 > src/84.txt
    cp src/84.txt dest/84.txt
    echo 85 > src/85.txt
    cp src/85.txt dest/85.txt
    echo 86 > src/86.txt
    cp src/86.txt dest/86.txt
    echo 87 > src/87.txt
    cp src/87.txt dest/87.txt
    echo 88 > src/88.txt
    cp src/88.txt dest/88.txt
    echo 89 > src/89.txt
    cp src/89.txt dest/89.txt
    echo 90 > src/90.txt
    cp src/90.txt dest/90.txt
    echo 91 > src/91.txt
    cp src/91.txt dest/91.txt
    echo 92 > src/92.txt
    cp src/92.txt dest/92.txt
    echo 93 > src/93.txt
    cp src/93.txt dest/93.txt
    echo 94 > src/94.txt
    cp src/94.txt dest/94.txt
    echo 95 > src/95.txt
    cp src/95.txt dest/95.txt
    echo 96 > src/96.txt
    cp src/96.txt dest/96.txt
    echo 97 > src/97.txt
    cp src/97.txt dest/97.txt
    echo 98 > src/98.txt
    cp src/98.txt dest/98.txt
    echo 99 > src/99.txt
    cp src/99.txt dest/99.txt
    

    体验make的美好

    假设现在需要一个最终的目标程序,其将所有这些文件的内容合在一起输出到一个名为kitty的文件中:

    kitty: $(destfiles)
    	@# Remember, $< is the input file, but $^ is ALL the input files.
    	@# Cat them into the kitty.
    	cat $^ > kitty
    

    输入make kitty cat kitty, 终端输出:

    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    

    修改其中一个源文件: vi src/25.txt, 将其内容改成: file 25.txt is changed!
    再次执行 make kitty cat kitty, 发现终端输出的 25 变成了 file 25.txt is changed!
    make的妙处就在于,其不会每次重新生成所有源文件,而只会重新构建源文件发生变化的那个目标文件。

    通行做法:用于测试的目标 test

    test: kitty
    	@echo "miao" && echo "tests all pass!"
    

    通常都会在makefile中加入test。此处将kitty作为先决条件,也就是kitty必须存在才能通过测试。

    通行做法:用于清理的目标 clean

    clean:
    	rm -rf *.txt src dest kitty
    

    将make生成的所有东西删除。

    make 发生错误

    make中只要有一条命令返回非零值,就会停止执行。加入以下内容:

    .PHONY: badkitty
    badkitty:
    	$(MAKE) kitty # The special var $(MAKE) means "the make currently in use"
    	false # <-- this will fail
    	echo "should not get here"
    

    输入:make badkitty, 终端输出:

    /Library/Developer/CommandLineTools/usr/bin/make kitty # The special var /Library/Developer/CommandLineTools/usr/bin/make means "the make currently in use"
    cat dest/0.txt dest/1.txt dest/2.txt dest/3.txt dest/4.txt dest/5.txt dest/6.txt dest/7.txt dest/8.txt dest/9.txt dest/10.txt dest/11.txt dest/12.txt dest/13.txt dest/14.txt dest/15.txt dest/16.txt dest/17.txt dest/18.txt dest/19.txt dest/20.txt dest/21.txt dest/22.txt dest/23.txt dest/24.txt dest/25.txt dest/26.txt dest/27.txt dest/28.txt dest/29.txt dest/30.txt dest/31.txt dest/32.txt dest/33.txt dest/34.txt dest/35.txt dest/36.txt dest/37.txt dest/38.txt dest/39.txt dest/40.txt dest/41.txt dest/42.txt dest/43.txt dest/44.txt dest/45.txt dest/46.txt dest/47.txt dest/48.txt dest/49.txt dest/50.txt dest/51.txt dest/52.txt dest/53.txt dest/54.txt dest/55.txt dest/56.txt dest/57.txt dest/58.txt dest/59.txt dest/60.txt dest/61.txt dest/62.txt dest/63.txt dest/64.txt dest/65.txt dest/66.txt dest/67.txt dest/68.txt dest/69.txt dest/70.txt dest/71.txt dest/72.txt dest/73.txt dest/74.txt dest/75.txt dest/76.txt dest/77.txt dest/78.txt dest/79.txt dest/80.txt dest/81.txt dest/82.txt dest/83.txt dest/84.txt dest/85.txt dest/86.txt dest/87.txt dest/88.txt dest/89.txt dest/90.txt dest/91.txt dest/92.txt dest/93.txt dest/94.txt dest/95.txt dest/96.txt dest/97.txt dest/98.txt dest/99.txt > kitty
    false # <-- this will fail
    make: *** [badkitty] Error 1
    

    参考资料

    Makefile

  • 相关阅读:
    [CSP-S模拟测试]:attack(支配树+LCA+bitset)
    [杂题]:C/c(二分答案)
    [杂题]:B/b(二分答案)
    二维莫队(离线)
    [CSP-S模拟测试]:联盟(搜索+树的直径)
    [CSP-S模拟测试]:蔬菜(二维莫队)
    [CSP-S模拟测试]:施工(DP+单调栈+前缀和)
    [CSP-S模拟测试]:画作(BFS+数学)
    [CSP-S模拟测试]:折射(DP)
    [CSP-S模拟测试]:养花(分块)
  • 原文地址:https://www.cnblogs.com/mrlonely2018/p/15485488.html
Copyright © 2020-2023  润新知