我使用GNU Make 4.0在IBM I系统上编译代码。Make莫名其妙地选择了错误的规则来构建一个类型的对象。
在这个平台上,程序对象是由模块构建的,模块是由源代码编译的。还有一个方便的快捷命令,通过从源代码创建临时模块,然后从中构建程序,可以直接从一段源代码创建程序。我遇到的问题是,Make使用快捷命令(crtbndrpg
)而不是两步版本(crtrpgmod
+ crtpgm
),即使目标规则指定程序应该从模块而不是快捷方式构建。
有两个makefile:一个通用的makefile描述了如何创建IBM i对象,一个特定于项目的makefile描述了这个项目中所有项目的对象依赖关系,include
是通用的makefile。我的通用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.
您的示例仍然难以阅读:创建一个最小的示例通常是最好的(即构造一个使用touch
等来创建文件的示例,并且不依赖于您的环境)。
另外,在recipe中使用$(eval ...)
来创建make变量赋值有点令人困惑。不要认为仅仅因为你在配方中这样做了,就涉及到某种作用域:这些变量仍然是全局赋值的。
%.PGM
的目标:
%.PGM: %.RPGLE
%.PGM:
你显然想使用第二个,但如果匹配模式规则的词干长度相等(这里两个词干相同,.PGM
),那么make
将始终选择你定义的第一个模式,因此如果可以,它将始终选择第一个模式。
因此,它将始终使用crtbndrpg
来构建目标,只要make
可以找出如何构建%.RPGLE
,那么模式规则将匹配
我不确定它们是否在简化过程中被省略了,但是您的显式规则缺少它们的配方。没有配方的模式规则意味着取消任何现有的隐式规则。https://www.gnu.org/software/make/manual/html_node/Canceling-Rules.html