Windows 11 上的 GNU Make 3.80
我有一个文件列表和一个目的地列表。我需要编写一条规则,将每个文件复制到其相应的目的地(在指定的子目录中)。请注意,文件名没有模式,它们是手动维护的列表;唯一的要求是文件(在 ADDFILES 中)存在。
本质上是这样的(为了视觉清晰度额外的间距):
ADDFILES = Makefile ../Docs/test.log images/screen.jpg
ASFILES = Makefile test.log images/screen.jpg
DESTDIR = Others/
$(addprefix $(DESTDIR),$(ASFILES)): $(ADDFILES)
copy $< $@
显然,这条规则不起作用。
结果应该是
copy Makefile Others/Makefile
copy ../Docs/test.log Others/test.log
copy images/screen.jpg Others/images/screen.jpg
我在没有先决条件的情况下进行了尝试,并以 $(ADDFILES) 作为先决条件。
有了先决条件($ADDFILES),
$<
始终是列表中的第一个单词(由于某种原因小写)。如果没有先决条件,$<
为空。
我对 make 不是很流利。我一直在寻找,并且正在接近,但我无法让它发挥作用。有可能吗?请记住,我在 Windows 上运行,没有可用的 *nix 类型 shell。
编辑添加
我正在寻找的是某种方式来解释 ADDFILES 和 ASFILES (来自上面的示例),就好像它是:
Others/Makefile: Makefile
copy $< $@
Others/test.log: ../Docs/test.log
copy $< $@
Others/images/screen.job: images.screen.jpg
copy $< $@
感谢所有看过并提供建议的人。我几乎可以用我所拥有的来解决它。但我一直在使用目录分隔符时遇到麻烦。 Make 会将它们带向任一方向(向前或向后); Windows 在一定程度上也会这么做。但在 Windows 命令行上,大多数(所有?)命令都将正斜杠视为开关。
工作的 Windows 解决方案(使用 make 3.8)需要写入文件并包含该文件。此示例中可能仍然存在问题,因为我在变量内的文件名中使用了正斜杠。我厌倦了试图逃避和转移它们。但它看起来像这样。
ADDFILES = Makefile ../Docs/test.log images/screen.jpg
ASFILES = Makefile test.log images/screen.jpg
DESTDIR = Others/
ADDJOIN := $(join $(addprefix $(DESTDIR),$(ASFILES)),$(addprefix #,$(ADDFILES)))
INCLMK := _addfiles_.mk
# Build make file for ADDFILES
$(shell rm $(INCLMK);\
for var in $(ADDJOIN); \
do readarray -td# parts <<<"$${var}#"; \
echo "$${parts[0]}: $${parts[1]}"; \
echo " mkdir -p $$(dirname $${parts[0]})";\
echo " cp $${parts[1]} $${parts[0]}"; \
echo; \
done >$(INCLMK))
include $(INCLMK)
所以,我最终安装了 cygwin 并使用了 bash。这也让我获得了更新的 GNU make (4.4.1)。因此,我无需额外的 makefile 即可完成此任务;规则成为当前调用的一部分。注意:生成的规则still要求配方以TAB字符开头。
ADDFILES = splitpair.sh project.xml
ASFILES = Others/splitpair.sh Others/xml/project.xml
ADDJOIN := $(join $(ASFILES),$(addprefix ^,$(ADDFILES)))
define addRule
$1: $2
mkdir -p `dirname $1`
cp $2 $1
endef
$(foreach pair,$(ADDJOIN),\
$(eval \
$(call \
addRule,\
$(firstword $(subst ^, ,$(pair))),\
$(lastword $(subst ^, ,$(pair))))))
我使用了一行,但为了便于阅读,将其在此处分开显示。请注意,其中一些行中的反斜杠之前有一个空格(在eval
之后和
call
之后;没有其他地方)。 ADDFILES 是要复制到特定目录 (
Others/
) 的现有
文件的列表。ASFILES 是相应的(目标)文件列表 - 我想要复制到的内容
ADDJOIN 逐字连接两个列表 - 即 ASFILES (
Others/splitpair.sh
) 中的第一个单词与 ADDFILES (
splitpair.sh
) 中的第一个单词连接。但在执行此操作时,我添加了一个分隔符(插入符号
^
),以便稍后可以将它们分开。然后将每个列表中的第二个单词组合起来(使用插入符号)。组合之间用空格分隔;所以组合后的条目就变成了单词。从上面来看,ADDJOIN 将如下所示:
Others/splitpair.sh^splitpair.sh Others/xml/project.xml^project.xml
foreach
命令遍历此列表。
ADDJOIN
中的每个单词(我们有两个)都被(依次)分配给变量
pair
。对于每个
pair
,我们使用
eval
(因为没有它,我们会失去
addRule
的格式)来调用
addRule
(就好像它是一个函数)传递两个参数。第一个参数 -
$(firstword $(subst ^, ,$(pair)))
- 用空格替换
pair
中的插入符号,使其变成两个单词;然后取其中的
firstword
(我的目标)。第二个参数 -
$(lastword $(subst ^, ,$(pair)))
- 进行相同的替换,但采用
lastword
(我的先决条件)。
addRule
接受这两个参数并创建规则。我现在在我正在处理的大 Makefile 中可以使用它。再次感谢您的所有建议。我希望这个解释将来对其他人有帮助。