]> git.eshelyaron.com Git - emacs.git/commitdiff
Move autoload.el to lisp/obsolete/
authorLars Ingebrigtsen <larsi@gnus.org>
Thu, 4 Aug 2022 15:03:59 +0000 (17:03 +0200)
committerLars Ingebrigtsen <larsi@gnus.org>
Thu, 4 Aug 2022 15:03:59 +0000 (17:03 +0200)
lisp/emacs-lisp/autoload.el [deleted file]
lisp/obsolete/autoload.el [new file with mode: 0644]

diff --git a/lisp/emacs-lisp/autoload.el b/lisp/emacs-lisp/autoload.el
deleted file mode 100644 (file)
index 6ad8e81..0000000
+++ /dev/null
@@ -1,909 +0,0 @@
-;;; autoload.el --- maintain autoloads in loaddefs.el  -*- lexical-binding: t -*-
-
-;; Copyright (C) 1991-1997, 2001-2022 Free Software Foundation, Inc.
-
-;; Author: Roland McGrath <roland@gnu.org>
-;; Keywords: maint
-;; Package: emacs
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs 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.
-
-;; GNU Emacs 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 GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This code helps GNU Emacs maintainers keep the loaddefs.el file up to
-;; date.  It interprets magic cookies of the form ";;;###autoload" in
-;; Lisp source files in various useful ways.  To learn more, read the
-;; source; if you're going to use this, you'd better be able to.
-
-;; The functions in this file have been largely superseded by
-;; loaddefs-gen.el.
-
-;;; Code:
-
-(require 'lisp-mode)                   ;for `doc-string-elt' properties.
-(require 'lisp-mnt)
-(require 'cl-lib)
-(require 'loaddefs-gen)
-
-;; This feels like it should be a defconst, but MH-E sets it to
-;; ";;;###mh-autoload" for the autoloads that are to go into mh-loaddefs.el.
-(defvar generate-autoload-cookie ";;;###autoload"
-  "Magic comment indicating the following form should be autoloaded.
-Used by \\[update-file-autoloads].  This string should be
-meaningless to Lisp (e.g., a comment).
-
-This string is used:
-
-\;;;###autoload
-\(defun function-to-be-autoloaded () ...)
-
-If this string appears alone on a line, the following form will be
-read and an autoload made for it.  If there is further text on the line,
-that text will be copied verbatim to `generated-autoload-file'.")
-
-(defvar autoload-excludes nil
-  "If non-nil, list of absolute file names not to scan for autoloads.")
-
-(defconst generate-autoload-section-header "\f\n;;;### "
-  "String that marks the form at the start of a new file's autoload section.")
-
-(defconst generate-autoload-section-trailer "\n;;;***\n"
-  "String which indicates the end of the section of autoloads for a file.")
-
-(defconst generate-autoload-section-continuation ";;;;;; "
-  "String to add on each continuation of the section header form.")
-
-;; In some ways it would be nicer to use a value that is recognizably
-;; not a time-value, eg t, but that can cause issues if an older Emacs
-;; that does not expect non-time-values loads the file.
-(defconst autoload--non-timestamp '(0 0 0 0)
-  "Value to insert when `autoload-timestamps' is nil.")
-
-(defvar autoload-timestamps nil                ; experimental, see bug#22213
-  "Non-nil means insert a timestamp for each input file into the output.
-We use these in incremental updates of the output file to decide
-if we need to rescan an input file.  If you set this to nil,
-then we use the timestamp of the output file instead.  As a result:
- - for fixed inputs, the output will be the same every time
- - incremental updates of the output file might not be correct if:
-   i) the timestamp of the output file cannot be trusted (at least
-     relative to that of the input files)
-   ii) any of the input files can be modified during the time it takes
-      to create the output
-   iii) only a subset of the input files are scanned
-   These issues are unlikely to happen in practice, and would arguably
-   represent bugs in the build system.  Item iii) will happen if you
-   use a command like `update-file-autoloads', though, since it only
-   checks a single input file.")
-
-(defvar autoload-modified-buffers)      ;Dynamically scoped var.
-
-(defalias 'make-autoload #'loaddefs-generate--make-autoload)
-
-;; Forms which have doc-strings which should be printed specially.
-;; A doc-string-elt property of ELT says that (nth ELT FORM) is
-;; the doc-string in FORM.
-;; Those properties are now set in lisp-mode.el.
-
-(defun autoload-find-generated-file (file)
-  "Visit the autoload file for the current buffer, and return its buffer."
-  (let ((enable-local-variables :safe)
-        (enable-local-eval nil)
-        (find-file-hook nil)
-        (delay-mode-hooks t))
-    ;; We used to use `raw-text' to read this file, but this causes
-    ;; problems when the file contains non-ASCII characters.
-    (with-current-buffer (find-file-noselect
-                          (autoload-ensure-file-writeable file))
-      (if (zerop (buffer-size)) (insert (autoload-rubric file nil t)))
-      (current-buffer))))
-
-(defun autoload-generated-file (outfile)
-  "Return OUTFILE as an absolute name.
-If `generated-autoload-file' is bound locally in the current
-buffer, that is used instead, and it is expanded using the
-default directory; otherwise, `source-directory'/lisp is used."
-  (expand-file-name (if (local-variable-p 'generated-autoload-file)
-                        generated-autoload-file
-                      outfile)
-                    ;; File-local settings of generated-autoload-file should
-                    ;; be interpreted relative to the file's location,
-                    ;; of course.
-                    (if (not (local-variable-p 'generated-autoload-file))
-                        (expand-file-name "lisp" source-directory))))
-
-(defun autoload-read-section-header ()
-  "Read a section header form.
-Since continuation lines have been marked as comments,
-we must copy the text of the form and remove those comment
-markers before we call `read'."
-  (save-match-data
-    (let ((beginning (point))
-         string)
-      (forward-line 1)
-      (while (looking-at generate-autoload-section-continuation)
-       (forward-line 1))
-      (setq string (buffer-substring beginning (point)))
-      (with-current-buffer (get-buffer-create " *autoload*")
-       (erase-buffer)
-       (insert string)
-       (goto-char (point-min))
-       (while (search-forward generate-autoload-section-continuation nil t)
-         (replace-match " "))
-       (goto-char (point-min))
-       (read (current-buffer))))))
-
-(defvar autoload-print-form-outbuf nil
-  "Buffer which gets the output of `autoload-print-form'.")
-
-(defun autoload-print-form (form)
-  "Print FORM such that `make-docfile' will find the docstrings.
-The variable `autoload-print-form-outbuf' specifies the buffer to
-put the output in."
-  (cond
-   ;; If the form is a sequence, recurse.
-   ((eq (car form) 'progn) (mapcar #'autoload-print-form (cdr form)))
-   ;; Symbols at the toplevel are meaningless.
-   ((symbolp form) nil)
-   (t
-    (let ((doc-string-elt (function-get (car-safe form) 'doc-string-elt))
-         (outbuf autoload-print-form-outbuf))
-      (if (and (numberp doc-string-elt) (stringp (nth doc-string-elt form)))
-         ;; We need to hack the printing because the
-         ;; doc-string must be printed specially for
-         ;; make-docfile (sigh).
-         (let* ((p (nthcdr (1- doc-string-elt) form))
-                (elt (cdr p)))
-           (setcdr p nil)
-           (princ "\n(" outbuf)
-           (let ((print-escape-newlines t)
-                 (print-escape-control-characters t)
-                  (print-quoted t)
-                 (print-escape-nonascii t))
-             (dolist (elt form)
-               (prin1 elt outbuf)
-               (princ " " outbuf)))
-           (princ "\"\\\n" outbuf)
-           (let ((begin (with-current-buffer outbuf (point))))
-             (princ (substring (prin1-to-string (car elt)) 1)
-                    outbuf)
-             ;; Insert a backslash before each ( that
-             ;; appears at the beginning of a line in
-             ;; the doc string.
-             (with-current-buffer outbuf
-               (save-excursion
-                 (while (re-search-backward "\n[[(]" begin t)
-                   (forward-char 1)
-                   (insert "\\"))))
-             (if (null (cdr elt))
-                 (princ ")" outbuf)
-               (princ " " outbuf)
-               (princ (substring (prin1-to-string (cdr elt)) 1)
-                      outbuf))
-             (terpri outbuf)))
-       (let ((print-escape-newlines t)
-             (print-escape-control-characters t)
-              (print-quoted t)
-             (print-escape-nonascii t))
-         (print form outbuf)))))))
-
-(defalias 'autoload-rubric #'loaddefs-generate--rubric)
-
-(defvar autoload-ensure-writable nil
-  "Non-nil means `autoload-find-generated-file' makes existing file writable.")
-;; Just in case someone tries to get you to overwrite a file that you
-;; don't want to.
-;;;###autoload
-(put 'autoload-ensure-writable 'risky-local-variable t)
-
-(defun autoload-ensure-file-writeable (file)
-  ;; Probably pointless, but replaces the old AUTOGEN_VCS in lisp/Makefile,
-  ;; which was designed to handle CVSREAD=1 and equivalent.
-  (and autoload-ensure-writable
-       (let ((modes (file-modes file)))
-        (if (and modes (zerop (logand modes #o0200)))
-             ;; Ignore any errors here, and let subsequent attempts
-             ;; to write the file raise any real error.
-             (ignore-errors (set-file-modes file (logior modes #o0200))))))
-  file)
-
-(defun autoload-insert-section-header (outbuf autoloads load-name file time)
-  "Insert into buffer OUTBUF the section-header line for FILE.
-The header line lists the file name, its \"load name\", its autoloads,
-and the time the FILE was last updated (the time is inserted only
-if `autoload-timestamps' is non-nil, otherwise a fixed fake time is inserted)."
-  ;; (cl-assert ;Make sure we don't insert it in the middle of another section.
-  ;;  (save-excursion
-  ;;    (or (not (re-search-backward
-  ;;              (concat "\\("
-  ;;                      (regexp-quote generate-autoload-section-header)
-  ;;                      "\\)\\|\\("
-  ;;                      (regexp-quote generate-autoload-section-trailer)
-  ;;                      "\\)")
-  ;;              nil t))
-  ;;        (match-end 2))))
-  (insert generate-autoload-section-header)
-  (prin1 `(autoloads ,autoloads ,load-name ,file ,time)
-        outbuf)
-  (terpri outbuf)
-  ;; Break that line at spaces, to avoid very long lines.
-  ;; Make each sub-line into a comment.
-  (with-current-buffer outbuf
-    (save-excursion
-      (forward-line -1)
-      (while (not (eolp))
-       (move-to-column 64)
-       (skip-chars-forward "^ \n")
-       (or (eolp)
-           (insert "\n" generate-autoload-section-continuation))))))
-
-(defun autoload-find-file (file)
-  "Fetch FILE and put it in a temp buffer.  Return the buffer."
-  ;; It is faster to avoid visiting the file.
-  (setq file (expand-file-name file))
-  (with-current-buffer (get-buffer-create " *autoload-file*")
-    (kill-all-local-variables)
-    (erase-buffer)
-    (setq buffer-undo-list t
-          buffer-read-only nil)
-    (delay-mode-hooks (emacs-lisp-mode))
-    (setq default-directory (file-name-directory file))
-    (insert-file-contents file nil)
-    (let ((enable-local-variables :safe)
-         (enable-local-eval nil))
-      (hack-local-variables))
-    (current-buffer)))
-
-(defalias 'autoload-file-load-name #'loaddefs-generate--file-load-name)
-
-(defun generate-file-autoloads (file)
-  "Insert at point a loaddefs autoload section for FILE.
-Autoloads are generated for defuns and defmacros in FILE
-marked by `generate-autoload-cookie' (which see).
-If FILE is being visited in a buffer, the contents of the buffer
-are used.
-Return non-nil in the case where no autoloads were added at point."
-  (interactive "fGenerate autoloads for file: ")
-  (let ((autoload-modified-buffers nil))
-    (autoload-generate-file-autoloads file (current-buffer) buffer-file-name)
-    autoload-modified-buffers))
-
-(defconst autoload-def-prefixes-max-entries 5
-  "Target length of the list of definition prefixes per file.
-If set too small, the prefixes will be too generic (i.e. they'll use little
-memory, we'll end up looking in too many files when we need a particular
-prefix), and if set too large, they will be too specific (i.e. they will
-cost more memory use).")
-
-(defconst autoload-def-prefixes-max-length 12
-  "Target size of definition prefixes.
-Don't try to split prefixes that are already longer than that.")
-
-(defalias 'autoload--make-defs-autoload #'loaddefs-generate--make-prefixes)
-
-(defun autoload--setup-output (otherbuf outbuf absfile load-name output-file)
-  (let ((outbuf
-         (or (if otherbuf
-                 ;; A file-local setting of
-                 ;; autoload-generated-file says we
-                 ;; should ignore OUTBUF.
-                 nil
-               outbuf)
-             (autoload-find-destination absfile load-name output-file)
-             ;; The file has autoload cookies, but they're
-             ;; already up-to-date. If OUTFILE is nil, the
-             ;; entries are in the expected OUTBUF,
-             ;; otherwise they're elsewhere.
-             (throw 'done otherbuf))))
-    (with-current-buffer outbuf
-      (point-marker))))
-
-(defun autoload--print-cookie-text (output-start load-name file)
-  (let ((standard-output (marker-buffer output-start)))
-     (search-forward generate-autoload-cookie)
-     (skip-chars-forward " \t")
-     (if (eolp)
-         (condition-case-unless-debug err
-             ;; Read the next form and make an autoload.
-             (let* ((form (prog1 (read (current-buffer))
-                            (or (bolp) (forward-line 1))))
-                    (autoload (make-autoload form load-name)))
-               (if autoload
-                   nil
-                 (setq autoload form))
-               (let ((autoload-print-form-outbuf
-                      standard-output))
-                 (autoload-print-form autoload)))
-           (error
-            (message "Autoload cookie error in %s:%s %S"
-                     file (count-lines (point-min) (point)) err)))
-
-       ;; Copy the rest of the line to the output.
-       (princ (buffer-substring
-               (progn
-                 ;; Back up over whitespace, to preserve it.
-                 (skip-chars-backward " \f\t")
-                 (if (= (char-after (1+ (point))) ? )
-                     ;; Eat one space.
-                     (forward-char 1))
-                 (point))
-              (progn (forward-line 1) (point)))))))
-
-(defvar autoload-builtin-package-versions nil)
-
-(defun autoload-generate-file-autoloads (file &optional outbuf outfile)
-  "Insert an autoload section for FILE in the appropriate buffer.
-Autoloads are generated for defuns and defmacros in FILE
-marked by `generate-autoload-cookie' (which see).
-
-If FILE is being visited in a buffer, the contents of the buffer are used.
-OUTBUF is the buffer in which the autoload statements should be inserted.
-
-If OUTBUF is nil, the output will go to OUTFILE, unless there's a
-buffer-local setting of `generated-autoload-file' in FILE.
-
-Return non-nil if and only if FILE adds no autoloads to OUTFILE
-\(or OUTBUF if OUTFILE is nil).  The actual return value is
-FILE's modification time."
-  ;; Include the file name in any error messages
-  (condition-case err
-      (let (load-name
-            (print-length nil)
-            (print-level nil)
-            (float-output-format nil)
-            (visited (get-file-buffer file))
-            (otherbuf nil)
-            (absfile (expand-file-name file))
-          (defs '())
-            ;; nil until we found a cookie.
-            output-start)
-        (when
-            (catch 'done
-              (with-current-buffer (or visited
-                                       ;; It is faster to avoid visiting the file.
-                                       (autoload-find-file file))
-                ;; Obey the no-update-autoloads file local variable.
-                (unless no-update-autoloads
-                  (or noninteractive (message "Generating autoloads for %s..." file))
-                  (setq load-name
-                        (if (stringp generated-autoload-load-name)
-                            generated-autoload-load-name
-                          (autoload-file-load-name absfile outfile)))
-                  ;; FIXME? Comparing file-names for equality with just equal
-                  ;; is fragile, eg if one has an automounter prefix and one
-                  ;; does not, but both refer to the same physical file.
-                  (when (and outfile
-                             (not outbuf)
-                             (not
-                              (if (memq system-type '(ms-dos windows-nt))
-                                  (equal (downcase outfile)
-                                         (downcase (autoload-generated-file
-                                                    outfile)))
-                                (equal outfile (autoload-generated-file
-                                                outfile)))))
-                    (setq otherbuf t))
-                  (save-excursion
-                    (save-restriction
-                      (widen)
-                      (when autoload-builtin-package-versions
-                        (let ((version (lm-header "version"))
-                              package)
-                          (and version
-                               (setq version (ignore-errors (version-to-list version)))
-                               (setq package (or (lm-header "package")
-                                                 (file-name-sans-extension
-                                                  (file-name-nondirectory file))))
-                               (setq output-start (autoload--setup-output
-                                                   otherbuf outbuf absfile
-                                                   load-name outfile))
-                               (let ((standard-output (marker-buffer output-start))
-                                     (print-quoted t))
-                                 (princ `(push (purecopy
-                                                ',(cons (intern package) version))
-                                               package--builtin-versions))
-                                 (princ "\n")))))
-
-                      ;; Do not insert autoload entries for excluded files.
-                      (unless (member absfile autoload-excludes)
-                        (goto-char (point-min))
-                        (while (not (eobp))
-                          (skip-chars-forward " \t\n\f")
-                          (cond
-                           ((looking-at (regexp-quote generate-autoload-cookie))
-                            ;; If not done yet, figure out where to insert this text.
-                            (unless output-start
-                              (setq output-start (autoload--setup-output
-                                                  otherbuf outbuf absfile
-                                                  load-name outfile)))
-                            (autoload--print-cookie-text output-start load-name file))
-                           ((= (following-char) ?\;)
-                            ;; Don't read the comment.
-                            (forward-line 1))
-                           (t
-                  ;; Avoid (defvar <foo>) by requiring a trailing space.
-                  ;; Also, ignore this prefix business
-                  ;; for ;;;###tramp-autoload and friends.
-                  (when (and (equal generate-autoload-cookie ";;;###autoload")
-                             (looking-at "(\\(def[^ ]+\\) ['(]*\\([^' ()\"\n]+\\)[\n \t]")
-                             (not (member
-                                   (match-string 1)
-                                   autoload-ignored-definitions)))
-                    (push (match-string-no-properties 2) defs))
-                            (forward-sexp 1)
-                            (forward-line 1)))))))
-
-          (when (and autoload-compute-prefixes defs)
-            ;; This output needs to always go in the main loaddefs.el,
-            ;; regardless of generated-autoload-file.
-            ;; FIXME: the files that don't have autoload cookies but
-            ;; do have definitions end up listed twice in loaddefs.el:
-            ;; once for their register-definition-prefixes and once in
-            ;; the list of "files without any autoloads".
-            (let ((form (autoload--make-defs-autoload defs load-name)))
-              (cond
-               ((null form))             ;All defs obey the default rule, yay!
-               ((not otherbuf)
-                (unless output-start
-                  (setq output-start (autoload--setup-output
-                                      nil outbuf absfile load-name outfile)))
-                (let ((autoload-print-form-outbuf
-                       (marker-buffer output-start)))
-                  (autoload-print-form form)))
-               (t
-                (let* ((other-output-start
-                        ;; To force the output to go to the main loaddefs.el
-                        ;; rather than to generated-autoload-file,
-                        ;; there are two cases: if outbuf is non-nil,
-                        ;; then passing otherbuf=nil is enough, but if
-                        ;; outbuf is nil, that won't cut it, so we
-                        ;; locally bind generated-autoload-file.
-                        (autoload--setup-output nil outbuf absfile load-name
-                                                outfile))
-                       (autoload-print-form-outbuf
-                        (marker-buffer other-output-start)))
-                  (autoload-print-form form)
-                  (with-current-buffer (marker-buffer other-output-start)
-                    (save-excursion
-                      ;; Insert the section-header line which lists
-                      ;; the file name and which functions are in it, etc.
-                      (goto-char other-output-start)
-                      (let ((relfile (file-relative-name absfile)))
-                        (autoload-insert-section-header
-                         (marker-buffer other-output-start)
-                         "actual autoloads are elsewhere" load-name relfile
-                        (if autoload-timestamps
-                            (file-attribute-modification-time
-                             (file-attributes absfile))
-                          autoload--non-timestamp))
-                        (insert ";;; Generated autoloads from " relfile "\n")))
-                    (insert generate-autoload-section-trailer)))))))
-
-                  (when output-start
-                    (let ((secondary-autoloads-file-buf
-                           (if otherbuf (current-buffer))))
-                      (with-current-buffer (marker-buffer output-start)
-                        (cl-assert (> (point) output-start))
-                        (save-excursion
-                          ;; Insert the section-header line which lists the file name
-                          ;; and which functions are in it, etc.
-                          (goto-char output-start)
-                          (let ((relfile (file-relative-name absfile)))
-                            (autoload-insert-section-header
-                             (marker-buffer output-start)
-                             () load-name relfile
-                             (if secondary-autoloads-file-buf
-                                 ;; MD5 checksums are much better because they do not
-                                 ;; change unless the file changes (so they'll be
-                                 ;; equal on two different systems and will change
-                                 ;; less often than time-stamps, thus leading to fewer
-                                 ;; unneeded changes causing spurious conflicts), but
-                                 ;; using time-stamps is a very useful optimization,
-                                 ;; so we use time-stamps for the main autoloads file
-                                 ;; (loaddefs.el) where we have special ways to
-                                 ;; circumvent the "random change problem", and MD5
-                                 ;; checksum in secondary autoload files where we do
-                                 ;; not need the time-stamp optimization because it is
-                                 ;; already provided by the primary autoloads file.
-                                 (md5 secondary-autoloads-file-buf
-                                      ;; We'd really want to just use
-                                      ;; `emacs-internal' instead.
-                                      nil nil 'emacs-mule-unix)
-                               (if autoload-timestamps
-                                   (file-attribute-modification-time
-                                   (file-attributes relfile))
-                                 autoload--non-timestamp)))
-                            (insert ";;; Generated autoloads from " relfile "\n")))
-                        (insert generate-autoload-section-trailer))))
-                  (or noninteractive
-                      (message "Generating autoloads for %s...done" file)))
-                (or visited
-                    ;; We created this buffer, so we should kill it.
-                    (kill-buffer (current-buffer))))
-              (or (not output-start)
-                  ;; If the entries were added to some other buffer, then the file
-                  ;; doesn't add entries to OUTFILE.
-                  otherbuf))
-          (file-attribute-modification-time (file-attributes absfile))))
-    (error
-     ;; Probably unbalanced parens in forward-sexp. In that case, the
-     ;; condition is scan-error, and the signal data includes point
-     ;; where the error was found; we'd like to convert that to
-     ;; line:col, but line-number-at-pos gets the wrong line in batch
-     ;; mode for some reason.
-     ;;
-     ;; At least this gets the file name in the error message; the
-     ;; developer can use goto-char to get to the error position.
-     (error "%s:0:0: error: %s: %s" file (car err) (cdr err)))
-    ))
-\f
-;; For parallel builds, to stop another process reading a half-written file.
-(defun autoload--save-buffer ()
-  "Save current buffer to its file, atomically."
-  ;; Similar to byte-compile-file.
-  (let* ((version-control 'never)
-         (tempfile (make-temp-file buffer-file-name))
-        (default-modes (default-file-modes))
-        (temp-modes (logand default-modes #o600))
-        (desired-modes (logand default-modes
-                               (or (file-modes buffer-file-name) #o666)))
-         (kill-emacs-hook
-          (cons (lambda () (ignore-errors (delete-file tempfile)))
-                kill-emacs-hook)))
-    (unless (= temp-modes desired-modes)
-      (set-file-modes tempfile desired-modes 'nofollow))
-    (write-region (point-min) (point-max) tempfile nil 1)
-    (backup-buffer)
-    (rename-file tempfile buffer-file-name t))
-  (set-buffer-modified-p nil)
-  (set-visited-file-modtime)
-  (or noninteractive (message "Wrote %s" buffer-file-name)))
-
-(defun autoload-save-buffers ()
-  (while autoload-modified-buffers
-    (with-current-buffer (pop autoload-modified-buffers)
-      (autoload--save-buffer))))
-
-;; FIXME This command should be deprecated.
-;; See https://debbugs.gnu.org/22213#41
-;;;###autoload
-(defun update-file-autoloads (file &optional save-after outfile)
-  "Update the autoloads for FILE.
-If prefix arg SAVE-AFTER is non-nil, save the buffer too.
-
-If FILE binds `generated-autoload-file' as a file-local variable,
-autoloads are written into that file.  Otherwise, the autoloads
-file is determined by OUTFILE.  If called interactively, prompt
-for OUTFILE; if called from Lisp with OUTFILE nil, use the
-existing value of `generated-autoload-file'.
-
-Return FILE if there was no autoload cookie in it, else nil."
-  (interactive (list (read-file-name "Update autoloads for file: ")
-                    current-prefix-arg
-                    (read-file-name "Write autoload definitions to file: ")))
-  (setq outfile (or outfile generated-autoload-file))
-  (let* ((autoload-modified-buffers nil)
-        ;; We need this only if the output file handles more than one input.
-        ;; See https://debbugs.gnu.org/22213#38 and subsequent.
-        (autoload-timestamps t)
-         (no-autoloads (autoload-generate-file-autoloads
-                        file nil
-                        (if (local-variable-p 'generated-autoload-file)
-                            generated-autoload-file
-                          outfile))))
-    (if autoload-modified-buffers
-        (if save-after (autoload-save-buffers))
-      (if (called-interactively-p 'interactive)
-          (message "Autoload section for %s is up to date." file)))
-    (if no-autoloads file)))
-
-(defun autoload-find-destination (file load-name output-file)
-  "Find the destination point of the current buffer's autoloads.
-FILE is the file name of the current buffer.
-LOAD-NAME is the name as it appears in the output.
-Returns a buffer whose point is placed at the requested location.
-Returns nil if the file's autoloads are up-to-date, otherwise
-removes any prior now out-of-date autoload entries."
-  (catch 'up-to-date
-    (let* ((buf (current-buffer))
-           (existing-buffer (if buffer-file-name buf))
-           (output-file (autoload-generated-file output-file))
-           (output-time (if (file-exists-p output-file)
-                            (file-attribute-modification-time
-                            (file-attributes output-file))))
-           (found nil))
-      (with-current-buffer (autoload-find-generated-file output-file)
-        ;; This is to make generated-autoload-file have Unix EOLs, so
-        ;; that it is portable to all platforms.
-        (or (eq 0 (coding-system-eol-type buffer-file-coding-system))
-           (set-buffer-file-coding-system 'unix))
-        (or (> (buffer-size) 0)
-            (error "Autoloads file %s lacks boilerplate" buffer-file-name))
-        (or (file-writable-p buffer-file-name)
-            (error "Autoloads file %s is not writable" buffer-file-name))
-        (widen)
-        (goto-char (point-min))
-        ;; Look for the section for LOAD-NAME.
-        (while (and (not found)
-                    (search-forward generate-autoload-section-header nil t))
-          (let ((form (autoload-read-section-header)))
-            (cond ((string= (nth 2 form) load-name)
-                   ;; We found the section for this file.
-                   ;; Check if it is up to date.
-                   (let ((begin (match-beginning 0))
-                         (last-time (nth 4 form))
-                         (file-time (file-attribute-modification-time
-                                    (file-attributes file))))
-                     (if (and (or (null existing-buffer)
-                                  (not (buffer-modified-p existing-buffer)))
-                              (cond
-                               ;; FIXME? Arguably we should throw a
-                               ;; user error, or some kind of warning,
-                               ;; if we were called from update-file-autoloads,
-                               ;; which can update only a single input file.
-                               ;; It's not appropriate to use the output
-                               ;; file modtime in such a case,
-                               ;; if there are multiple input files
-                               ;; contributing to the output.
-                               ((and output-time
-                                    (member last-time
-                                            (list t autoload--non-timestamp)))
-                                (not (time-less-p output-time file-time)))
-                               ;; last-time is the time-stamp (specifying
-                               ;; the last time we looked at the file) and
-                               ;; the file hasn't been changed since.
-                               ((listp last-time)
-                                (not (time-less-p last-time file-time)))
-                               ;; last-time is an MD5 checksum instead.
-                               ((stringp last-time)
-                                (equal last-time
-                                      (md5 buf nil nil 'emacs-mule)))))
-                         (throw 'up-to-date nil)
-                       (autoload-remove-section begin)
-                       (setq found t))))
-                  ((string< load-name (nth 2 form))
-                   ;; We've come to a section alphabetically later than
-                   ;; LOAD-NAME.  We assume the file is in order and so
-                   ;; there must be no section for LOAD-NAME.  We will
-                   ;; insert one before the section here.
-                   (goto-char (match-beginning 0))
-                   (setq found t)))))
-        (or found
-            (progn
-              ;; No later sections in the file.  Put before the last page.
-              (goto-char (point-max))
-              (search-backward "\f" nil t)))
-        (unless (memq (current-buffer) autoload-modified-buffers)
-          (push (current-buffer) autoload-modified-buffers))
-        (current-buffer)))))
-
-(defun autoload-remove-section (begin)
-  (goto-char begin)
-  (search-forward generate-autoload-section-trailer)
-  (delete-region begin (point)))
-
-;;;###autoload
-(defun update-directory-autoloads (&rest dirs)
-  "Update autoload definitions for Lisp files in the directories DIRS.
-In an interactive call, you must give one argument, the name of a
-single directory.  In a call from Lisp, you can supply multiple
-directories as separate arguments, but this usage is discouraged.
-
-The function does NOT recursively descend into subdirectories of the
-directory or directories specified.
-
-In an interactive call, prompt for a default output file for the
-autoload definitions.  When called from Lisp, use the existing
-value of `generated-autoload-file'.  If any Lisp file binds
-`generated-autoload-file' as a file-local variable, write its
-autoloads into the specified file instead."
-  (declare (obsolete make-directory-autoloads "28.1"))
-  (interactive "DUpdate autoloads from directory: ")
-  (make-directory-autoloads
-   dirs
-   (if (called-interactively-p 'interactive)
-       (read-file-name "Write autoload definitions to file: ")
-     generated-autoload-file)))
-
-;;;###autoload
-(defun make-directory-autoloads (dir output-file)
-  "Update autoload definitions for Lisp files in the directories DIRS.
-DIR can be either a single directory or a list of
-directories.  (The latter usage is discouraged.)
-
-The autoloads will be written to OUTPUT-FILE.  If any Lisp file
-binds `generated-autoload-file' as a file-local variable, write
-its autoloads into the specified file instead.
-
-The function does NOT recursively descend into subdirectories of the
-directory or directories specified."
-  (interactive "DUpdate autoloads from directory: \nFWrite to file: ")
-  (let* ((files-re (let ((tmp nil))
-                    (dolist (suf (get-load-suffixes))
-                       ;; We don't use module-file-suffix below because
-                       ;; we don't want to depend on whether Emacs was
-                       ;; built with or without modules support, nor
-                       ;; what is the suffix for the underlying OS.
-                      (unless (string-match "\\.\\(elc\\|so\\|dll\\)" suf)
-                         (push suf tmp)))
-                     (concat "\\`[^=.].*" (regexp-opt tmp t) "\\'")))
-        (files (apply #'nconc
-                      (mapcar (lambda (d)
-                                (directory-files (expand-file-name d)
-                                                  t files-re))
-                              (if (consp dir) dir (list dir)))))
-         (done ())                      ;Files processed; to remove duplicates.
-         (changed nil)                  ;Non-nil if some change occurred.
-        (last-time)
-         ;; Files with no autoload cookies or whose autoloads go to other
-         ;; files because of file-local autoload-generated-file settings.
-        (no-autoloads nil)
-         ;; Ensure that we don't do odd things when putting the doc
-         ;; strings into the autoloads file.
-         (left-margin 0)
-         (autoload-modified-buffers nil)
-        (output-time
-         (and (file-exists-p output-file)
-              (file-attribute-modification-time
-                (file-attributes output-file)))))
-
-    (with-current-buffer (autoload-find-generated-file output-file)
-      (save-excursion
-       ;; Canonicalize file names and remove the autoload file itself.
-       (setq files (delete (file-relative-name buffer-file-name)
-                           (mapcar #'file-relative-name files)))
-
-       (goto-char (point-min))
-       (while (search-forward generate-autoload-section-header nil t)
-         (let* ((form (autoload-read-section-header))
-                (file (nth 3 form)))
-           (cond ((and (consp file) (stringp (car file)))
-                  ;; This is a list of files that have no autoload cookies.
-                  ;; There shouldn't be more than one such entry.
-                  ;; Remove the obsolete section.
-                  (autoload-remove-section (match-beginning 0))
-                  (setq last-time (nth 4 form))
-                  (if (member last-time (list t autoload--non-timestamp))
-                      (setq last-time output-time))
-                  (dolist (file file)
-                    (let ((file-time (file-attribute-modification-time
-                                      (file-attributes file))))
-                      (when (and file-time
-                                 (not (time-less-p last-time file-time)))
-                        ;; file unchanged
-                        (push file no-autoloads)
-                        (setq files (delete file files))))))
-                 ((not (stringp file)))
-                 ((or (not (file-exists-p file))
-                       ;; Remove duplicates as well, just in case.
-                       (member file done))
-                   ;; Remove the obsolete section.
-                   (setq changed t)
-                  (autoload-remove-section (match-beginning 0)))
-                 ((not (time-less-p (let ((oldtime (nth 4 form)))
-                                      (if (member oldtime
-                                                  (list
-                                                   t autoload--non-timestamp))
-                                          output-time
-                                        oldtime))
-                                     (file-attribute-modification-time
-                                     (file-attributes file))))
-                  ;; File hasn't changed.
-                  nil)
-                 (t
-                   (setq changed t)
-                   (autoload-remove-section (match-beginning 0))
-                   (if (autoload-generate-file-autoloads
-                        ;; Passing `current-buffer' makes it insert at point.
-                        file (current-buffer) buffer-file-name)
-                       (push file no-autoloads))))
-            (push file done)
-           (setq files (delete file files)))))
-      ;; Elements remaining in FILES have no existing autoload sections yet.
-      (let ((no-autoloads-time (or last-time '(0 0 0 0)))
-            (progress (make-progress-reporter
-                       (byte-compile-info
-                        (concat "Scraping files for "
-                                (file-relative-name output-file)))
-                       0 (length files) nil 10))
-            (file-count 0)
-            file-time)
-       (dolist (file files)
-          (progress-reporter-update progress (setq file-count (1+ file-count)))
-         (cond
-          ;; Passing nil as second argument forces
-          ;; autoload-generate-file-autoloads to look for the right
-          ;; spot where to insert each autoloads section.
-          ((setq file-time
-                 (autoload-generate-file-autoloads file nil buffer-file-name))
-           (push file no-autoloads)
-           (if (time-less-p no-autoloads-time file-time)
-               (setq no-autoloads-time file-time)))
-           (t (setq changed t))))
-        (progress-reporter-done progress)
-
-       (when no-autoloads
-         ;; Sort them for better readability.
-         (setq no-autoloads (sort no-autoloads 'string<))
-         ;; Add the `no-autoloads' section.
-         (goto-char (point-max))
-         (search-backward "\f" nil t)
-         (autoload-insert-section-header
-          (current-buffer) nil nil
-           ;; Filter out the other loaddefs files, because it makes
-           ;; the list unstable (and leads to spurious changes in
-           ;; ldefs-boot.el) since the loaddef files can be created in
-           ;; any order.
-           (seq-filter (lambda (file)
-                         (not (string-match-p "[/-]loaddefs.el" file)))
-                       no-autoloads)
-           (if autoload-timestamps
-              no-autoloads-time
-            autoload--non-timestamp))
-         (insert generate-autoload-section-trailer)))
-
-      ;; Don't modify the file if its content has not been changed, so `make'
-      ;; dependencies don't trigger unnecessarily.
-      (if (not changed)
-          (set-buffer-modified-p nil)
-        (autoload--save-buffer))
-
-      ;; In case autoload entries were added to other files because of
-      ;; file-local autoload-generated-file settings.
-      (autoload-save-buffers))))
-
-(defun batch-update-autoloads--summary (strings)
-  (let ((message ""))
-    (while strings
-      (when (> (length (concat message " " (car strings))) 64)
-        (byte-compile-info (concat message " ...") t "SCRAPE")
-        (setq message ""))
-      (setq message (if (zerop (length message))
-                        (car strings)
-                      (concat message " " (car strings))))
-      (setq strings (cdr strings)))
-    (when (> (length message) 0)
-      (byte-compile-info message t "SCRAPE"))))
-
-;;;###autoload
-(defun batch-update-autoloads ()
-  "Update loaddefs.el autoloads in batch mode.
-Calls `update-directory-autoloads' on the command line arguments.
-Definitions are written to `generated-autoload-file' (which
-should be non-nil)."
-  ;; For use during the Emacs build process only.
-  ;; Exclude those files that are preloaded on ALL platforms.
-  ;; These are the ones in loadup.el where "(load" is at the start
-  ;; of the line (crude, but it works).
-  (unless autoload-excludes
-    (let ((default-directory (file-name-directory generated-autoload-file))
-         file)
-      (when (file-readable-p "loadup.el")
-       (with-temp-buffer
-         (insert-file-contents "loadup.el")
-         (while (re-search-forward "^(load \"\\([^\"]+\\)\"" nil t)
-           (setq file (match-string 1))
-           (or (string-match "\\.el\\'" file)
-               (setq file (format "%s.el" file)))
-           (or (string-match "\\`site-" file)
-               (push (expand-file-name file) autoload-excludes)))))))
-  (let ((args command-line-args-left))
-    (batch-update-autoloads--summary args)
-    (setq command-line-args-left nil)
-    (make-directory-autoloads args generated-autoload-file)))
-
-(provide 'autoload)
-
-;;; autoload.el ends here
diff --git a/lisp/obsolete/autoload.el b/lisp/obsolete/autoload.el
new file mode 100644 (file)
index 0000000..6ad8e81
--- /dev/null
@@ -0,0 +1,909 @@
+;;; autoload.el --- maintain autoloads in loaddefs.el  -*- lexical-binding: t -*-
+
+;; Copyright (C) 1991-1997, 2001-2022 Free Software Foundation, Inc.
+
+;; Author: Roland McGrath <roland@gnu.org>
+;; Keywords: maint
+;; Package: emacs
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs 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 GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This code helps GNU Emacs maintainers keep the loaddefs.el file up to
+;; date.  It interprets magic cookies of the form ";;;###autoload" in
+;; Lisp source files in various useful ways.  To learn more, read the
+;; source; if you're going to use this, you'd better be able to.
+
+;; The functions in this file have been largely superseded by
+;; loaddefs-gen.el.
+
+;;; Code:
+
+(require 'lisp-mode)                   ;for `doc-string-elt' properties.
+(require 'lisp-mnt)
+(require 'cl-lib)
+(require 'loaddefs-gen)
+
+;; This feels like it should be a defconst, but MH-E sets it to
+;; ";;;###mh-autoload" for the autoloads that are to go into mh-loaddefs.el.
+(defvar generate-autoload-cookie ";;;###autoload"
+  "Magic comment indicating the following form should be autoloaded.
+Used by \\[update-file-autoloads].  This string should be
+meaningless to Lisp (e.g., a comment).
+
+This string is used:
+
+\;;;###autoload
+\(defun function-to-be-autoloaded () ...)
+
+If this string appears alone on a line, the following form will be
+read and an autoload made for it.  If there is further text on the line,
+that text will be copied verbatim to `generated-autoload-file'.")
+
+(defvar autoload-excludes nil
+  "If non-nil, list of absolute file names not to scan for autoloads.")
+
+(defconst generate-autoload-section-header "\f\n;;;### "
+  "String that marks the form at the start of a new file's autoload section.")
+
+(defconst generate-autoload-section-trailer "\n;;;***\n"
+  "String which indicates the end of the section of autoloads for a file.")
+
+(defconst generate-autoload-section-continuation ";;;;;; "
+  "String to add on each continuation of the section header form.")
+
+;; In some ways it would be nicer to use a value that is recognizably
+;; not a time-value, eg t, but that can cause issues if an older Emacs
+;; that does not expect non-time-values loads the file.
+(defconst autoload--non-timestamp '(0 0 0 0)
+  "Value to insert when `autoload-timestamps' is nil.")
+
+(defvar autoload-timestamps nil                ; experimental, see bug#22213
+  "Non-nil means insert a timestamp for each input file into the output.
+We use these in incremental updates of the output file to decide
+if we need to rescan an input file.  If you set this to nil,
+then we use the timestamp of the output file instead.  As a result:
+ - for fixed inputs, the output will be the same every time
+ - incremental updates of the output file might not be correct if:
+   i) the timestamp of the output file cannot be trusted (at least
+     relative to that of the input files)
+   ii) any of the input files can be modified during the time it takes
+      to create the output
+   iii) only a subset of the input files are scanned
+   These issues are unlikely to happen in practice, and would arguably
+   represent bugs in the build system.  Item iii) will happen if you
+   use a command like `update-file-autoloads', though, since it only
+   checks a single input file.")
+
+(defvar autoload-modified-buffers)      ;Dynamically scoped var.
+
+(defalias 'make-autoload #'loaddefs-generate--make-autoload)
+
+;; Forms which have doc-strings which should be printed specially.
+;; A doc-string-elt property of ELT says that (nth ELT FORM) is
+;; the doc-string in FORM.
+;; Those properties are now set in lisp-mode.el.
+
+(defun autoload-find-generated-file (file)
+  "Visit the autoload file for the current buffer, and return its buffer."
+  (let ((enable-local-variables :safe)
+        (enable-local-eval nil)
+        (find-file-hook nil)
+        (delay-mode-hooks t))
+    ;; We used to use `raw-text' to read this file, but this causes
+    ;; problems when the file contains non-ASCII characters.
+    (with-current-buffer (find-file-noselect
+                          (autoload-ensure-file-writeable file))
+      (if (zerop (buffer-size)) (insert (autoload-rubric file nil t)))
+      (current-buffer))))
+
+(defun autoload-generated-file (outfile)
+  "Return OUTFILE as an absolute name.
+If `generated-autoload-file' is bound locally in the current
+buffer, that is used instead, and it is expanded using the
+default directory; otherwise, `source-directory'/lisp is used."
+  (expand-file-name (if (local-variable-p 'generated-autoload-file)
+                        generated-autoload-file
+                      outfile)
+                    ;; File-local settings of generated-autoload-file should
+                    ;; be interpreted relative to the file's location,
+                    ;; of course.
+                    (if (not (local-variable-p 'generated-autoload-file))
+                        (expand-file-name "lisp" source-directory))))
+
+(defun autoload-read-section-header ()
+  "Read a section header form.
+Since continuation lines have been marked as comments,
+we must copy the text of the form and remove those comment
+markers before we call `read'."
+  (save-match-data
+    (let ((beginning (point))
+         string)
+      (forward-line 1)
+      (while (looking-at generate-autoload-section-continuation)
+       (forward-line 1))
+      (setq string (buffer-substring beginning (point)))
+      (with-current-buffer (get-buffer-create " *autoload*")
+       (erase-buffer)
+       (insert string)
+       (goto-char (point-min))
+       (while (search-forward generate-autoload-section-continuation nil t)
+         (replace-match " "))
+       (goto-char (point-min))
+       (read (current-buffer))))))
+
+(defvar autoload-print-form-outbuf nil
+  "Buffer which gets the output of `autoload-print-form'.")
+
+(defun autoload-print-form (form)
+  "Print FORM such that `make-docfile' will find the docstrings.
+The variable `autoload-print-form-outbuf' specifies the buffer to
+put the output in."
+  (cond
+   ;; If the form is a sequence, recurse.
+   ((eq (car form) 'progn) (mapcar #'autoload-print-form (cdr form)))
+   ;; Symbols at the toplevel are meaningless.
+   ((symbolp form) nil)
+   (t
+    (let ((doc-string-elt (function-get (car-safe form) 'doc-string-elt))
+         (outbuf autoload-print-form-outbuf))
+      (if (and (numberp doc-string-elt) (stringp (nth doc-string-elt form)))
+         ;; We need to hack the printing because the
+         ;; doc-string must be printed specially for
+         ;; make-docfile (sigh).
+         (let* ((p (nthcdr (1- doc-string-elt) form))
+                (elt (cdr p)))
+           (setcdr p nil)
+           (princ "\n(" outbuf)
+           (let ((print-escape-newlines t)
+                 (print-escape-control-characters t)
+                  (print-quoted t)
+                 (print-escape-nonascii t))
+             (dolist (elt form)
+               (prin1 elt outbuf)
+               (princ " " outbuf)))
+           (princ "\"\\\n" outbuf)
+           (let ((begin (with-current-buffer outbuf (point))))
+             (princ (substring (prin1-to-string (car elt)) 1)
+                    outbuf)
+             ;; Insert a backslash before each ( that
+             ;; appears at the beginning of a line in
+             ;; the doc string.
+             (with-current-buffer outbuf
+               (save-excursion
+                 (while (re-search-backward "\n[[(]" begin t)
+                   (forward-char 1)
+                   (insert "\\"))))
+             (if (null (cdr elt))
+                 (princ ")" outbuf)
+               (princ " " outbuf)
+               (princ (substring (prin1-to-string (cdr elt)) 1)
+                      outbuf))
+             (terpri outbuf)))
+       (let ((print-escape-newlines t)
+             (print-escape-control-characters t)
+              (print-quoted t)
+             (print-escape-nonascii t))
+         (print form outbuf)))))))
+
+(defalias 'autoload-rubric #'loaddefs-generate--rubric)
+
+(defvar autoload-ensure-writable nil
+  "Non-nil means `autoload-find-generated-file' makes existing file writable.")
+;; Just in case someone tries to get you to overwrite a file that you
+;; don't want to.
+;;;###autoload
+(put 'autoload-ensure-writable 'risky-local-variable t)
+
+(defun autoload-ensure-file-writeable (file)
+  ;; Probably pointless, but replaces the old AUTOGEN_VCS in lisp/Makefile,
+  ;; which was designed to handle CVSREAD=1 and equivalent.
+  (and autoload-ensure-writable
+       (let ((modes (file-modes file)))
+        (if (and modes (zerop (logand modes #o0200)))
+             ;; Ignore any errors here, and let subsequent attempts
+             ;; to write the file raise any real error.
+             (ignore-errors (set-file-modes file (logior modes #o0200))))))
+  file)
+
+(defun autoload-insert-section-header (outbuf autoloads load-name file time)
+  "Insert into buffer OUTBUF the section-header line for FILE.
+The header line lists the file name, its \"load name\", its autoloads,
+and the time the FILE was last updated (the time is inserted only
+if `autoload-timestamps' is non-nil, otherwise a fixed fake time is inserted)."
+  ;; (cl-assert ;Make sure we don't insert it in the middle of another section.
+  ;;  (save-excursion
+  ;;    (or (not (re-search-backward
+  ;;              (concat "\\("
+  ;;                      (regexp-quote generate-autoload-section-header)
+  ;;                      "\\)\\|\\("
+  ;;                      (regexp-quote generate-autoload-section-trailer)
+  ;;                      "\\)")
+  ;;              nil t))
+  ;;        (match-end 2))))
+  (insert generate-autoload-section-header)
+  (prin1 `(autoloads ,autoloads ,load-name ,file ,time)
+        outbuf)
+  (terpri outbuf)
+  ;; Break that line at spaces, to avoid very long lines.
+  ;; Make each sub-line into a comment.
+  (with-current-buffer outbuf
+    (save-excursion
+      (forward-line -1)
+      (while (not (eolp))
+       (move-to-column 64)
+       (skip-chars-forward "^ \n")
+       (or (eolp)
+           (insert "\n" generate-autoload-section-continuation))))))
+
+(defun autoload-find-file (file)
+  "Fetch FILE and put it in a temp buffer.  Return the buffer."
+  ;; It is faster to avoid visiting the file.
+  (setq file (expand-file-name file))
+  (with-current-buffer (get-buffer-create " *autoload-file*")
+    (kill-all-local-variables)
+    (erase-buffer)
+    (setq buffer-undo-list t
+          buffer-read-only nil)
+    (delay-mode-hooks (emacs-lisp-mode))
+    (setq default-directory (file-name-directory file))
+    (insert-file-contents file nil)
+    (let ((enable-local-variables :safe)
+         (enable-local-eval nil))
+      (hack-local-variables))
+    (current-buffer)))
+
+(defalias 'autoload-file-load-name #'loaddefs-generate--file-load-name)
+
+(defun generate-file-autoloads (file)
+  "Insert at point a loaddefs autoload section for FILE.
+Autoloads are generated for defuns and defmacros in FILE
+marked by `generate-autoload-cookie' (which see).
+If FILE is being visited in a buffer, the contents of the buffer
+are used.
+Return non-nil in the case where no autoloads were added at point."
+  (interactive "fGenerate autoloads for file: ")
+  (let ((autoload-modified-buffers nil))
+    (autoload-generate-file-autoloads file (current-buffer) buffer-file-name)
+    autoload-modified-buffers))
+
+(defconst autoload-def-prefixes-max-entries 5
+  "Target length of the list of definition prefixes per file.
+If set too small, the prefixes will be too generic (i.e. they'll use little
+memory, we'll end up looking in too many files when we need a particular
+prefix), and if set too large, they will be too specific (i.e. they will
+cost more memory use).")
+
+(defconst autoload-def-prefixes-max-length 12
+  "Target size of definition prefixes.
+Don't try to split prefixes that are already longer than that.")
+
+(defalias 'autoload--make-defs-autoload #'loaddefs-generate--make-prefixes)
+
+(defun autoload--setup-output (otherbuf outbuf absfile load-name output-file)
+  (let ((outbuf
+         (or (if otherbuf
+                 ;; A file-local setting of
+                 ;; autoload-generated-file says we
+                 ;; should ignore OUTBUF.
+                 nil
+               outbuf)
+             (autoload-find-destination absfile load-name output-file)
+             ;; The file has autoload cookies, but they're
+             ;; already up-to-date. If OUTFILE is nil, the
+             ;; entries are in the expected OUTBUF,
+             ;; otherwise they're elsewhere.
+             (throw 'done otherbuf))))
+    (with-current-buffer outbuf
+      (point-marker))))
+
+(defun autoload--print-cookie-text (output-start load-name file)
+  (let ((standard-output (marker-buffer output-start)))
+     (search-forward generate-autoload-cookie)
+     (skip-chars-forward " \t")
+     (if (eolp)
+         (condition-case-unless-debug err
+             ;; Read the next form and make an autoload.
+             (let* ((form (prog1 (read (current-buffer))
+                            (or (bolp) (forward-line 1))))
+                    (autoload (make-autoload form load-name)))
+               (if autoload
+                   nil
+                 (setq autoload form))
+               (let ((autoload-print-form-outbuf
+                      standard-output))
+                 (autoload-print-form autoload)))
+           (error
+            (message "Autoload cookie error in %s:%s %S"
+                     file (count-lines (point-min) (point)) err)))
+
+       ;; Copy the rest of the line to the output.
+       (princ (buffer-substring
+               (progn
+                 ;; Back up over whitespace, to preserve it.
+                 (skip-chars-backward " \f\t")
+                 (if (= (char-after (1+ (point))) ? )
+                     ;; Eat one space.
+                     (forward-char 1))
+                 (point))
+              (progn (forward-line 1) (point)))))))
+
+(defvar autoload-builtin-package-versions nil)
+
+(defun autoload-generate-file-autoloads (file &optional outbuf outfile)
+  "Insert an autoload section for FILE in the appropriate buffer.
+Autoloads are generated for defuns and defmacros in FILE
+marked by `generate-autoload-cookie' (which see).
+
+If FILE is being visited in a buffer, the contents of the buffer are used.
+OUTBUF is the buffer in which the autoload statements should be inserted.
+
+If OUTBUF is nil, the output will go to OUTFILE, unless there's a
+buffer-local setting of `generated-autoload-file' in FILE.
+
+Return non-nil if and only if FILE adds no autoloads to OUTFILE
+\(or OUTBUF if OUTFILE is nil).  The actual return value is
+FILE's modification time."
+  ;; Include the file name in any error messages
+  (condition-case err
+      (let (load-name
+            (print-length nil)
+            (print-level nil)
+            (float-output-format nil)
+            (visited (get-file-buffer file))
+            (otherbuf nil)
+            (absfile (expand-file-name file))
+          (defs '())
+            ;; nil until we found a cookie.
+            output-start)
+        (when
+            (catch 'done
+              (with-current-buffer (or visited
+                                       ;; It is faster to avoid visiting the file.
+                                       (autoload-find-file file))
+                ;; Obey the no-update-autoloads file local variable.
+                (unless no-update-autoloads
+                  (or noninteractive (message "Generating autoloads for %s..." file))
+                  (setq load-name
+                        (if (stringp generated-autoload-load-name)
+                            generated-autoload-load-name
+                          (autoload-file-load-name absfile outfile)))
+                  ;; FIXME? Comparing file-names for equality with just equal
+                  ;; is fragile, eg if one has an automounter prefix and one
+                  ;; does not, but both refer to the same physical file.
+                  (when (and outfile
+                             (not outbuf)
+                             (not
+                              (if (memq system-type '(ms-dos windows-nt))
+                                  (equal (downcase outfile)
+                                         (downcase (autoload-generated-file
+                                                    outfile)))
+                                (equal outfile (autoload-generated-file
+                                                outfile)))))
+                    (setq otherbuf t))
+                  (save-excursion
+                    (save-restriction
+                      (widen)
+                      (when autoload-builtin-package-versions
+                        (let ((version (lm-header "version"))
+                              package)
+                          (and version
+                               (setq version (ignore-errors (version-to-list version)))
+                               (setq package (or (lm-header "package")
+                                                 (file-name-sans-extension
+                                                  (file-name-nondirectory file))))
+                               (setq output-start (autoload--setup-output
+                                                   otherbuf outbuf absfile
+                                                   load-name outfile))
+                               (let ((standard-output (marker-buffer output-start))
+                                     (print-quoted t))
+                                 (princ `(push (purecopy
+                                                ',(cons (intern package) version))
+                                               package--builtin-versions))
+                                 (princ "\n")))))
+
+                      ;; Do not insert autoload entries for excluded files.
+                      (unless (member absfile autoload-excludes)
+                        (goto-char (point-min))
+                        (while (not (eobp))
+                          (skip-chars-forward " \t\n\f")
+                          (cond
+                           ((looking-at (regexp-quote generate-autoload-cookie))
+                            ;; If not done yet, figure out where to insert this text.
+                            (unless output-start
+                              (setq output-start (autoload--setup-output
+                                                  otherbuf outbuf absfile
+                                                  load-name outfile)))
+                            (autoload--print-cookie-text output-start load-name file))
+                           ((= (following-char) ?\;)
+                            ;; Don't read the comment.
+                            (forward-line 1))
+                           (t
+                  ;; Avoid (defvar <foo>) by requiring a trailing space.
+                  ;; Also, ignore this prefix business
+                  ;; for ;;;###tramp-autoload and friends.
+                  (when (and (equal generate-autoload-cookie ";;;###autoload")
+                             (looking-at "(\\(def[^ ]+\\) ['(]*\\([^' ()\"\n]+\\)[\n \t]")
+                             (not (member
+                                   (match-string 1)
+                                   autoload-ignored-definitions)))
+                    (push (match-string-no-properties 2) defs))
+                            (forward-sexp 1)
+                            (forward-line 1)))))))
+
+          (when (and autoload-compute-prefixes defs)
+            ;; This output needs to always go in the main loaddefs.el,
+            ;; regardless of generated-autoload-file.
+            ;; FIXME: the files that don't have autoload cookies but
+            ;; do have definitions end up listed twice in loaddefs.el:
+            ;; once for their register-definition-prefixes and once in
+            ;; the list of "files without any autoloads".
+            (let ((form (autoload--make-defs-autoload defs load-name)))
+              (cond
+               ((null form))             ;All defs obey the default rule, yay!
+               ((not otherbuf)
+                (unless output-start
+                  (setq output-start (autoload--setup-output
+                                      nil outbuf absfile load-name outfile)))
+                (let ((autoload-print-form-outbuf
+                       (marker-buffer output-start)))
+                  (autoload-print-form form)))
+               (t
+                (let* ((other-output-start
+                        ;; To force the output to go to the main loaddefs.el
+                        ;; rather than to generated-autoload-file,
+                        ;; there are two cases: if outbuf is non-nil,
+                        ;; then passing otherbuf=nil is enough, but if
+                        ;; outbuf is nil, that won't cut it, so we
+                        ;; locally bind generated-autoload-file.
+                        (autoload--setup-output nil outbuf absfile load-name
+                                                outfile))
+                       (autoload-print-form-outbuf
+                        (marker-buffer other-output-start)))
+                  (autoload-print-form form)
+                  (with-current-buffer (marker-buffer other-output-start)
+                    (save-excursion
+                      ;; Insert the section-header line which lists
+                      ;; the file name and which functions are in it, etc.
+                      (goto-char other-output-start)
+                      (let ((relfile (file-relative-name absfile)))
+                        (autoload-insert-section-header
+                         (marker-buffer other-output-start)
+                         "actual autoloads are elsewhere" load-name relfile
+                        (if autoload-timestamps
+                            (file-attribute-modification-time
+                             (file-attributes absfile))
+                          autoload--non-timestamp))
+                        (insert ";;; Generated autoloads from " relfile "\n")))
+                    (insert generate-autoload-section-trailer)))))))
+
+                  (when output-start
+                    (let ((secondary-autoloads-file-buf
+                           (if otherbuf (current-buffer))))
+                      (with-current-buffer (marker-buffer output-start)
+                        (cl-assert (> (point) output-start))
+                        (save-excursion
+                          ;; Insert the section-header line which lists the file name
+                          ;; and which functions are in it, etc.
+                          (goto-char output-start)
+                          (let ((relfile (file-relative-name absfile)))
+                            (autoload-insert-section-header
+                             (marker-buffer output-start)
+                             () load-name relfile
+                             (if secondary-autoloads-file-buf
+                                 ;; MD5 checksums are much better because they do not
+                                 ;; change unless the file changes (so they'll be
+                                 ;; equal on two different systems and will change
+                                 ;; less often than time-stamps, thus leading to fewer
+                                 ;; unneeded changes causing spurious conflicts), but
+                                 ;; using time-stamps is a very useful optimization,
+                                 ;; so we use time-stamps for the main autoloads file
+                                 ;; (loaddefs.el) where we have special ways to
+                                 ;; circumvent the "random change problem", and MD5
+                                 ;; checksum in secondary autoload files where we do
+                                 ;; not need the time-stamp optimization because it is
+                                 ;; already provided by the primary autoloads file.
+                                 (md5 secondary-autoloads-file-buf
+                                      ;; We'd really want to just use
+                                      ;; `emacs-internal' instead.
+                                      nil nil 'emacs-mule-unix)
+                               (if autoload-timestamps
+                                   (file-attribute-modification-time
+                                   (file-attributes relfile))
+                                 autoload--non-timestamp)))
+                            (insert ";;; Generated autoloads from " relfile "\n")))
+                        (insert generate-autoload-section-trailer))))
+                  (or noninteractive
+                      (message "Generating autoloads for %s...done" file)))
+                (or visited
+                    ;; We created this buffer, so we should kill it.
+                    (kill-buffer (current-buffer))))
+              (or (not output-start)
+                  ;; If the entries were added to some other buffer, then the file
+                  ;; doesn't add entries to OUTFILE.
+                  otherbuf))
+          (file-attribute-modification-time (file-attributes absfile))))
+    (error
+     ;; Probably unbalanced parens in forward-sexp. In that case, the
+     ;; condition is scan-error, and the signal data includes point
+     ;; where the error was found; we'd like to convert that to
+     ;; line:col, but line-number-at-pos gets the wrong line in batch
+     ;; mode for some reason.
+     ;;
+     ;; At least this gets the file name in the error message; the
+     ;; developer can use goto-char to get to the error position.
+     (error "%s:0:0: error: %s: %s" file (car err) (cdr err)))
+    ))
+\f
+;; For parallel builds, to stop another process reading a half-written file.
+(defun autoload--save-buffer ()
+  "Save current buffer to its file, atomically."
+  ;; Similar to byte-compile-file.
+  (let* ((version-control 'never)
+         (tempfile (make-temp-file buffer-file-name))
+        (default-modes (default-file-modes))
+        (temp-modes (logand default-modes #o600))
+        (desired-modes (logand default-modes
+                               (or (file-modes buffer-file-name) #o666)))
+         (kill-emacs-hook
+          (cons (lambda () (ignore-errors (delete-file tempfile)))
+                kill-emacs-hook)))
+    (unless (= temp-modes desired-modes)
+      (set-file-modes tempfile desired-modes 'nofollow))
+    (write-region (point-min) (point-max) tempfile nil 1)
+    (backup-buffer)
+    (rename-file tempfile buffer-file-name t))
+  (set-buffer-modified-p nil)
+  (set-visited-file-modtime)
+  (or noninteractive (message "Wrote %s" buffer-file-name)))
+
+(defun autoload-save-buffers ()
+  (while autoload-modified-buffers
+    (with-current-buffer (pop autoload-modified-buffers)
+      (autoload--save-buffer))))
+
+;; FIXME This command should be deprecated.
+;; See https://debbugs.gnu.org/22213#41
+;;;###autoload
+(defun update-file-autoloads (file &optional save-after outfile)
+  "Update the autoloads for FILE.
+If prefix arg SAVE-AFTER is non-nil, save the buffer too.
+
+If FILE binds `generated-autoload-file' as a file-local variable,
+autoloads are written into that file.  Otherwise, the autoloads
+file is determined by OUTFILE.  If called interactively, prompt
+for OUTFILE; if called from Lisp with OUTFILE nil, use the
+existing value of `generated-autoload-file'.
+
+Return FILE if there was no autoload cookie in it, else nil."
+  (interactive (list (read-file-name "Update autoloads for file: ")
+                    current-prefix-arg
+                    (read-file-name "Write autoload definitions to file: ")))
+  (setq outfile (or outfile generated-autoload-file))
+  (let* ((autoload-modified-buffers nil)
+        ;; We need this only if the output file handles more than one input.
+        ;; See https://debbugs.gnu.org/22213#38 and subsequent.
+        (autoload-timestamps t)
+         (no-autoloads (autoload-generate-file-autoloads
+                        file nil
+                        (if (local-variable-p 'generated-autoload-file)
+                            generated-autoload-file
+                          outfile))))
+    (if autoload-modified-buffers
+        (if save-after (autoload-save-buffers))
+      (if (called-interactively-p 'interactive)
+          (message "Autoload section for %s is up to date." file)))
+    (if no-autoloads file)))
+
+(defun autoload-find-destination (file load-name output-file)
+  "Find the destination point of the current buffer's autoloads.
+FILE is the file name of the current buffer.
+LOAD-NAME is the name as it appears in the output.
+Returns a buffer whose point is placed at the requested location.
+Returns nil if the file's autoloads are up-to-date, otherwise
+removes any prior now out-of-date autoload entries."
+  (catch 'up-to-date
+    (let* ((buf (current-buffer))
+           (existing-buffer (if buffer-file-name buf))
+           (output-file (autoload-generated-file output-file))
+           (output-time (if (file-exists-p output-file)
+                            (file-attribute-modification-time
+                            (file-attributes output-file))))
+           (found nil))
+      (with-current-buffer (autoload-find-generated-file output-file)
+        ;; This is to make generated-autoload-file have Unix EOLs, so
+        ;; that it is portable to all platforms.
+        (or (eq 0 (coding-system-eol-type buffer-file-coding-system))
+           (set-buffer-file-coding-system 'unix))
+        (or (> (buffer-size) 0)
+            (error "Autoloads file %s lacks boilerplate" buffer-file-name))
+        (or (file-writable-p buffer-file-name)
+            (error "Autoloads file %s is not writable" buffer-file-name))
+        (widen)
+        (goto-char (point-min))
+        ;; Look for the section for LOAD-NAME.
+        (while (and (not found)
+                    (search-forward generate-autoload-section-header nil t))
+          (let ((form (autoload-read-section-header)))
+            (cond ((string= (nth 2 form) load-name)
+                   ;; We found the section for this file.
+                   ;; Check if it is up to date.
+                   (let ((begin (match-beginning 0))
+                         (last-time (nth 4 form))
+                         (file-time (file-attribute-modification-time
+                                    (file-attributes file))))
+                     (if (and (or (null existing-buffer)
+                                  (not (buffer-modified-p existing-buffer)))
+                              (cond
+                               ;; FIXME? Arguably we should throw a
+                               ;; user error, or some kind of warning,
+                               ;; if we were called from update-file-autoloads,
+                               ;; which can update only a single input file.
+                               ;; It's not appropriate to use the output
+                               ;; file modtime in such a case,
+                               ;; if there are multiple input files
+                               ;; contributing to the output.
+                               ((and output-time
+                                    (member last-time
+                                            (list t autoload--non-timestamp)))
+                                (not (time-less-p output-time file-time)))
+                               ;; last-time is the time-stamp (specifying
+                               ;; the last time we looked at the file) and
+                               ;; the file hasn't been changed since.
+                               ((listp last-time)
+                                (not (time-less-p last-time file-time)))
+                               ;; last-time is an MD5 checksum instead.
+                               ((stringp last-time)
+                                (equal last-time
+                                      (md5 buf nil nil 'emacs-mule)))))
+                         (throw 'up-to-date nil)
+                       (autoload-remove-section begin)
+                       (setq found t))))
+                  ((string< load-name (nth 2 form))
+                   ;; We've come to a section alphabetically later than
+                   ;; LOAD-NAME.  We assume the file is in order and so
+                   ;; there must be no section for LOAD-NAME.  We will
+                   ;; insert one before the section here.
+                   (goto-char (match-beginning 0))
+                   (setq found t)))))
+        (or found
+            (progn
+              ;; No later sections in the file.  Put before the last page.
+              (goto-char (point-max))
+              (search-backward "\f" nil t)))
+        (unless (memq (current-buffer) autoload-modified-buffers)
+          (push (current-buffer) autoload-modified-buffers))
+        (current-buffer)))))
+
+(defun autoload-remove-section (begin)
+  (goto-char begin)
+  (search-forward generate-autoload-section-trailer)
+  (delete-region begin (point)))
+
+;;;###autoload
+(defun update-directory-autoloads (&rest dirs)
+  "Update autoload definitions for Lisp files in the directories DIRS.
+In an interactive call, you must give one argument, the name of a
+single directory.  In a call from Lisp, you can supply multiple
+directories as separate arguments, but this usage is discouraged.
+
+The function does NOT recursively descend into subdirectories of the
+directory or directories specified.
+
+In an interactive call, prompt for a default output file for the
+autoload definitions.  When called from Lisp, use the existing
+value of `generated-autoload-file'.  If any Lisp file binds
+`generated-autoload-file' as a file-local variable, write its
+autoloads into the specified file instead."
+  (declare (obsolete make-directory-autoloads "28.1"))
+  (interactive "DUpdate autoloads from directory: ")
+  (make-directory-autoloads
+   dirs
+   (if (called-interactively-p 'interactive)
+       (read-file-name "Write autoload definitions to file: ")
+     generated-autoload-file)))
+
+;;;###autoload
+(defun make-directory-autoloads (dir output-file)
+  "Update autoload definitions for Lisp files in the directories DIRS.
+DIR can be either a single directory or a list of
+directories.  (The latter usage is discouraged.)
+
+The autoloads will be written to OUTPUT-FILE.  If any Lisp file
+binds `generated-autoload-file' as a file-local variable, write
+its autoloads into the specified file instead.
+
+The function does NOT recursively descend into subdirectories of the
+directory or directories specified."
+  (interactive "DUpdate autoloads from directory: \nFWrite to file: ")
+  (let* ((files-re (let ((tmp nil))
+                    (dolist (suf (get-load-suffixes))
+                       ;; We don't use module-file-suffix below because
+                       ;; we don't want to depend on whether Emacs was
+                       ;; built with or without modules support, nor
+                       ;; what is the suffix for the underlying OS.
+                      (unless (string-match "\\.\\(elc\\|so\\|dll\\)" suf)
+                         (push suf tmp)))
+                     (concat "\\`[^=.].*" (regexp-opt tmp t) "\\'")))
+        (files (apply #'nconc
+                      (mapcar (lambda (d)
+                                (directory-files (expand-file-name d)
+                                                  t files-re))
+                              (if (consp dir) dir (list dir)))))
+         (done ())                      ;Files processed; to remove duplicates.
+         (changed nil)                  ;Non-nil if some change occurred.
+        (last-time)
+         ;; Files with no autoload cookies or whose autoloads go to other
+         ;; files because of file-local autoload-generated-file settings.
+        (no-autoloads nil)
+         ;; Ensure that we don't do odd things when putting the doc
+         ;; strings into the autoloads file.
+         (left-margin 0)
+         (autoload-modified-buffers nil)
+        (output-time
+         (and (file-exists-p output-file)
+              (file-attribute-modification-time
+                (file-attributes output-file)))))
+
+    (with-current-buffer (autoload-find-generated-file output-file)
+      (save-excursion
+       ;; Canonicalize file names and remove the autoload file itself.
+       (setq files (delete (file-relative-name buffer-file-name)
+                           (mapcar #'file-relative-name files)))
+
+       (goto-char (point-min))
+       (while (search-forward generate-autoload-section-header nil t)
+         (let* ((form (autoload-read-section-header))
+                (file (nth 3 form)))
+           (cond ((and (consp file) (stringp (car file)))
+                  ;; This is a list of files that have no autoload cookies.
+                  ;; There shouldn't be more than one such entry.
+                  ;; Remove the obsolete section.
+                  (autoload-remove-section (match-beginning 0))
+                  (setq last-time (nth 4 form))
+                  (if (member last-time (list t autoload--non-timestamp))
+                      (setq last-time output-time))
+                  (dolist (file file)
+                    (let ((file-time (file-attribute-modification-time
+                                      (file-attributes file))))
+                      (when (and file-time
+                                 (not (time-less-p last-time file-time)))
+                        ;; file unchanged
+                        (push file no-autoloads)
+                        (setq files (delete file files))))))
+                 ((not (stringp file)))
+                 ((or (not (file-exists-p file))
+                       ;; Remove duplicates as well, just in case.
+                       (member file done))
+                   ;; Remove the obsolete section.
+                   (setq changed t)
+                  (autoload-remove-section (match-beginning 0)))
+                 ((not (time-less-p (let ((oldtime (nth 4 form)))
+                                      (if (member oldtime
+                                                  (list
+                                                   t autoload--non-timestamp))
+                                          output-time
+                                        oldtime))
+                                     (file-attribute-modification-time
+                                     (file-attributes file))))
+                  ;; File hasn't changed.
+                  nil)
+                 (t
+                   (setq changed t)
+                   (autoload-remove-section (match-beginning 0))
+                   (if (autoload-generate-file-autoloads
+                        ;; Passing `current-buffer' makes it insert at point.
+                        file (current-buffer) buffer-file-name)
+                       (push file no-autoloads))))
+            (push file done)
+           (setq files (delete file files)))))
+      ;; Elements remaining in FILES have no existing autoload sections yet.
+      (let ((no-autoloads-time (or last-time '(0 0 0 0)))
+            (progress (make-progress-reporter
+                       (byte-compile-info
+                        (concat "Scraping files for "
+                                (file-relative-name output-file)))
+                       0 (length files) nil 10))
+            (file-count 0)
+            file-time)
+       (dolist (file files)
+          (progress-reporter-update progress (setq file-count (1+ file-count)))
+         (cond
+          ;; Passing nil as second argument forces
+          ;; autoload-generate-file-autoloads to look for the right
+          ;; spot where to insert each autoloads section.
+          ((setq file-time
+                 (autoload-generate-file-autoloads file nil buffer-file-name))
+           (push file no-autoloads)
+           (if (time-less-p no-autoloads-time file-time)
+               (setq no-autoloads-time file-time)))
+           (t (setq changed t))))
+        (progress-reporter-done progress)
+
+       (when no-autoloads
+         ;; Sort them for better readability.
+         (setq no-autoloads (sort no-autoloads 'string<))
+         ;; Add the `no-autoloads' section.
+         (goto-char (point-max))
+         (search-backward "\f" nil t)
+         (autoload-insert-section-header
+          (current-buffer) nil nil
+           ;; Filter out the other loaddefs files, because it makes
+           ;; the list unstable (and leads to spurious changes in
+           ;; ldefs-boot.el) since the loaddef files can be created in
+           ;; any order.
+           (seq-filter (lambda (file)
+                         (not (string-match-p "[/-]loaddefs.el" file)))
+                       no-autoloads)
+           (if autoload-timestamps
+              no-autoloads-time
+            autoload--non-timestamp))
+         (insert generate-autoload-section-trailer)))
+
+      ;; Don't modify the file if its content has not been changed, so `make'
+      ;; dependencies don't trigger unnecessarily.
+      (if (not changed)
+          (set-buffer-modified-p nil)
+        (autoload--save-buffer))
+
+      ;; In case autoload entries were added to other files because of
+      ;; file-local autoload-generated-file settings.
+      (autoload-save-buffers))))
+
+(defun batch-update-autoloads--summary (strings)
+  (let ((message ""))
+    (while strings
+      (when (> (length (concat message " " (car strings))) 64)
+        (byte-compile-info (concat message " ...") t "SCRAPE")
+        (setq message ""))
+      (setq message (if (zerop (length message))
+                        (car strings)
+                      (concat message " " (car strings))))
+      (setq strings (cdr strings)))
+    (when (> (length message) 0)
+      (byte-compile-info message t "SCRAPE"))))
+
+;;;###autoload
+(defun batch-update-autoloads ()
+  "Update loaddefs.el autoloads in batch mode.
+Calls `update-directory-autoloads' on the command line arguments.
+Definitions are written to `generated-autoload-file' (which
+should be non-nil)."
+  ;; For use during the Emacs build process only.
+  ;; Exclude those files that are preloaded on ALL platforms.
+  ;; These are the ones in loadup.el where "(load" is at the start
+  ;; of the line (crude, but it works).
+  (unless autoload-excludes
+    (let ((default-directory (file-name-directory generated-autoload-file))
+         file)
+      (when (file-readable-p "loadup.el")
+       (with-temp-buffer
+         (insert-file-contents "loadup.el")
+         (while (re-search-forward "^(load \"\\([^\"]+\\)\"" nil t)
+           (setq file (match-string 1))
+           (or (string-match "\\.el\\'" file)
+               (setq file (format "%s.el" file)))
+           (or (string-match "\\`site-" file)
+               (push (expand-file-name file) autoload-excludes)))))))
+  (let ((args command-line-args-left))
+    (batch-update-autoloads--summary args)
+    (setq command-line-args-left nil)
+    (make-directory-autoloads args generated-autoload-file)))
+
+(provide 'autoload)
+
+;;; autoload.el ends here