A make file for exporting all inkscape svg to pdf - makefile

I'm trying to write a make file that will create PDF from every inkscape SVG in a directory. From the make manual and various tutorials, it seems a pattern rule is the way to go, so I have
%.pdf : %.svg
inkscape -A $*.pdf $*.svg
I know the inkscape command works if I do it manually. When I invoke make though, I get
$ make
make: *** No targets. Stop.
Since the pdf files don't exist yet, I can't invoke make *.pdf and make *.svg won't match any targets. Also, I can't find a way to put an all target in that depends on the pattern.
One final problem; This is part of a large project, and I would like to invoke make in this directory recursively, but if make alone doesn't work, what target should I invoke recursively and how do I do this?

Your pattern is correct, but a pattern tells make how to build a target if you ask for one. You still have to ask for it, and since you haven't that's why you get the "no targets" message.
If you want to find all the SVG files and convert them, you can use the wildcard function:
SVGFILES := $(wildcard *.svg)
all: $(SVGFILES:%.svg=%.pdf)
%.pdf : %.svg
inkscape -A $*.pdf $*.svg
I don't quite understand your second question. Once you have the above you can just use normal $(MAKE) (always use this, never make) in a parent makefile to build these files.

Related

makefile for metapost: how to compile file-N.pdf

I want to let makefile manage the compilation of figures with metapost.
The source file is file.mp. This generates .mps files file.1, file.2 etc. that are then converted to file-1.pdf, file-2.pdf etc.
Here are my rules:
export TEX = latex
%: %.1
mptopdf $*
%.1: %.mp
mpost $*
So that when I run make file it creates all the files.
However, I am not satisfied with this solution. Namely, I'd like to be able to let only one of the files be compiled (say file-2.pdf) by entering make file-2.
Unfortunately, I don't know how to write the rule for this, although I suspect it might be trivial.
I thought the problem could be solved by extracting the number from the file name given in the command line (i.e. extract 2 from file-2) but it is not clear to me how to do it either.

How to use GNU make to update files in all subdirectories containing a particular file?

In my project, I have a set of sub-directories that contain package.yaml files, for e.g.:
A/package.yaml
B/package.yaml
C/package.yaml
If I run hpack A/package.yaml, the file A/A.cabal is (re-)generated. The list of such directories can change over time, so I want to use GNU make to find all immediate sub-directories containing package.yaml files and generate the corresponding .cabal files using hpack.
I tried this based on another question, but it didn't work:
HPACK_FILES := $(wildcard */package.yaml)
PKG_DIRS := $(subst /,,$(dir $(HPACK_FILES)))
CABAL_FILES := $(addsuffix .cabal,$(join $(dir $(HPACK_FILES)),$(PKG_DIRS)))
test:
#echo $(CABAL_FILES)
update-cabal: $(CABAL_FILES)
%.cabal: package.yaml
hpack $<
However, make update-cabal says there's nothing to be done. make test however does output the right cabal files. How can I fix this?
Cheers!
The problem is this:
%.cabal: package.yaml
There is no file package.yaml. The files are named things like A/package.yaml. That is not the same thing.
Because the prerequisite doesn't exist, make decides that this pattern rule cannot match and so it goes looking for another rule that might be able to build the target. It doesn't find any rule that can build the target, so make says there's nothing to do because all the output files already exist.
Unfortunately what you want to do is not at all easy with make, because make is most comfortable with input and output files that are tied together by the filename with extensions, or similar. And in particular, it has a really hard time with relationships where the variable part is repeated more than once (as in, A/A.cabal where the A is repeated). There's no easy way to do that in make.
You'll have to use an advanced feature such as eval to do this. Something like:
# How to build a cabal file
%.cabal:
hpack $<
# Declare the prerequisites
$(foreach D,$(dir $(HPACK_FILES)),$(eval $D/$D.cabal: $D/package.yml))

Makefile pattern rules not working

I am learning makefiles, and can't just wrap my head around this problem i am having, and would like to understand how/why this fail.
I have half a dozen erlang files in a src directory. I want to compile these into a ebin directory, without having to define a rule for each and every one of them. According to the Gnu make documentation, pattern rules should be right up my alley.
However, with the following makefile, all I get from make is make: *** No targets. Stop. Why is that?
ebin/%.beam: src/%.erl
mkdir -p ebin
erlc -o ebin $<
Edit: Based on this answer, I now understand that i would have to explicitly declare the targets, for instance by using make ebin/cmplx.beam. However, i still do not understand how i should write my makefile to get my desired behaviour - since I have half a dozen targets (and in other projects even more), this seems like an unnecessary hassle. Is there not a way to define targets based on the source file names?
The target rule tells make that whenever it needs to produce a beam file in the ebin directory, and there exists a corresponding erl file in the src directory, it can use erlc.
However, this doesn't tell make that this is what it needs to do. You could explicitly tell make what it needs to do by giving it a target on the command line:
make ebin/foo.beam
If you don't give a target on the command line, make will pick the first non-pattern rule in the makefile as its target. However, your makefile doesn't have any non-pattern rules, so there is no target.
What you probably want is that for each existing erl file in src, make should consider the corresponding beam file in ebin to be a target. You can achieve that by calling wildcard and patsubst:
erl_files=$(wildcard src/*.erl)
beam_files=$(patsubst src/%.erl,ebin/%.beam,$(erl_files))
ebin/%.beam: src/%.erl
mkdir -p ebin
erlc -o ebin $<
all: $(beam_files)
(The indented lines need to be actual physical tabs, not spaces.)
That way, running make will rebuild all beam files that are out of date. all gets chosen as the default target, and it in turn depends on all beam existing or potential, each of which in turn depends on the corresponding erl file.
This trick is described in the GNU make manual.

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.

Makefile – build all possible targets

I'd like to use a makefile to convert a set of svgs to pngs. The following snippet shows what I've done so far.
%.png: origs/%.svg
convert -resize "32x" $< $#
make foo.png works now. but I'm stuck with the all target. I'd like to convert everything (all svgs that is) with a single command.
In all examples I've found the all target does something like this:
all: ${OBJECTS}
But I'm sure there's a simpler way for my case, please help me find it ! :D
Depending on the version of make you're using, you may be able to define a set of targets based on all the svgs that are present. For example, in GNU make:
SVG = $(wildcard *.svg)
PNG = $(SVG:.svg=.png)
all: $(PNG)
I don't remember if make can do that.
You could add a shell foreach statement to your all:
( cd origs ; for file in *.svg ; do ; convert ${file} ; done )
You need the parens to make the foreach share the same environment (shell).
I have too many semicolons; I can never remember where they're needed and not needed when turning a multiline shell command into a one-liner.
What you have up there is a pattern rule. It tells make how to make a certian kind of target (those ending with ".png"), rather than any target in particular. So what you have is something that allows you type in an arbitrary "make foo.png" and it will know how to do that.
The way I would generalise this to create a rule for making "all .png's you can make from this directory" would be using a variable. Put a line something like this at the top of your makefile:
SVGs = *.svg
PNGs = $(subst .svg,.png,$(SVGs))
The first line will create a variable SVGs that contains all the files in your directory ending in ".svg". The second creates a variable PNGs containing the same list, but with ".png" on the end instead.
Then you should create a rule to build all SVG's like so:
allsvgs : $(PNGs)
Note that I did not call it "all". The "all" target is an unnoficial standard target that should always mean "build every target my makefile supports", In your case I suppose you could make a case for putting "allsvgs" on all's list of targets, but as your makefile grows you will need to add stuff to it.

Resources