如何根据目标列表从列表中找到先决条件

问题描述 投票:0回答:1

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 $< $@
makefile gnu-make
1个回答
0
投票

感谢所有看过并提供建议的人。我几乎可以用我所拥有的来解决它。但我一直在使用目录分隔符时遇到麻烦。 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 中可以使用它。再次感谢您的所有建议。我希望这个解释将来对其他人有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.