Reputation: 241
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
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