【问题标题】:Why is Make ignoring an explicit pattern rule?为什么 Make 忽略一个显式的模式规则?
【发布时间】:2016-11-14 21:04:18
【问题描述】:

我正在使用 GNU Make 4.0 在 IBM i 系统上编译代码。 Make 莫名其妙地选择了错误的规则来构建一种类型的对象。

在这个平台上,程序对象是由模块构建的,模块是从源代码编译而来的。还有一个方便快捷的命令,通过从源代码创建一个临时模块,然后从它构建一个程序,直接从一个源代码创建一个程序。我遇到的问题是 Make 使用的是快捷命令 (crtbndrpg) 而不是两步版本 (crtrpgmod + crtpgm),即使目标规则指定程序应该从一个模块而不是快捷方式。

有两个生成文件:一个描述如何创建 IBM i 对象的通用生成文件,一个描述此项目中所有项目的对象依赖关系的项目特定的生成文件,includes 通用生成文件。我的通用 makefile 看起来像这样(为简单起见进行了编辑):

# `IBMiMake`, a generic makefile that describes how to create IBM i objects.

OBJPATH := $(CURDIR)
override OBJPATH := $(shell echo "$(OBJPATH)" | tr '[:lower:]' '[:upper:]')

%.MODULE: %.RPGLE
    $(eval crtcmd := crtrpgmod module($(OBJLIB)/$*) srcstmf('$<') $(CRTRPGMODFLAGS))
    @system "$(crtcmd)" > $(LOGPATH)/$(notdir $<).log

%.PGM: %.RPGLE
    $(eval crtcmd := crtbndrpg pgm($(OBJLIB)/$*) srcstmf('$<') $(CRTBNDRPGFLAGS))
    system "$(crtcmd)" >$(LOGPATH)/$(notdir $<).log 2>&1

%.PGM:
    $(eval crtcmd := crtpgm pgm($(OBJLIB)/$*) module($(basename $(filter %.MODULE,$(notdir $^)))) $(CRTPGMFLAGS))
    system "$(crtcmd)" >$(LOGPATH)/$@.log 2>&1

项目特定的 makefile 如下所示(也为简单起见进行了编辑):

# `xpmake`, to create objects in this project.
ROOTDIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
IBMIMAKE := $(ROOTDIR)/../SDE/IBMiMake
include $(IBMIMAKE)

# AB2001.B.MODULE -- CRTRPGMOD
AB2001.B.MODULE: AB2001.B.RPGLE

# AB2001.B.PGM -- CRTPGM
AB2001.B.PGM: AB2001.B.MODULE

要构建有问题的对象:

bash-4.2$ make AB2001.B.PGM OBJPATH:='/qsys.lib/xp33make.lib' -f xp33make/xpmake -d --no-builtin-rules

应该发生什么:它应该首先使用crtrpgmod 命令创建模块,它会这样做。然后它应该使用crtpgm 命令创建程序。然而,它并没有通过crtpgm 创建程序,而是出于某种原因尝试使用crtbndrpg 命令直接从源代码构建程序。我唯一能想到的可能是 Make 将 AB2001.B.MODULE 视为中间文件并选择绕过crtrpgmod 步骤。这可能是真的吗?如何让我遵守自己的规则而不是想太多?

这是输出:

GNU Make 4.0
Built for powerpc-ibm-aix5.3.0.0
Copyright (C) 1988-2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Reading makefiles...
Reading makefile 'xp33make/xpmake'...
Reading makefile '/home/SMEEP/Source/xp33make/../SDE/IBMiMake' (search path) (no ~ expansion)...
Updating makefiles....
 Considering target file '/home/SMEEP/Source/xp33make/../SDE/IBMiMake'.
  Looking for an implicit rule for '/home/SMEEP/Source/xp33make/../SDE/IBMiMake'.
  No implicit rule found for '/home/SMEEP/Source/xp33make/../SDE/IBMiMake'.
  Finished prerequisites of target file '/home/SMEEP/Source/xp33make/../SDE/IBMiMake'.
 No need to remake target '/home/SMEEP/Source/xp33make/../SDE/IBMiMake'.
 Considering target file 'xp33make/xpmake'.
  Looking for an implicit rule for 'xp33make/xpmake'.
  No implicit rule found for 'xp33make/xpmake'.
  Finished prerequisites of target file 'xp33make/xpmake'.
 No need to remake target 'xp33make/xpmake'.
Updating goal targets....
Considering target file 'AB2001.B.PGM'.
 File 'AB2001.B.PGM' does not exist.
 Looking for an implicit rule for 'AB2001.B.PGM'.
 Trying pattern rule with stem 'AB2001.B'.
 Trying implicit prerequisite 'AB2001.B.CLLE'.
 Trying pattern rule with stem 'AB2001.B'.
 Trying implicit prerequisite 'AB2001.B.RPGLE'.
 Found an implicit rule for 'AB2001.B.PGM'.
  Considering target file 'AB2001.B.RPGLE'.
   Looking for an implicit rule for 'AB2001.B.RPGLE'.
   No implicit rule found for 'AB2001.B.RPGLE'.
   Finished prerequisites of target file 'AB2001.B.RPGLE'.
  No need to remake target 'AB2001.B.RPGLE'; using VPATH name '/home/SMEEP/Source/xp33make/AB2001.B.RPGLE'.
  Considering target file 'AB2001.B.MODULE'.
   Looking for an implicit rule for 'AB2001.B.MODULE'.
   Trying pattern rule with stem 'AB2001.B'.
   Trying implicit prerequisite 'AB2001.B.C'.
   Trying pattern rule with stem 'AB2001.B'.
   Trying implicit prerequisite 'AB2001.B.CLLE'.
   Trying pattern rule with stem 'AB2001.B'.
   Trying implicit prerequisite 'AB2001.B.RPGLE'.
   Found prerequisite 'AB2001.B.RPGLE' as VPATH '/home/SMEEP/Source/xp33make/AB2001.B.RPGLE'
   Found an implicit rule for 'AB2001.B.MODULE'.
    Pruning file '/home/SMEEP/Source/xp33make/AB2001.B.RPGLE'.
    Pruning file '/home/SMEEP/Source/xp33make/AB2001.B.RPGLE'.
   Finished prerequisites of target file 'AB2001.B.MODULE'.
   Prerequisite '/home/SMEEP/Source/xp33make/AB2001.B.RPGLE' is older than target 'AB2001.B.MODULE'.
   Prerequisite '/home/SMEEP/Source/xp33make/AB2001.B.RPGLE' is older than target 'AB2001.B.MODULE'.
  No need to remake target 'AB2001.B.MODULE'; using VPATH name '/QSYS.LIB/XP33MAKE.LIB/AB2001.B.MODULE'.
 Finished prerequisites of target file 'AB2001.B.PGM'.
Must remake target 'AB2001.B.PGM'.
system "crtbndrpg pgm(XP33MAKE/AB2001.B) srcstmf('/home/SMEEP/Source/xp33make/AB2001.B.RPGLE')" >/home/SMEEP/Source/xp33make/Logs/2016-11-14_11.42.55-Mon/AB2001.B.RPGLE.log 2>&1
Putting child 30016df0 (AB2001.B.PGM) PID 1155363 on the chain.
Live child 30016df0 (AB2001.B.PGM) PID 1155363 
Reaping losing child 30016df0 PID 1155363 
/home/SMEEP/Source/xp33make/../SDE/IBMiMake:476: recipe for target 'AB2001.B.PGM' failed
Removing child 30016df0 PID 1155363 from chain.

【问题讨论】:

  • 为什么要指定 crtbndrpg 规则?所有 ILE RPG 程序都可以使用 crtpgmod+crtpgm 创建,即使是那些可能使用 crtbndrpg 创建的程序。
  • 你是对的,这就是我最终要走的方向。

标签: makefile ibm-midrange


【解决方案1】:

您的示例仍然难以阅读:创建一个最小的示例通常是最好的(即构建一个使用touch 等创建文件的示例,并且不依赖于您的环境)。

此外,在配方中使用$(eval ...) 来创建make 变量赋值有点令人困惑。不要认为仅仅因为您在秘籍中执行此操作就涉及某种范围:这些变量仍然是全局分配的。

无论如何,问题在于您有两种方法可以构建与%.PGM 匹配的目标:

%.PGM: %.RPGLE
%.PGM:

您显然想使用第二个,但如果匹配模式规则的词干长度相等(这里两者具有相同的词干,.PGM),那么make 将始终选择您定义的第一个模式所以如果可以的话,它总是会选择第一个。

所以,它将始终使用crtbndrpg 来构建该目标,只要make 可以弄清楚如何构建%.RPGLE,那么该模式规则就会匹配。

【讨论】:

  • 谢谢。你是对的,它太复杂了。我努力创建一个通用示例,但将来我会确保我成功。鉴于规则%.c: %.b%.b: %.a%.c: %.a,是否有任何可能的方法来控制哪个规则将对xyz.c: xyz.bxyz.c: xyz.a 之类的定义生效?我们有一些项目应该使用快捷方式%.c: %.a 规则创建,但其他项目应该使用%.c: %.a 加上%.c: %.b 的两个步骤。我们如何告诉 Make 使用哪个?
  • 尝试在 xpmake 中添加另一个没有配方的规则,以便从 IBMiMake 中取消不需要的规则,例如 %.PGM: %.RPGLE
  • 如果您不想在给定的 makefile 中使用其中一种模式,那么您可以按照 jaeheung 的说法将其删除。如果您需要同一个 makefile 中的所有模式来处理不同的事情,那么您就不能让它自己去做。它不能只凭直觉知道你想做什么;它将始终使用相同的算法来搜索每个目标的规则。在这种情况下,您必须为不使用“标准”行为的目标创建显式规则,也许是静态模式规则。
【解决方案2】:

我不确定它们是否在简化过程中被省略,但您的明确规则缺少它们的配方。 没有配方的模式规则意味着取消任何现有的隐式规则。 https://www.gnu.org/software/make/manual/html_node/Canceling-Rules.html

【讨论】:

  • 只有在模式规则没有配方的情况下才会取消模式规则。在这里,您的模式规则有食谱。无配方规则只是定义了额外的先决条件。由于没有配方,因此没有明确的规则,make 将搜索模式规则以找到配方。
猜你喜欢
  • 2012-02-08
  • 1970-01-01
  • 2017-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多