PedroA
PedroA

Reputation: 1925

makefile not expanding dynamic prerequisites

I want to have a makefile that will take some strings as prefixes for some files (NAMES) and from there work on the target and prerequisite file names. In the example below, for example, the idea would be to convert 2 a csv files (foo.csv and bar.csv) to tabular (although I'm just echoing the target and prerequisite).

NAMES = foo bar

PR = $(patsubst %,%.csv,$(NAMES))
TB = $(patsubst %,%.tsv,$(NAMES))

all: $(TB)

%.tsv: $(PR)
    @echo $< $@

This prints:

foo.csv foo.tsv
foo.csv bar.tsv

So, it looks like that makefile is not expanding correctly the prerequisites in PR as I would expect to see bar.csv bar.tsv on the second line.

However, if I print $PR and $TB, both seem to be set properly:

$(info $$PR is [${PR}])
$(info $$TB is [${TB}])
# prints
$PR is [foo.csv bar.csv]
$TB is [foo.tsv bar.tsv]

Any idea how to get this working properly?

Note that I have both foo.csv and bar.csv files in the working directory.

Upvotes: 0

Views: 465

Answers (1)

G.M.
G.M.

Reputation: 12899

The problem lies in the way you're using the built in variable $<. If you expand the variables manually and rewrite the makefile it becomes...

NAMES = foo bar

PR = $(patsubst %,%.csv,$(NAMES))
TB = $(patsubst %,%.tsv,$(NAMES))

all: foo.tsv bar.tsv

%.tsv: foo.csv bar.csv
    @echo $< $@

But $< refers to the first prerequisite which is always foo.csv regardless of the target.

One solution might be to use a scoped static pattern rule. So something like...

NAMES = foo bar

PR = $(patsubst %,%.csv,$(NAMES))
TB = $(patsubst %,%.tsv,$(NAMES))

all: $(TB)

# Tell make how to build a .tsv from a .csv but constrain the rule
# so that it only applies to .tsv files that are part of $(TB).
#
$(TB): %.tsv: %.csv
    @echo 'building target [$@] with $$< = [$<]'

The above results in...

building target [foo.tsv] with $< = [foo.csv]
building target [bar.tsv] with $< = [bar.csv]

Upvotes: 2

Related Questions