Subject: [PATCH] emacs: Generate and install autoloads

From: Pengji Zhang <[email-masked]>
Date: Sun, 18 Aug 2024 15:42:55 +0800

Previously when installed with 'make install', autoloads in sources
were not scraped. So users still had to load the full library
beforehand in order to use Notmuch.

Now we generate and install such a file for 'make install-emacs'. With
this change, users can replace in their Emacs configuration:

    (require 'notmuch)

with a much cheaper:

    (require 'notmuch-autoloads)

but are still able to use 'M-x notmuch'.

Note that this new file is not included in the 'make elpa' package, so
it does not break for those users, who have already been enjoying
autoloads generated by 'package.el'.

Besides, this should not break packaging for most distros. Even if
they have generated and maintained such a file using their package
managers, Emacs does not choke on an existing output file when
scraping autoloads.

Re: thread starting at id:[email-masked]

---

PS I am not familiar with Debian packaging but I have the impression
that its system for Emacs packages is sophisticated. Do we need to do
anything here in the Notmuch repository?

Thanks!
Pengji
---
 emacs/.gitignore       |  1 +
 emacs/Makefile.local   | 13 ++++++-
 emacs/autoloads-gen.el | 79 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 92 insertions(+), 1 deletion(-)
 create mode 100644 emacs/autoloads-gen.el

diff --git a/emacs/.gitignore b/emacs/.gitignore
index b9873b0a..c1af442b 100644
--- a/emacs/.gitignore
+++ b/emacs/.gitignore
@@ -3,3 +3,4 @@
 /*.rsti
 /notmuch-version.el
 /notmuch-pkg.el
+/notmuch-autoloads.el
diff --git a/emacs/Makefile.local b/emacs/Makefile.local
index 0f1f0eb2..7991a859 100644
--- a/emacs/Makefile.local
+++ b/emacs/Makefile.local
@@ -38,6 +38,16 @@ $(dir)/notmuch-pkg.el: $(srcdir)/$(dir)/notmuch-pkg.el.tmpl
 all: $(dir)/notmuch-pkg.el
 install-emacs: $(dir)/notmuch-pkg.el
 
+emacs_autoloads := $(dir)/notmuch-autoloads.el
+ifeq ($(WITH_EMACS),1)
+$(emacs_autoloads): $(emacs_sources) $(dir)/autoloads-gen.el
+	$(call quiet,EMACS) -batch -L emacs -l autoloads-gen.el \
+		-f autoloads-gen-batch $@ $(emacs_sources)
+
+all: $(emacs_autoloads)
+install-emacs: $(emacs_autoloads)
+endif
+
 emacs_mua := $(dir)/notmuch-emacs-mua
 emacs_mua_desktop := $(dir)/notmuch-emacs-mua.desktop
 
@@ -115,6 +125,7 @@ install-emacs: $(emacs_sources) $(emacs_images)
 	install -m0644 $(emacs_sources) "$(DESTDIR)$(emacslispdir)"
 ifeq ($(WITH_EMACS),1)
 	install -m0644 $(emacs_bytecode) "$(DESTDIR)$(emacslispdir)"
+	install -m0644 $(emacs_autoloads) "$(DESTDIR)$(emacslispdir)"
 endif
 	mkdir -p "$(DESTDIR)$(emacsetcdir)"
 	install -m0644 $(emacs_images) "$(DESTDIR)$(emacsetcdir)"
@@ -130,4 +141,4 @@ ifeq ($(WITH_DESKTOP),1)
 endif
 
 CLEAN := $(CLEAN) $(emacs_bytecode) $(dir)/notmuch-version.el $(dir)/notmuch-pkg.el \
-	$(emacs_docstrings) docstring.stamp
+	$(emacs_autoloads) $(emacs_docstrings) docstring.stamp
diff --git a/emacs/autoloads-gen.el b/emacs/autoloads-gen.el
new file mode 100644
index 00000000..9a1a7254
--- /dev/null
+++ b/emacs/autoloads-gen.el
@@ -0,0 +1,79 @@
+;;; autoloads-gen.el --- help generate autoloads  -*- lexical-binding: t -*-
+;;
+;; Copyright (C) 2024 Pengji Zhang
+;;
+;; This file is part of Notmuch.
+;;
+;; Notmuch is free software: you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Notmuch is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Notmuch.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Helpers for generating a `notmuch-autoloads.el' file.
+;;
+;; This file is written specifically for the Notmuch project. Some
+;; design choices here perhaps only make sense for Notmuch.
+;;
+;; An alternative way is to directly call `package-generate-autoloads'
+;; on our source directory. It was not chosen because we could not
+;; easily exclude files. Besides, that function is for packages, so
+;; using it on a non-package directory feels a bit hacky.
+
+;;; Code:
+
+(require 'seq) ; `seq-uniq', `seq-difference' (both in Emacs >= 25)
+
+(defvar generated-autoload-file)
+(defvar autoload-excludes)
+
+(defun autoloads-gen-batch ()
+  "Generate autoloads on the command line.
+First argument is the output file, and the rest are source files."
+  (let ((output-file (car command-line-args-left))
+	(sources (cdr command-line-args-left)))
+    (setq command-line-args-left nil)
+    (autoloads-gen (expand-file-name output-file)
+		   (mapcar #'expand-file-name sources))))
+
+(defun autoloads-gen (output-file sources)
+  "Generate autoloads for SOURCES and write them to OUTPUT-FILE.
+All filenames should be absolute.
+
+Note that this function always generate OUTPUT-FILE anew, instead
+of just updating added or changed autoloads."
+  ;; Here we always generate a new file to avoid potential troubles
+  ;; when switching Emacs versions, and also to update the timestamp
+  ;; of the output file reliably.
+  (let* ((dirs (seq-uniq (mapcar #'file-name-directory sources)))
+	 (excludes (mapcan (lambda (dir)
+			     (seq-difference (directory-files dir t)
+					     sources))
+			   dirs)))
+    ;; NOTE: The generated file does not contain the additional
+    ;; expression to modify `load-path', as is done by `package.el',
+    ;; because it is tedious to do for Emacs <= 29. Besides, this file
+    ;; is intended to be installed to some directory that is already
+    ;; in `load-path'.
+    (if (fboundp 'loaddefs-generate)
+	(loaddefs-generate dirs output-file excludes nil nil t)
+      ;; In Emacs >= 29, we have the new `loaddefs-gen' library, used
+      ;; above, and that superseded the now obsolete `autoload'
+      ;; library, used below.
+      (when (file-exists-p output-file)
+	(delete-file output-file))
+      (let ((generated-autoload-file output-file)
+	    (autoload-excludes excludes)
+	    (backup-inhibited t))
+	(mapc #'update-directory-autoloads dirs)))))
+
+;;; autoloads-gen.el ends here
-- 
2.46.0

_______________________________________________
notmuch mailing list -- [email-masked]
To unsubscribe send an email to [email-masked]