简短的回答:
应用列出的模式规则。后缀规则仅列出但未使用。
长答案:
当您使用它转储 Make 的内部数据库时,make -p -f /dev/null
它会打印预定义的规则和变量。输出分为不同的部分。例如,我的 Make (v3.81) 返回以下内容:
# GNU Make 3.81
# Copyright (C) 2006 Free Software Foundation, Inc.
# This is free software; see the source for copying conditions.
# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
# This program built for i686-pc-linux-gnu make: *** No targets. Stop.
# Make data base, printed on Fri May 31 12:48:50 2013
# Variables
...
# Directories
...
# Implicit Rules
...
# Pattern-specific variable values
...
# Files
...
# VPATH Search Paths
....
使用 GNU Make 管理项目和 GNU Make 手册对不同部分进行了如下解释:
变量部分列出了每个变量以及描述性注释。但是,没有列出自动变量。
目录部分对 Make 开发人员比对 Make 用户更有用。它列出了 Make 检查的目录,包括可能存在但通常不存在的 SCCS 和 RCS 子目录。对于每个目录,Make 显示实现细节,例如设备号、inode 和文件模式匹配的统计信息。
隐式规则部分如下。这包含 make 数据库中的所有内置和用户定义的模式规则。
下一节列出了在 makefile 中定义的特定于模式的变量。回想一下,特定于模式的变量是变量定义,其范围恰好是它们关联的模式规则的执行时间。
文件部分随后列出了与特定文件相关的所有显式和后缀规则。[在此上下文中的文件意味着目标]
最后一部分标记为 VPATH。它包含搜索路径并列出 VPATH 的值和所有 vpath 模式。
因此,应用的规则列在“隐式规则”部分。后缀规则作为“文件”部分的一部分列出。
真的很长的答案:
每个人都知道源代码是唯一真正的文档;)所以,忠于 GNU 精神,我冒险进入 Make 的源代码,试图弄清楚它发生了什么。免责声明:我只浏览了大约两个小时 - 足以大致了解 Make 的架构。
初始化阶段:
main.c:第 1600 行(我只是删除了几个处理不同平台的#ifdef ):
/* Define the initial list of suffixes for old-style rules. */
set_default_suffixes ();
/* Define the file rules for the built-in suffix rules. These will later
be converted into pattern rules. We used to do this in
install_default_implicit_rules, but since that happens after reading
makefiles, it results in the built-in pattern rules taking precedence
over makefile-specified suffix rules, which is wrong. */
install_default_suffix_rules ();
/* Define some internal and special variables. */
define_automatic_variables ();
/* Set up the MAKEFLAGS and MFLAGS variables
so makefiles can look at them. */
define_makeflags (0, 0);
/* Define the default variables. */
define_default_variables ();
default_file = enter_file (strcache_add (".DEFAULT"));
default_goal_var = define_variable_cname (".DEFAULT_GOAL", "", o_file, 0);
// I removed the block that evalutes user input entered
// through the `--eval` switch for brevity
[...]
/* Read all the makefiles. */
read_makefiles = read_all_makefiles (makefiles == 0 ? 0 : makefiles->list);
/* Set up MAKEFLAGS and MFLAGS again, so they will be right. */
define_makeflags (1, 0);
/* Make each `struct dep' point at the `struct file' for the file
depended on. Also do magic for special targets. */
snap_deps ();
/* Convert old-style suffix rules to pattern rules. It is important to
do this before installing the built-in pattern rules below, so that
makefile-specified suffix rules take precedence over built-in pattern
rules. */
convert_to_pattern ();
/* Install the default implicit pattern rules.
This used to be done before reading the makefiles.
But in that case, built-in pattern rules were in the chain
before user-defined ones, so they matched first. */
install_default_implicit_rules ();
/* Compute implicit rule limits. */
count_implicit_rule_limits ();
/* Construct the listings of directories in VPATH lists. */
build_vpath_lists ();
- 函数 set_default_suffixes() 只定义了 .SUFFIXES 变量,仅此而已。
- 接下来,通过 install_default_suffix_rules() 函数定义默认后缀规则。它将内置的后缀规则添加为目标。
- 我将跳过接下来的两个函数,直接跳转到 define_default_variables(),这也很容易解释。它定义了 ARCH、AR、CC、CXX 等。现在基本上已经设置了 Make 的默认环境。
- 之后定义 .DEFAULT 和 .DEFAULT_GOAL 目标。它们分别记录在Special-Targets和Special-Variables中。
- 然后通过 read_all_makefiles() 评估 Makefile。Make的评估可能很棘手。但是,基本思想很简单:循环文件中的行。策略是在 FILENAMES 中累积目标名称,在 DEPS 中累积依赖关系,在 COMMANDS 中累积命令。这些用于在遇到下一个规则(或 eof)的开始时定义规则。在我们的例子中,这一步可以忽略,因为我们调用了 Make with
-f /dev/null
。
- 然后 snap_deps() 将目标与其依赖项相关联。它们存储为 dep 结构的链表(在 dep.h 中定义)。
- 现在是有趣的部分。Convert_to_pattern() 遍历 .SUFFIXES 列表中定义的后缀,将其转换为等效的模式规则并将它们附加到现有模式规则链中。这正是您引用的部分中记录的内容。由于所有用户定义的规则都已包含在第 5 步中,因此它们优先于转换后的内置后缀规则。
构建阶段:
稍后,当 Make 尝试构建目标时,它仅搜索规则数据库。规则搜索在implicit.c 中实现。
为什么规则在打印数据库输出中出现双倍?
最后,我查看了--print-database
开关背后的逻辑。
main.c:第 3078 行:
/* Print a bunch of information about this and that. */
static void
print_data_base ()
{
time_t when;
when = time ((time_t *) 0);
printf (_("\n# Make data base, printed on %s"), ctime (&when));
print_variable_data_base ();
print_dir_data_base ();
print_rule_data_base ();
print_file_data_base ();
print_vpath_data_base ();
strcache_print_stats ("#");
when = time ((time_t *) 0);
printf (_("\n# Finished Make data base on %s\n"), ctime (&when));
}
print_rule_data_base() 函数只是漂亮地打印所有“活动”规则。所有现有的后缀规则之前也已转换为模式规则。
print_file_data_base() 函数列出了所有目标。后缀规则仍然在那里。实际上,似乎没有从数据库中删除目标的功能。但是,从我收集的内容来看,后缀目标是未使用的。