Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading a file inside makefile

I want to read a file called metafile inside a makefile.

metafile looks something like this:
file1
file2
file3

I need to read this metafile inside my makefile line by line and check if the files mentioned inside exists or not and only print names of files which exists.

I've tried a few things without success. like:

FILE=`cat metafile`
for line in $(FILE); if [ -e $${line} ]; then echo $${line} fi; done;
like image 436
hari Avatar asked Nov 28 '12 20:11

hari


1 Answers

You can put an arbitrary piece of shell script in a target. Keeping the file's contents in a Makefile variable does not make any sense to me, unless you also need the data in other targets for other reasons. (If so, you cannot use backticks, anyway.)

target:
        @while read -r file; do \
            test -e "$$file" && echo "$$file"; \
        done <metafile

For what it's worth, the while loop is a safer and more idiomatic way to loop over a file's lines in a shell script than the for loop with backticks, even though you see that a lot.

The @ prevents Make from echoing the shell script commands; take that out if for some reason you need to see them. In fact, I recommend against using this, especially while you are debugging -- use make -s to have make run silently once you are confident your recipe works correctly.

A more idiomatic way to do this in a Makefile is to have a target depend on these files, and use Make's own logic:

target: file1 file2 file3
        @echo $(filter-out $?,$^)

This is GNU Make syntax; it might get more complex if you want to be portable to other Make flavors (to the point where maybe the shell script is preferable after all). It will echo everything on one line, but if you need separate lines, that should be a trivial fix.

I would simply build a small auxiliary Makefile snippet and include the dependencies:

target: target.d
target.d: metafile
        sed 's/^/target: /' $< >$@
include target.d

This builds a small list of dependencies so you don't need to list them in the target: dependencies explicitly; so instead of file1 file2 file3 in the recipe above, the dependencies would live in the generated target.d which would contain

target: file1
target: file2
target: file3

You need to filter out the dependency on target.d (or leave it undeclared; I believe GNU Make should cope).

like image 71
tripleee Avatar answered Oct 05 '22 08:10

tripleee