It has been ages since I wrote a Makefile, so may be this is a very silly question. So please forgive me if I came here to ask, but I cannot understand the behaviour of make with the Makefile that follows. In all the executions below, the folder output/ and the output files do not exist, so they should be built.
.PHONY: all
all: $(FILES2)
FLD ::= output/
FILES1 ::= $(addprefix $(FLD), out11 out12)
FILES2 ::= $(addprefix $(FLD), out21 out22)
$(warning FILES1: $(FILES1))
$(warning FILES2: $(FILES2))
$(FILES1): script1.py
python3 script1.py --output_fld=$(FLD)
$(FILES2): $(FILES1) script2.py
python3 script2.py --output_fld=$(FLD)
When run with make -f Makefile, I get:
Makefile:8: FILES1: output/out11 output/out12
Makefile:9: FILES2: output/out21 output/out22
make: Nothing to be done for 'all'.
When run with make -d -f Makefile, I get a long list of messages ending with:
Considering target file 'all'.
File 'all' does not exist.
Finished prerequisites of target file 'all'.
Must remake target 'all'.
Successfully remade target file 'all'.
make: Nothing to be done for 'all'.
When run with make output/out11 (or make output/out12) (i.e. with an explicit target) I get:
make output/out11
Makefile:8: FILES1: output/out11 output/out12
Makefile:9: FILES2: output/out21 output/out22
python3 script1.py --output_fld=output/
I am using GNU Make V4.1 on Ubuntu 18.04.5 LTS. I have seen that Make v4.3 introduced a special syntax for grouped targets, but I cannot use it here.
Now, the question: what do I need to correct (and understand) in order to have make all actually executing the commands for building the targets?
You have this:
all: $(FILES2)
...
FILES2 ::= $(addprefix $(FLD), out21 out22)
When the all target is defined, the FILES2 variable is not set yet, so it expands to the empty string, so all has no prerequisites and no recipe to build it, so there's nothing for make to do here.
The variable $(FILES2) does not contain any value and all target has no pre-requisites. In order to solve this issue, define the variables FILES1 and FILES2 before as shown:
.PHONY: all
FLD ::= output/
FILES1 ::= $(addprefix $(FLD), out11 out12)
FILES2 ::= $(addprefix $(FLD), out21 out22)
$(warning FILES1: $(FILES1))
$(warning FILES2: $(FILES2))
all: $(FILES2)
$(FILES1): script1.py
echo "Executing script 1"
python3 script1.py --output_fld=$(FLD)
$(FILES2): $(FILES1) script2.py
echo "Executing script 2"
python3 script2.py --output_fld=$(FLD)
Related
This question is a follow-up to What makefile lazy evaluation rule governs this behavior?. I'm still trying to grok some of the rules of gnu make's lazy evaluation.
I want to have a make variable for the content of a directory after that directory has been updated by a recipe.
This Makefile demonstrates that $(A_FILE) is evaluated to find the created file when it's in the "parent" of the recipe that actually creates the file:
A_FILE = $(wildcard subdir/*)
all: a
#echo $(A_FILE)
a:
#mkdir ./subdir
#touch subdir/b
$ rm -rf ./subdir/ && make
subdir/b
$
But the following Makefile has a seemingly trivial change: $(A_FILE) is referenced in the recipe where its containing directory is updated - but now the variable is empty:
A_FILE = $(wildcard subdir/*)
all: a
#echo $(A_FILE)
a:
#mkdir ./subdir
#touch subdir/b
#sleep 1
#echo $(A_FILE)
$ rm -rf ./subdir/ && make
$
I added the sleep to rule out timing issues of the directory being trawled too quickly after it had been updated.
What gives? Why does $(A_FILE) get evaluated against the updated subdir content if it's referenced in the higher-layer recipe but not in the lower-layer recipe where it's actually updated?
GNU make evaluates all lines in the recipe before it starts running any line in the recipe. So, when it is getting ready to run your recipe for the rule a it first expands all the lines, including the last line with $(A_FILE) in it. At that point no parts of the recipe have been run yet so the result is empty.
Then after all the expansion, the shell is invoked to run the lines in the recipe.
i was compiling a kernel module thermal.c at an ARCH linux distro using Makefile
Makefile:
obj-m += thermal.o
all:
make -C /lib/modules/$(uname -r)/build/ M=$(PWD) modules
clean:
make -C /lib/modules/$(uname -r)/build/ M=$(PWD) clean
the make command output is:
make -C /lib/modules//build/ M=/home/user/dir modules
make[1]: *** /lib/modules//build/: No such file or directory. Stop.
make: *** [Makefile:4: all] Error 2
uname -r output : 5.6.8-arch1-1
make expands the recipes before passing them to the shell. In your case make replaced $(PWD) by the value of the make variable named PWD (correct) but it also replaced $(uname -r) by the value of the make variable named uname -r. As there was no such make variable defined, the result was the empty string. Using $$(uname -r) solves the problem because make expands it as $(uname -r), exactly what you want to pass to the shell.
In summary, you must escape the $ you want to preserve from the make expansion by doubling them:
all:
make -C /lib/modules/$$(uname -r)/build/ M=$(PWD) modules
clean:
make -C /lib/modules/$$(uname -r)/build/ M=$(PWD) clean
Hopefully this is a very simple question. I have a makefile pattern rule that looks like this:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
I want the makefile to build a number of .so files, so I tried to get it to build two files (radgrd_py.so and lodiso_py.so) by doing this:
radgrd_py.so lodiso_py.so:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
and then tried this:
radgrd_py.so:
lodiso_py.so:
%.so : %.f %.pyf
f2py -c -L${LAPACK_DIR} ${GRASPLIBS} -m $* $^ ${SOURCES} --opt='-02' --f77flags='-fcray-pointer' >> silent.txt
But in each case, it only builds the first target that I specify. If I run 'make radgrd_py.so' it works fine, I'm just not sure how to specify a list of files that need to be built so I can just run 'make'.
The usual trick is to add a 'dummy' target as the first that depends on all targets you want to build when running a plain make:
all: radgrd_py.so lodiso_py.so
It is a convention to call this target 'all' or 'default'. For extra correctness, let make know that this is not a real file by adding this line to your Makefile:
.PHONY: all
Best way is to add:
.PHONY: all
.DEFAULT: all
all: radgrd_py.so lodiso_py.so
Explanations:
make uses the first target appearing when no .DEFAULT is specified.
.PHONY informs make that the targets (a coma-separated list, in fact) don't create any file or folder.
all: as proposed by schot
I'm trying to write a makefile to produce several output files for each of several sources, using pattern rules.
I have the following Makefile (GNU Make 3.8.1):
all : foo.all bar.all
%.all : %.pdf %.svg
#echo Made $*
%.pdf :
touch $#
%.svg :
touch $#
.PHONY: foo.all bar.all
Since *.all do not represent real output files, I tried marking them as .PHONY. However, running make then doesn't work:
$ ls
Makefile
$ make
make: Nothing to be done for `all'.
According to make -d:
No implicit rule found for `all'.
Considering target file `foo.all'.
File `foo.all' does not exist.
Finished prerequisites of target file `foo.all'.
Must remake target `foo.all'.
Successfully remade target file `foo.all'.
Considering target file `bar.all'.
File `bar.all' does not exist.
Finished prerequisites of target file `bar.all'.
Must remake target `bar.all'.
Successfully remade target file `bar.all'.
Finished prerequisites of target file `all'.
Must remake target `all'.
Successfully remade target file `all'.
make: Nothing to be done for `all'.
which seems to be pretending to run the %.all rules, but skipping the bodies.
But with the .PHONY line commented out, Make runs the targets, but then spontaneously decides to delete the output files:
$ make
touch foo.pdf
touch foo.svg
Made foo
touch bar.pdf
touch bar.svg
Made bar
rm foo.pdf foo.svg bar.pdf bar.svg
According to make -d, it says:
Removing intermediate files...
Minimal example
A minimal example giving anomalous behavior:
%.all: %.out
#echo Made $*
%.out:
touch $#
I expect running make somefile.all to cause it to create the file somefile.out, but it gets deleted:
$ make somefile.all
touch somefile.out
Made somefile
rm somefile.out
Keeping make from deleting intermediary files
I recommend against using .PRECIOUS (see below as to why). Using .SECONDARY would preserve the .out files:
TARGETS=foo bar
all: $(TARGETS:=.all)
%.all: %.out
#echo Made $*
%.out:
touch $#
.SECONDARY: $(TARGETS:=.out)
$(TARGETS:=.all) just appends .all to all names in TARGETS. $(TARGETS:=.out) appends .out. We apparently cannot use %.out as a target of .SECONDARY. These just save having to relist all targets individually.
I prefer to not use .PRECIOUS for this because the documentation says
if make is killed or interrupted during the execution of their recipes, the target is not deleted.
This can leave corrupted files in the file system. Here's an example.
all: foo.all bar.all
%.all: %.out
#echo Made $*
%.out:
sh -e -c 'echo "{1, 2, 3" > $#; FAIL!; echo "}" >> $#'
.PRECIOUS: %.out
The FAIL! command simulates a tool that crashes in the middle of its work. Here's a shell session working with the Makefile above:
$ ls
Makefile
$ make
sh -e -c 'echo "{1, 2, 3" > foo.out; FAIL!; echo "}" >> foo.out'
sh: 1: FAIL!: not found
make: *** [foo.out] Error 127
$ cat foo.out
{1, 2, 3
Yikes... my foo.out file is incomplete. Let's try making again:
$ make
Made foo
sh -e -c 'echo "{1, 2, 3" > bar.out; FAIL!; echo "}" >> bar.out'
sh: 1: FAIL!: not found
make: *** [bar.out] Error 127
$ cat *.out
{1, 2, 3
{1, 2, 3
Make is none the wiser about files left around by earlier runs so when you run make again, it will take the corrupted files at face value. foo.out was not remade (despite the "Made foo" message) because it already exists and the Makefile went straight to trying to make bar.
.SECONDARY makes it so that:
The targets which .SECONDARY depends on are treated as intermediate files, except that they are never automatically deleted.
This means they are never automatically deleted just because they are intermediate files. The default make behavior of deleting targets that were being rebuilt if the tool rebuilding them crashed is not affected.
Using .PHONY with pattern rules
It seems though that .PHONY works only for targets that are explicit, not inferred. I've not found documentation confirming this. However, this works:
TARGETS:=foo bar
TARGETS_all:=$(TARGETS:=.all)
.PHONY: all
all: $(TARGETS_all)
.PHONY: $(TARGETS_all)
$(TARGETS_all): %.all: %.out
#echo Made $*
%.out:
touch $#
.SECONDARY: $(TARGETS:=.out)
In this rule $(TARGETS_all): %.all: %.out $(TARGETS_all): gives the list of targets to which the pattern can be applied. It makes foo.all and bar.all explicit targets. Without this, they would be inferred targets.
You can test that it works by creating file called foo.all in your directory and run make over and over. The foo.all file has no effect on make.
Your somefile.out files are considered intermediate by GNU make, which is why they are automatically deleted in your example. You can instruct GNU make to preserve these files by use the of .PRECIOUS special target, like this:
%.all: %.out
#echo Made $*
%.out:
touch $#
.PRECIOUS: %.out
Directory tree
.
| Makefile
| src
| Makefile
| spec
| test
in ./Makefile
default: all
.DEFAULT:
$(MAKE) -C $#
in src/Makefile
.PHONY: all spec test ...
spec:
bundle exec cucumber ../spec
When I am in the src directory the "make spec" works well.
..././src/# make spec
blablabla
But when I am in the root directory i get that there is "nothing to be done" but it is a phony target
..././# make spec
make: Nothing to be done for `spec'.
I suppose it is a problem with the name of task that is the same as the name of the directory, with a sub makefile.
I suppose it is a problem with the name of task that is the same as the name of the directory, with a sub makefile.
Yep.
Try something like:
all :
forward_ : ;
% : forward_
$(MAKE) -C $#
.PHONY : all forward_
Phony forward_ target is supposed to trigger re-evaluation of % target even when there is an existing file or directory with $# name.