1

With the Makefile I'm working on, I convert pdf files into txt files.

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.

Example: I have following files in my folder:

pdfsource.pdf and donotharm.txt

Running my makefile would create following file:

pdfsource.txt

For now, my clean looks like this:

rm -f *.txt

Using make clean would not only delete pdfsource.txt, which is desired, but also 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.

Thanks in advance!

Two-Tu
  • 107
  • 2
  • 10
  • Be aware: `.PRECIOUS` won't help you if you run `rm -f *.txt`. That's a whole different program: nothing in the `rm` command knows or cares what you files you may have marked `.PRECIOUS` in your makefile. That only has meaning to `make` itself, so that it won't delete those files for you. If you specifically write a rule (like `clean`) that deletes them `.PRECIOUS` has no impact on that. – MadScientist Jul 02 '18 at 10:48

2 Answers2

3

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.

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)
Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51
0

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
Mischa
  • 2,240
  • 20
  • 18