Debian contributors end up with a number of Debian installations on their workstations for various purposes; there are perhaps five or six on my laptop right now. In addition to this, I now have three copies of GNU Emacs, too.


This is the version of Emacs in Debian stable. I have to keep it available for testing various of the Debian packages I maintain.


This is a build of Emacs 29.0.50 out of upstream git, with native Wayland support, and some custom Debian packaging to integrate it with Debian’s emacsen-common infrastructure: Emacs addon packages are pre-bytecompiled against this version of Emacs, and re-bytecompilation is fully automated. This is nice if you want to use development snapshots of Emacs but get your addon packages from Debian, as I do. These are, roughly, the extent of my changes on top of upstream:

diff --git a/.gitignore b/.gitignore
index 78557a5e87..9743ccca0c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,11 @@
 # in Git 1.8.2 (March 2013).

+# Debian packaging
 # Personal customization.

diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index de4cebccca..1596b5a1bf 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -311,6 +311,7 @@ package-directory-list
       (and (stringp f)
            (equal (file-name-nondirectory f) "site-lisp")
            (push (expand-file-name "elpa" f) result)))
+    (push "/usr/share/emacs-snapshot/site-lisp/elpa" result)
     (nreverse result))
   "List of additional directories containing Emacs Lisp packages.
 Each directory name should be absolute.
diff --git a/lisp/startup.el b/lisp/startup.el
index b79467339b..c54ab89b33 100644
--- a/lisp/startup.el
+++ b/lisp/startup.el
@@ -1374,7 +1374,12 @@ command-line
     ;; be loaded from site-run-file and wants to test if -q was given
     ;; should check init-file-user instead, since that is already set.
     ;; See cus-edit.el for an example.
-    (if site-run-file
+    (when site-run-file
+        (let ((file "/etc/emacs/site-start.d/00debian.el"))
+          ;; When the Emacs build invokes Emacs, such as in the
+          ;; Makefile rule for ${unidir}/emoji-labels.el, 00debian.el
+          ;; might not exist.  Should be fine to just skip the load.
+          (when (file-readable-p file) (load file)))
         ;; Sites should not disable the startup screen.
         ;; Only individuals should disable the startup screen.
         (let ((inhibit-startup-screen inhibit-startup-screen))

If you’re using Wayland on Debian, or you just want or need a newer Emacs, you might like to install these snapshot builds yourself from, suites “bullseye-backports” and “unstable”.


The snapshot builds described in the previous section are what I use on machines other than my laptop. On my laptop, I have my Wayland compositor configured to use the emacs and emacsclient binaries in ~/src/emacs, if they exist. This is a build of a branch with work-in-progress patches I’m planning to send upstream, plus bug fixes, reversions of commits that introduced regressions which affect my setup, etc..

Why have this in addition to the emacs-snapshot.deb builds – if there are temporary fixup commits, why not apply them and build a .deb just for local use? Well, that is indeed what I was doing until recently, but if you’re developing patches for upstream Emacs it’s pretty inconvenient. Hyperlinks to function definitions in Help buffers take you somewhere read-only in /opt, for example, and rebuilds are slow because, by default, Debian package builds begin by cleaning the tree.

In addition to the diff above (minus the .gitignore change), and the temporary fixup commits, I also apply the following change on this branch. Having the above diff applied implies that a recent emacs-snapshot.deb is installed, to provide the byte-compiled addons. This informal dependency should work well enough so long as I update the snapshot .debs described in the previous section often enough.

diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c
index 7769e015ed..3af4f7d0cf 100644
--- a/lib-src/emacsclient.c
+++ b/lib-src/emacsclient.c
@@ -1773,7 +1773,10 @@ start_daemon_and_retry_set_socket (void)
-      char emacs[] = "emacs";
+      const char *devel_build_rel = "/src/emacs/src/emacs";
+      char *emacs = xmalloc (strlen (egetenv ("HOME"))
+                + strlen (devel_build_rel) + 1);
+      strcpy ( stpcpy (emacs, egetenv ("HOME")), devel_build_rel);
       char daemon_option[] = "--daemon";
       char *d_argv[3];
       d_argv[0] = emacs;
@@ -1790,7 +1793,7 @@ start_daemon_and_retry_set_socket (void)
      d_argv[1] = daemon_arg;
 # endif
-      execvp ("emacs", d_argv);
+      execvp (emacs, d_argv);
       message (true, "%s: error starting emacs daemon\n", progname);
       exit (EXIT_FAILURE);

And I use something like this to have my Wayland compositor use these builds:


if [ -e "$HOME/src/emacs/admin/README.melete" \ # confirm we're on the branch
    -a -x "$HOME/src/emacs/lib-src/emacsclient" \
    -a -d "/usr/share/emacs-snapshot/site-lisp/elpa" ]; then
    EMACSCLIENT=$(command -v emacsclient)

$EMACSCLIENT -a "" -nc

There’s something similar in my shell configuration.