How to define prerequisite for automatic variable in Makefile? - makefile

How to modify my Makefile to generate 1.bar, 2.bar and 3.bar by typing make all?
The problem is that all depends on $(bars) and it is empty unless I first run make foo.
foo:
touch 1.foo 2.foo 3.foo
bars = $(patsubst %.foo,%.bar,$(wildcard *.foo))
%.bar: %.foo
cp $< $#
all: $(bars)

You'll have to list the files *.foo in your makefile:
foos = 1.foo 2.foo 3.foo
foo:
touch $(foos)
bars = $(foos:.foo=.bar)
...
You have to have some starting point in your makefile. Make cannot infer the list of things to build starting from absolutely no information at all.
If you don't know what the output will be from a command the simplest way do it is with recursive make. Something like this:
all: geotiff.file
gdal_retile.py $<
$(MAKE) output
output: $(patsubst %.foo,%.bar,$(wildcard *.foo))
%.bar: %.foo
cp $< $#

Related

How to dynamically generate Makefile targets

Say I have a few files named foo.c, bar.c, baz.c, ... I want to create a Makefile target for each one that runs a build task.
foo:
make foo.c
.PHONY: foo
foo.c:
run build foo
bar:
make bar.c
.PHONY: bar
bar.c:
run build bar
...
I essentially just want to do make foo and it builds make foo.c. But I have x number of files and want to have make tasks for each. How to accomplish this. Something like:
FILES = $(foo bar baz ...)
$(FILES): $(FILES)
make $(FILE)
.PHONY: $(FILE)
$(FILES).c: $(FILES)
run build $(FILE)
But all the files are independent from each other.
You can use pattern rules for the .c targets and static pattern rules for the ones that have to be phony targets (i.e., foo and bar in your example):
targets := foo bar
.PHONY: $(targets)
# static pattern rule
$(targets): %:
make $*.c
# pattern rule
%.c:
run build $*

makefile not expanding dynamic prerequisites

I want to have a makefile that will take some strings as prefixes for some files (NAMES) and from there work on the target and prerequisite file names. In the example below, for example, the idea would be to convert 2 a csv files (foo.csv and bar.csv) to tabular (although I'm just echoing the target and prerequisite).
NAMES = foo bar
PR = $(patsubst %,%.csv,$(NAMES))
TB = $(patsubst %,%.tsv,$(NAMES))
all: $(TB)
%.tsv: $(PR)
#echo $< $#
This prints:
foo.csv foo.tsv
foo.csv bar.tsv
So, it looks like that makefile is not expanding correctly the prerequisites in PR as I would expect to see bar.csv bar.tsv on the second line.
However, if I print $PR and $TB, both seem to be set properly:
$(info $$PR is [${PR}])
$(info $$TB is [${TB}])
# prints
$PR is [foo.csv bar.csv]
$TB is [foo.tsv bar.tsv]
Any idea how to get this working properly?
Note that I have both foo.csv and bar.csv files in the working directory.
The problem lies in the way you're using the built in variable $<. If you expand the variables manually and rewrite the makefile it becomes...
NAMES = foo bar
PR = $(patsubst %,%.csv,$(NAMES))
TB = $(patsubst %,%.tsv,$(NAMES))
all: foo.tsv bar.tsv
%.tsv: foo.csv bar.csv
#echo $< $#
But $< refers to the first prerequisite which is always foo.csv regardless of the target.
One solution might be to use a scoped static pattern rule. So something like...
NAMES = foo bar
PR = $(patsubst %,%.csv,$(NAMES))
TB = $(patsubst %,%.tsv,$(NAMES))
all: $(TB)
# Tell make how to build a .tsv from a .csv but constrain the rule
# so that it only applies to .tsv files that are part of $(TB).
#
$(TB): %.tsv: %.csv
#echo 'building target [$#] with $$< = [$<]'
The above results in...
building target [foo.tsv] with $< = [foo.csv]
building target [bar.tsv] with $< = [bar.csv]

Makefile: defining rules and prerequisites in recipes

I have a setup where the files I want to process with make are dependent on the output of another program. Building the program and all its prerequisites
is also a complicated task so I would like to use make for this as well. Now my problem is, that it doesn't seem that one can generate rules and prerequisites in Makefile recipes. Consider the following code:
bar:
echo target1 target2 target3 > bar
foo: bar
$(eval BAR := $(shell cat bar))
define FUN
$(1):
touch a$(1)
endef
ifdef BAR
$(foreach i,$BAR,$(eval $(call FUN,$(i))))
endif
blub: foo $(BAR)
I replaced a big set of complicated recipes that lead to the generation of the list of files I want to have in the end by the bar recipe. In reality, producing the content of bar is very complicated and should be done by a set of Makefile recipes and cannot just be done by (as the above suggests):
BAR:=$(shell echo target1 target2 target3)
I would like to put the foreach loop into the recipe for foo but that fails with prerequisites cannot be defined in recipes which makes sense and is also explained in function define in makefile
But it seems that when I do make blub that at the time when foo eval's BAR to a different value, the prerequisites for blub are not re-evaluated.
So I think ultimately I'm looking for two things:
how do I generate recipes dynamically at runtime, based on (and dependent on) what another recipe (bar in this case) outputs?
how do I update the prerequisites of a target (blub in this case) dynamically at runtime, based on (and dependent on) what another recipe (bar in this case) outputs?
Thank you!
EDIT: SOLUTION
With the help of #user657267 the following seems to solve my problem:
.PHONY: all
all: blub
-include bar.make
.PHONY: blub
blub: $(BAR)
echo $^
bar.make: Makefile
printf 'BAR=target1 target2 target3\n' > $#
printf 'target1 target2 target3:\n' >>$#
printf '\ttouch $$#' >> $#
.PHONY: clean
clean:
rm -f target1 target2 target3 bar.make
Sounds like you should be using make's self-remaking features
-include bar.make
blub: $(BAR)
#echo $^
bar.make:
#echo BAR := target1 target2 target3 > $#
#echo target1 target2 target3: ; touch $$# >> $#
Obviously the recipes for bar.make are contrived, in the real world they'd probably invoke some kind of script that outputs a valid makefile.

How to avoid duplication in Makefile targets with similar recipes?

I have a Makefile which has a lot of targets and the recipe for each target is quite similar.
foo:
gcc foo.c -o foo
mv foo ~/bin
bar:
gcc bar.c -o bar
mv bar ~/bin
baz:
gcc baz.c -o baz
mv baz ~/bin
I would like to avoid all this duplication. I would like to have something like below (this is not valid syntax; this only expresses my intention).
TARGET_NAME:
gcc $(TARGET_NAME).c -o $(TARGET_NAME)
mv $(TARGET_NAME) ~/bin
Is it possible to do something like this? If not, what is the best Makefile I can write that can minimize duplication in recipes?
Your makefile is wrong because your targets (foo, bar, etc.) don't depend on their source files (foo doesn't depend on foo.c, etc.) So, changing the source code won't cause the target to be rebuilt.
Also, your makefile says you're creating a file foo, but your recipe actually creates a file ~/bin/foo, which is not the same thing.
Anyway, this is exactly what pattern rules are for:
EXES = foo bar baz
all: $(addprefix $(HOME)/bin/,$(EXES))
$(HOME)/bin/%:: %.c
gcc $< -o $#
(Thanks to Beta for pointing out my think-o in the original)
A make rule can actually match multiple targets:
foo bar baz:
gcc $#.c -o $#
mv $# ~/bin
However, you should make the dependencies explicit in the rules:
foo: foo.c
bar: bar.c
baz: baz.c
foo bar baz:
gcc $< -o $#
mv $# ~/bin
The first three lines only specifiy the dependencies without any actions to actually build them. You can generate these with the help of gcc: gcc -MM foo.c will print a rule for foo.c.

Makefile automatic variable changed by prerequisite

first time here. I am relatively new to makefiles. Here is my current makefile:
# Closure compiler php script path
closure = ../../cli/scripts/Compilers/closure.php
# Destination directory
dest = ../../static/js/
# Build directory
build = build/
# Tell "make" to search build and destination dirs
vpath %.o $(build)
vpath %.js $(dest)
all: main.js
#echo "Done.";
main.js: \
date.o \
jquery.autocomplete.o \
jquery.bullseye.o \
jquery.clickopen.o \
jquery.fbmodal.o \
jquery.helpers.o \
jquery.pulljson.o \
jquery.thumbrotate.o \
jquery.timefmt.o \
jquery.tools.o \
layout.main.o
cat $^ > $(dest)$#
%.o: %.js
php $(closure) $*.js $(build)$#
clean:
rm -rf $(build)*.o
rm -rf $(dest)*.js
The problem is with the following line:
cat $^ > $(dest)$#.
It is supposed to cat all the prerequisite objects (minified javascript) into one final js library. According to makefile docs, $^ is an automatic variable which contains a list of prerequisites with directories they are in. From my experience, it behaves differently depending on wether prerequisite needs to be compiled or not.
If prerequisite is up-to-date, this code works perfectly and $^ contains a list like:
build/date.o build/jquery.autocomplete.o build/jquery.bullseye.o....
However if prerequisite needs a fresh compile, then $^ gets directory part stripped and looks like:
date.o jquery.autocomplete.o jquery.bullseye.o
Only the file which needs a fresh compile gets directory part stripped.
I have managed to work around this issue by replacing
cat $^ > $(dest)$#
with
cat $(addprefix $(build), $(^F) ) > $(dest)$#.
I don't like it because:
It's a hack
$(^F) is semi-deprecated
I want to understand why make behaves like this.
thanks
Look here:
# Tell "make" to search build and destination dirs
vpath %.o $(build)
If Make is looking for foo.o, it will look in the local directory first. If it finds no foo.o there, it will look in $(build) (i.e. build/, and you might reconsider your variable names).
And how would Make build foo.o, if it couldn't find it anywhere? With this rule:
%.o: %.js
php $(closure) $*.js $(build)$#
This rule violates an important guideline of makefiles, in that the target (foo.o) is not the name of the thing actually built (build/foo.o).
Now consider what happens when Make tries to execute this rule:
main.js: date.o ...
cat $^ > $(dest)$#
So if date.o is up to date, it's in build/. Make finds it there, and the automatic variable $^ expands to build/date.o ...
But if date.o must be rebuilt, then Make looks to the %.o rule, which promises to build date.o (not build/date.o), so Make takes that rule at its word and $^ expands to date.o ...
There are several ways to solve this problem. I'd do something like this:
OBJS := date.o jquery.autocomplete.o jquery.bullseye.o ...
OBJS := $(addprefix $(build),$(OBJS))
$(dest)main.js: $(OBJS)
cat $^ > $#
# you might have to tinker with this rule a little
$(build)%.o: %.js
php $(closure) $< $#

Resources