Making a Multiplatform Emacs Configuration

For Linux, macOS, and MS Windows

These days, I use three different operating systems at work and home: Ubuntu Linux (Dell Latitude 7490 13" laptop), Microsoft Windows (Dell Latitude 7400 13" laptop), and macOS (27" iMac). My primary tool across these platforms is Emacs, which I use for nearly everything—coding (C++, Python), blogging (Hugo), reading (Elfeed), note-taking (Org Mode, org-roam), diary, and agenda management (beorg on iPhone, synchronized via Dropbox across all computers), among other tasks.

Naturally, I want a single Emacs configuration file—.emacs or, if you prefer, init.el—to work seamlessly across all these platforms.

Emacs is arguably the most platform-agnostic software available. However, some OS-specific differences must be addressed. These can be grouped into several categories:

  1. Paths for external executables, particularly on Windows.
  2. OS-specific key bindings, especially on macOS.
  3. Various OS-specific tweaks, particularly for Windows.
  4. Font sizes, which depend on screen size and resolution.

Below, I explore these issues in greater detail.

Introduction

First, we need to determine the operating system type.

;;;; OS Detection
(defvar os-windows (string-equal system-type "windows-nt") "Running on Windows.")
(defvar os-linux (string-equal system-type "gnu/linux") "Running on Linux.")
(defvar os-macos (string-equal system-type "darwin") "Running on macOS.")

Paths

;;; Environment Variables.
(defvar my/home (getenv "HOME"))

(when os-linux
  (setenv "PATH"
          (concat
           my/home "/lib/grpc/bin" path-separator ; gRPC binaries
           (getenv "PATH")))
  (setenv "PKG_CONFIG_PATH"
          (concat
           my/home "/lib/grpc/lib/pkgconfig")))

;; Add Cygwin path on Windows.
(when os-windows
  (setq exec-path (cons "C:/cygwin64/bin" exec-path)))

;; Clang/clangd compiler on Windows.
(when os-windows
  (setq exec-path (append exec-path '("C:/bin/LLVM/9.0.0/bin"))))

;; Clang/clangd compiler on macOS.
(when os-macos
  (setq exec-path (append exec-path '("/usr/local/Cellar/llvm/11.0.0_1/bin"))))

The exec-path built-in variable contains a list of directories Emacs searches to run programs in subprocesses. Each element is either a string (directory name) or nil (indicating the default directory).

OS-Specific Key Bindings

macOS

Disable the Command key as Meta and enable Option as Meta (Alt).

;;;; `macOS' keyboard
(when os-macos
    (setq mac-command-key-is-meta nil
          mac-command-modifier 'super
          mac-option-key-is-meta t
          mac-option-modifier 'meta))

Prevent accidentally closing the frame or Emacs app by disabling ⌘-w and ⌘-q.

(when os-macos
  (global-unset-key (kbd "s-w"))
  (global-unset-key (kbd "s-q")))

OS-Specific Tweaks

Microsoft Windows

Increase the default Windows pipe buffer size. (Note: This may no longer be necessary, but I include it for compatibility.)

(when os-windows
  (setq w32-pipe-read-delay 0)
  (setq irony-server-w32-pipe-buffer-size (* 64 1024)))

Configure Dired to resemble its appearance on Linux/macOS.

(if os-windows
    (setq dired-listing-switches "/A:H /O:NG")
  ;; Linux/macOS
  (setq dired-listing-switches "-laGgh1v --group-directories-first --time-style=long-iso"))

Linux

Set the default browser on Linux.

(when os-linux
  (setq browse-url-browser-function 'browse-url-firefox))

Font Size

I use the same .emacs configuration on both a 13" laptop and a 27" desktop, which have significantly different screen sizes and resolutions. This requires font size adjustments.

(cond
 (os-linux (defvar my/font-height 140 "The default font height for Emacs on Linux (in 1/10th points)."))
 (os-macos (defvar my/font-height 180 "The default font height for Emacs on macOS (in 1/10th points)."))
 (t (defvar my/font-height 140 "The default font height for Emacs on Windows and other systems (in 1/10th points).")))

Set the default font size based on the OS type.

(custom-set-faces
 `(default ((t (:height ,my/font-height :width normal :family "Aporetic Sans Mono"))))
)

Note the use of the backquote macro for dynamic font height.

Summary

With these configurations, I can use a single .emacs file across all my machines, ensuring a consistent Emacs experience regardless of the operating system.

Happy emacsing!

— The Emacs Cat.