make clean: Only remove files that have been generated

Multi tool use
make clean: Only remove files that have been generated
With the Makefile
I'm working on, I convert pdf files into txt files.
Makefile
I've implemented a clean
target that would remove all .txt files. However, I do not wish to delete the source files, only those that have been generated.
clean
Example:
I have following files in my folder:
pdfsource.pdf
and donotharm.txt
pdfsource.pdf
donotharm.txt
Running my makefile would create following file:
pdfsource.txt
pdfsource.txt
For now, my clean
looks like this:
clean
rm -f *.txt
Using make clean
would not only delete pdfsource.txt
, which is desired, but also donotharm.txt
.
make clean
pdfsource.txt
donotharm.txt
I think I could use: .PRECIOUS: donotharm.txt
, but this is really specific. I'd like to have a general solution to this.
.PRECIOUS: donotharm.txt
Thanks in advance!
.PRECIOUS
rm -f *.txt
rm
.PRECIOUS
make
clean
.PRECIOUS
2 Answers
2
You can list the generated files in a make variable and use it to clean only these:
PDF := $(wildcard *.pdf)
TEXT := $(patsubst %.pdf,%.txt,$(PDF))
...
clean:
rm -f $(TEXT)
Or, if you prefer a more compact (but a bit less readable) form:
clean:
rm -f $(patsubst %.pdf,%.txt,$(wildcard *.pdf))
Of course, this works only if there is no {foo.pdf,foo.txt}
pair for which you want to preserve foo.txt
from deletion by make clean
.
{foo.pdf,foo.txt}
foo.txt
make clean
Note: using make variables, in such a case, is usually a good idea because they can be shared among various rules. Example:
PDF := $(wildcard *.pdf)
TEXT := $(patsubst %.pdf,%.txt,$(PDF))
.PHONY: all clean
all: $(TEXT)
$(TEXT): %.txt: %.pdf
pdftotext $< $@
clean:
rm -f $(TEXT)
Another approach: "make -nps" gives you all make's metadata about dependencies. For any intermediate file, it prints
filename: ...
So you can exactly delete such files with a generic "clean" rule:
clean:; MAKEFLAGS= ${MAKE} -j1 -spinf $(word 1,${MAKEFILE_LIST})
| sed -n '/^# I/,$${/^[^#[%.][^ %]*: /s/:.*//p;}; 1s|.*|${clean}|p' | xargs rm -rf
The first line handles use of makefiles other than the defaults (makefile, GNUmakefile, Makefile)
In the "sed" command:
/^# I/,$
... selects the zone of make metadata with dependencies.
/^[^#[%.][^ %]*: /
... filters out comments, implicit rules, and files with no dependencies (the trailing space). It doesn't filter out phony targets; oh well.
Finally:
1s|.*|${clean}|p
adds any explicit targets for "clean" -- what you know that make does not; e.g.
clean += tmpdir/* *.gcda
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Be aware:
.PRECIOUS
won't help you if you runrm -f *.txt
. That's a whole different program: nothing in therm
command knows or cares what you files you may have marked.PRECIOUS
in your makefile. That only has meaning tomake
itself, so that it won't delete those files for you. If you specifically write a rule (likeclean
) that deletes them.PRECIOUS
has no impact on that.– MadScientist
Jul 2 at 10:48