Post-build step for multiple targets - makefile

I have a makefile that has multiple targets for outputting data in different formats, e.g. make html, make pdf, make txt etc. and I would like to have pre-build and post-build steps that run when any of these options are used. I have the pre-build step sorted, but not sure how I can get the post-build step working properly.
.PHONY: html pdf txt pre-build post-build
pre-build:
do-pre-build-stuff
post-build:
do-post-build-stuff
html: data.dat
generate-html data.dat
pdf: data.dat
generate-pdf data.dat
txt: data.dat
generate-txt data.dat
data.dat: pre-build
generate-some-data > data.dat
How can I get the post-build step to run after every target?

You have to write a different rule for each one, unfortunately. But you can make it simpler with a static pattern rule:
html pdf txt: %: real-%
do-post-build-stuff
real-html: data.dat
generate-html data.dat
real-pdf: data.dat
generate-pdf data.dat
real-txt: data.dat
generate-txt data.dat
This creates targets html, pdf, and txt which depend on the real- versions. The real- versions do the actual work, then after they're done the post-build stuff is done as a recipe in the base target (html, pdf, and txt).
That rule is just a shorthand so you don't have to write it all out; the result is identical:
html: real-html
do-post-build-stuff
pdf: real-pdf
do-post-build-stuff
txt: real-txt
do-post-build-stuff

Related

Makefile - pdf generation using LaTeX

I wrote a simple makefile to generate pdf using latex and I succeeded.
However, There are 2 point that irritates me:
when I run make the output PDF is in the same folder where the makefile is written and I want to change that
I want to copy the pdf file generated to another file with another name but I don't know how to do that
Here is a snippet of my code:
# Generating the file
$(FILE).pdf: $(IMAGES) $(PACKAGES) $(COMMON_TEX_SOURCES) $(FILE_TEX_SOURCES) $(FILE_IMAGES)
latexmk -lualatex $(FILE)
##############################################################################
#rule to generate file
file: $(FILE).pdf
Your help is appreciated
To make the target go into a another folder, change the target path:
some/dir/$(FILE).pdf: $(IMAGES) ...
To copy the file from one place to another:
some/other/dir/$(FILE).pdf: some/dir/$(FILE).pdf
cp $< $#

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?
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

GNU Make - build only out-of-date file in directory

Pretty new to GNU Make. This is a less complex example of something more general I have been trying to get to work.
I have many input files that have similar name format .txt, and I have a shell script that will take the input file and generate an output of the same name but with a different extension .wc. I have written the following Make file.
# name of dependencies
SRC = $(wildcard *.txt)
# get name of targets (substitute .wc for .txt)
TAR = $(SRC:.txt=.wc)
all: $(TAR)
%.wc: %.txt
sh word_count.sh $<
This runs fine, and will generate all the .wc output files. However, if I modify one of the input(dependency) files, they are all rebuilt. So the question is; what is the best way to get GNU Make to only process the modified .txt files in the directory?

Makefile for gnuplot (Many figures) and latex integration

Question: How do I get a makefile that can check an arbitrary number of *.eps and *.gp (gnuplot codes) and has a rule to build new *.eps and *.tex files from the newly edited *.gp files?
Goal:
Create a Makefile that checks if any of my chapters (.tex), plots (.eps, .tex), or gnuplot codes (.gp) have changed since last compile. Create a generic rule that executes necessary *.gp codes before compiling document.
EDIT: More details on GOAL: I would like Make to build Thesis.pdf but before doing so execute any foo.gp files that have been altered since the last build. the .gp files may be updated for a number of reasons including changing of an axis label, a legend entry, added data...
Background: I am writing my dissertation and intend to make use of both LaTex and GNUplot. Due to the large number of figures it seems like a good call to put together a makefile that insures if any of my gnuplot codes (*.gp) are changed that the necessary codes are executed (and the unchanged *.gp codes are not) before compiling the latex document. I am using epslatex to generate *.eps and *.tex files (to be used with \input --- not standalone). If it's not abundantly clear from the sample code this is my first stab at a makefile.
EDIT: More details on GNUplot
gnuplot foo.gp produces foo.eps (includes all graphic portions of a plot) and foo.tex (a tex file that formats the figure and adds all necessary text). foo.gp is a script that builds a plot (much like plotting in MatLab or with MatPlotLib in python). The foo.tex file is used as \intut{foo.tex} in the latex figure environment. I will likely have in the neighborhood of 100figures that my advisor will no doubt have me edit to ad nauseum meaning I will be repeatedly be editing many different gnuplot scripts.
Dir structure:
Root Dir: ~/dissertation
Latex files Dir: ~/dissertation/text (this is also where my makefile currently is)
Gnuplot codes Dir: ~/dissertation/figures/gnuplot_codes
Gnuplot output Dir: ~/dissertation/figures/figs
Here is my code thus far:
PAPER=Thesis
CODES=$(wildcard ../figures/gnuplot_codes/*.gp) # list of all gnuplot scripts
EPSES=$(wildcard ../figures/figs/*.eps) # list of all eps files
FIGTEX=$(wildcard ../figures/figs/*.tex) # list of all associated tex files
all: $(EPSES) $(FIGTEX) $(CODES) $(PAPER).pdf
evince $(PAPER).pdf
# This is the line I can't figure out ---
# if any of the gnuplot codes are updated it runs all of them
$(EPSES) $(FIGTEX): $(CODES)
gnuplot $(CODES)
# compiles the latex document using latexmk
$(PAPER).pdf: $(PAPER).tex $(EPSES) $(FIGTEX) $(CODES)
latexmk -latex="latex -interaction=nonstopmode" -use-make $<
dvips $(PAPER).dvi -Ppdf
ps2pdf $(PAPER).ps
# This catches any missing *.eps files thrown back from latexmk
# I feel like I should have a way of checking before
# running $(PAPER).pdf rule
../figures/figs/%.eps: ../figures/gnuplot_codes/%.gp
gnuplot $<
# same as the rule above but for *.tex
../figures/figs/%.tex: ../figures/gnuplot_codes/%.gp
gnuplot $<
# this cleans all the latex files
clean:
latexmk -CA
We'll start with the list of existing gp files:
CODES=$(wildcard ../figures/gnuplot_codes/*.gp)
So far, so good. This list tells us which gp files exist, and therefore which eps and tex files can be built. (We don't care which ones already exist.)
EPSES=$(patsubst ../figures/gnuplot_codes/%.gp,../figures/figs/%.eps, $(CODES))
FIGTEX=$(patsubst ../figures/gnuplot_codes/%.gp,../figures/figs/%.tex, $(CODES))
Now for the rule to run gnuplot and produce those files. The trouble with this version:
$(EPSES) $(FIGTEX): $(CODES)
gnuplot $(CODES)
is that it makes all gp files prerequisites of every eps and tex file; change one gp file, and you must rebuild everything. So get rid of it and replace it with a pattern rule:
../figures/figs/%.eps ../figures/figs/%.tex: ../figures/gnuplot_codes/%.gp
gnuplot $<
(I don't know how gnuplot knows where to put its output files; you didn't specify, so I'll assume you have that part worked out. If you're having trouble with that, I'll be happy to help.)
Now for the Thesis.pdf rule:
# compiles the latex document using latexmk
$(PAPER).pdf: $(PAPER).tex $(EPSES) $(FIGTEX)
latexmk -latex="latex -interaction=nonstopmode" -use-make $<
dvips $(PAPER).dvi -Ppdf
ps2pdf $(PAPER).ps
I removed the prerequisite $(CODES) because it appears to be redundant. The recipe could probably be improved (and generalized to produce other pdf files) but hey, if it ain't broke...
Finally the rule that runs the show (and should come first, if you want it to be the default):
all: $(EPSES) $(FIGTEX) $(CODES) $(PAPER).pdf
evince $(PAPER).pdf
Unless evince actually uses the gp, eps and tex files, we can do without those prequisites:
all: $(PAPER).pdf
evince $<
Give all that a try.

GNU Make and wildcards - missing files

I have a Makefile with the following type of rule:
%.html:
./generate-images.py > $#
make $(patsubst %.png,%.gif,$(wildcard *.png))
The generate-images script writes not only the HTML file (to stdout) but several .png files to the current directory. The goal here is to convert them to .gif. (not really, but this is an example)
This works if I invoke it directly. The problem is: If I invoke it from another rule where foo.html is a dependency, the wildcard statement fails to find any files. In other words, it just called make with no arguments, which is not what I want here.
What's the deal with the wildcard? Or, is there a better way to do this?
While your problem may be something different, I clearly see one.
The whole text of all commands within the rule is simultaneously processed so that make's functions and variables get expanded. Assume you have no .png files in the directory, and you invoke make so it should regenerate them: a.png and b.png. Then, after you invoke make, the text of the rule would effectively look like this:
file.html:
./generate-images.py > file.html
make
because at the moment of reading the makefile there were no .png files! After the first line is executed, the files will appear, but the next line was already generated to be just "make".
And only when you invoke your makefile for the second time, will it expand to
file.html:
./generate-images.py > file.html
make a.gif b.gif
This is not what you want. So I suggest doing it in The Right Way.
# If you have batch conversion program, this may be helpful
images.stamp: *.png
convert_all_images $?
touch images.stamp
# OR, if you want convert one-by-one with means of make
images.stamp: $(wildcard *.png)
touch images.stamp
%.gif: %.png
convert_one --from=$^ --to=$#
# HTML would look like
%.html:
./generate-images.py > $#
make images.stamp
So when you invoke make all, it generates htmls and converts newly generated images. Note that it will only convert the images that are updated, which is what you want.
Thanks to Beta for pointing out the mess with gif/png extensions.
That sounds like it's evaluating all of the $() expressions as it's processing the Makefile, rather than as it executes each rule. You could add a rule to your makefile like so:
images: $(patsubst %.png,%.gif,$(wildcard *.png))
.PHONY: images
and then change your example snippet to
%.html:
./generate-images.py > $#
make images
so that Make evaluates the glob at the right time. This is something about which checking the manual might be worthwhile.

Resources