Function: loaddefs-generate
loaddefs-generate is an autoloaded and byte-compiled function defined
in loaddefs-gen.el.gz.
Signature
(loaddefs-generate DIRS OUTPUT-FILE &optional EXCLUDED-FILES EXTRA-DATA INCLUDE-PACKAGE-VERSION GENERATE-FULL)
Documentation
Generate loaddefs files for Lisp files in directories given by DIRS.
DIRS can be either a single directory or a list of directories.
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.
This function does NOT recursively descend into subdirectories of the directories specified by DIRS.
Optional argument EXCLUDED-FILES, if non-nil, should be a list of files, such as preloaded files, whose autoloads should not be written to OUTPUT-FILE.
If EXTRA-DATA is non-nil, it should be a string; include that string at the beginning of the generated file. This will also force the generation of OUTPUT-FILE even if there are no autoloads to put into that file.
If INCLUDE-PACKAGE-VERSION is non-nil, include package version data.
If GENERATE-FULL is non-nil, regenerate all the loaddefs files anew, instead of just updating them with the new/changed autoloads.
Aliases
hload-path--make-directory-autoloads
Source Code
;; Defined in /usr/src/emacs/lisp/emacs-lisp/loaddefs-gen.el.gz
;;;###autoload
(defun loaddefs-generate (dirs output-file &optional excluded-files
extra-data include-package-version
generate-full)
"Generate loaddefs files for Lisp files in directories given by DIRS.
DIRS can be either a single directory or a list of directories.
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.
This function does NOT recursively descend into subdirectories of the
directories specified by DIRS.
Optional argument EXCLUDED-FILES, if non-nil, should be a list of
files, such as preloaded files, whose autoloads should not be written
to OUTPUT-FILE.
If EXTRA-DATA is non-nil, it should be a string; include that string
at the beginning of the generated file. This will also force the
generation of OUTPUT-FILE even if there are no autoloads to put into
that file.
If INCLUDE-PACKAGE-VERSION is non-nil, include package version data.
If GENERATE-FULL is non-nil, regenerate all the loaddefs files anew,
instead of just updating them with the new/changed autoloads."
(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\\|dylib\\)" suf)
(push suf tmp)))
(concat "\\`[^=.].*" (regexp-opt tmp t) "\\'")))
(files (apply #'nconc
(mapcar (lambda (d)
(directory-files (expand-file-name d)
t files-re))
(ensure-list dirs))))
(updating (and (file-exists-p output-file) (not generate-full)))
(defs nil))
;; Allow the excluded files to be relative.
;; We used to do (expand-file-name file dirs), which strangely enough
;; doesn't signal an error when DIRS is a list but does something weird
;; instead, so let's preserve the old behavior when DIRS is a string,
;; even tho it's different from what we do when it's a list.
(let ((basedir (if (stringp dirs) dirs)))
(setq excluded-files
(mapcar (lambda (file) (expand-file-name file basedir))
excluded-files)))
;; Collect all the autoload data.
(let ((progress (make-progress-reporter
(byte-compile-info
(format "Scraping %s files for loaddefs"
(length files)))
0 (length files) nil 10))
(output-time
(file-attribute-modification-time (file-attributes output-file)))
(file-count 0))
(dolist (file files)
(progress-reporter-update progress (setq file-count (1+ file-count)))
(when (or (not updating)
(time-less-p output-time
(file-attribute-modification-time
(file-attributes file))))
;; If we're scanning for package versions, we want to look
;; at the file even if it's excluded.
(let* ((excluded (member file excluded-files))
(package-data
(and include-package-version (if excluded 'only t))))
(when (or package-data (not excluded))
(setq defs (nconc (loaddefs-generate--parse-file
file output-file package-data)
defs))))))
(progress-reporter-done progress))
;; First group per output file.
(dolist (fdefs (seq-group-by (lambda (x) (expand-file-name (car x)))
defs))
(let ((loaddefs-file (car fdefs))
hash)
(with-temp-buffer
(if (and updating (file-exists-p loaddefs-file))
(insert-file-contents loaddefs-file)
(insert (loaddefs-generate--rubric
loaddefs-file nil t include-package-version))
(search-backward "\f")
(when extra-data
(insert extra-data)
(ensure-empty-lines 1)))
(setq hash (buffer-hash))
;; Then group by source file (and sort alphabetically).
(dolist (section (sort (seq-group-by #'cadr (cdr fdefs))
(lambda (e1 e2)
(string<
(file-name-sans-extension
(file-name-nondirectory (car e1)))
(file-name-sans-extension
(file-name-nondirectory (car e2)))))))
(pop section)
(let* ((relfile (file-relative-name
(cadar section)
(file-name-directory loaddefs-file)))
(head (concat "\n\f\n;;; Generated autoloads from "
relfile "\n\n")))
(when (file-exists-p loaddefs-file)
;; If we're updating an old loaddefs file, then see if
;; there's a section here for this file already.
(goto-char (point-min))
(if (not (search-forward head nil t))
;; It's a new file; put the data at the end.
(progn
(goto-char (point-max))
(search-backward "\f\n" nil t))
;; Delete the old version of the section. Strictly
;; speaking this should search for "\n\f\n;;;", but
;; there are loaddefs files in the wild that only
;; have two ';;'. (Bug#63236)
(delete-region (match-beginning 0)
(and (search-forward "\n\f\n;;")
(match-beginning 0)))
(forward-line -2)))
(insert head)
(dolist (def (reverse section))
(setq def (caddr def))
(if (stringp def)
(princ def (current-buffer))
(loaddefs-generate--print-form def))
(unless (bolp)
(insert "\n")))))
;; Only write the file if we actually made a change.
(unless (equal (buffer-hash) hash)
(write-region (point-min) (point-max) loaddefs-file nil 'silent)
(byte-compile-info
(file-relative-name loaddefs-file (car (ensure-list dirs)))
t "GEN")))))
;; If processing files without any autoloads, the above loop will
;; not generate any files. If the function was invoked with
;; EXTRA-DATA, we want to ensure that even if no autoloads were
;; found, that at least a file will have been generated containing
;; the contents of EXTRA-DATA:
(when (and extra-data (not (file-exists-p output-file)))
(with-temp-buffer
(insert (loaddefs-generate--rubric output-file nil t))
(search-backward "\f")
(insert extra-data)
(ensure-empty-lines 1)
(write-region (point-min) (point-max) output-file nil 'silent)))))