How to dynamically generate Makefile targets - makefile

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 $*

Related

How to define prerequisite for automatic variable in 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 $< $#

why do echo work in %: foo.o rule but not in %: %.o?

This is my current makefile
.PHONY = all clean
all: foo
#echo "Dependencies: $<"
%: %.o
#echo "Checking.. $#, <- $<"
gcc -lm foo.o -o foo
#echo "\n"
%.o: %.c
#echo "Creating object.. $#, <- $<"
gcc -c foo.c
#echo "\n"
clean:
#echo "Cleaning up..."
rm -rvf foo.o foo
When I run make, it doesn't print out any echoed strings, but I still get the executable file. This is all the things that get printed to the terminal
gcc foo.c -o foo
echo "Dependencies: foo"
When I replace %: %.0 rule with %: foo.o, everything is printed to the terminal normally
Creating object.. foo.o, <- foo.c
gcc -c foo.c
Checking.. foo, <- foo.o
gcc -lm foo.o -o foo
Dependencies: foo
rm foo.o
In both cases, I still get the executable file foo and it works normally, but why do I get 2 different results in the terminal?
When I run make, it doesn't print out any echoed strings, but I still get the executable file.
Since you do not have an explicit rule for building foo, (GNU) make performs an implicit rule search, by which it attempts to find a chain of one or more pattern rules, whether user-provided or built-in, by which it can build foo. Although it could choose to apply your rule to build foo.o from foo.c and then your rule to build foo from foo.o, it has a shorter chain available: a built-in rule for building foo directly from foo.c. It chooses the latter because it's shorter.
When I replace %: %.0 rule with %: foo.o, everything is printed to the terminal normally
This is a bit of a quirk of the implicit rule search procedure. When you make that change, make identifies the revised rule as "applicable" for building foo on account of the only prerequisite having an explicit name (this is item 5.3 in the algorithm described in the manual). The built-in rule for building directly from %.c is also applicable, but the one given in the makefile has precedence (among rule chains of the same length). The fact that make has to figure out separately how to make foo.o doesn't enter into consideration in this case (this is the quirky part, but follows clearly from the docs).
Of course, this particular quirk is rarely triggered, because a rule of the form of your revised one is almost always inappropriate. It says that whatever target is to be built, it can be built from foo.o, via the provided recipe, but that recipe really works only for building foo. Instead of %: foo.o, then, you really ought to make it foo: foo.o:
.PHONY = all clean
all: foo
#echo "Dependencies: $<"
foo: foo.o
#echo "Checking.. $#, <- $<"
gcc -o $# $< -lm
#echo "\n"
%.o: %.c
#echo "Creating object.. $#, <- $<"
gcc -c foo.c
#echo "\n"
clean:
#echo "Cleaning up..."
rm -rvf foo.o foo
Additional notes:
link library options such as -lm should come at the end of the link line. The relative order of these and object files on the command line matters.
Avoid repeating yourself. Rules' recipes should use automatic variables where possible to avoid repeating the target or prerequisite names.

Specify all Makefile targets as .PHONY with wildcard

All targets in my Makefile aren't real files, is it valid to specify just .PHONY: %. Or should I list all targets?
You need to list all the targets that are meant to be phony targets as prerequisites of the .PHONY target instead of just writing .PHONY: %.
.PHONY: % doesn't do what you think it does (i.e., turning every target into a phony target).
As an example, consider the following makefile:
.PHONY: %
foo:
#echo creating $#
#touch $#
For this makefile above:
$ make
creating foo
$ make
make: 'foo' is up to date.
Therefore, the target foo is not turned into a phony target by having .PHONY: % in your makefile. Otherwise, foo's recipe would have been executed, since phony targets are always outdated.

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.

Resources