• Makefile(make)常见规则(二)


    Makefile(make)常见规则

    Author:Once day date:2022年7月28日

    推荐参考文档:makefile隐含规则_csdn博客_陈皓

    1.make的运行规则

    make命令执行后有三个退出码:

    • 0,表示成功执行

    • 1,如果make运行时出现任何错误,其返回1

    • 2,如果你使用了make的“-q”选项,并且make使得一些目标不需要更新,那么返回2。

    2.指定Makefile文件名字

    默认的情况下一般采用“Makefile”和“makefile”的默认文件名。

    可以使用-f--file参数来指定文件:

    make -f onceday.mk
    
    • 1

    3.指定目标

    一般makefile的最终目标是makefile中的第一个目标,其他的目标一般是由这个目标连带出来。

    可以通过以下语句来制定目标:

    make label
    
    • 1

    有一个make的环境变量叫“MAKECMDGOALS”,会存放所指定的终极目标的列表,如果命令行上,没有指定目标,那么这个变量是空值。

    配合使用终极目标和伪目标:

    .PHONY: all
    all: once day
    
    • 1
    • 2

    当执行make all便会同时完成onceday两个目标。

    GNU常用的伪目标名称有以下这些(具体功能需要自己实现)

    • “all”,编译所有的目标

    • “clean”,删除所有被make创建的文件

    • “install”,安装已编译好的程序 ,本质是把目标执行文件拷贝到指定目标中

    • “print”,列出改变过的源文件

    • “tar”, 把源程序打包备份,生成tar文件

    • “dist”,创建一个压缩文件, 一般是把tar文件压成Z文件 ,或者gz文件。

    • “TAGS”,更新所有的目标,以备完整地

    • ”check“和”test“,用来测试makefile的流程

    4.make检查规则

    不让makefile中的规则执行起来,只想检查一下我们的命令,或是执行的序列。

    "-n"
    "--just-print"
    "--dry-run"
    "--recon"
    
    • 1
    • 2
    • 3
    • 4

    不执行参数,这些参数只是打印命令,不管目标是否更新,把规则和连带规则下的命令打印出来,但不执行。

    "-t"
    "--touch"
    
    • 1
    • 2

    这个参数的意思就是把目标文件的时间更新,但不更改目标文件。也就是说,make假装编译目标,但不是真正的编译目标,只是把目标变成已编译过的状态。

    "-q"
    "--question"
    
    • 1
    • 2

    这个参数的行为是找目标的意思,也就是说,如果目标存在,那么其什么也不会输出,当然也不会执行编译,如果目标不存在,其会打印出一条出错信息。

    "-W "
    "--what-if="
    "--assume-new="
    "--new-file="
    
    • 1
    • 2
    • 3
    • 4

    这个参数需要指定一个文件。一般是是源文件(或依赖文件),Make会根据规则推导来运行依赖于这个文件的命令,一般来说,可以和“-n”参数一同使用,来查看这个依赖文件所发生的规则命令。

    5.make的参数

    5.1 忽略和其他版本的兼容性
    "-b"
    "-m"
    
    • 1
    • 2
    5.2 认为所有的目标都需要更新(重编译)
    "-B"
    "--always-make"
    
    • 1
    • 2
    5.3 指定读取makefile的目录
    "-C "
    "--directory="
    make -C once/once -C day
    make -C once/once/day    #这两条语句等价
    
    • 1
    • 2
    • 3
    • 4

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

    5.4 输出调试信息
    "-d"
    "--debug[=options]"
    
    • 1
    • 2

    --debug输出最简单的调试信息,-d输出所有的调式信息。

    以下是可选的几个级别:

    • a:all,输出所有的调试信息

    • b:basic,只输出简单的调试信息,即不需要重编译的目标

    • v:verbose,输出的信息包括哪个makefile被解析,不需要被重编译的依赖文件(或是依赖目标)等

    • i:implicit,输出所有的隐含规则

    • j:jobs:输出执行规则中命令的详细信息,如命令的PID,返回码等

    • m:makefile,输出make读取makefile,更新makefile,执行makefile的信息

    5.5 指明环境变量的值覆盖makefile中定义的变量的值。
    "-e"
    "--environment-overrides"
    
    • 1
    • 2
    5.6 指明需要执行的makefile
    "-f="
    "--file="
    "--makefile="
    
    • 1
    • 2
    • 3
    5.7 执行时忽略所有的错误
    "-i"
    "--ignore-errors"
    
    • 1
    • 2
    5.8 指定一个包含makefile的搜索目录
    "-I "
    "--include-dir="
    
    • 1
    • 2

    可以使用多个“-I”参数来指定多个目录

    5.9 同时运行命令的个数
    "-j []"
    "--jobs[=]"
    
    • 1
    • 2

    如果没有这个参数,make运行命令时能运行多少就运行多少。

    5.10 出错也不停止运行
    "-k"
    "--keep-going"
    
    • 1
    • 2

    如果生成一个目标失败了,那么依赖于其上的目标就不会被执行了

    5.11 指定make运行命令的负载
    "-l "
    "--load-average[=]"
    "--max-load[=]"
    
    • 1
    • 2
    • 3
    5.12 不重新生成指定的file,即使作为其他目标的依赖文件
    "-o "
    "--old-file="
    "--assume-old="
    
    • 1
    • 2
    • 3
    5.13 输出makefile中的所有数据
    "-p"
    "--print-data-base"
    
    • 1
    • 2

    输出makefile中的所有数据,包括所有的规则和变量。

    只想输出信息而不想执行makefile,可以使用make -qp

    查看执行makefile前的预设变量和规则,可以使用make -p -f /dev/null

    5.14 检查所指定的目标是否需要更新
    "-q"
    "--question"
    
    • 1
    • 2

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

    5.15 禁止make使用任何隐含规则
    "-r"
    "--no-builtin-rules"
    
    • 1
    • 2
    5.16 禁止make使用任何作用于变量上的隐含规则
    "-R"
    "--no-builtin-variables"
    
    • 1
    • 2
    5.17 在命令运行时不输出命令的输出
    "-s"
    "--silent"
    "--quiet"
    
    • 1
    • 2
    • 3
    5.18 取消参数-k的作用
    "-S"
    "--no-keep-going"
    "--stop"
    
    • 1
    • 2
    • 3
    5.19 输出目录信息
    "-w"
    "--print-directory"
    #以下命令禁止“-w”选项
    "--no-print-directory"
    
    • 1
    • 2
    • 3
    • 4
    5.20 输出警告信息
    "--warn-undefined-variables"
    
    • 1

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

    6.隐含规则

    make会有一些默认的规则,如根据[.o]文件反推出[.c]文件。

    没有必要使用隐含规则,因此这里省略。

    具体参考:makefile隐含规则_csdn博客_陈皓

    一般使用以下几个变量:

    • CC,默认gcc

    • CXX,默认g++

    • CFLAGS,C语言编译器参数

    • CXXFLAGS,C++语言编译器参数

    7.定义模式规则

    "%“的展开发生在变量和函数的展开之后,变量和函数的展开发生在make载入Makefile时,而模式规则中的”%"则发生在运行时。

    一个模式规则就好像一个一般的规则,只是在规则中,目标的定义需要有"%“字符。”%“的意思是表示一个或多个任意字符。在依赖目标中同样可以使用”%“,只是依赖目标中的”%"的取值,取决于其目标。

    示例:

    %.o :%.c
    $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
    
    • 1
    • 2

    可以把所有的[.c]文件都编译成[.o]文件。

    8.自动化变量

    所谓自动化变量,就是这种变量会把模式中所定义的一系列的文件自动地挨个取出,直至所有的符合模式的文件都取完了。这种自动化变量只应出现在规则的命令中。

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

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

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

    • $?,所有比目标新的依赖目标的集合。以空格分隔。

    • $^,所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。

    • $+,所有依赖目标的集合,但是不去除重复的依赖目标。

    • $*,表示目标模式中"%“及其之前的部分,如果目标是"dir/a.foo.b”,并且目标的模式是"a.%.b",那么,"$*“的值就是"dir/a.foo”。

    9.模式匹配规则

    模式匹配的茎有以下两种:

    %.c  #1245.c
    src/1%5.c    #src/1245.c
    
    • 1
    • 2

    对于%.c其茎为:1245,对于src/a%c.c,其茎为:src/24。这些将被传递到这个模式的其他目标中。如%.o,则两个对应的是1245.osrc/24.c

    可以像以下这样重载内建隐含规则:

    %.o :%.c
        $(CC) -c $(CPPFLAGS) $(CFLAGS) -D$(date)
    
    • 1
    • 2

    如果命令处空白,则等价于取消内建的隐含规则。

    make会对内建的后缀规则(如.o,.c)自动使用模式匹配,如果其对应的隐含规则所需的依赖文件存在,那么就会采纳该隐藏规则!

    可以取消隐藏规则,来加快处理速度,以及避免未知错误。

    10.使用make更新函数库文件

    函数库文件也就是对Object文件(程序编译的中间文件)的打包文件。在Unix下,一般是由命令"ar"来完成打包工作。

    一个函数库文件由多个文件组成,以如下格式指定函数库文件及其组成:archive(member)

    foolib(once.o day.o)
    foolib(*.o)
    
    • 1
    • 2

    括号类的成员会被当前目标来搜索,因此,它依赖于隐藏规则来工作。

    可借助后缀规则和隐含规则来生成函数库打包文件。

    (%.o) : %.c
    $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $*.o
    $(AR) r $@ $*.o
    $(RM) $*.o
    
    • 1
    • 2
    • 3
    • 4


    makefile+make的入门学习到此结束了,路漫漫其修远兮,有缘再见!

  • 相关阅读:
    WEB网页设计期末作业个人主页——基于HTML+CSS制作个人简介网站
    count(*)查询性能很差?用这5招轻松优化
    语义化标签
    【Python】模块
    List集合之UML、特点、遍历方式、迭代器原理、泛型、装拆箱及ArrayList、LinkedList和Vector的区别
    【图解大数据技术】流式计算:Spark Streaming、Flink
    【c++】四种类型转换的用法
    初识Cpp之 六、内存分配
    Kotlin 进阶 学习 委托
    【SpringBoot+微信小程序】公交线路查询系统(源码+远程部署+代码讲解+答辩教学)
  • 原文地址:https://blog.csdn.net/Once_day/article/details/126038144