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'.
This commit is contained in:
parent
6861ed1175
commit
ec22e923c0
3 changed files with 96 additions and 22 deletions
|
@ -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
|
||||
|
|
5
etc/NEWS
5
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
|
||||
|
||||
---
|
||||
|
|
103
lisp/subr.el
103
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)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue