2

公平警告:我在使用 makefile 方面有点新手,所以这可能是显而易见的。我要做的是使用 make 来运行第三方代码生成工具,当且仅当该生成工具的源文件(称为 .abc 文件)发生更改时。我在http://www.cmcrossroads.com/ask-mr-make/6795-rebuilding-when-a-files-checksum-changes引用了这个例子,它展示了如何构建 MD5,我稍微调整了这个想法:

文件:abc.mk

target = all
files    := $(wildcard Abc/*.abc)
bltfiles := $files $(addsuffix .built,$files)

all: $bltfiles

%.built: %.abc %.abc.md5
    @echo "Building $*"
    @ #Command that generates code from a .abc file
    @touch $@

%.md5: FORCE
    @echo "Checking $* for changes..."
    @ #Command to update the .md5 file, if the sum of the .abc file is different

FORCE:

我打算让每个 .abc 文件有两个辅助文件: .abc.built & .abc.md5 。.built 文件只是最后一次构建的虚拟目标和时间戳,因为生成工具生成的代码不能轻易定义为目标。.md5 文件包含 .abc 文件最后已知内容的哈希值。仅当文件的哈希更改时才应更新它。

但是,.built 文件仅在不存在时才会创建。.md5 规则根本不会运行,即使 .abc 文件具有较新的时间戳,.built 规则也不会重新构建。难道我做错了什么?

更新: 为了后代,这是我要工作的版本:

文件:abc.mk

# Call this makefile as: make all --file=abc.mk

# Default Target
target = all

COMP_ABC_FILES := $(wildcard Abc/*.abc)
COMP_BLT_FILES := $(COMP_ABC_FILES) $(addsuffix .built, $(COMP_ABC_FILES) )

# This line is needed to keep make from deleting intermediary output files:
.SECONDARY: 

# Targets:
.PHONY: all
all: $(COMP_BLT_FILES)

Abc/%.abc.built: Abc/%.abc Abc/%.abc.md5
    @echo "Building $*"
    @ #Command that generates code from a .abc file
    @touch $@

%.md5: FORCE
    @echo "Checking $* for changes..."
    @$(if $(filter-out $(shell cat $@ 2>/dev/null),$(shell md5sum $*)),md5sum $* > $@)

# Empty rule to force re-build of files:
FORCE:

clean:
    @echo "Cleaning .built & .md5 files..."
    @rm Abc/*.built
    @rm Abc/*.md5
4

2 回答 2

1

在三个地方修复你的makefile:

target = all
files    := $(wildcard Abc/*.abc)
bltfiles := $(files) $(patsubst %.abc,%.built,$(files))

all: $(bltfiles)

#Abc/%.abc.built: Abc/%.abc Abc/%.abc.md5
%.built: %.abc %.abc.md5
    @echo "Building $*"
    @ #Command that generates code from a .abc file
    @touch $@

%.md5: FORCE
    @echo "Checking $* for changes..."
    @ #Command to update the .md5 file, if the sum of the .abc file is different

FORCE:

注意变化:

  1. bltfiles := $(files) $(patsubst %.abc,%.built,$(files))

    结果是“Abc/a.built Abc/b.built”而不是“Abc/a.abc.built Abc/b.abc.built”,考虑到规则的%.built定义方式,这是必需的

  2. all: $(bltfiles)

    如上所述,with $(files), '$bltfiles' 需要是$(bltfiles),否则 make 会将其解释为$(f)ilesand $(b)ltfiles

提示:这里有一个为 makefile 提供语法高亮的编辑器很好


演示

mkdir -pv Abc; touch Abc/{a,b,c,d,e,f,g}.abc
make -Bs -f abc.mk

输出像

Checking Abc/e.abc for changes...
Building Abc/e
Checking Abc/g.abc for changes...
Building Abc/g
Checking Abc/b.abc for changes...
Building Abc/b
Checking Abc/f.abc for changes...
Building Abc/f
Checking Abc/a.abc for changes...
Building Abc/a
Checking Abc/c.abc for changes...
Building Abc/c
Checking Abc/d.abc for changes...
Building Abc/d
于 2012-10-08T16:58:57.287 回答
0

由于 sehe 已修复但未解释:Makefile 语法与 shell 语法不同。默认情况下(由于历史遗失的原因)make 变量只有一个字符长。如果你想要一个更长的变量名,你必须把它放在括号中,这样它才能正确解析。$files例如,写入实际上扩展了字符串“iles”,因为 make 只解析和扩展了“f”变量(为空)的值。

是的,这很奇怪。但这是 make 工作的方式。始终将变量放在括号中。

于 2012-10-08T17:03:46.340 回答