Produce to the rescue!
# Compile
%.o : %.c
cc -c $<
# Link
% : %.o
cc -o $@ $<
# Compile
[%{name}.o]
dep.c = %{name}.c
recipe = cc -c %{c}
# Link
[%{name}]
dep.o = %{name}.o
recipe = cc -o %{target} %{o}
out/%.pos : out/%.pos.auto out/%.pos.corr
./src/scripts/apply_corrections $< \
--corrections out/$*.pos.corr > $@
DRY violation!
[out/%{name}.pos]
dep.auto = %{name}.pos.auto
dep.corr = %{name}.pos.corr
recipe = ./src/scripts/apply_corrections %{auto} %{corr} > %{target}
[%{name}.pdf]
deps = %{name}.tex bibliography.bib
recipe =
pdflatex %{name}
bibtex %{name}
pdflatex %{name}
pdflatex %{name}
.SECONDEXPANSION:
out/%.labeled : out/$$(subst test,train,$$(subst dev,train,$$*)).model \
out/$$(basename $$*).feat
wapiti label -m $< out/$(basename $*).feat > $@
[out/%{corpus}.%{portion}.%{fset}.labeled]
dep.model = out/%{corpus}.train.%{fset}.model
dep.input = out/%{corpus}.%{portion}.feat
recipe = wapiti label -m %{model} %{input} > %{target}
[/out/(?P<corpus>.*)\.(?P<portion>dev|test)\.(?P<fset>.*)\.labeled/]
dep.model = out/%{corpus}.train.%{fset}.model
dep.input = out/%{corpus}.%{portion}.feat
recipe = wapiti label -m %{model} %{input} > %{target}
[out/%{corpus}.%{portion}.%{fset}.labeled]
cond = %{portion in ('dev', 'test')}
dep.model = out/%{corpus}.train.%{fset}.model
dep.input = out/%{corpus}.%{portion}.feat
recipe = wapiti label -m %{model} %{input} > %{target}
.PHONY: clean
clean:
rm *.o temp
[vacuum]
type = task
recipe = rm *.o temp
sources := foo.c bar.c baz.s ugh.h
foo: $(sources)
cc $(filter %.c %.s,$(sources)) -o foo
[]
sources = foo.c bar.c baz.s ugh.h
[foo]
deps = %{sources}
recipe = cc %{' '.join([f for f in sources.split() \
if f.endswith('.c') or f.endswith('.s')])}
%
vs. $*
confusion$$
in recipe$PATH
argparse
for command-line optionsconfigparser
and shlex
for parsing Producefileseval
for evaluating Python expressionssubprocess
for executing recipeslogging
for info and debugging
None of them support multiple wildcards!
# Compile
rule '.o' =< ['.c'] do |t|
sh "cc -c #{t.source}"
end
%{wildcards}
and %{"expressions"}
file
or task
build_if_necessary(target)
:
def build_if_necessary(target):
if target in out_of_date or target in missing:
build(target)
def build(target):
for dd in direct_dependencies[target]:
build_if_necessary(dd)
run_recipe(target)
out_of_date.discard(target)
missing.discard(target)
file
and it does not exist.
task
The time of a task is 0
.
The time of a missing file is the time of its newest direct dependency (or 0
if none).
The time of an existing file is its last-modified time.
Photo courtesy of Patrick Feller, CC BY 2.0