您的位置:首页 > 其它

跟我一起学Makefile——重点总结

2020-04-29 19:22 113 查看

《跟我一起学Makefile》文章里,个人认为比较重要的知识点总结

  1. **反斜杠(\)**是换行符的意思。这样比较便于 Makefile 的易读

  2. make 会比较目标文件依赖文件的修改日期,如果 依赖文件的日期要比目标文件的日期要新,或者 依赖文件不存在的话,那么,make 就会执行后续定义的命令。

  3. 如果冒号后什么也没有,那么,make 就不会自动去找文件的依赖性,例如clean:,也就不会自动执行其后所定义的命令。但是如果一个文件在最开头,是例外,不管有没有依赖,都会被当成默认目标执行。(第一个目标文件就是默认文件)

  4. 为了 makefile 的易维护,在 makefile 中我们可以使用变量。makefile 的变量也就是一个字符串,可以理解成 C 语言中的宏。变量在声明时需要给予初值,而在使用时,需要给在变量名前加上“$”符号。如果你要使用真实的“$”字符,那么你需要用“$$”来表示。

  5. 定义伪目标更为稳健的做法是:

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

    .PHONY 意思表示 clean 是一个“伪目标”。不成文的规矩是——“clean 从来都是放在文件的最后”
    一个示例就是,如果你的 Makefile 需要一口气生成若干个可执行文件,但你只想简单地敲一个 make 完事,并且,所有的目标文件都写在一个 Makefile 中,那么你可以使用“伪目标”这个特性:(伪目标放在最前面,是默认目标,相当于指定了,所以也一定会执行)

    all : prog1 prog2 prog3
    .PHONY : all
    prog1 : prog1.o utils.o
    cc -o prog1 prog1.o utils.o
    prog2 : prog2.o
    cc -o prog2 prog2.o
    prog3 : prog3.o sort.o utils.o
    cc -o prog3 prog3.o sort.o utils.o
  6. 注释是用“#”字符

  7. 在 Makefile 使用 include 关键字可以把别的Makefile 包含进来,include 的语法是:

    include <filename>
    ,
    include
    绝不能是[Tab]键开始。
    include
    <filename>
    可以用一个或多个空格隔开

    include foo.make *.mk $(bar)
    等价于:
    include foo.make a.mk b.mk c.mk e.mk f.mk
  8. 规则包含两个部分,一个是依赖关系,一个是生成目标的方法。Makefile 中只应该有一个最终目标,第一条规则中的目标将被确立为最终的目标

  9. 如果我们的文件名中有通配符,如:“*”,那么可以用转义字符“\”,如“

    \*
    "来表示真实的“*”字符,而不是任意长度的字符串

  10. objects = *.o
    上面这个例子,表示了,通符同样可以用在变量中。 但[*.o]不会展开,objects的值就是“*.o”。Makefile 中的变量其实就是 C/C++中的宏。如果你要让通配符在变量中展开,也就是让 objects 的值是所有[.o]的文件名的集合,那么,你可以这样:objects := $(wildcard *.o)

  11. 当 make 需要去找寻文件的依赖关系时,你可以在文件前加上路径

  12. 静态模式

    <targets ...>: <target-pattern>: <prereq-patterns ...>
    <commands>

    $(objects): %.o: %.c 表示objects中的.o文件的依赖是.c   其中 .o文件是属于objects里面定义的

  13. make 会把其要执行的命令行在命令执行前输出到屏幕上。当我们用“@”字符在命令行前,那么,这个命令将不被 make 显示出来。如:

    @echo 正在编译 XXX 模块......

    当 make 执行时,会输出“
    正在编译 XXX 模块......
    ”字串,但不会输出命令,如果没有“@”,那么,make 将输出:
    echo 正在编译 XXX 模块......正在编译 XXX 模块......

  14. make 参数“-n”,那么其只是显示命令,但不会执行命令。可以查看makefile有没有写错

  15. make 参数“-s”则是静默输出 。

    make -s
    禁止显示命令,但是命令执行了,这样方便修改err和warning

  16. -d 相当于debug  -f 指定需要的makefile  -i忽略所有的错误 VPATH指定依赖文件路径  -I指定头文件所在的目录  -v输出make的版本

  17. 定义命令包(多行变量)。定义这种命令序列的语法以“define”开始,以“endef”结束,如:

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

    可以这么使用

    foo.c : foo.y
    $(run-yacc)
  18. 注意=  :=   ?=  这三种等号的区别

  19. 如果我们要定义一个变量,其值是一个空格,那么我们可以这样来:

    nullstring :=
    space := $(nullstring)  # end of the line

    nullstring 是一个 Empty 变量,其中什么也没有,而我们的 space 的值是一个空格。先用一个 Empty 变量来标明变量的值开始了,而后面采用“#”注释符来表示变量定义的终止。如果直接用

    space := #
    将不会有空格。必须前面要先从一个变量算起,再用#,才会有空格因此这里需要定义一个空变量。另外,
    dir := /foo/bar  #
     只要#符号离末尾距离大于1(2345678等等),都只会空一个空格。

  20. 变量的高级用法:第一种是变量值的替换

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

    另外一种变量替换的技术是以“静态模式”(参见前面章节)定义的,如:

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

    第二种高级用法是——“把变量的值再当成变量”

    x = variable1
    variable2 := Hello
    y = $(subst 1,2,$(x))
    z = y
    a := $($($(z)))
    first_second = Hello
    a = first
    d
    all = $($a_$b)
  21. 追加变量值
    我们可以使用“+=”操作符给变量追加值,如:

    objects = main.o foo.o bar.o utils.o
    objects += another.o
  22. 使用条件判断:ifeq ifneq ifdef ifndef
    ifeq格式:

    <conditional-directive>
    <text-if-true>
    else
    <text-if-false>
    endif

    <conditional-directive>
    这一行上,多余的空格是被允许的,但是不能以[Tab]键做
    为开始(不然就被认为是命令)。包括定义变量时,不能有tab,但是可以有空格,因为tab后代表命令

    示例:

    ifeq ($(CC),gcc)
    libs=$(libs_for_gcc)
    else
    libs=$(normal_libs)
    endif
    ifneq (<arg1>, <arg2>)

    ifdef格式:

    ifdef <variable-name>
    如果变量
    <variable-name>
    的值非空,那到表达式为真。否则,表达式为假。

    示例:

    foo =
    ifdef foo
    frobozz = yes
    else
    frobozz = no
    endif

    特别注意的是,make 是在读取 Makefile 时就计算条件表达式的值,并根据条件表达式
    的值来选择语句,所以,你最好不要把自动化变量(如“$@”等)放入条件表达式中

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

    $(<function> <arguments>)

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

  24. 字符串处理函数 subst
    $(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”。

  25. 模式字符串替换函数——patsubst
    $(patsubst <pattern>,<replacement>,<text>)
    示例:
    $(patsubst %.c,%.o,x.c.c bar.c)
    把字串“x.c.c bar.c”符合模式[%.c]的单词替换成[%.o],返回结果是“x.c.o bar.o”
    “$(objects:.o=.c)”和“$(patsubst %.o,%.c,$(objects))”是一样的。

  26. 取目录函数——dir。
    $(dir <names…>)
    功能:从文件名序列<names>中取出目录部分。目录部分是指最后一个反斜杠(“/”)之前
    的部分。如果没有反斜杠,那么返回“./”。
    返回:返回文件名序列<names>的目录部分。
    示例: $(dir src/foo.c hacks)返回值是“src/ ./”。

  27. 取文件函数——notdir。
    $(notdir <names…>)  .  
    功能:从文件名序列<names>中取出非目录部分。非目录部分是指最后一个反斜杠(“ /”)
    之后的部分。
    返回:返回文件名序列<names>的非目录部分。
    示例: $(notdir src/foo.c hacks)返回值是“foo.c hacks”。

  28. foreach 函数 用来做循环用的

    $(foreach <var>,<list>,<text>)
    把参数<list>中的单词逐一取出放到参数<var>所指定的变量中,然后再执行<text>所包含的表达式
    <var>最好是一个变量名,<list>可以是一个表达式,而<text>中一般会使用<var>
    这个参数来依次枚举<list>中的单词。举个例子:

    names := a b c d
    files := $(foreach n,$(names),$(n).o)
    一般我们可以使用“$(wildcard *.c)”来获取工作目录下的所有的.c文件列表

    foreach 中的<var>参数是一个临时的局部变量,foreach 函数执行完后,参数
    <var>的变量将不在作用,其作用域只在 foreach 函数当中

  29. 函数 wildcard
    通配符“%”只能用在规则中,只有在规则中它才会展开,如果在变量定义和函数使用时,通配符不会自动展开,这个时候就要用到函数 wildcard

  30. 我们可以给 make 命令指定一个特殊名字的 Makefile。要使用 make 的“-f”参数。

    make –f hchen.mk
  31. 有一点需要注意的是,"%“的展开发生在变量和函数的展开之后,变量和函数的展开发
    生在 make 载入 Makefile 时,而模式规则中的”%"则发生在运行时。

  32. $@  规则中的目标集合

  33. $<  依赖文件集合的第一个文件,是符合规则的一系列依赖文件的集合

  34. $^  规则中所有的依赖文件集合

  35. gcc 命令的时候加上-o 来指定生成的可执行文件名字

  36. -c: 只编译不链接为可执行文件,编译器将输入的.c 文件编译为.o 的目标文件。
    -o: <输出文件名>用来指定编译结束以后的输出文件名,如果使用这个选项的话 GCC 默认编译出来的可执行文件名字为 a.out。
    -O: 对程序进行优化编译

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: