Makefile 用规则做出奇怪的行为

Makefile 用规则做出奇怪的行为,makefile,gnu,Makefile,Gnu,我有一个创建文件的规则,还有一个复制它的规则。但是在运行make时,规则的先决条件被调用了两次,但我不知道为什么 如果先决条件中有$(shell./myscript)而不是实际的$(警告…),则会调用该脚本两次 复制错误的生成文件: NAME := test $(NAME): @touch $@ install-$(NAME): $(NAME) install-copy-$(NAME) .PHONY: install-$(NAME) .PRECIOUS: %.copy .SECO

我有一个创建文件的规则,还有一个复制它的规则。但是在运行make时,规则的先决条件被调用了两次,但我不知道为什么

如果先决条件中有$(shell./myscript)而不是实际的$(警告…),则会调用该脚本两次

复制错误的生成文件:

NAME := test

$(NAME):
    @touch $@

install-$(NAME): $(NAME) install-copy-$(NAME)

.PHONY: install-$(NAME)
.PRECIOUS: %.copy

.SECONDEXPANSION:

%.copy: $$*
    @cp $< $@

install-copy-%: $$(warning START) $$*.copy $$(warning END)
    @echo done

make: START
make: START
make: END
done
make: START
make: END
done
NAME := test
INSTALL_DIR := saved

# generate the documentation into $$*/
generateDoc-%:
    touch $*/$(shell head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')

install-$(NAME): generateDoc-$(NAME) install-doc-$(NAME)

.PHONY: install-$(NAME)
.PRECIOUS: $(INSTALL_DIR)/%

.SECONDEXPANSION:

$(INSTALL_DIR)/%: $$(NAME)/$$*
    cp $< $@

install-doc-%: $$(warning START) $$(subst $$*,$$(INSTALL_DIR),$$(shell find $$* -type f)) $$(warning END)
    @echo done
预期输出:

NAME := test

$(NAME):
    @touch $@

install-$(NAME): $(NAME) install-copy-$(NAME)

.PHONY: install-$(NAME)
.PRECIOUS: %.copy

.SECONDEXPANSION:

%.copy: $$*
    @cp $< $@

install-copy-%: $$(warning START) $$*.copy $$(warning END)
    @echo done

make: START
make: START
make: END
done
make: START
make: END
done
NAME := test
INSTALL_DIR := saved

# generate the documentation into $$*/
generateDoc-%:
    touch $*/$(shell head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')

install-$(NAME): generateDoc-$(NAME) install-doc-$(NAME)

.PHONY: install-$(NAME)
.PRECIOUS: $(INSTALL_DIR)/%

.SECONDEXPANSION:

$(INSTALL_DIR)/%: $$(NAME)/$$*
    cp $< $@

install-doc-%: $$(warning START) $$(subst $$*,$$(INSTALL_DIR),$$(shell find $$* -type f)) $$(warning END)
    @echo done
为什么START被输出两次? 如果我有一个调用脚本而不是$(警告)的函数,那么脚本将被调用两次

我不知道。。。 我希望保留.second扩展,因为我不希望在未调用规则时调用$(shell脚本…)或$(警告…)。 我无法列出将安装在.PRECIOUS中的所有文件,因为我不知道,因为此文件是由外部脚本生成的。(像强氧)。使用.PRECIOUS:%.copy第一次输出START两次,但一旦文件存在,则输出START一次

谢谢

带有真实案例的Makefile:

NAME := test

$(NAME):
    @touch $@

install-$(NAME): $(NAME) install-copy-$(NAME)

.PHONY: install-$(NAME)
.PRECIOUS: %.copy

.SECONDEXPANSION:

%.copy: $$*
    @cp $< $@

install-copy-%: $$(warning START) $$*.copy $$(warning END)
    @echo done

make: START
make: START
make: END
done
make: START
make: END
done
NAME := test
INSTALL_DIR := saved

# generate the documentation into $$*/
generateDoc-%:
    touch $*/$(shell head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')

install-$(NAME): generateDoc-$(NAME) install-doc-$(NAME)

.PHONY: install-$(NAME)
.PRECIOUS: $(INSTALL_DIR)/%

.SECONDEXPANSION:

$(INSTALL_DIR)/%: $$(NAME)/$$*
    cp $< $@

install-doc-%: $$(warning START) $$(subst $$*,$$(INSTALL_DIR),$$(shell find $$* -type f)) $$(warning END)
    @echo done
NAME:=test
安装目录:=已保存
#将文档生成到$$*/
generateDoc-%:
触摸$*/$(壳体封头/开发/铀矿场-tr-dc A-Za-z0-9封头-c 13;回波“”)
安装-$(名称):generateDoc-$(名称)安装文档-$(名称)
.PHONY:install-$(名称)
.PRECIOUS:$(安装目录)/%
.第二次扩展:
$(安装目录)/%:$$(名称)/$$*
cp$<$@
安装文档-%:$$(警告开始)$$(子文件$$*,$$(安装目录),$$(shell查找$$*-类型f))$$(警告结束)
@回音完成

make-d
解释了在进行目标
测试之后,它会尝试使目标
安装副本测试(调用第一对开始/结束)。之后,它将使用中间文件
test.copy
查找规则

所有这些都假设您运行
makeinstalltest

> make install-test -n
touch test
make: START
make: END
make: START
make: END
cp test test.copy
done
rm test.copy
自然的解决办法是指定

.PRECIOUS: $(NAME).copy

我不知道,但是把
警告
语句放在先决条件列表中是非常奇怪的。是的,这只是为了表明先决条件被读取了两次。。。我使用一个shell命令来列出需要安装的文件,而不是此警告。此命令代价高昂,我不想启动两次。如果doxygen在/usr/doc中创建文件,则
shell ls$$$*/documentation
将找不到要从中复制的文件no,首先,我们使用generateDoc-%生成文档:它将文档文件生成到test/documentation中,然后我们调用install doc-,将文档安装到/usr/doc:ls test/documentation中会找到所有生成的文件。但是目标`$(NAME)/documentation/%`是最新的,
cp测试/文档/%
/usr/doc
将不会发生。我无法在preciouse中添加.copy,我可以只添加preciouse:%.copy但不起作用。(仅当文件已存在时有效,但不是第一次)。我无法添加所有.copy名称,因为它的文件是由外部脚本(doxygen)生成的。因此,我运行doxygen命令,然后运行$(shell在doxygen目录中查找,以获取要安装的所有文件),因此解决方案不起作用:(您可以将
.PRECIOUS:$(名称)。甚至在
.SECONDEXPANSION:
之前复制
(实际上,
$(名称):
也可以移到上面)。我的意思是,
$(名称).copy
,而不是
%.copy
!是的,但我不能。这里只是一个复制我的案例的例子。在我的真实案例中,它不是$(NAME).copy,但所有由doxygen生成的文件。我无法添加。请珍惜doxygen将生成的所有文件名。您明白吗?让我们尝试准备一个简单的示例,更好地表示您的用例。此外,您是否需要保留.copy文件?也许,make最终删除它们会更好?