Figure 1: Behold! Emacs 27!

Figure 1: Behold! Emacs 27!

When upgrading to Emacs 27 there were quite a few weird things I had to address.

My Emacs is installed via Gentoo Portage. The USE flags I have set (to enable/disable features at build time) essentially configure my Emacs to be like Lucid Emacs builds. Here’s the USE flags:

Xaw3d acl alsa athena cairo dbus dynamic-loading gif gmp gui
imagemagick inotify jpeg lcms libxml2 png source ssl svg threads
tiff toolkit-scroll-bars xft xpm zlib -aqua -games -gconf -gfile
-gpm -gsettings -gtk -gzip-el -harfbuzz -json -kerberos -livecd
-m17n-lib -mailutils -motif -selinux -sound -systemd -wide-int

Make note that cairo support is enabled. This manifests one of the gotchas.

§Bitmap font support has been removed

In my ~/.Xdefaults I have the following line:

*font: -*-terminus-bold-*-*-*-*-320-*-*-*-*-*-*

Unfortunately, this causes my Emacs to exit with code 255 after printing the following error:

Font ‘-*-terminus-bold-*-*-*-*-320-*-*-*-*-*-*’ is not defined

Looking in the NEWS file, there is a mention of bitmap support has been removed due to cairo building with pango now.

It turns out setting a catchall Xresources setting to configure font for all old-style applications can cause problems with Emacs which uses Emacs.font resource to configure a font. Insofar the other X applications appear to use *font* only for old-style bitmap fonts.

In order to keep the *font setting, override Emacs.font:

Emacs.font: Mono-12

Now Emacs 27 launches on my workstation.

Quick background. On my workstation I have Gentoo with OpenRC. To set up Emacs Daemon, install app-emacs/emacs-daemon, then create a symbolic link to “instantiate the service” (i.e. cd /etc/init.d && ln -s emacs.winston emacs). Then simply run rc-service emacs.winston start (don’t forget to rc-update add emacs.winston default).

Anyway, I’m not sure went on here, but /etc/init.d/emacs.winston start consistently launched Emacs 26. I did eselect emacs set emacs-27 to configure the emacs and emacsclient programs in my path for Emacs 27. No luck. I also set EMACS in /etc/conf.d/emacs.winston, but that did not work either. No clue what went on here, but the solution was simple - don’t deal with the problem - emerge -avc emacs:26.

§emacsclient: can’t find socket

Now Emacs Daemon for Emacs 27 successfully launched, this caused a new problem when running emacsclient -c to create a new frame.

emacsclient: can't find socket; have you started the server?
emacsclient: To start the server in Emacs, type "M-x server-start".
emacsclient: No socket or alternate editor.  Please use:

        --server-file      (or environment variable EMACS_SERVER_FILE)
        --alternate-editor (or environment variable ALTERNATE_EDITOR)

After a quick search on the Gentoo bug tracker, this bug looked appropriate: #794649: app-emacs/emacs-daemon fails to set the socket location emacsclient 27 expects by default.

This bug references upstream Emacs bugreport: #33847: 27.0.50; emacsclient does not find server socket.

The TL;DR on Gentoo OpenRC does not have XDG_RUNTIME_DIR set when the service is started via rc-service emacs.winston start. Emacs Daemon then proceeds to create the socket file under /tmp. Once I log in to my desktop, elogind sets XDG_RUNTIME_DIR and emacsclient looks there, does not find a socket file, then gives up. In the bugreport there was a possible solution identified to do just that - search for the old socket file in /tmp.

There might be a patch floating around (check Archlinux, Debian, etc), but I wanted to address this upstream issue without a patch if possible. It’s just less work and portable to other systems that don’t patch this surprising behavior. The solution was to create file /etc/profile.d/ with the following contents:

EMACS_SOCKET_NAME="/tmp/emacs$(id -u)/server"

Log out and log back in to load the new profile.d environment in a new session. emacsclient -c should now work because it will look for the socket file in /tmp.

There was in issue with my Emacs configuration that prevents use-package from being installed on first startup. This appears to be caused by package-refresh-contents never being called and (package-install 'use-package) fails to find the package to install.

It would be pretty slow to always execute (package-refresh-contents) on every startup, adding tens of seconds to startup time. The workaround is to add a first-boot functionality:

(defconst winny/initialized-cookie-path
  (concat user-emacs-directory "/.w-firstboot-initialized"))
(unless (file-exists-p winny/initialized-cookie-path)
  ;; Run this body only on first startup.
  (message "Detected first boot.  Doing initialization steps...")
    (write-file winny/initialized-cookie-path))
  (message "First boot-only initialization complete."))

On first startup the file ~/.emacs.d/.w-firstboot-initialized will not exist. This allows the unless form’s body to execute. Besides writing messages to the *Messages* buffer and running the critical section ((package-refresh-contents)), the with-temp-buffer expression writes out an empty file to ~/.emacs.d/.w-firstboot-initialized.

Now a git clone --recursive .emacs.d && emacs works without special user intervention. One downside of my setup with use-package is the slow initialization. It takes at least a couple minutes to install all the packages during first startup. Maybe one day my Emacs startup be fast and instantaneous from git clone