目标未绑定到宏扩展的Makefile作业中的自动变量

时间:2018-11-23 16:28:46

标签: makefile sh

我正在尝试编写包含很多相似之处的作业。

EMACS_VERS     := 22.1 23.4 24.5 25.3 26.1
LOCAL_LISPDIRS := $(patsubst %,local/%/site-lisp,$(EMACS_VERS))

$(addsuffix /leaf, $(LOCAL_LISPDIRS)): site-lisp/leaf
    mkdir -p $(@D)
    cp -rf site-lisp/$(@F) $@
    $(MAKE) --no-print-directory -C $(dir $(@D)) .make-repo-$(@F)

$(addsuffix /orglyth, $(LOCAL_LISPDIRS)): site-lisp/orglyth
    mkdir -p $(@D)
    cp -rf site-lisp/$(@F) $@
    $(MAKE) --no-print-directory -C $(dir $(@D)) .make-repo-$(@F)

$(addsuffix /cort, $(LOCAL_LISPDIRS)): site-lisp/cort
    mkdir -p $(@D)
    cp -rf site-lisp/$(@F) $@
    $(MAKE) --no-print-directory -C $(dir $(@D)) .make-repo-$(@F)

但是,当通过下面的宏扩展这些作业时,目标名称未绑定到自动变量,并且发生了错误。

define build_repo
$1: $2
    mkdir -p $(@D)
    cp -rf site-lisp/$(@F) $@
    $(MAKE) --no-print-directory -C $(dir $(@D)) .make-repo-$(@F)
endef

$(eval $(call build_repo,$(addsuffix /leaf,$(LOCAL_LISPDIRS)),site-lisp/leaf))
$(eval $(call build_repo,$(addsuffix /orglyth,$(LOCAL_LISPDIRS)),site-lisp/orglyth))
$(eval $(call build_repo,$(addsuffix /cort,$(LOCAL_LISPDIRS)),site-lisp/cort))

上面的代码得到以下错误。我认为发生这种情况是因为目标名称不是自动变量绑定。

mkdir -p
usage: mkdir [-pv] [-m mode] directory ...
make: *** [Makefile:72: local/22.1/site-lisp/leaf.el] Error 64

有没有办法解决这个问题?

另一方面,以下代码已被拒绝,因为仅在叶子中更改文件时才会生成对leaf,orglyth,cort的更改。

REPOS       := leaf orglyth cort
REPODIRS    := $(addprefix site-lisp/, $(REPOS))
LOCAL_REPOS := $(foreach repo, $(REPOS), $(addsuffix /$(repo), $(LOCAL_LISPDIRS)))
$(LOCAL_REPOS): $(REPODIRS)
    mkdir -p $(@D)
    cp -rf site-lisp/$(@F) $@
    $(MAKE) --no-print-directory -C $(dir $(@D)) .make-repo-$(@F)

目录树:

local
├── 22.1
│   └── site-lisp
│       ├── cort
│       ├── leaf
│       └── orglyth
├── 23.4
│   └── site-lisp
│       ├── cort
│       ├── leaf
│       └── orglyth
├── 24.5
│   └── site-lisp
│       ├── cort
│       ├── leaf
│       └── orglyth
├── 25.3
│   └── site-lisp
│       ├── cort
│       ├── leaf
│       └── orglyth
└── 26.1
    └── site-lisp
        ├── cort
        ├── leaf
        └── orglyth
site-lisp
├── cort
├── leaf
└── orglyth

2 个答案:

答案 0 :(得分:1)

您的宏被扩展了两次。将所有$符号加倍以退出第一个扩展。

由于您有两个嵌套循环(版本和存储库),因此很难使用模式规则而不是宏。但是您可能可以更有效地使用宏:

# $(1): repo
# $(2): version
define build_repo
local/$(2)/site-lisp/$(1): site-lisp/$(1)
    mkdir -p $$(@D)
    cp -rf site-lisp/$$(@F) $$@
    $$(MAKE) --no-print-directory -C $$(dir $$(@D)) .make-repo-$$(@F)
endef
$(foreach r,$(REPOS),$(foreach v,$(EMACS_VERS),$(eval $(call build_repo,$(r),$(v)))))

或者:

# $(1): repo
# $(2): version
define build_repo
local/$(2)/site-lisp/$(1): site-lisp/$(1)
    mkdir -p local/$(2)/site-lisp
    cp -rf site-lisp/$(1) local/$(2)/site-lisp/$(1)
    $(MAKE) --no-print-directory -C local/$(2) .make-repo-$(1)
endef
$(foreach r,$(REPOS),$(foreach v,$(EMACS_VERS),$(eval $(call build_repo,$(r),$(v)))))

第二个版本不需要任何$转义,因为在第一个扩展中所有内容均已正确完整地扩展。是的,即使是$(MAKE),在您的情况下很可能在第一次或第二次扩展中都进行了相同的扩展。

但是请记住,这是一个特例。如果您继续使用$(eval...)函数,请不要忘记双重扩展...

答案 1 :(得分:0)

感谢@Renaud Pacelet的好评!

define build_repo
$1: $2;
    mkdir -p $$(@D)
    cp -rf site-lisp/$$(@F) $$@
    $$(MAKE) --no-print-directory -C $$(dir $$(@D)) .make-repo-$$(@F)
endef

$(call build_repo,$(addsuffix /leaf,$(LOCAL_LISPDIRS)),site-lisp/leaf)
$(call build_repo,$(addsuffix /orglyth,$(LOCAL_LISPDIRS)),site-lisp/orglyth)
$(call build_repo,$(addsuffix /cort,$(LOCAL_LISPDIRS)),site-lisp/cort)

有了这段代码,我得到了我想要的,没有错误。但是,还有一种更聪明的不使用宏的方法吗?

[附加说明]

我看着@Renaud Pacalet的回答并深思熟虑。

实际上,当更改存储库时,我必须建立在所有版本上,因此可以按如下所示进行一个循环。

LOCALDIRS := $(addprefix local/, $(EMACS_VERS))

define build_repo
$(addsuffix /site-lisp/$(1), $(LOCALDIRS)): $(LISPDIR)/$(1)
    mkdir -p $$(@D)
    cp -rf site-lisp/$$(@F) $$@
    $$(MAKE) --no-print-directory -C $$(dir $$(@D)) .make-repo-$$(@F)
endef
$(foreach repo, $(REPOS), $(eval $(call build_repo,$(repo))))