Packaging of add-ons for GNU Emacs

Purpose

The purpose of this document is to promote good practice in packaging add-ons for GNU Emacs, and to encourage the submission of more Emacs add-on packages to the package collection by providing easy to use spec file templates.

Important notes on these Guidelines

The guidelines in the following sections make extensive use of the macros defined in /usr/lib/rpm/macros.d/macros.emacs which is installed with the emacs-common package.

There are two distinct cases where consideration of these guidelines is required:

  1. This case refers to the situation where a package’s principal purpose is to provide extra functionality for Emacs, and the package serves no purpose without the presence of Emacs. An example of this case is the VM mail reader, as packaged in emacs-vm. Below we refer to this as Case I.

  2. This case refers to the situation where a package’s principal functionality does not require Emacs, but the package also includes some auxiliary Elisp files to provide support for the package in Emacs. Below we refer to this as Case II.

Package naming and sub-package organization

Case I

Where a package is primarily an add-on for Emacs, the main package should be called emacs-foo.

Case II

Where a package’s principal functionality does not require Emacs, but the package also includes some auxiliary Elisp files to provide support for the package in Emacs, these should be included in the main package which will need to Require the emacs-filesystem package. More detail below.

Package contents

Case I

Files specific to GNU Emacs should be placed in the main package, emacs-foo. This should contain the elisp source, compiled elisp and any other files needed to use the package or sub-package with GNU Emacs.

Case II

The compiled elisp source and the elisp source files should be packaged as part of the main package, and not split out into separate packages.

File locations

File locations for GNU Emacs add-on (sub-)packages: * All elisp and related files for the package should be installed in the directory %{_emacs_sitelispdir}/foo. * If the package requires a startup file this should be called foo-init.el and be placed in %{_emacs_sitestartdir}.

Package Requires

Case I

Package Requires for GNU Emacs add-on (sub-)packages: * Where relevant emacs-foo must have Requires: emacs-common-foo = %{version}-%{release} * emacs-foo must have Requires: emacs(bin)%{?_emacs_version: >= %{_emacs_version}}

Case II

If the package has auxillary files for use with GNU Emacs, the package must have Requires: emacs-filesystem >= %{_emacs_version}

Package BuildRequires

Package BuildRequires for GNU Emacs add-on packages: * In general it should suffice to have BuildRequires: emacs-nw

Manual byte compilation

Usually package Elisp compilation is handled via a make file shipped with the package, but on some occasions it may be necessary to add commands to the %build section of the spec file to byte compile files. In that case, use %{_emacs_bytecompile} file.el

It is a requirement that all Elisp files are byte compiled and packaged, unless there is a good reason not to, in which case this should be documented with a comment in the spec file.

Use of BuildArch: noarch

If an add-on package requires only byte compilation of elisp then BuildArch: noarch should be used. This is highly unlikely to ever apply to Case II.

Example spec file templates

Template for an add-on package for GNU Emacs (Case I)

This is a template for a package for GNU Emacs. The main package is called emacs-foo and contains all files needed to run package foo with GNU Emacs. This includes both compiled and source elisp files.

%global pkg foo
%global pkgname Foo

Name:           emacs-%{pkg}
Version:
Release:        %autorelease
Summary:

Group:
License:
URL:
Source0:

BuildArch:      noarch
BuildRequires:  emacs-nw
Requires:       emacs(bin)%{?_emacs_version: >= %{_emacs_version}}

%description
%{pkgname} is an add-on package for GNU Emacs. It does wonderful things...


%prep
%autosetup -n %{pkg}-%{version}

%build


%install


%post


%preun


%files
%doc
%{_emacs_sitelispdir}/%{pkg}
%{_emacs_sitestartdir}/*.el


%changelog
%autochangelog

Template for a package which contains auxiliary GNU Emacs files (Case II)

This is a skeleton of a package which also includes support files for GNU Emacs

Name:           foo
Version:
Release:        %autorelease
Summary:

Group:
License:
URL:
Source0:

BuildRequires:  emacs-nw
Requires:       emacs-filesystem%{?_emacs_version: >= %{_emacs_version}}

%description
Foo is a package which contains auxiliary Emacs support files.


%prep
%autosetup

%build


%install


%post


%preun


%files
%doc
%{_emacs_sitelispdir}/foo
%{_emacs_sitestartdir}/*.el

%changelog
%autochangelog

Principles behind the guidelines

Location of installed files

Files for add-on package foo should be placed in %{_emacs_sitelispdir}/foo which evaluates to /usr/share/emacs/site-lisp/foo.

Usually an add-on package will require a startup file, and this should be called foo-init.el and be placed in %{_emacs_sitestartdir} which evaluates to /usr/share/emacs/site-lisp/site-start.d/.

Packaging of source elisp files

Typically, an Emacs add-on package will be compiled from source elisp files. The resulting compiled elisp files will then be included in the relevant emacs-foo package. It is important to also include the source elisp files for several reasons. For example when debugging a problem with an Emacs package, the Elisp debugger can look up the relevant code or symbol definition in the source lisp file if present. Also, it’s sometimes helpful to jump to a variable description string from the Emacs help system.

BuildArch for Emacs add-on packages

You should set BuildArch: noarch for add-on packages which only compile elisp files during building.

If the package building process also compiles programs in other languages, you may need to not set BuildArch.

Requires for GNU Emacs

Add-on packages should have appropriate Requires entries for the flavor of Emacs they are targeted at. GNU Emacs is available in multiple packages - some details of these packages follow.

  1. The emacs package is built with pure GTK support to allow the user to run Emacs in a windowed environment.

  2. The emacs-gtk+x11 package is built with X11 support via the GTK toolkit to allow the user to run Emacs in a windowed environment.

  3. The emacs-lucid package is built with X11 support via the Lucid toolkit to allow the user to run Emacs in a windowed environment.

  4. The emacs-nw package is built without GUI support. It is suitable for running in a terminal.

Note:

  • The emacs, emacs-gtk+x11, emacs-lucid, and emacs-nw packages all have Requires: emacs-common.

  • The emacs, emacs-gtk+x11, emacs-lucid, and emacs-nw packages all have a virtual Provides: emacs(bin).

Assuming your add-on package will work in both a windowed and a console Emacs session, it is wrong to have Requires: emacs as that would pull in a dependency on GTK even if the console variant of Emacs is installed. Rather you should use Requires: emacs(bin) for GNU Emacs add-on packages.

If the package ONLY works with GTK support built into Emacs, then the package should have Requires: emacs. This is very uncommon.

Why we need versioned Requires

Many elisp packages aim for backwards source level compatibility by checking whether some features exist in the Emacs in use when the package is being run or byte-compiled. If yes, they use what’s available. If no, they provide their own versions of missing functions, macros etc. This propagates into *.elc during byte compilation, and quite a few functions do get added between upstream Emacs releases.

So let’s say I byte-compile a package into *.elc with Emacs 29.3. Elisp package quux checks if the foo-bar function is available in the Emacs being used to byte-compile it. Yes, it is, so the internal backwards compat version of foo-bar included in quux does not end up in the *.elc. Now, let’s assume foo-bar was added in Emacs 29.3 and didn’t exist in 29.2 and we’re trying to run the *.elc with 29.2 → boom, foo-bar is not available. Note: this wouldn’t happen if only *.el were shipped - *.elc are the potential and likely problem. Requiring >= version of the Emacs used to byte-compile the *.elc is not the only solution (nor enough for all corner cases), but is the best one we currently have available.

The main package and subpackages will need to have appropriately versioned Requires to ensure that a recent enough version of Emacs is installed. Emacs byte compiled lisp is usually forward compatible with later Emacs versions, but is frequently not compatible with earlier versions of Emacs.

Determining the Required Emacs version at package build time

It is recommended to derive greater-than-or-equal-to valued versioned dependencies from the version of Emacs used to byte-compile the package at package build time. The emacs-common package includes /usr/lib/rpm/macros.d/macros.emacs which defines a %\{_emacs_version} macro containing the version of Emacs installed.

Other packages containing Emacsen add-ons (Case II)

It is often the case that a software package, while not being primarily an Emacs add-on package, will contain components for Emacs. For example, the Gnuplot program contains some elisp files for editing Gnuplot input files in GNU Emacs and running Gnuplot from GNU Emacs. In this case, we want to enable the Emacs support IF Emacs is installed, but we don’t want to mandate the installation of Emacs on installation of this package since Emacs is not required for providing the core functionality of the package. To enable this, the emacs-filesystem sub-package was created which owns the /usr/share/emacs/site-lisp directory. A package can then Require the emacs-filesystem package in order to install its Elisp files without pulling in Emacs and its dependency chain.