Makefile之运行参数

Makefile之运行参数


下一篇:练习10 Makefile之隐式规则,上一篇:练习8 Makefile之使用函数目录首页

温故知新

make 工具的用法可以有多种方式,主要取决于你在运行时是否提供参数。最简单的用法是,如果你在没有提供任何参数的情况下运行 make,它会重新编译所有过期的文件。通常,Makefile 是这样编写的,以便在不带任何参数的情况下运行 make 就能实现这个目标。

但你可能只想更新其中的一些文件;可能希望使用不同的编译器或不同的编译选项;可能只想查找哪些文件已经过期而不进行实际更改。

通过在运行 make 时提供参数,你可以执行这些操作以及其他许多操作。

make 的退出状态总是以下三个值之一:

  • 0:如果 make 成功,则退出状态为零。
  • 2:如果 make 遇到任何错误,则退出状态为两。它将打印描述特定错误的消息。
  • 1:如果使用 -q 标志,并且 make 确定某个目标尚未更新,则退出状态为一。

下一篇:练习10 Makefile之隐式规则,上一篇:练习8 Makefile之使用函数目录首页

指定Makefile的参数

make 工具中,你可以通过 -f--file 选项(--makefile 也可以)来指定 Makefile 的名称。例如,-f altmake 表示使用 altmake 文件作为 Makefile。

如果你多次使用 -f 标志,并在每个 -f 后跟一个参数,所有指定的文件将联合使用作为 Makefile。

如果你没有使用 -f--file 标志,默认情况下会尝试使用 GNUmakefilemakefileMakefile,按照这个顺序,使用首个存在或可创建的文件作为 Makefile。


下一篇:练习10 Makefile之隐式规则,上一篇:练习8 Makefile之使用函数目录首页

指定目标的论据

make 工具中,目标是 make 应该最终努力更新的目标。其他目标也会被更新,如果它们作为目标的先决条件,或作为目标的先决条件的先决条件等等。

默认情况下,目标是 Makefile 中的第一个目标(不计算以句点开头的目标)。因此,makefiles 通常是这样编写的,使得第一个目标用于编译描述的整个程序或程序。如果 Makefile 中的第一个规则有多个目标,只有规则中的第一个目标成为默认目标,而不是整个列表。你可以使用 .DEFAULT_GOAL 变量(参见其他特殊变量)在 Makefile 中管理默认目标的选择。

你还可以通过 make 命令行参数指定不同的目标。将目标名称作为参数。如果指定了多个目标,make 将按照指定的顺序依次处理它们。

在 Makefile 中的任何目标都可以指定为目标(除非它以 - 开头或包含 =,在这种情况下,它将被解析为开关或变量定义)。即使 Makefile 中不存在的目标也可以指定,如果 make 能够找到说明如何制作它们的隐含规则。

make 将特殊变量 MAKECMDGOALS 设置为你在命令行上指定的目标列表。如果在命令行上没有指定目标,此变量为空。请注意,此变量只应在特殊情况下使用。

一个适当使用的示例是在 clean 规则中避免包含 .d 文件(参见 Generating Prerequisites Automatically),这样 make 就不会创建它们,只是立即将它们删除:

sources = foo.c bar.c

ifeq (,$(filter clean,$(MAKECMDGOALS))
include $(sources:.c=.d)
endif

指定目标的一个用途是,如果你只想编译程序的一部分,或者只想编译多个程序中的一个。指定每个你想要重新制作的文件作为目标。例如,考虑一个包含多个程序的目录,其中的 makefile 开始如下:

.PHONY: all
all: size nm ld ar as

如果你正在处理 size 程序,你可能想说 make size,这样只有该程序的文件会被重新编译。

指定目标的另一个用途是制作通常不制作的文件。例如,可能有一个包含调试输出的文件,或者一个专门为测试而编译的程序版本,该版本在 Makefile 中有一个规则但不是默认目标的先决条件。

指定目标的另一个用途是运行与虚拟目标相关联的配方或空目标。许多 Makefile 包含一个名为 clean 的虚拟目标,它删除除源文件以外的所有内容。当你明确使用 make clean 时,才会执行此操作。以下是典型的虚拟和空目标名称列表。

  • all: 制作 Makefile 知道的所有顶级目标。
  • clean: 删除通过运行 make 通常创建的所有文件。
  • mostlyclean: 类似于 clean,但可能不删除人们通常不希望重新编译的一些文件。例如,GCC 的 mostlyclean 目标不会删除 libgcc.a,因为很少需要重新编译它,而且需要很长时间。
  • distclean, realclean, clobber: 这些目标中的任何一个都可能被定义为删除比 clean 更多的文件。例如,这将删除通常由 make 自动创建的配置文件或链接,即使 Makefile 本身不能创建这些文件。
  • install: 将可执行文件复制到用户通常搜索命令的目录;将可执行文件使用的任何辅助文件复制到它们将查找它们的目录中。
  • print: 打印已更改的源文件的列表。
  • tar: 创建源文件的 tar 文件。
  • shar: 创建源文件的 shell 存档(shar 文件)。
  • dist: 创建源文件的发布文件。这可能是一个 tar 文件、一个 shar 文件、上述任意一个的压缩版本,甚至是上述多个的压缩版本。
  • TAGS: 为此程序更新标签表。
  • check, test: 对此 Makefile 构建的程序执行自检。

下一篇:练习10 Makefile之隐式规则,上一篇:练习8 Makefile之使用函数目录首页

代替执行配方

make 工具中,有一些选项可以指定 make 执行的操作而不是更新目标。

  • -n--just-print--dry-run--recon:这是一个“不执行”操作,它使 make 打印出为使目标更新而需要执行的命令,但实际上并不执行它们。请注意,即使使用了此标志,仍然会执行一些配方。此外,仍然会执行用于更新包含的 Makefile 的任何配方。

    make -n
    
  • -t--touch:这是一个“Touch”操作,它将目标标记为已更新,但实际上并不更改它们。换句话说,make 假装更新目标,但实际上并没有改变它们的内容;只是它们的修改时间被更新了。

    make -t
    
  • -q--question:这是一个“Question”操作,它会静默地检查目标是否已更新,但不执行配方;退出代码显示是否需要进行任何更新。

    make -q
    
  • -W file--what-if=file--assume-new=file--new-file=file:“What if”操作。每个 -W 标志后面都跟着一个文件名。make 记录给定文件的修改时间为当前时间,尽管实际的修改时间保持不变。可以与 -n 标志一起使用,以查看如果修改特定文件会发生什么。

    make -n -W file
    

请注意,-n-t-q 选项不会影响以 + 字符开始或包含字符串 $(MAKE)${MAKE} 的配方行。请注意,只有包含 + 字符或字符串 $(MAKE)${MAKE} 的行才会运行,而不管这些选项如何。规则中的其他行除非以 + 开头或包含 $(MAKE)${MAKE},否则不会运行。

-t 标志阻止虚拟目标被更新,除非有以 + 开头或包含 $(MAKE)${MAKE} 的配方行。

-W 标志提供了两个功能:

  • 如果还使用 -n-q 标志,则可以查看如果修改某些文件,make 会执行什么操作。
  • 如果没有 -n-q 标志,当 make 实际执行配方时,-W 标志可以指示 make 假装某些文件已被修改,而实际上并没有运行这些文件的配方。

请注意,选项 -p-v 允许您获取关于 make 或正在使用的 Makefile 的其他信息。


下一篇:练习10 Makefile之隐式规则,上一篇:练习8 Makefile之使用函数目录首页

避免重新编译某些文件

在修改了某个源文件但不想重新编译所有依赖它的文件时,可以使用 -t 标志。这个标志告诉 make 不要运行规则中的命令,而是通过更改目标的最后修改日期将其标记为最新。可以按照以下步骤进行操作:

  1. 使用命令 make 重新编译确实需要重新编译的源文件,确保在开始之前对象文件是最新的。
  2. 在头文件中进行更改。
  3. 使用命令 make -t 标记所有对象文件为最新。下次运行 make 时,对头文件的更改将不会引起任何重新编译。

如果在一些文件确实需要重新编译的时候已经更改了头文件,那么做此操作已经为时过晚。相反,可以使用 -o file 标志,该标志将指定的文件标记为“旧文件”。这意味着文件本身将不会被重新创建,也不会因此重新创建其他文件。按照以下步骤操作:

  1. 使用 make -o headerfile 重新编译独立于特定头文件的原因需要编译的源文件。如果涉及多个头文件,为每个头文件使用单独的 -o 选项。
  2. 使用 make -t 触摸所有对象文件。

下一篇:练习10 Makefile之隐式规则,上一篇:练习8 Makefile之使用函数目录首页

覆盖变量

在命令行参数中包含 ‘=’ 的参数指定了一个变量的值:‘v=x’ 将变量 v 的值设置为 x。如果以这种方式指定了一个值,那么 Makefile 中对同一变量的所有常规赋值都会被忽略;我们说它们被命令行参数覆盖。

使用这个功能的最常见方式是向编译器传递额外的标志。例如,在一个正确编写的 Makefile 中,变量 CFLAGS 被包含在每个运行 C 编译器的规则中,所以一个名为 foo.c 的文件会被编译成这样:

cc -c $(CFLAGS) foo.c

因此,无论你为 CFLAGS 设置什么值,都会影响每一次编译。Makefile 可能会为 CFLAGS 指定通常的值,例如:

CFLAGS=-g

每次运行 make 时,你都可以覆盖这个值。例如,如果你执行 ‘make CFLAGS=’-g -O’',那么每次 C 编译都会使用 ‘cc -c -g -O’。

变量 CFLAGS 只是许多标准变量中的一个,这样你就可以通过这种方式更改它们。获取完整列表。

你还可以编写 Makefile 来查看用户定义的其他变量,从而使用户能够通过更改这些变量来控制 Makefile 的其他方面。

在用命令行参数覆盖变量时,可以定义递归展开变量或者简单展开变量。上面示例中展示的是递归展开变量;要创建简单展开变量,可以用 ‘:=’ 或 ‘::=’ 代替 ‘=’。但是,除非你想在你指定的值中包含一个变量引用或函数调用,否则创建哪种类型的变量并没有影响。

Makefile 有一种方式可以改变用户覆盖的变量,即使用 override 指令,该指令的语法如下:‘override variable = value’。


下一篇:练习10 Makefile之隐式规则,上一篇:练习8 Makefile之使用函数目录首页

测试程序的编译

通常情况下,当在执行 shell 命令时发生错误时,make 会立即放弃,返回非零状态。对于任何目标,都不会执行进一步的规则。错误意味着目标无法正确重建,make 会在了解到错误时立即报告。

当你正在编译刚刚修改的程序时,这通常不是你想要的。相反,你可能希望 make 尝试编译每个可以尝试的文件,以显示尽可能多的编译错误。

在这种情况下,你应该使用 ‘-k’ 或 ‘–keep-going’ 标志。这告诉 make 在放弃并返回非零状态之前继续考虑挂起目标的其他前提,如果需要的话,重新生成它们。例如,在编译一个对象文件时发生错误,‘make -k’ 将继续编译其他对象文件,即使它已经知道链接它们将是不可能的。除了在 shell 命令失败后继续执行外,‘make -k’ 还会在发现无法生成目标或前提文件时尽可能继续。这总会导致错误消息,但是如果没有 ‘-k’,这将是致命错误。

make 的通常行为假定你的目的是使目标保持最新;一旦 make 了解到这是不可能的,它可能会立即报告失败。‘-k’ 标志表示真正的目的是尽可能测试程序中所做的更改,也许是为了找到几个独立的问题,以便在下一次尝试编译之前纠正它们。这就是为什么 Emacs 的 M-x compile 命令默认传递 ‘-k’ 标志的原因。


下一篇:练习10 Makefile之隐式规则,上一篇:练习8 Makefile之使用函数目录首页

临时文件

在某些情况下,make 需要创建自己的临时文件。在运行 make 期间,这些文件不能被干扰,包括所有递归调用的 make 实例。

如果环境变量 MAKE_TMPDIR 被设置,那么 make 创建的所有临时文件都会放在那里。

如果 MAKE_TMPDIR 没有设置,那么将使用当前操作系统的标准位置用于临时文件。对于 POSIX 系统,这将是在 TMPDIR 环境变量中设置的位置,否则将使用系统的默认位置(例如,/tmp)。在 Windows 上,首先检查 TMP,然后检查 TEMP,然后检查 TMPDIR,最后使用系统默认的临时文件位置。

请注意,这个目录必须已经存在,否则 make 将失败:make 不会尝试创建它。

这些变量不能在 Makefile 中设置:GNU make 在开始读取 Makefile 之前必须能够访问这个位置。


下一篇:练习10 Makefile之隐式规则,上一篇:练习8 Makefile之使用函数目录首页

选项总结

这是 make 命令可以理解的所有选项的列表:

  • ‘-b’, ‘-m’: 这些选项为了与其他版本的 make 兼容而被忽略。

  • ‘-B’, ‘–always-make’: 将所有目标都视为过时。即使其先决条件的状态不清楚,GNU make 也会继续考虑这些目标,并使其全部重新生成。

  • ‘-C dir’, ‘–directory=dir’: 在读取 Makefile 之前切换到目录 dir。如果有多个 ‘-C’ 选项,每个都相对于前一个解释。通常与递归调用 make 一起使用。

  • ‘-d’, ‘–debug[=options]’: 打印除正常处理之外的调试信息。具体的调试级别和类型可以通过参数指定。例如,‘-d’ 相当于 ‘–debug=a’。

  • ‘-e’, ‘–environment-overrides’: 使来自环境的变量优先于 Makefile 中的变量。

  • ‘-E string’, ‘–eval=string’: 将字符串 string 作为 Makefile 语法进行评估。

  • ‘-f file’, ‘–file=file’, ‘–makefile=file’: 读取名为 file 的文件作为 Makefile。

  • ‘-h’, ‘–help’: 提示 make 可以理解的选项,然后退出。

  • ‘-i’, ‘–ignore-errors’: 忽略重新生成文件时执行的所有配方中的错误。

  • ‘-I dir’, ‘–include-dir=dir’: 指定搜索包含的 Makefile 的目录 dir。

  • ‘-j [jobs]’, ‘–jobs[=jobs]’: 指定同时运行的配方(作业)的数量。

  • ‘–jobserver-style=[style]’: 选择使用的作业服务器样式。

  • ‘-k’, ‘–keep-going’: 在错误发生后继续尽可能多地执行。

  • ‘-l [load]’, ‘–load-average[=load]’, ‘–max-load[=load]’: 指定在有其他正在运行的作业并且负载平均值至少为 load 时,不应启动新的配方。

  • ‘-L’, ‘–check-symlink-times’: 在支持符号链接的系统上,使 make 也考虑符号链接的时间戳。

  • ‘-n’, ‘–just-print’, ‘–dry-run’, ‘–recon’: 打印将执行的配方,但不执行它们。

  • ‘-o file’, ‘–old-file=file’, ‘–assume-old=file’: 不要重新生成文件 file,即使它比其先决条件旧,并且不要因文件的更改而重新生成任何东西。

  • ‘-O[type]’, ‘–output-sync[=type]’: 确保每个配方的完整输出以一个不间断的序列打印。

  • ‘-p’, ‘–print-data-base’: 打印读取 Makefile 后生成的数据库(规则和变量值)。

  • ‘-q’, ‘–question’: “问题模式”。仅返回一个退出状态,指示指定的目标是否已经是最新,是否需要重新生成,或是否遇到错误。

  • ‘-r’, ‘–no-builtin-rules’: 消除使用内置隐式规则。

  • ‘-R’, ‘–no-builtin-variables’: 消除使用内置规则特定变量。

  • ‘-s’, ‘–silent’, ‘–quiet’: 静默操作,不打印正在执行的配方。

  • ‘-S’, ‘–no-keep-going’, ‘–stop’: 取消 ‘-k’ 选项的效果。

  • ‘–shuffle[=mode]’: 启用前件关系的随机调整。

  • ‘-t’, ‘–touch’: 触摸文件而不是运行其配方。

  • ‘–trace’: 显示 make 执行的跟踪信息。

  • ‘-v’, ‘–version’: 打印 make 程序的版本以及版权、作者列表和无担保声明,然后退出。

  • ‘-w’, ‘–print-directory’: 在执行 Makefile 之前和之后打印包含的工作目录。

  • ‘–no-print-directory’: 在 -w 下禁用工作目录的打印。

  • ‘-W file’, ‘–what-if=file’, ‘–new-file=file’, ‘–assume-new=file’: 假装目标文件刚刚被修改。

  • ‘–warn-undefined-variables’: 每当 make 看到对未定义变量的引用时发出警告。

请注意,这是一个长列表,上面列出的选项可能不适用于所有版本的 make


下一篇:练习10 Makefile之隐式规则,上一篇:练习8 Makefile之使用函数目录首页

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值