Recently I've been quite obsessed with Make. I think it might be the
perfect tool to deal with complex software projects that consist of
many different systems that are build using various languages (my
team at issuu uses it to the build, test, & deploy our frontend,
backend and various internal tools). However, I'll save that rant for
another blog post but given my fascination with Make I recently set out
to write a
Makefile for this blog.
This blog is currently written in an awkward mix of org-mode and
jekyll. Previously my work-flow has been to manually start
serve -w and then export
org-mode files from within
emacs. This is
a bit tedious and it diverges from the work-flow I've come to expect
from my other projects where saving a file automatically triggers a
In this blog post I'll explain how I was able to export my
files from a
Makefile. You can find the entire solution on Github at
1 Publishing from the shell
The first step was to figure out how to publish a single
file from the shell. Turns out that this could be achieved fairly
easily by using some of the command-line arguments that emacs provide.
emacs \ --quick \ --directory <path-to-org-mode> \ --script init.el \ --eval "(org-publish-file \"<path-to-org-file>\" nil nil)"
Lets look at each of the options:
--quickis used to reduce the boot time of emacs. It's equivalent to using all of
--no-splash, that is, it will start a bare-bones version of emacs that doesn't use any of your personal configuration or packages.
--directoryadds a directory to the emacs load path. In this case I use it to add
org-modeto the load path.
emacsto run a file as an Emacs Lisp script. In this case I use it to run a script,
init.el, that configures
org-modeso it knows how to publish my project. Using
--scriptalso has the convenient effect that
emacsdoesn't start an interactive display; it simply executes the script and exits. Together with
--evalthis means you can use
emacsjust as an interpreter for Emacs Lisp which is exactly what we need in this case.
--evaltells emacs to evaluate an Emacs Lisp expression. The expression that I'm using publishes an
This is all there is to it. Writing a
Makefile that runs this command
.org file and watches for changes to perform a rebuild is
fairly simple (if you know Make, if not I strongly recommend the first
couple of chapters Managing Projects with GNU Make, it's awesome.).
Random thought It's quite fun to play around with using
emacs just for
its ability to interpret Emacs Lisp. You can play around with it like
emacs --batch --eval "(message \"hi there\")"
You could stop here and you would have a nice way to export
files from Make. However, I got curious and explored another way to do
it. In the next section I'll show a way to speed up the build-time a
bit – it's really not necessary but it is quite fun and it requires a
couple of tricks that might be useful in other scenarios.
2 Speeding up the build using
emacs has the capability of starting an
emacs server that you can
connect to using
emacsclient. There are various use-cases for this
but in this case we'll use it to avoid having to start a fresh
emacs instance whenever we want to export an
Keeping the original goal in mind, that
make watch should rebuild the
necessary things whenever a file is saved, here's what we want to have
Jekyllrunning in server mode so I can see my blog locally and have it rebuild whenever a
- A loop that calls
make buildevery second. This is the simplest solution to re-export my
.orgfiles when they are changed.
Instead of having
make build starting a fresh
emacs every time a
file needs to be build (as we did in the previous section) let us
instead start an
emacs server and connect to it using
emacsclient. This means our
make watch target should have an extra
emacsserver that can export
In order to achieved this we need to use a couple of tricks. I'll go through each of them now.
2.1 A target that runs other targets in parallel
In order to run these three
make targets we'll introduce the first
xargs -P to start processes. Here's a
(or well, it's a multi-line variable that supposed to be used with
call, but I like to think of it as a function) that will run all the
targets you give it in separate processes
# $(call make-parallel, targets) # Runs (sub) make targets, with each target running in a separate process define make-parallel $(call print-rule,$0,$1 - [$(words $1) targets]) $(QUIET)echo $1 | xargs \ -n 1 \ -P $(words $1) \ $(MAKE) --no-print-directory -f $(firstword $(MAKEFILE_LIST)) endef
I then use it like this to run three targets in parallel
watch_targets := \ _watch-continous-make \ _watch-jekyll-server \ _watch-emacs-server watch: $(call make-parallel, $(watch_targets))
make watch will result in three invocations of
running in parallel, namely
make _watch-emacs-server. When I hit
(control-c) all of the processes are killed (as long as the targets
are running in the foreground).
2.2 Starting and stopping an
Now to the next piece of the puzzle, namely how to start, communicate
with, and stop and
2.2.1 Starting & stopping the server
By using the emacs command-line option
can start an emacs server and give it a specific name. We explicitly
give the daemon a name so we can refer to it later. Here's how the
emacs daemon is started.
emacs \ --quick \ --directory <path-to-org-mode> \ --script init.el \ --daemon=<daemon-name>
org-mode I've added an extra important thing to the
init.el file that is required in order to start many daemons and have
emacsclient communicate with a specific one:
(setq server-use-tcp t) ;; If non-nil, use TCP sockets instead of local sockets.
Alright, so that's how to get the
emacs server up and running but
there's one problem. When using the
emacs will run
in the background. That's a problem as my
requires that all the targets run in the foreground in order to be
able to shut them down once I hit
^C. In order to fix this I came up
with this little hack.
#! /bin/sh trap "emacsclient --server-file=$1 --eval '(kill-emacs)'; exit" SIGINT SIGHUP SIGKILL tail -f /dev/null
It's a shell script that will run forever (this is achieved by
-f /dev/null. However it also registers a
SIGKILL events. The
trap kills the server by using
emacsclient to send
(kill-emacs) to the server.
So the final
_watch-emacs-server target looks like this
# Starts emacs in server-mode, blocks until SIGINT/SIGHUP/SIGKILL is # sent and then shuts down the emacs server instance. _watch-emacs-server: $(QUIET)emacs \ --quick \ --directory $(abspath $(setup.dir)/org-$(org_version)/lisp) \ --script init.el \ --daemon=$(strip $(emacs_daemon_name)) $(if $(QUIET),&> /dev/null,) $(QUIET)sh wait-and-shutdown.sh $(emacs_daemon_name)
2.2.2 Communicating with the server
Once the daemon is running you can start an
emacsclient and use it to export
.org file like this.
emacsclient \ --server-file=$(strip $(emacs_daemon_name)) \ --eval "(org-publish-file \"<path-to-org-file>\" nil nil)"
The last trick is to create a make target that simply calls
# Calls `make build` every second. _watch-continous-make: $(QUIET)while true; do \ sleep 1; \ $(MAKE) \ -f $(firstword $(MAKEFILE_LIST)) \ --no-print-directory \ build WATCH_MODE=1 \ | grep -v "Nothing to be done for" ; \ done
That's it. I hope you learned a few