user123
user123

Reputation: 241

Target not known beforehand in the Makefile

I am trying to use makefile to manage my building process in a small project, where the target number and target names are not known beforehand but depends on the input. Specifically, I want to generate a bunch of data files (say .csv files) according to a cities_list.txt file with a list of city names inside. For example, if the contents of the txt file are:

newyork washington toronto

then a script called write_data.py would generate three files called newyork.csv, washington.csv and toronto.csv. When the content of the cities_list.txt file changes, I want make to deal with this change cleverly, i.e. only update the new-added cities files.

I was trying to define variable names in target names to make this happen but didn't succeed. I'm now trying to create a bunch of intermediate .name files as below:

all: *.csv

%.name: cities_list.txt
        /bin/bash gen_city_files.sh $<

%.csv: %.name write_data.py
        python3 write_data.py $<

clean:
        rm *.name *.csv

This seems to be very close to success, but it only gives me one .csv file. The reason is obvious, because make can't determine what files should be generated for the all target. How can I let make know that this *.csv should contain all the files where there exists a corresponding *.name file? Or is there any better way to achieve what I wanted to do here?

Upvotes: 0

Views: 69

Answers (1)

Beta
Beta

Reputation: 99084

All right, this should do it. We'd like a variable assignment at the head of the file:

CITY_FILES := newyork.csv washington.csv toronto.csv

There are two ways to do this. This way:

-include cities.mak

# this rule can come later in the makefile, near the bottom
cities.mak: cities_list.txt
    @sed 's/^/CITIES := /' $< > $@

and this way:

CITIES := $(shell cat cities_list.txt)

After we've done one of those two, we can construct the list of needed files:

CITY_FILES := $(addsuffix .csv, $(CITIES))

and build them:

# It is convenient to have this be the first rule in the makefile.
all: $(CITY_FILES)

%.csv: write_data.py
    python3 $< $*.name

Upvotes: 1

Related Questions