emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master ec22e923c0: Teach 'symbol-file' about .eln natively-compiled file


From: Eli Zaretskii
Subject: master ec22e923c0: Teach 'symbol-file' about .eln natively-compiled files
Date: Wed, 3 Aug 2022 10:17:04 -0400 (EDT)

branch: master
commit ec22e923c0dab286cdcf18595e836f1013e9a9f1
Author: Eli Zaretskii <eliz@gnu.org>
Commit: Eli Zaretskii <eliz@gnu.org>

    Teach 'symbol-file' about .eln natively-compiled files
    
    * lisp/subr.el (locate-eln-file): New function.
    (symbol-file): Accept an optional 3rd argument NATIVE-P, and, if
    non-nil, try to locate and report the .eln file where SYMBOL was
    defined.
    
    * etc/NEWS:
    * doc/lispref/loading.texi (Where Defined): Document the new
    optional argument of 'symbol-file'.
---
 doc/lispref/loading.texi |  10 ++++-
 etc/NEWS                 |   5 +++
 lisp/subr.el             | 103 +++++++++++++++++++++++++++++++++++++----------
 3 files changed, 96 insertions(+), 22 deletions(-)

diff --git a/doc/lispref/loading.texi b/doc/lispref/loading.texi
index 54fc16ec9f..e8dce433a5 100644
--- a/doc/lispref/loading.texi
+++ b/doc/lispref/loading.texi
@@ -1032,7 +1032,7 @@ with a call to @code{provide}.  The order of the elements 
in the
 @cindex symbol, where defined
 @cindex where was a symbol defined
 
-@defun symbol-file symbol &optional type
+@defun symbol-file symbol &optional type native-p
 This function returns the name of the file that defined @var{symbol}.
 If @var{type} is @code{nil}, then any kind of definition is acceptable.
 If @var{type} is @code{defun}, @code{defvar}, or @code{defface}, that
@@ -1043,6 +1043,14 @@ The value is normally an absolute file name.  It can 
also be @code{nil},
 if the definition is not associated with any file.  If @var{symbol}
 specifies an autoloaded function, the value can be a relative file name
 without extension.
+
+If the optional third argument @var{native-p} is non-@code{nil}, and
+Emacs was built with native compilation support (@pxref{Native
+Compilation}), this function will try to find the @file{.eln} file
+that defined @var{symbol}, instead of the @file{.elc} or @file{.el}
+file.  If such a @file{.eln} file is found and is not outdated, the
+function will return its absolute file name; otherwise it will report
+the name of either the source or the byte-compiled file.
 @end defun
 
   The basis for @code{symbol-file} is the data in the variable
diff --git a/etc/NEWS b/etc/NEWS
index b88fb63662..7e8ed465eb 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2575,6 +2575,11 @@ things to be saved.
 ** New function 'string-equal-ignore-case'.
 This compares strings ignoring case differences.
 
+** 'symbol-file' can now report natively-compiled .eln files.
+If Emacs was built with native-compilation enabled, Lisp programs can
+now call 'symbol-file' with the new optional 3rd argument non-nil to
+request the name of the .eln file which defined a given symbol.
+
 ** Themes
 
 ---
diff --git a/lisp/subr.el b/lisp/subr.el
index ff82d0d1d8..1b59db0604 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -2700,18 +2700,44 @@ This is to `put' what `defalias' is to `fset'."
         (setcdr ps (cons symbol (cdr ps))))))
   (put symbol prop val))
 
-(defun symbol-file (symbol &optional type)
+(defvar comp-native-version-dir)
+(defvar native-comp-eln-load-path)
+(declare-function subr-native-elisp-p "data.c")
+(declare-function native-comp-unit-file "data.c")
+(declare-function subr-native-comp-unit "data.c")
+(declare-function comp-el-to-eln-rel-filename "comp.c")
+
+(defun locate-eln-file (eln-file)
+  "Locate a natively-compiled ELN-FILE by searching its load path.
+This function looks in directories named by `native-comp-eln-load-path'."
+  (or (locate-file-internal (concat comp-native-version-dir "/" eln-file)
+                  native-comp-eln-load-path)
+      (locate-file-internal
+       ;; Preloaded *.eln files live in the preloaded/ subdirectory of
+       ;; the last entry in `native-comp-eln-load-path'.
+       (concat comp-native-version-dir "/preloaded/" eln-file)
+       (last native-comp-eln-load-path))))
+
+(defun symbol-file (symbol &optional type native-p)
   "Return the name of the file that defined SYMBOL.
 The value is normally an absolute file name.  It can also be nil,
 if the definition is not associated with any file.  If SYMBOL
 specifies an autoloaded function, the value can be a relative
 file name without extension.
 
-If TYPE is nil, then any kind of definition is acceptable.  If
-TYPE is `defun', `defvar', or `defface', that specifies function
+If TYPE is nil, then any kind of SYMBOL's definition is acceptable.
+If TYPE is `defun', `defvar', or `defface', that specifies function
 definition, variable definition, or face definition only.
 Otherwise TYPE is assumed to be a symbol property.
 
+If NATIVE-P is non-nil, and SYMBOL was loaded from a .eln file,
+this function will return the absolute file name of that .eln file,
+if found.  Note that if the .eln file is older than its source .el
+file, Emacs won't load such an outdated .eln file, and this function
+will not return it.  If the .eln file couldn't be found, or is
+outdated, the function returns the corresponding .elc or .el file
+instead.
+
 This function only works for symbols defined in Lisp files.  For
 symbols that are defined in C files, use `help-C-file-name'
 instead."
@@ -2719,24 +2745,59 @@ instead."
           (symbolp symbol)
           (autoloadp (symbol-function symbol)))
       (nth 1 (symbol-function symbol))
-    (catch 'found
-      (pcase-dolist (`(,file . ,elems) load-history)
-       (when (if type
-                 (if (eq type 'defvar)
-                     ;; Variables are present just as their names.
-                     (member symbol elems)
-                   ;; Many other types are represented as (TYPE . NAME).
-                   (or (member (cons type symbol) elems)
-                        (memq symbol (alist-get type
-                                                (alist-get 'define-symbol-props
-                                                           elems)))))
-               ;; We accept all types, so look for variable def
-               ;; and then for any other kind.
-               (or (member symbol elems)
-                    (let ((match (rassq symbol elems)))
-                     (and match
-                          (not (eq 'require (car match)))))))
-          (throw 'found file))))))
+    (if (and native-p (or (null type) (eq type 'defun))
+            (symbolp symbol)
+            (native-comp-available-p)
+            ;; If it's a defun, we have a shortcut.
+            (subr-native-elisp-p (symbol-function symbol)))
+       ;; native-comp-unit-file returns unnormalized file names.
+       (expand-file-name (native-comp-unit-file (subr-native-comp-unit
+                                                 (symbol-function symbol))))
+      (let ((elc-file
+            (catch 'found
+              (pcase-dolist (`(,file . ,elems) load-history)
+                (when (if type
+                          (if (eq type 'defvar)
+                              ;; Variables are present just as their
+                              ;; names.
+                              (member symbol elems)
+                            ;; Many other types are represented as
+                            ;; (TYPE . NAME).
+                            (or (member (cons type symbol) elems)
+                                (memq
+                                 symbol
+                                 (alist-get type
+                                            (alist-get 'define-symbol-props
+                                                       elems)))))
+                        ;; We accept all types, so look for variable def
+                        ;; and then for any other kind.
+                        (or (member symbol elems)
+                            (let ((match (rassq symbol elems)))
+                              (and match
+                                   (not (eq 'require (car match)))))))
+                  (throw 'found file))))))
+       ;; If they asked for the .eln file, try to find it.
+       (or (and elc-file
+                native-p
+                (native-comp-available-p)
+                (let* ((sans-ext (file-name-sans-extension elc-file))
+                       (el-file
+                        (and (fboundp 'zlib-available-p)
+                             (zlib-available-p)
+                             (concat sans-ext ".el.gz")))
+                       (el-file-backup (concat sans-ext ".el")))
+                  (or (and el-file (file-exists-p el-file))
+                      (and (file-exists-p el-file-backup)
+                           (setq el-file el-file-backup))
+                      (setq el-file nil))
+                  (when (stringp el-file)
+                    (let ((eln-file (locate-eln-file
+                                     (comp-el-to-eln-rel-filename el-file))))
+                      ;; Emacs will not load an outdated .eln file,
+                      ;; so we mimic this behavior here.
+                      (if (file-newer-than-file-p eln-file el-file)
+                          eln-file)))))
+           elc-file)))))
 
 (declare-function read-library-name "find-func" nil)
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]