makel is a project consisting of a Makefile (makel.mk
) that Emacs
package authors can use to facilitate quality checking (linting and
tests). The Makefile can be used both locally on the developer machine
and remotely on a continuous integration machine. These are the rules
provided by makel.mk
:
- test-ert
- run your ERT (the Emacs Lisp Regression Testing tool) tests.
- test-buttercup
- run your buttercup tests.
- lint-checkdoc
- collect and report checkdoc (the Emacs coding convention tool) errors.
- lint-package-lint
- collect and report package-lint (a linting library for package definitions) errors.
- lint-compile
- collect and report errors and warnings from the Emacs Lisp compiler.
- lint
- starts all linting-related rules.
- test
- starts all test-related rules (both ert and buttercup tests).
- check
- starts all lint and test rules.
- makel-version
- displays makel’s version
What distinguishes makel from similar tools (see below) is its simplicity: simplicity to use it in your Emacs package (there are just a handful of variables to define) and simplicity to understand what it does (it’s just a Makefile).
Alongside your package, create a Makefile
file containing the
following code:
makel.mk:
# Download makel
@if [ -f ../makel/makel.mk ]; then \
ln -s ../makel/makel.mk .; \
else \
curl \
--fail --silent --show-error --insecure --location \
--retry 9 --retry-delay 9 \
-O https://github.com/DamienCassou/makel/raw/v0.8.0/makel.mk; \
fi
# Include makel.mk if present
-include makel.mk
The lines above indicate that you want to use makel.mk
if present in
the current directory. If not, you want to use the one from a sibling
directory (../makel/makel.mk
) or from Internet.
You decide which version of makel you want to use by changing the URL
(here v0.8.0
is the latest version).
You have to tell makel which files you want each rule to look at. This is a bit verbose but easy to understand (and easy to copy/paste :-)). This can be done by setting a few variables at the beginning of your Makefile:
# Space-separated list of the dependencies of your project (include
# package-lint and/or buttercup if you want makel to use these tools):
ELPA_DEPENDENCIES=package-lint
# List of package archives to download above dependencies
# from. Available archives are: gnu (aka elpa), elpa-devel, nongnu,
# melpa, melpa-stable and org:
ELPA_ARCHIVES=melpa
# List of ERT test files:
TEST_ERT_FILES=$(wildcard test/*.el)
# List of buttercup test directories:
TEST_BUTTERCUP_OPTIONS=specs
# List of files to check for Emacs conventions:
LINT_CHECKDOC_FILES=$(wildcard *.el) ${TEST_ERT_FILES}
# List of files to check for packaging guidelines:
LINT_PACKAGE_LINT_FILES=$(wildcard *.el)
# List of files to check for compilation errors and warnings:
LINT_COMPILE_FILES=${LINT_CHECKDOC_FILES}
The variable ELPA_DEPENDENCIES
list Emacs packages that you want
makel to download if not already present. This is especially useful on
a continuous integration environment where no external package is
usually installed. If some of the dependencies you need are not
available on a package archive (or not in a recent-enough version),
you can add URLs to DOWNLOAD_DEPENDENCIES
and they will be
downloaded to the project’s main directory.
Above code uses the wildcard
Make function to list Emacs Lisp files
in the current directory as well as the test/
sub-directory. makel
makes sure to remove any *-autoloads.el
file from such a list before
doing anything.
Now that you have configured makel, you just need to use it. A design choice I made is that makel should only print important information: this is to avoid making you spend time searching for potential problems in a log that doesn’t contain any. If everything is fine, makel will only print the tasks it runs:
$ make check
# Run ert tests from test/libmpdel-test.el…
# Run checkdoc on libmpdel.el, test/libmpdel-test.el…
# Run package-lint on libmpdel.el…
# Run byte compilation on libmpdel.el, test/libmpdel-test.el…
makel is only noisy if there actually is a problem to report:
$ make check
# Run ert tests from test/libmpdel-test.el…
Loading /home/cassou/.emacs.d/lib/libmpdel/test/libmpdel-test.el (source)...
Running 29 tests (2018-10-03 20:49:23+0200)
passed 1/29 libmpdel-test--message-filter-activates-saved-buffer
passed 2/29 libmpdel-test--message-filter-keeps-current-buffer-if-saved-one-died
passed 3/29 libmpdel-test--msghandler-status-updates-volume
passed 4/29 libmpdel-test--raw-send-command-with-handler-add-ignore-handler
[…]
Test libmpdel-test-artist-name condition:
(ert-test-failed
((should
(equal "The Artist"
(libmpdel-artist-name artist)))
:form
(equal "The Artist" "The Artists")
:value nil :explanation
(arrays-of-different-length 10 11 "The Artist" "The Artists" first-mismatch-at 10)))
FAILED 12/29 libmpdel-test-artist-name
passed 13/29 libmpdel-test-create-song-from-data
passed 14/29 libmpdel-test-current-playlist-p
Ran 29 tests, 28 results as expected, 1 unexpected (2018-10-03 20:49:23+0200)
1 unexpected results:
FAILED libmpdel-test-artist-name
make: *** [makel.mk:55: test-ert] Error 1
The following Emacs packages (all from me :-)) are already using makel and could act as examples:
Package name | Description |
---|---|
libmpdel | Library to communicate with Music Player Daemon (MPD), server-side application for playing music |
mpdel | User interface for Music Player Daemon (MPD), server-side application for playing music |
libelcouch | Library to communicate with CouchDB databases |
elcouch | User interface to view and manipulate CouchDB databases |
khardel | User interface to integrate khard, a console cardav client |
If you are looking for something similar to makel, you might be interested in these projects:
I designed and implemented makel after having used both Cask and EMake for some time. My opinion is that makel is simpler to use and maintain (it’s only a Makefile and it has many unit tests) but may lack some features you might need.
Regarding makem.sh, I suggest you try it if you like makel. It seems like it’s a better version of it: more features, more documentation, easier to setup. I haven’t used it yet but I will probably try it soon.
Regarding Cask, I was frustrated by the complexity (I mean understanding how things work and play together) and warnings/errors I and others would regularly get.
Regarding EMake, I opened a few PRs and issues to make it do what I need but the maintainer and I disagreed on several core decisions. I made sure I agree with all decisions I took for makel :-).
Eldev is a new alternative that seems to be worth keeping an eye on. For now, it doesn’t support running buttercup or checking the quality of the code.
See COPYING. Copyright (c) 2018-2023 Damien Cassou.