GNU make: stem matching and multiple dependencies - makefile

I have 2 files, filea and fileb, and want to produce filec.
My Makefile looks like this
f%ec: f%eb
f%ec: f%ea
cat $^ > $#
Yet, the effect of typing make is only:
cat filea > filec
That is, fileb is not a prerequisite for filec. When not using the % signs, that is when the Makefile is
filec: fileb
filec: filea
cat $^ > $#
the resulting action is
cat filea fileb > filec
Why that? And how should the first Makefile be modified in order to have the expected result?

In the second makefile:
filec: fileb
filec: filea
cat $^ > $#
There are two rules for filec, only one of which has commands, so Make combines the lists of prereqs and runs the one with commands. In the first makefile:
f%ec: f%eb
f%ec: f%ea
cat $^ > $#
There are two different pattern rules which could match filec, so Make has to choose one (it doesn't realize it could apply both at the same time, and in principle they could both have commands). Since one lacks commands, it chooses the other one. The simplest way to get the desired behavior is by combining the rules:
f%ec: f%ea f%eb
cat $^ > $#

Related

makefile computing diff fails

When I try to compute the diff between two text files:
results.txt: file1.txt file2.txt
diff $(word 1,$^) $(word 2,$^) > $#
I get this weird (?) error:
$ make
diff file1.txt file2.txt > results.txt
makefile:2: recipe for target 'results.txt' failed
make: *** [results.txt] Error 1
What's wrong with my makefile?
The issue is that diff typically has a non-zero exit code if the files differ. This will cause make to infer the command failed. The easy fix would be to tell make to ignore the exit code...
results.txt: file1.txt file2.txt
-diff $(word 1,$^) $(word 2,$^) > $#
Edit: If the aim is to get rid of the diagnostic message entirely then you could just use something like...
results.txt: file1.txt file2.txt
diff $(word 1,$^) $(word 2,$^) > $# || exit 0

Dynamic targets based on the dependency in Makefile

There are a couple of kind of similar issues but I could not fit any of the proposed concepts to my case.
Just to give a little bit of context: I have a set of Julia files which create plots as PDFs which are part of a make procedure to create scientific papers, something like:
plots = $(shell find $(PLOT_PATH)/*.jl | sed 's/\.jl/\.pdf/g')
$(PLOT_PATH)/%.pdf: $(PLOT_PATH)/%.jl $(JULIA_SYSIMAGE)
$(JL) --project $< -o $(PLOT_PATH)
$(DOCUMENT_FILENAME).pdf: FORCE $(plots) $(figures)
latexmk $(DOCUMENT_FILENAME).tex
In the current setup, each XYZ.jl file is creating a XYZ.pdf file and it works absolutely fine.
Now I am dealing with cases where it would be much easier to create multiple plots from single Julia files, so a script like this:
#!/usr/bin/env julia
using PGFPlotsX
...
...
pgfsave("whatever.pdf")
pgfsave("another.pdf")
pgfsave("yetanother.pdf")
so that one could do a grep pgfsave SCRIPT | awk... to figure out the targets. However, I could not figure out how to generate dynamic targets (plots) based on the contents of the dependency file (Julia script).
An MWE for my problem is the following: I have a couple of files (dependencies) which are generating a bunch of targets, which are defined inside those files (and can be access via awk/grep/sed/whatever). For now, let's say that these are simply *.txt files and each line is a target.
file: a.txt
foo
bar
baz
file: b.txt
naarf
fjoord
A very basic (non-working) manual Makefile to demonstrate the goal would be something like this (it does not work as it cannot figure out how to make foo etc. but it shows the pattern for *.txt which needs to be repeated):
file: Makefile
all_products := $(shell find *.txt | xargs cat)
final_product: $(all_products)
echo $< > $#
(foo bar baz): a.txt
touch $(shell cat $<)
(narf fjoord): b.txt
touch $(shell cat $<)
so in principle, I need something to "process" the dependency (*.txt) to create a list of the targets, like
$(shell cat $%): %.txt
echo $< > $#
but I cannot manage to get a reference to the dependency on the target side ($% does not work).
Any ideas? Maybe the whole approach is just a bad idea ;)
A combination of GNU make foreach, eval and call functions is probably what you need. With your example:
TXT := $(wildcard *.txt)
.PHONY: all
.DEFAULT_GOAL := all
define MY_MACRO
$(1)-targets := $$(shell cat $(1))
$$($(1)-targets): $(1)
echo $$< > $$#
all: $$($(1)-targets)
endef
$(foreach t,$(TXT),$(eval $(call MY_MACRO,$(t))))
(pay attention to the $$ in the macro definition, they are needed). And then:
$ make
make
echo a.txt > foo
echo a.txt > bar
echo a.txt > baz
echo b.txt > naarf
echo b.txt > fjoord
If you want the recipe to build all targets at once you'll need a recent enough GNU make version (4.3 or later) and its new rule with grouped targets (x y z&: w):
TXT := $(wildcard *.txt)
.PHONY: all
.DEFAULT_GOAL := all
define MY_MACRO
$(1)-targets := $$(shell cat $(1))
$$($(1)-targets)&: $(1)
touch $$($(1)-targets)
all: $$($(1)-targets)
endef
$(foreach t,$(TXT),$(eval $(call MY_MACRO,$(t))))
And then:
$ make
touch foo bar baz
touch naarf fjoord
Note that in this case we could also use a simpler and less GNU make-dependent solution. Just use empty dummy files as time stamps, for instance .a.txt.tag for a.txt, and a static pattern rule:
TXT := $(wildcard *.txt)
TAG := $(patsubst %,.%.tag,$(TXT))
.PHONY: all
all: $(TAG)
$(TAG): .%.tag: %
touch `cat $<` $#

Make: run code before a dependency is checked

I have a target that depends on an external library:
output.txt: library/build.txt main.txt
cat library/build.txt main.txt >output.txt
(This is just an example, my actual makefile is much more complicated)
However, library/build.txt is generated by a separate makefile.
I need to run the library makefile (to potentially update build.txt) before make checks if library/build.txt is newer than output.txt
I could just have it run $(MAKE) -C library, every time, but I'm hoping to only call that when it is needed (meaning, when you try to make a target which depends on library/build.txt)
Is this possible? (maybe there's a way to get a list of dependencies and then run something if that list contains library/build.txt?)
You can try things like :
FORCE:
library/build.txt: FORCE
#echo make to build $#
output.txt: library/build.txt main.txt
cat $^ > $#

Simple inference rule in makefile

I'm currently learning how to use makefiles. But I'm struggling with % pattern rules. I've boiled down my failing makefile to this very simple example:
I fill an empty directory with:
echo aaa > a.in && echo bbb > b.in
A first makefile like this works very well:
a.out : a.in
cat $< > $#
as
make && echo *.out && cat *.out
returns
cat a.in > a.out
a.out
aaa
but when I try to use a pattern rule modifying the makefile as follows:
%.out : %.in
cat $< > $#
make then returns me:
make: *** No targets. Stop.
It seems like a very simple problem but I can't get to what I am missing...
If you have a makefile with no targets lists (only patterns), and you just type make, then you haven't told make that it should build anything specific, so it won't do anything.
A pattern rule doesn't mean "go find all the files that match this pattern and build them". A pattern rule tells make "if you need to find a way to build a file that matches this target pattern, then here's how you do it".
If you type make a.out so make knows that you want to build a target a.out, then make will use your pattern rule to build it.
Alternatively, you can add the target to your makefile, something like this:
.PHONY: all
all: a.out
%.out : %.in
cat $< > $#

Makefile with multiples rules sharing same recipe

I'd like to know if it's possible to write a Makefile with several rules, each one defining its own prerequisites and executing all of them the same recipe without duplicating the recipe. Example:
TARGETS= file1 file2 file3
all: $(TARGETS)
file1: dep1 dep2
file2: dep2 dep3 dep4
file3: dep2 dep1
cat $^ > $#
Thanks!
Yes, it is written in a rather obvious way:
TARGETS= file1 file2 file3
all: $(TARGETS)
file1: dep1 dep2
file2: dep2 dep3 dep4
file3: dep2 dep1
$(TARGETS):
cat $^ > $#
UPD.
Just to clarify.
Generic make rule looks like this:
targets... : prerequisites...
recipe
...
Any part of the rule can be omitted. Without the recipe, one can populate the list of prerequisites anywhere in the makefile, a target can occur in the left hand side of multiple rule statements.
For example, the following is equivalent to the example above (well, assuming that the Makefile is properly designed so that the order of prerequisites does not matter):
file1 file3 : dep1
file1 file2 file3 : dep2
file2 : dep3 dep4
Unlike listing prerequisites, there can be at most one explicit recipe for each target. Inside the recipe you can use automatic variables to get the target name, the list of prerequisites, etc.
UPD. 2
As #Calmarius mentions in comments this doesn't apply to pattern rules, like %.txt: %.foo.
Multiple patterns within targets mean that the rule produces all these targets at once.
This pattern rule has two targets:
%.tab.c %.tab.h: %.y
bison -d $<
This tells make that the recipe bison -d x.y will make both x.tab.c and x.tab.h.
If the file foo depends on
the files parse.tab.o and scan.o and the file scan.o depends on the
file parse.tab.h, when parse.y is changed, the recipe bison -d parse.y
will be executed only once, and the prerequisites of both
parse.tab.o and scan.o will be satisfied.
One may define multiple prerequisites in a pattern rule though (that is, provided that its targets contain a % stem, otherwise it would be a regular rule).

Resources