Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Makefile processing files with same extension

Tags:

makefile

This seems slightly related to How to write Makefile where target and source files have the same extension?. In that question the extensions are the same, but the input and output files seem to be in the same directory and filenames are being conditionally renamed.

I have a large collection of .txt files in ../src/ that need to be processed, and dumped into ./ (which is a directory called target/) as txt files of the same name. I want to use make, so that only files in ../src/ that have been changed get updated in ./. I would like to get the prototype working before I put the real code in.

My Makefile in ./ is as follows:

DIR = ../src
INPUTS = $(wildcard $(DIR)/*.txt)
OUTPUTS = $(patsubst $(DIR)/%.txt,%.txt,$(INPUTS))

all: $(OUTPUTS)

.PHONY: $(INPUTS)

check:
    @echo "DIR = $(DIR)"
    @echo "INPUTS = $(INPUTS)"
    @echo "OUTPUTS = $(OUTPUTS)"

%.txt: $(DIR)/%.txt
    sed -e "s/test/cat/g" "$<" > $@

For now, the contents of ../src/ are test1.txt and test2.txt. As the Makefile stands now, running make test2.txt generates the file as expected.

target/ $ make test2.txt
sed -e "s/test/cat/g" "../src/test2.txt" > test2.txt

Running make check shows the INPUTS and OUTPUTS correctly.

target/ $ make check
DIR = ../src
INPUTS = ../src/test1.txt ../src/test2.txt
OUTPUTS = test1.txt test2.txt

If I run make all, it generates every file, every time. This is expected with the .PHONY $(INPUTS) line in there.

If I remove the .PHONY $(INPUTS) target, Make gets all bound up in itself trying to find the target to make ../src/test1.txt and keeps prefixing $(DIR) in front of it until it makes too long of a filename and gives up.

make: stat: ../src/../src/../src/ [repeat for a few pages] ../src/../src/test1.txt: File name too long
make: stat: ../src/../src/../src/ [repeat for a few pages] ../src/../src/../src/test1.txt: File name too long
make: *** No rule to make target `../src/../src/../src/[repeat]../src/../src/test1.txt', needed by `../src/[repeat]../src/../src/test1.txt'.  Stop.

It never does get to processing test2.txt.


As I was drafting this, I had the idea to remove the ../ from the DIR, and relocate the Makefile so it was parent to both src/ and target/. That approach seems to work, but isn't ideal. Eventually there would be a chain of these Makefiles, each pulling from one directory to another.

Is there a way to keep the Makefile in 'target/' along with the generated destination files, and base those destination files off of something in a relative path?

like image 240
Matt D. Avatar asked Sep 16 '25 10:09

Matt D.


1 Answers

Replace

%.txt: $(DIR)/%.txt

with:

${CURDIR}/%.txt: $(DIR)/%.txt

This way %.txt does not match any .txt file in any directory. In other words, you limit this rule's scope to files in ${CURDIR}/ only and this prevents that endless recursion.

See §10.5.4 How Patterns Match for more details.

It is also good practice to avoid relative paths:

DIR = $(abspath ../src)
like image 103
Maxim Egorushkin Avatar answered Sep 18 '25 09:09

Maxim Egorushkin