Improve blog post further

This commit is contained in:
Midgard 2020-06-09 13:46:31 +02:00
parent 1045870497
commit 102b12cd25
Signed by untrusted user who does not match committer: midgard
GPG key ID: 511C112F1331BBB4

View file

@ -10,7 +10,7 @@ I wanted to use graphics instead of words so the language centres of my dear aud
Rather than importing slide-sized graphics in a GUI, I thought a makefile would be a nice way to do the trick. Rather than importing slide-sized graphics in a GUI, I thought a makefile would be a nice way to do the trick.
Makefiles these days are commonly used as a shell script with multiple entry points. Makefiles these days are commonly used as a shell script with multiple entry points.
But it's more than that! But they can do much more than that!
You give it a filename, and it will build that file if its dependencies have been changed. You give it a filename, and it will build that file if its dependencies have been changed.
Traditionally makefiles are used for C programs, but there's no reason you can't use them for any build you want. Traditionally makefiles are used for C programs, but there's no reason you can't use them for any build you want.
Even this website is built by a makefile! Even this website is built by a makefile!
@ -23,7 +23,7 @@ OUTPUT = slides.pdf
``` ```
We'll make a list of SVGs in the current directory, and convert it into a list of PDF targets. We'll make a list of SVGs in the current directory, and convert it into a list of PDF targets.
Sorting is necessary to be able to place your slides in the order you want. Sorting is necessary to put your slides in the order you want.
The `$(:=)` construct is used to go from `%.svg` to `build/%.pdf`. The `$(:=)` construct is used to go from `%.svg` to `build/%.pdf`.
```makefile ```makefile
SLIDES ::= $(sort $(wildcard *.svg)) SLIDES ::= $(sort $(wildcard *.svg))
@ -31,19 +31,19 @@ SLIDES_PDF ::= $(SLIDES:%.svg=build/%.pdf)
``` ```
I love this next rule. I love this next rule.
It teaches make that it should use Inkscape if it needs to create a PDF. It teaches *make* that it should use Inkscape if it needs to create a PDF.
`$@` refers to the target (`build/….pdf`), and `$<` refers to the first dependency (`….svg`). `$@` refers to the target (`build/….pdf`), and `$<` refers to the first dependency (`….svg`).
Inkscape's `-A filename` option exports to PDF without opening the GUI. Inkscape's `--export-pdf filename` option exports to PDF without opening the GUI.
**TODO: isn't there a way to automatically depend on all parent directories?** **TODO: isn't there a way to automatically depend on all parent directories?**
```makefile ```makefile
build/%.pdf: %.svg build build/%.pdf: %.svg build
inkscape -A "$@" "$<" inkscape --export-pdf "$@" "$<"
``` ```
Now we tell make that the final output can be created from the individual slides. Now we tell *make* that the final output can be created from the individual slides (`$(SLIDES_PDF)`) by calling pdfjoin.
Make will recursively make sure that all dependencies are up to date. *Make* will recursively make sure that all dependencies are up to date.
Because we add the SVG source file as a dependency, it will know that the individual PDF files have to be rebuilt if their source was changed. Because we add the SVG source file as a dependency, it will know that the individual PDF files have to be rebuilt if their source was changed.
And if any slide was changed, the end result will be updated too. And if any slide was changed, the end result will be updated too.
But if there was no change, it won't; nothing is rebuilt unnecessarily! But if there was no change, it won't; nothing is rebuilt unnecessarily!
@ -56,7 +56,7 @@ $(OUTPUT): $(SLIDES_PDF)
``` ```
If you look at the `build/%.pdf` rule, you see that it depends on `build`. If you look at the `build/%.pdf` rule, you see that it depends on `build`.
With this simple, final rule, make will know how to create this directory. With this rule, *make* will know how to create this directory.
```makefile ```makefile
build: build:
mkdir -p "$@" mkdir -p "$@"
@ -72,11 +72,42 @@ clean:
rm -rf "$(OUTPUT)" build/ rm -rf "$(OUTPUT)" build/
``` ```
This concludes the Makefile portion of this post. One more thing: the default target, for when you call *make* without arguments, is the first one in the makefile (with [some caveats][gmake_docs_targets]).
You could override this with `.DEFAULT_GOAL := your_target_name_here`, but it's just as easy to reorder the rules, which is what I've done in the summary below.
[gmake_docs_targets]: https://www.gnu.org/software/make/manual/html_node/Goals.html "Goals GNU make documentation"
This is the finished makefile:
```makefile
OUTPUT = slides.pdf
SLIDES ::= $(sort $(wildcard *.svg))
SLIDES_PDF ::= $(SLIDES:%.svg=build/%.pdf)
$(OUTPUT): $(SLIDES_PDF)
pdfjoin $(SLIDES_PDF) -o "$@"
build/%.pdf: %.svg build
inkscape --export-pdf "$@" "$<"
build:
mkdir -p "$@"
.PHONY: clean
clean:
rm -rf "$(OUTPUT)" build/
```
**TODO: write about first rule being the default** **TODO: write about first rule being the default**
**TODO: split into 2 posts?** **TODO: split into 2 posts?**
## Further help with *make*
I'm using *GNU make* and I'll admit I don't know if this works in other flavours.
GNU's documentation is installed on my system and accessible with `info make` (<kbd>tab</kbd> to jump to next link, <kbd>enter</kbd> to activate it, <kbd>l</kbd> to return to previous screen, <kbd>Shift+h</kbd> for help).
When online you can also use the [online documentation][gmake_docs].
[gmake_docs]: https://www.gnu.org/software/make/manual/html_node/index.html "GNU make documentation"
## Creating and presenting slides ## Creating and presenting slides
Create one SVG per slide, you can do that in Inkscape. Create one SVG per slide, you can do that in Inkscape.