branch: externals/compat commit 12774be87c7d52640be4c3d54e65236ba69b9a0e Author: Jonas Bernoulli <jo...@bernoul.li> Commit: Philip Kaludercic <phil...@posteo.net>
Fix using compat libraries uncompiled `compat-entwine' is called in two and only three distinct situations. 1. When "compat.el" is being loaded without having been compiled before. This can happen while a third-party library is being compiled, which requires `compat'. 2. When "compat.el" is being evaluated, such as when using `eval-buffer'. 3. When "compat.el" is being compiled. In all cases we need to detect where "compat.el" is located, because that also tells us where the "compat-XY.el" libraries are located and `compat-entwine' needs to read the contents of those files. To detect the location of "compat.el" we consult various variables, which we expect to either be nil or "/path/to/compat.el". We didn't use the correct variables. Some time ago Stefan added a call to `macro-file-name' to the front of that search, which fixes the search for Emacs 28.1. Older Emacs releases lack that function, so for those we still ended up consulting the wrong variables. To fix that use `current-load-list' directly, treating it the same way as `macro-file-name' does. If that gives us a non-nil value, then we are dealing with one of the first two cases and we are done. Otherwise we are dealing with the third case and `byte-compile-current-file' gives us the correct value. One of these sources is always non-nil, so drop the variables we used to fall back to. Then we pass the version from `compat-entwine' to the `compat--generate-function' function by binding the new variable `compat--entwine-version'. Previously this was done by binding `byte-compile-current-file`. The caller then had to extract the version from the name of that file. Binding `byte-compile-current-file` was also part of the bug that prevented compilation of a third-party library, which depends on "compat-XY.el", when compat's libraries have not been compiled yet. To fix that we have to change the order of the possible sources of the version string in `compat--generate-function' functions. As before we use the version explicitly specified for the function being processed, if any. Then we use value of the new `compat--entwine-version' variable, if that is bound and non-nil, i.e., if the binding from `compat-entwine' is in effect. Previously we would have tried `byte-compile-current-file' at this point instead, but while that might be non-nil because we used to bind it in `compat--generate-function', it could also be non-nil because an arbitrary third-party library is being compiled. That is a problem if that third-party library depends on "compat-XY.el" and the latter hasn't been compiled before: The `compat--generate-function' function is called directly in that case, without the binding from `compat-entwine' in effect. We need `byte-compile-current-file' to be some "compat-XY.el" library; not some arbitrary third-party library. Then we try `current-load-list' like in `compat-entwine', which here is some "compat-XY.el" library when some third-party library is being compiled and that requires that "compat-XY.el" library. Finally, if we could not determine a version any other way, then we know that some "compat-XY.el" library is being compiled. In that case, and only then, we can get the version string from `byte-compile-current-file'. --- compat-macs.el | 54 ++++++++++++++++++++++++++++-------------------------- compat.el | 30 ++++++++++++++++++++---------- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/compat-macs.el b/compat-macs.el index fec167a99a..85f31b8804 100644 --- a/compat-macs.el +++ b/compat-macs.el @@ -82,19 +82,22 @@ DEF-FN, INSTALL-FN, CHECK-FN, ATTR and TYPE." (max-version (plist-get attr :max-version)) (feature (plist-get attr :feature)) (cond (plist-get attr :cond)) - (version (or (plist-get attr :version) - (let ((file (or (bound-and-true-p byte-compile-current-file) - load-file-name - (buffer-file-name)))) - ;; Guess the version from the file the macro is - ;; being defined in. - (cond - ((not file) emacs-version) - ((string-match - "compat-\\([[:digit:]]+\\)\\.\\(?:elc?\\)\\'" - file) - (concat (match-string 1 file) ".1")) - ((error "No version number could be extracted")))))) + (version ; If you edit this, also edit `compat--generate-verbose'. + (or (plist-get attr :version) + (bound-and-true-p compat--entwine-version) + (let* ((file (car (last current-load-list))) + (file (if (stringp file) + ;; Some library, which requires compat-XY.el, + ;; is being compiled and compat-XY.el has not + ;; been compiled yet. + file + ;; compat-XY.el is being compiled. + (bound-and-true-p byte-compile-current-file)))) + (if (and file + (string-match + "compat-\\([[:digit:]]+\\)\\.\\(?:elc?\\)\\'" file)) + (concat (match-string 1 file) ".1") + (error "BUG: No version number could be extracted"))))) (realname (or (plist-get attr :realname) (intern (format "compat--%S" name)))) (check (cond @@ -155,19 +158,18 @@ DEF-FN, INSTALL-FN, CHECK-FN, ATTR and TYPE." (max-version (plist-get attr :max-version)) (feature (plist-get attr :feature)) (cond (plist-get attr :cond)) - (version (or (plist-get attr :version) - (let ((file (or (bound-and-true-p byte-compile-current-file) - load-file-name - (buffer-file-name)))) - ;; Guess the version from the file the macro is - ;; being defined in. - (cond - ((not file) emacs-version) - ((string-match - "compat-\\([[:digit:]]+\\)\\.\\(?:elc?\\)\\'" - file) - (concat (match-string 1 file) ".1")) - ((error "No version number could be extracted")))))) + (version ; If you edit this, also edit `compat--generate-minimal'. + (or (plist-get attr :version) + (bound-and-true-p compat--entwine-version) + (let* ((file (car (last current-load-list))) + (file (if (stringp file) + file + (bound-and-true-p byte-compile-current-file)))) + (if (and file + (string-match + "compat-\\([[:digit:]]+\\)\\.\\(?:elc?\\)\\'" file)) + (concat (match-string 1 file) ".1") + (error "BUG: No version number could be extracted"))))) (realname (or (plist-get attr :realname) (intern (format "compat--%S" name)))) (body `(progn diff --git a/compat.el b/compat.el index ed60ba53ab..a5d6346af1 100644 --- a/compat.el +++ b/compat.el @@ -49,6 +49,7 @@ ;; separately, by explicitly requiring the feature that defines them. (eval-when-compile (defvar compat--generate-function) + (defvar compat--entwine-version) (defmacro compat-entwine (version) (cond ((or (not (eq compat--generate-function 'compat--generate-minimal)) @@ -58,11 +59,24 @@ (file (expand-file-name (format "compat-%d.el" version) (file-name-directory - (or (if (fboundp 'macroexp-file-name) - (macroexp-file-name) - (or (bound-and-true-p byte-compile-current-file) - load-file-name)) - (buffer-file-name))))) + (or + ;; Some third-party library, which requires + ;; compat.el, is being compiled, loaded or + ;; evaluated, and compat.el hasn't been compiled + ;; yet. + ;; cd compat && make clean && cd ../other && \ + ;; make clean all + ;; + ;; Or compat.el is being evaluated. + ;; cd compat && make clean && emacs -Q -L . compat.el + ;; M-x eval-buffer + ;; + ;; (Like `macroexp-file-name' from Emacs 28.1.) + (let ((file (car (last current-load-list)))) + (and (stringp file) file)) + ;; compat.el is being compiled. + ;; cd compat && make clean all + (bound-and-true-p byte-compile-current-file))))) defs) (with-temp-buffer (insert-file-contents file) @@ -70,11 +84,7 @@ (while (progn (forward-comment 1) (not (eobp))) - ;; We bind `byte-compile-current-file' before - ;; macro-expanding, so that `compat--generate-function' - ;; can correctly infer the compatibility version currently - ;; being processed. - (let ((byte-compile-current-file file) + (let ((compat--entwine-version (number-to-string version)) (form (read (current-buffer)))) (cond ((memq (car-safe form)