Simple Makefile doesn't clean - makefile

I have this Makefile:
default:
mv presentacion.pdf /tmp
pdflatex presentacion.tex
clean:
rm -f *.{aux,log,nav,out,snm,toc}
The order make works well but when I try to do a make clean the shell outputs:
rm -f *.{aux,log,nav,out,snm,toc}
And does not remove the files. What's wrong in the code?

Try to set the shell to bash in your makefile (according docs)
SHELL=/bin/bash
default:
mv presentacion.pdf /tmp
pdflatex presentacion.tex
clean:
rm -f *.{aux,log,nav,out,snm,toc}

You can let make add the prefix to your files (instead of bash), by using addprefix:
PREFIXES := aux log nav out snm toc
FILES := $(addprefix *., $(PREFIXES))
default:
mv presentacion.pdf /tmp
pdflatex presentacion.tex
clean:
rm -f $(FILES)

Related

Why is the make target up to date even when using .phony?

I have a Makefile that looks like this:
RENDER_HTML=jupyter nbconvert --execute --to html
MATE40001_TARGETS=$(wildcard MATE40001/notes/*.ipynb)
.phony: all
all: MATE40001
.phony: variables
variables:
#echo MATE40001_TARGETS:
#echo ${MATE40001_TARGETS} | sed 's/ /\n/' | sed 's/MATE/\tMATE/'
.phony: MATE40001
MATE40001: ${MATE40001_TARGETS}
mkdir -p $#/html/
${RENDER_HTML} $^
mv $#/notes/*.html $#/html/
.phony: clean
clean:
rm -rf */html/ *~ */notes/*.html
When I run:
make
make clean
make
make MATE40001
I get the following output:
...
<normal output>
...
rm -rf */html/ *~ */notes/*.html
make: Nothing to be done for 'all'.
make: 'MATE40001' is up to date.
As far as I understand, make is looking for the file MATE40001 which exists as a folder and then stops because there are no updated files. However I do not want this to happen, and I thought that adding .phony: MATE40001 would stop this problem.
What do I need to add/change to fix this issue?
from comment by #G.M.
Use .PHONY instead of .phony

Make says file is up to date, but it does not exist

I want
I am trying to compile some latex that has snippets of python code and the output of those snippets. I need the document to be always updated with the last changes made in the snippets and in their outputs, so the idea is maintain a makefile that could monitor this changes and generate the updated outputs.
So if I modify the file a/11.py, I want make to execute it to generate a new output a/11.out.
I have
This is my makefile
DOC=myPdf
STY=st
PY_DIR=a/
TEX=pdflatex -shell-escape -interaction=batchmode -file-line-error
$(DOC).pdf: $(PY_DIR)11.out $(PY_DIR)12.out $(DOC).tex $(STY).sty
$(TEX) $(DOC).tex
$(PY_DIR)11.out:
$(cd PY_DIR && python3 11.py > 11.out)
$(PY_DIR)12.out:
$(cd PY_DIR && python3 12.py > 12.out)
.PHONY: clean
clean:
rm *.aux *.log > /dev/null 2>&1
I wonder
Even when the file a/11.out doesn't exist, and I instruct make a/11.out make says: make: 'a/11.out' is up to date. (I am still learning make, so I probably have more mistakes).
I saw
Make in subfolder, but because I am not using $(MAKE), I cannot use it.
Similar question, but I don't think it is the same.
Thank you for your time :)
Update
This is my new version, based in the answer of Renaud (thanks for your help), some python scripts are intended to output text (xxxt.py), and others to plot images (xxxi.py), so there is no redirection for them:
DOC :=myPdf
STY :=st
PY_DIR :=a/
TEX :=pdflatex -shell-escape -interaction=batchmode -file-line-error
PYS := $(wildcard $(PY_DIR)*.py)
OUTS := $(patsubst %.py,%.out,$(PYS))
.PHONY: all clean
all: $(DOC).pdf
%.pdf: %.tex $(STY).sty $(OUTS)
$(TEX) $<
$(PY_DIR)%.out: $(PY_DIR)%t.py
cd $(PY_DIR) && python3 $*t.py > $*.out
$(PY_DIR)%.png: $(PY_DIR)%i.py
cd $(PY_DIR) && python3 $*i.py
clean:
rm *.aux *.log > /dev/null 2>&1
The directory looks like this:
./st.sty
./myPdf.tex
./myPdf.pdf
./a/11t.py
./a/11.out
./a/12i.py
./a/12.png
./a/21t.py
./a/...
However, now right after modifying myPdf.tex, make says make: Nothing to be done for 'all'.
What am I doing wrong?
Your recipes are wrong. Make expands the recipes before passing them to the shell. As there is no make variable named cd PY_DIR && python3 11.py > 11.out, $(cd PY_DIR && python3 11.py > 11.out) expands as the empty string and make considers that there is nothing to do for $(PY_DIR)11.out. Just write your recipes as plain shell (and fix the other bug with the unexpanded PY_DIR):
$(PY_DIR)11.out:
cd $(PY_DIR) && python3 11.py > 11.out
$(PY_DIR)12.out:
cd $(PY_DIR) && python3 12.py > 12.out
Note: if you want make to re-run the recipes when your python scripts change you should let him know that the output files depend on the python scripts. The best is probably to use a pattern rule instead of one specific rule per file:
$(PY_DIR)%.out: $(PY_DIR)%.py
cd $(PY_DIR) && python3 $*.py > $*.out
($* is a make automatic variable, it expands as the stem of the pattern).
A few more improvements:
You could ask make to find alone the python scripts, compute the names of the output files and store all this in make variables that you can used in your other rules.
You can use a pattern rule for the xx.tex -> xx.pdf process. And use another make automatic variable for it: $< that expands as the first prerequisite.
DOC := myPdf
STY := st
PY_DIR := a/
TEX := pdflatex -shell-escape -interaction=batchmode -file-line-error
PYS := $(wildcard $(PY_DIR)*.py)
OUTS := $(patsubst %.py,%.out,$(PYS))
.PRECIOUS: $(OUTS)
.PHONY: all clean
all: $(DOC).pdf
%.pdf: %.tex $(OUTS) $(STY).sty
$(TEX) $<
$(PY_DIR)%.out: $(PY_DIR)%.py
cd $(PY_DIR) && python3 $*.py > $*.out
.PHONY: clean
clean:
rm *.aux *.log > /dev/null 2>&1
Note: I declared $(OUTS) as precious such that make does not delete them when it is done with the building of $(DOC).pdf.
Update with the new specifications and separated python scripts for xx.out and xx.png production:
DOC := myPdf
STY := st
PY_DIR := a
TEX := pdflatex -shell-escape -interaction=batchmode -file-line-error
PYTS := $(wildcard $(PY_DIR)/*t.py)
PYIS := $(wildcard $(PY_DIR)/*i.py)
OUTS := $(patsubst $(PY_DIR)/%t.py,$(PY_DIR)/%.out,$(PYTS))
PNGS := $(patsubst $(PY_DIR)/%i.py,$(PY_DIR)/%.png,$(PYIS))
.PRECIOUS: $(OUTS) $(PNGS)
.PHONY: all clean
all: $(DOC).pdf
%.pdf: %.tex $(STY).sty $(OUTS) $(PNGS)
$(TEX) $<
$(PY_DIR)/%.out: $(PY_DIR)/%t.py
cd $(PY_DIR) && python3 $*t.py > $*.out
$(PY_DIR)/%.png: $(PY_DIR)/%i.py
cd $(PY_DIR) && python3 $*i.py
clean:
rm -f *.aux *.log > /dev/null 2>&1
Notes:
I slightly modified the definition of PY_DIR such that, when used in other parts of the Makefile, it is clear that it is a directory path. Just a matter of taste, I guess.
I added the -f option to your clean recipe such that it doesn't fail if the files to delete do not exist.
Update:
As noted by MadScientist in a comment, using $* is less generic than referring to the target ($#) and the prerequisite ($<). But as we are operating not directly on them but on their directory ($(PY_DIR)) and base file names (xx[it].py, xx.out, xx.png), switching from $* to other, more generic, automatic variables is not that simple.
But make has some more tricks that can help here: $#, $<... have variants ($(#F), $(#D)...) that expand to just the directory part or the file part. Note that, according the GNU make manual:
These variants are semi-obsolete in GNU make since the functions dir
and notdir can be used to get a similar effect.
Anyway, if we wanted to avoid $* here is what we could use instead:
$(PY_DIR)/%.out: $(PY_DIR)/%t.py
cd $(#D) && python3 $(<F) > $(#F)
$(PY_DIR)/%.png: $(PY_DIR)/%i.py
cd $(#D) && python3 $(<F)
Or (modern version):
$(PY_DIR)/%.out: $(PY_DIR)/%t.py
cd $(dir $#) && python3 $(notdir $<) > $(notdir $#)
$(PY_DIR)/%.png: $(PY_DIR)/%i.py
cd $(dir $#) && python3 $(notdir $<)

Object directory in Makefile.am

My current Makefile.am looks something like this:
bin_PROGRAMS = MyProgram
AM_CPPFLAGS = -I../shared
MyProgram_SOURCES = main.cpp Source1.cpp ../shared/Source2.cpp
clean : clean-am
rm -f *~
rm -f DEADJOE
distclean: distclean-am
rm -f *~
rm -f DEADJOE
rm -f Makefile
rm -f *log
This creates all the .o files in the current directory. How can I specify a different object directory in a Makefile.am? I failed to find this in the GNU documentation, although I am sure it must be there somewhere.
You can't do this in Makefile.am. This approach is not generally supported by autoconf and automake at all.
Instead, Automake supports configuring and building outside the source tree. So in your current tree, "make distclean", then:
mkdir ../build
cd ../build
../src/configure
make

Makefile -j does useless things

I have a shell program that generates 3 files from one source file. For instance I can have 'makedocumentation' that take in input foo.tex and generates foo.pdf, foo.dvi and foo.ps.
Because of performances issues I have to call my Makefile with the option -j8.
With this example file:
names = a b
src = $(addsuffix .def,$(names))
a = $(patsubst %.def,%.inc,$(src))
b = $(patsubst %.def,%.asm,$(src))
c = $(patsubst %.def,%.h,$(src))
obj = $(a) $(b) $(c)
command= cp $(1) $(basename $(1)).inc; \
cp $(1) $(basename $(1)).asm; \
cp $(1) $(basename $(1)).h
all: $(obj)
init: clean $(src)
$(src): %:
touch $#
$(a): %.inc: %.def
$(call command, $<)
$(b): %.asm: %.def
$(call command, $<)
$(c): %.h: %.def
$(call command, $<)
clean:
-rm -f *.def
-rm -f *.inc
-rm -f *.asm
-rm -f *.h
If I run it without -j I get:
$ make
cp a.def a.inc; cp a.def a.asm; cp a.def a.h
cp b.def b.inc; cp b.def b.asm; cp b.def b.h
And in the other case:
$ make -j8
cp a.def a.inc; cp a.def a.asm; cp a.def a.h
cp b.def b.inc; cp b.def b.asm; cp b.def b.h
cp a.def a.inc; cp a.def a.asm; cp a.def a.h
cp b.def b.inc; cp b.def b.asm; cp b.def b.h
cp a.def a.inc; cp a.def a.asm; cp a.def a.h
cp b.def b.inc; cp b.def b.asm; cp b.def b.h
We can observe that in parallel mode, make regenerates files that already exists.
I would like to avoid it...
I also tried something like:
a.inc a.asm a.h: a.def
command $<
But I don't get any better result.
Any help ?
As you wrote the original makefile you haven't told make that the output files share any relationship so it can't know that they've already been built and so it has to try to build each one each time.
Your modified idea is the right idea but unforunately make doesn't interpret that sort of definition as indicating that the single command will generate all the files and instead it sees it as a way to build each individual file (written in a compact shorthand).
A rule with multiple targets is equivalent to writing many rules, each
with one target, and all identical aside from that.
The only way to tell make that N output files are generated from 1 rule body is with multiple pattern rules
Pattern rules may have more than one target. Unlike normal rules, this
does not act as many different rules with the same prerequisites and
recipe. If a pattern rule has multiple targets, make knows that the
rule's recipe is responsible for making all of the targets. The recipe
is executed only once to make all the targets. When searching for a
pattern rule to match a target, the target patterns of a rule other
than the one that matches the target in need of a rule are incidental:
make worries only about giving a recipe and prerequisites to the file
presently in question. However, when this file's recipe is run, the
other targets are marked as having been updated themselves.

Makefile: rule that match multiple patterns

I have this rule in my Makefile, that responds to flags I pass:
$(BUILD_DIR)/disable_%:
mkdir -p $(BUILD_DIR)
touch $(BUILD_DIR)/disable_$*
rm -f $(BUILD_DIR)/enable_$*
cd $(BUILD_DIR) && rm -f Makefile
$(BUILD_DIR)/enable_%:
mkdir -p $(BUILD_DIR)
touch $(BUILD_DIR)/enable_$*
rm -f $(BUILD_DIR)/disable_$*
cd $(BUILD_DIR) && rm -f Makefile
What this means is that when changing the flags by which I invoke the makefile, I can trigger some recompilations that could depend on these flags.
The code presented above is a bit redundant: you see that I remove a file, touch another and remove a Makefile in both cases. The only thing that changes is the name of the files that I touch/remove, and they are related.
For instance,
make clean
make enable_debug=yes enable_video=no # will compile from zero
make enable_debug=no enable_video=no # flag change detected -> recompile some submodules that depend on this flag
Provided that the only thing that changes between the two rules ( [en|dis]able ), what I would like is to only have 1 generic rule, something like that:
# match 2 parts in the rule
$(BUILD_DIR)/%ble_%:
mkdir -p $(BUILD_DIR)
touch $(BUILD_DIR)/(???)ble_$* # should be $#
rm -f $(BUILD_DIR)/(???)able_$* # should be disable if $# is enable and inverse
cd $(BUILD_DIR) && rm -f Makefile
Is this possible ?
PS: Sorry if I didn't get the title correctly, I couldn't figure how to explain it better.
$(BUILD_DIR)/enable_% $(BUILD_DIR)/disable_%:
mkdir -p $(BUILD_DIR)
rm -f $(BUILD_DIR)/*able_$*
touch $#
cd $(BUILD_DIR) && rm -f Makefile
Not literally what you wanted (multi-wildcards are forbidden in make), but does quite the same.

Resources