bash - GNU Make 如何为不在同一目录中的文件制定静态模式规则?

标签 bash shell makefile

我想使用 make 并创建一个静态模式规则,目标位于 output 目录中,先决条件文件位于前面的目录中,并且它有递归地工作。

我这里有一个最小的例子:

.
├── anotherdir
│   ├── output
│   │   ├── source3.md
│   │   └── source4.md
│   ├── source3.json
│   └── source4.json
├── output
│   ├── source1.md
│   └── source2.md
├── source1.json
└── source2.json

如果 output 目录不存在,我想生成它们,并且我想从 *.json 生成 *.md 文件> 如果它们不存在,则使用 make,或者 *.json 已更新。

到目前为止,我有以下Makefile:

SOURCE_FILES := $(shell find ./ -name "*.json")
OUTPUT_FILES := $(join $(addsuffix output/,$(dir $(SOURCE_FILES))), $(addsuffix .md,$(basename $(notdir $(SOURCE_FILES)))))

.PHONY: all
all: $(OUTPUT_FILES)

$(OUTPUT_FILES): %.md: %.json
    mkdir -p $(dir $@)
    # Command to create MD file from json file into the output directory here

从 json 文件创建 MD 文件的实际命令在这里并不重要,因为我有一个我将调用的脚本,它将为我执行此操作。这里的问题是,当我尝试运行它时,我得到以下输出:

> make all
make: *** No rule to make target 'anotherdir/output/source4.json', needed by 'anotherdir/output/source4.md'.  Stop.

显然,source4.json 不在anotherdir/output 中,而是在前面的目录中,也就是anotherdir。我不知道如何使模式 $(OUTPUT_FILES): %.md: %.json 正确匹配它。

还是静态模式规则在这里不好?我不确定该怎么做才能适合我的情况。

编辑:我试着做这样的事情:

$(OUTPUT_FILES): %.md: $(join $(subst output,,$(dir %)), $(addsuffix .json,$(basename $(notdir %))))

这不起作用,我仍然得到:

> make all
make: *** No rule to make target 'anotherdir/output/source4.json', needed by 'anotherdir/output/source4.md'.  Stop.

编辑 2:为了澄清,我从以下文件开始

.
├── anotherdir
│   ├── source3.json
│   └── source4.json
├── source1.json
└── source2.json

然后当我运行 make 时,我希望它生成这样的输出文件夹

.
├── anotherdir
│   ├── output
│   │   ├── source3.md
│   │   └── source4.md
│   ├── source3.json
│   └── source4.json
├── output
│   ├── source1.md
│   └── source2.md
├── source1.json
└── source2.json

我想使用某种智能 makefile 语法来获取这些文件名,而无需自己进行硬编码。因此,我查看了文档,发现静态模式规则可能是我想要的解决方案,只是我无法获得正确的先决条件模式。

最佳答案

我会这样做:

首先,像您一样找到源文件(稍作改动以防止难看的双斜线):

SOURCE_FILES := $(shell find . -name "*.json")

如果我们可以一次使用两个通配符,一个模式文件会很好,但 Make 不能完全做到这一点。所以我建议使用模板:

define template
TDIR := $(dir $(1))output
TARG := $$(TDIR)/$(notdir $(basename $(1))).md
$$(TARG): $(1)
    mkdir -p $$@
    @echo building $$@ from $$<
    # Command to create MD file from json file into the output directory here
endef

$(foreach SOURCE,$(SOURCE_FILES),$(eval $(call template,$(SOURCE))))

如果这可行,剩下的就是构建一个输出文件列表,以及一个将所有这些文件作为先决条件的默认规则:

define template
TDIR := $(dir $(1))output
TARG := $$(TDIR)/$(notdir $(basename $(1))).md
OUTPUT_FILES += $$(TARG)
$$(TARG): $(1)
    mkdir -p $$@
    @echo building $$@ from $$<
    # Command to create MD file from json file into the output directory here
endef

all:

$(foreach SOURCE,$(SOURCE_FILES),$(eval $(call template,$(SOURCE))))

all: $(OUTPUT_FILES)

它不是很漂亮,但它似乎有效。

关于bash - GNU Make 如何为不在同一目录中的文件制定静态模式规则?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57367690/

相关文章:

git - 有效地将项目添加到 git 索引

bash 标准输出后跟同一行的提示

bash - 如何将密码传递给 pg_dump?

c++ - gcc 自动依赖完整路径

c - Bash 一个 liner 来编译、执行和回显返回值?

linux - 使用 shell 脚本 (bash) 查找我的系统的特定接口(interface)的 IP 地址

python - 从另一个目录查找数据 (.txt) 并将名称保存在列表中

bash - 如何在docker容器中获取本地主机IP地址?

linux - 如何在 Makefile 中使用 chroot?

c++ - Makefile 编译 c 和 cpp 文件