【问题标题】:Why does GNU make define implicit pattern and implicit suffix rules?为什么 GNU make 定义隐式模式和隐式后缀规则?
【发布时间】:2015-01-08 21:37:45
【问题描述】:

看着Catalogue of Implicit Rules 的几个语句让我想知道:

默认后缀列表为:.out、.a、.ln、.o、.c、.cc、.C、.cpp、.p、.f、.F、.m、.r、.y 、.l、.ym、.lm、.s、.S、.mod、.sym、.def、.h、.info、.dvi、.tex、.texinfo、.texi、.txinfo、.w、. ch .web、.sh、.elc、.el。 下面描述的所有先决条件具有这些后缀之一的隐式规则实际上都是后缀规则。

嗯,不是吗?

$ make -p -f/dev/null | grep '%.o: %\.c$' -A2
%.o: %.c
#  recipe to execute (built-in):
    $(COMPILE.c) $(OUTPUT_OPTION) $<

后缀.c在列表中但定义为模式规则?

好的,它也定义了一个后缀规则:

make -p -f/dev/null | grep '^.c.o:' -A5
.c.o:
#  Implicit rule search has not been done.
#  Modification time never checked.
#  File has not been updated.
#  recipe to execute (built-in):
    $(COMPILE.c) $(OUTPUT_OPTION) $<

但是为什么呢?

后缀规则定义在模式规则之后。那么模式规则应该优先,对吧?

但既然动作是相等的,那还有什么意义呢?

【问题讨论】:

    标签: makefile gnu-make


    【解决方案1】:

    简答:

    应用列出的模式规则。后缀规则只列出不使用。

    长答案:

    当您使用 make -p -f /dev/null 转储 Make 的内部数据库时,它会打印预定义的规则和变量。输出分为不同的部分。例如,我的 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
    ....
    

    Managing Projects with GNU Make and the GNU Make manual 对不同部分的解释如下:

    变量部分列出了每个变量以及描述 评论。但是没有列出自动变量。

    目录部分对 Make 开发人员比对 Make 更有用 用户。它列出了 Make 检查的目录,包括 SCCS 和 RCS 子目录可能存在,但通常不存在。对于每个 目录,Make 显示实现细节,例如设备 文件模式匹配的数量、inode 和统计信息。

    隐式规则部分如下。这包含所有内置和 make 数据库中用户定义的模式规则。

    下一节列出了定义在 生成文件。回想一下,特定于模式的变量是可变的 范围正好是它们的执行时间的定义 关联的模式规则。

    文件部分遵循并列出了所有显式和后缀规则 与特定文件有关。 [在此上下文中的文件意味着目标]

    最后一部分标记为 VPATH。它包含搜索路径和列表 VPATH 的值和所有的 vpath 模式。

    因此,应用的规则列在“隐式规则”部分。后缀规则作为“文件”部分的一部分列出。

    很长的答案:

    每个人都知道源代码是唯一真正的文档;)因此,忠于 GNU 精神,我冒险进入 Make 的源代码,试图弄清楚它发生了什么。 免责声明:我只浏览了大约两个小时 - 足以大致了解 Make 的架构。

    初始化阶段: main.c :第 1600 行(我只是删除了几个处理不同平台的 #ifdefs):

    /* 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 ();
    
    1. 函数 set_default_suffixes() 只定义了 .SUFFIXES 变量,仅此而已。
    2. 接下来,默认后缀规则通过 install_default_suffix_rules() 函数定义。它将内置的后缀规则添加为目标。
    3. 我将跳过接下来的两个函数,直接跳转到define_default_variables(),这也很容易解释。它定义了 ARCH、AR、CC、CXX 等。现在基本上已经设置了 Make 的默认环境。
    4. 之后定义 .DEFAULT 和 .DEFAULT_GOAL 目标。它们分别记录在 Special-TargetsSpecial-Variables 中。
    5. 然后 Makefile 由 read_all_makefiles() 评估。 Make的评估可能很棘手。但是,基本思想很简单:循环文件中的行。策略是在 FILENAMES 中累积目标名称,在 DEPS 中累积依赖关系,在 COMMANDS 中累积命令。这些用于在遇到下一个规则(或 eof)的开始时定义规则。在我们的例子中,可以忽略这一步,因为我们使用 -f /dev/null 调用了 Make。
    6. 然后 snap_deps() 将目标与其依赖项相关联。它们存储为 dep 结构的链表(在 dep.h 中定义)。
    7. 现在是有趣的部分。 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() 函数列出了所有目标。后缀规则仍然在那里。实际上,似乎没有从数据库中删除目标的功能。但是,根据我收集到的信息,后缀目标在其他方面未使用。

    【讨论】:

    • 是的,当然 - 但这并不能解释为什么内置的 GNU make 隐式规则目录包含重复先前模式规则定义的后缀规则。
    • @maxschlepzig 你是对的 - 我已经挖掘并详细阐述了我之前的答案
    【解决方案2】:

    非常简短的回答是:后缀规则的定义是因为POSIX make requires them to be built-in。请参阅名为“默认规则”的部分。模式规则是(非 POSIX)GNU 增值。

    【讨论】:

      猜你喜欢
      • 2017-09-26
      • 1970-01-01
      • 2012-02-08
      • 1970-01-01
      • 2013-06-13
      • 1970-01-01
      • 1970-01-01
      • 2011-03-06
      • 1970-01-01
      相关资源
      最近更新 更多