[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
FIXED!! Re: Clarification of eval-after-load [was: Problem mit symlinks,
From: |
Alan Mackenzie |
Subject: |
FIXED!! Re: Clarification of eval-after-load [was: Problem mit symlinks, locate-library and load-history] |
Date: |
Sun, 14 May 2006 11:07:49 +0000 (GMT) |
Hi, again, Emacs!
On Wed, 10 May 2006, Alan Mackenzie wrote:
>Hi, Emacs!
>The doc string (and manual entry) for eval-after-load are a bit hazy and
>indefinite. Here is the doc-string:
> "Arrange that, if FILE is ever loaded, FORM will be run at that time.
> This makes or adds to an entry on `after-load-alist'.
> If FILE is already loaded, evaluate FORM right now.
> It does nothing if FORM is already on the list for FILE.
> FILE must match exactly. Normally FILE is the name of a library,
> with no directory or extension specified, since that is how `load'
> is normally called.
> FILE can also be a feature (i.e. a symbol), in which case FORM is
> evaluated whenever that feature is `provide'd."
>Some problems are:
>(i) "FILE must match exactly" doesn't say what FILE must match, or how it
>must match it, and it is unclear what "exactly" means. Given this
>description, I would not expect the argument "font-lock" to match the
>file name "font-lock.elc", but it does. :-(
>(ii) The doc-string doesn't say what happens when FILE gets loaded again.
Combining this with these OTHER PROBLEMS (already posted on emacs-devel):
> I do: emacs-22.0.50.1 -Q
> M-x load-file <ret> ~acm/emacs/emacs/lisp/progmodes/cc-mode.elc
> C-h v load-history.
>
> Then:
> M-: (eval-after-load "cc-mode" '(beep)) fails.
> M-: (eval-after-load "cc-fonts" '(beep)) beeps.
> M-: (eval-after-load "english" '(beep)) fails.
>
> Here are these file names as they appear in load-history:
>
> 1. "/home/acm/emacs/emacs/lisp/progmodes/cc-mode.elc"
> 2. "/mnt/hda7/emacs/lisp/progmodes/cc-fonts.elc"
> 3. "/mnt/hda7/emacs/lisp/language/english.elc"
>
> 1 and 2 are incompatible. 3 is plain wrong - the actual file is
> english.el (english.elc doesn't exist; you can't compile english).
and
> Start Emacs 22 with -Q, then visit a file.c.
>
> Emacs displays the message:
>
> File mode specification error: (void-variable c-font-lock-keywords-3)
#########################################################################
The following patch, though large, fixes all of these problems, thusly:
1. The file name recorded in load-history is the absolute true file name
of the file actually loaded. The way this is done for preloaded files
has been simplified.
2. (eval-after-load FILE ...) now triggers on ANY file which matches
FILE, not just the one (if any) found in load-path.
3. (eval-after-load "foo" ...), for example will trigger on "..../foo",
"..../foo.el", "..../foo.elc", or even "..../foo.el.gz".
[Incidentally, it needs BASE_PURESIZE to be increased.]
2006-05-14 Alan Mackenzie <address@hidden>
* startup.el (command-line): For names of preloaded files, don't
append ".elc" (now done in Fload), and call file-truename on the
lisp directory.
* international/mule.el (load-with-code-conversion): Do the
eval-after-load stuff by calling do-after-load-evaluation.
* subr.el (eval-after-load): Fix the doc-string. Allow FILE to
match ANY loaded file with the right name, not just those in
load-path.
* subr.el: New functions load-history-regexp,
load-history-filename-element, loaded-filename,
get-after-load-alist-matches, do-after-load-evaluation.
* loadup.el: load emacs-lisp/regexp-opt at preload time to support
Fload.
Index: lisp/startup.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/startup.el,v
retrieving revision 1.407
diff -c -r1.407 startup.el
*** lisp/startup.el 5 May 2006 14:05:54 -0000 1.407
--- lisp/startup.el 14 May 2006 09:51:50 -0000
***************
*** 644,661 ****
;; Convert preloaded file names to absolute.
(let ((lisp-dir
! (file-name-directory
! (locate-file "simple" load-path
! (get-load-suffixes)))))
(setq load-history
(mapcar (lambda (elt)
(if (and (stringp (car elt))
(not (file-name-absolute-p (car elt))))
(cons (concat lisp-dir
! (car elt)
! (if (string-match "[.]el$" (car elt))
! "" ".elc"))
(cdr elt))
elt))
load-history)))
--- 644,660 ----
;; Convert preloaded file names to absolute.
(let ((lisp-dir
! (file-truename
! (file-name-directory
! (locate-file "simple" load-path
! (get-load-suffixes))))))
(setq load-history
(mapcar (lambda (elt)
(if (and (stringp (car elt))
(not (file-name-absolute-p (car elt))))
(cons (concat lisp-dir
! (car elt))
(cdr elt))
elt))
load-history)))
Index: lisp/subr.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/subr.el,v
retrieving revision 1.507
diff -c -r1.507 subr.el
*** lisp/subr.el 7 May 2006 20:49:01 -0000 1.507
--- lisp/subr.el 14 May 2006 09:52:01 -0000
***************
*** 1385,1416 ****
t))
nil))
(defun eval-after-load (file form)
"Arrange that, if FILE is ever loaded, FORM will be run at that time.
- This makes or adds to an entry on `after-load-alist'.
If FILE is already loaded, evaluate FORM right now.
! It does nothing if FORM is already on the list for FILE.
! FILE must match exactly. Normally FILE is the name of a library,
! with no directory or extension specified, since that is how `load'
! is normally called.
! FILE can also be a feature (i.e. a symbol), in which case FORM is
! evaluated whenever that feature is `provide'd."
(let ((elt (assoc file after-load-alist)))
- ;; Make sure there is an element for FILE.
(unless elt (setq elt (list file)) (push elt after-load-alist))
! ;; Add FORM to the element if it isn't there.
(unless (member form (cdr elt))
! (nconc elt (list form))
! ;; If the file has been loaded already, run FORM right away.
! (if (if (symbolp file)
! (featurep file)
! ;; Make sure `load-history' contains the files dumped with
! ;; Emacs for the case that FILE is one of them.
! ;; (load-symbol-file-load-history)
! (when (locate-library file)
! (assoc (locate-library file) load-history)))
! (eval form))))
! form)
(defun eval-next-after-load (file)
"Read the following input sexp, and run it whenever FILE is loaded.
--- 1385,1494 ----
t))
nil))
+ (defun load-history-regexp (file)
+ "Form a regexp to find FILE in load-history.
+ FILE, a string, is described in eval-after-load's doc-string."
+ (if (file-name-absolute-p file)
+ (setq file (file-truename file)))
+ (concat (if (file-name-absolute-p file) "\\`" "\\<")
+ (regexp-quote file)
+ (if (file-name-extension file)
+ ""
+ (regexp-opt (cons "" load-suffixes)))
+ "\\(" (regexp-opt jka-compr-load-suffixes) "\\)?\\'"))
+
+ (defun load-history-filename-element (file)
+ "Get the first element of load-history which matches FILE.
+ Return nil if there isn't one.
+
+ FILE, a string, is described in eval-after-load's doc-string."
+ (let* ((regexp (load-history-regexp file))
+ (loads load-history)
+ (load-elt (and loads (car loads))))
+ (save-match-data
+ (while (and loads
+ (or (null (car load-elt))
+ (not (string-match regexp (car load-elt)))))
+ (setq loads (cdr loads)
+ load-elt (and loads (car loads)))))
+ load-elt))
+
+ (defun loaded-filename (file)
+ "Get the absolute file name from which Elisp file FILE was loaded.
+ Return nil if the file isn't found. The returned file name will be a true
+ name \(i.e. with all its symbolic links having been chased out).
+
+ FILE is a string. See eval-after-load for precise description."
+ (let ((elt (load-history-filename-element file)))
+ (and elt (car elt))))
+
(defun eval-after-load (file form)
"Arrange that, if FILE is ever loaded, FORM will be run at that time.
If FILE is already loaded, evaluate FORM right now.
!
! If a matching file is loaded again, FORM will be evaluated again.
!
! If FILE is a string, it may be either an absolute or a relative file
! name, and may have an extension \(e.g. \".el\") or may lack one, and
! additionally may or may not have an extension denoting a compressed
! format \(e.g. \".gz\").
!
! When FILE is absolute, it is first converted to a true name by chasing
! out symbolic links. Only a file of this name \(see next paragraph for
! extensions) will trigger the evaluation of FORM. When FILE is relative,
! a file whose absolute true name ends in FILE will trigger evaluation.
!
! When FILE lacks an extension, a file name with any extension will trigger
! evaluation. Otherwise, its extension must match FILE's. A further
! extension for a compressed format \(e.g. \".gz\") on FILE will not affect
! this name matching.
!
! Alternatively, FILE can be a feature (i.e. a symbol), in which case FORM
! is evaluated whenever that feature is `provide'd.
!
! Usually FILE is just a library name like \"font-lock\" or a feature name
! like 'font-lock.
!
! This function makes or adds to an entry on `after-load-alist'."
! ;; Add this FORM into after-load-alist (regardless of whether we'll be
! ;; evaluating it now).
(let ((elt (assoc file after-load-alist)))
(unless elt (setq elt (list file)) (push elt after-load-alist))
! ;; Add FORM to the element unless it's already there.
(unless (member form (cdr elt))
! (nconc elt (list form))))
!
! ;; Is there an already loaded file whose name (or `provide' name)
! ;; matches FILE?
! (if (if (symbolp file)
! (featurep file)
! (loaded-filename file))
! (eval form)))
!
! (defun get-after-load-alist-matches (abs-file)
! "Get all the matches in after-load-alist for the file name ABS-FILE.
! ABS-FILE, a string, should be the absolute true name of a file just loaded."
! (let ((elements after-load-alist)
! element result)
! (while elements
! (setq element (car elements))
! (if (and (stringp (car element))
! (string-match (load-history-regexp (car element)) abs-file))
! (push element result))
! (setq elements (cdr elements)))
! (nreverse result)))
!
! (defun do-after-load-evaluation (abs-file)
! "Evaluate all `eval-after-load' forms, if any, for ABS-FILE.
! ABS-FILE, a string, should be the absolute true name of a file just loaded."
! (let ((file-elements (get-after-load-alist-matches abs-file))
! file-element form)
! (while file-elements
! (setq file-element (car file-elements)
! file-elements (cdr file-elements))
! (while (setq file-element (cdr file-element)) ; discard the file name.
! (setq form (car file-element))
! (eval form)))))
(defun eval-next-after-load (file)
"Read the following input sexp, and run it whenever FILE is loaded.
Index: lisp/loadup.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/loadup.el,v
retrieving revision 1.148
diff -c -r1.148 loadup.el
*** lisp/loadup.el 20 Feb 2006 22:14:54 -0000 1.148
--- lisp/loadup.el 14 May 2006 09:52:02 -0000
***************
*** 211,216 ****
--- 211,217 ----
(load "vc-hooks")
(load "jka-cmpr-hook")
(load "ediff-hook")
+ (load "emacs-lisp/regexp-opt") ; needed for Fload.
(if (fboundp 'x-show-tip) (load "tooltip"))
(message "%s" (garbage-collect))
Index: lisp/international/mule.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/international/mule.el,v
retrieving revision 1.234
diff -c -r1.234 mule.el
*** lisp/international/mule.el 21 Apr 2006 12:22:24 -0000 1.234
--- lisp/international/mule.el 14 May 2006 09:52:08 -0000
***************
*** 98,106 ****
))
(let (kill-buffer-hook kill-buffer-query-functions)
(kill-buffer buffer)))
! (let ((hook (assoc file after-load-alist)))
! (when hook
! (mapcar (function eval) (cdr hook))))
(unless (or nomessage noninteractive)
(if source
(message "Loading %s (source)...done" file)
--- 98,105 ----
))
(let (kill-buffer-hook kill-buffer-query-functions)
(kill-buffer buffer)))
! (do-after-load-evaluation fullname)
!
(unless (or nomessage noninteractive)
(if source
(message "Loading %s (source)...done" file)
2006-05-14 Alan Mackenzie <address@hidden>
* lread.c (Vload_history): Enhance doc-string to say that the file
is the absolute truename of the loaded file.
* lread.c (readevalloop): Call file-truename on the name for
load-history, except at preloading time.
* lread.c (Fload): At preloading time, preserve the extension of
the filename which goes into load-history. New variable
hist_file_name.
* lread.c (Fload): Do eval-after-load stuff by calling the lisp
function do-after-load-evaluation.
Index: src/lread.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/lread.c,v
retrieving revision 1.350
diff -c -r1.350 lread.c
*** src/lread.c 27 Feb 2006 02:04:35 -0000 1.350
--- src/lread.c 14 May 2006 09:51:44 -0000
***************
*** 718,725 ****
register int fd = -1;
int count = SPECPDL_INDEX ();
Lisp_Object temp;
! struct gcpro gcpro1, gcpro2;
! Lisp_Object found, efound;
/* 1 means we printed the ".el is newer" message. */
int newer = 0;
/* 1 means we are loading a compiled file. */
--- 718,725 ----
register int fd = -1;
int count = SPECPDL_INDEX ();
Lisp_Object temp;
! struct gcpro gcpro1, gcpro2, gcpro3;
! Lisp_Object found, efound, hist_file_name;
/* 1 means we printed the ".el is newer" message. */
int newer = 0;
/* 1 means we are loading a compiled file. */
***************
*** 727,732 ****
--- 727,733 ----
Lisp_Object handler;
int safe_p = 1;
char *fmode = "r";
+ Lisp_Object tmp[2];
#ifdef DOS_NT
fmode = "rt";
#endif /* DOS_NT */
***************
*** 743,749 ****
the need to gcpro noerror, nomessage and nosuffix.
(Below here, we care only whether they are nil or not.)
The presence of this call is the result of a historical accident:
! it used to be in every file-operations and when it got removed
everywhere, it accidentally stayed here. Since then, enough people
supposedly have things like (load "$PROJECT/foo.el") in their .emacs
that it seemed risky to remove. */
--- 744,750 ----
the need to gcpro noerror, nomessage and nosuffix.
(Below here, we care only whether they are nil or not.)
The presence of this call is the result of a historical accident:
! it used to be in every file-operation and when it got removed
everywhere, it accidentally stayed here. Since then, enough people
supposedly have things like (load "$PROJECT/foo.el") in their .emacs
that it seemed risky to remove. */
***************
*** 763,769 ****
if (SCHARS (file) > 0)
{
int size = SBYTES (file);
- Lisp_Object tmp[2];
found = Qnil;
GCPRO2 (file, found);
--- 764,769 ----
***************
*** 847,852 ****
--- 847,859 ----
Vloads_in_progress = Fcons (found, Vloads_in_progress);
}
+ /* Get the name for load-history. */
+ hist_file_name = (! NILP (Vpurify_flag)
+ ? Fconcat (2, (tmp[0] = Ffile_name_directory (file),
+ tmp[1] = Ffile_name_nondirectory (found),
+ tmp))
+ : found) ;
+
if (!bcmp (SDATA (found) + SBYTES (found) - 4,
".elc", 4))
/* Load .elc files directly, but not when they are
***************
*** 857,863 ****
struct stat s1, s2;
int result;
! GCPRO2 (file, found);
if (!safe_to_load_p (fd))
{
--- 864,870 ----
struct stat s1, s2;
int result;
! GCPRO3 (file, found, hist_file_name);
if (!safe_to_load_p (fd))
{
***************
*** 911,924 ****
if (fd >= 0)
emacs_close (fd);
! val = call4 (Vload_source_file_function, found, file,
NILP (noerror) ? Qnil : Qt,
NILP (nomessage) ? Qnil : Qt);
return unbind_to (count, val);
}
}
! GCPRO2 (file, found);
#ifdef WINDOWSNT
emacs_close (fd);
--- 918,931 ----
if (fd >= 0)
emacs_close (fd);
! val = call4 (Vload_source_file_function, found, hist_file_name,
NILP (noerror) ? Qnil : Qt,
NILP (nomessage) ? Qnil : Qt);
return unbind_to (count, val);
}
}
! GCPRO3 (file, found, hist_file_name);
#ifdef WINDOWSNT
emacs_close (fd);
***************
*** 957,970 ****
load_descriptor_list
= Fcons (make_number (fileno (stream)), load_descriptor_list);
load_in_progress++;
! readevalloop (Qget_file_char, stream, (! NILP (Vpurify_flag) ? file :
found),
Feval, 0, Qnil, Qnil, Qnil, Qnil);
unbind_to (count, Qnil);
! /* Run any load-hooks for this file. */
! temp = Fassoc (file, Vafter_load_alist);
! if (!NILP (temp))
! Fprogn (Fcdr (temp));
UNGCPRO;
if (saved_doc_string)
--- 964,986 ----
load_descriptor_list
= Fcons (make_number (fileno (stream)), load_descriptor_list);
load_in_progress++;
! readevalloop (Qget_file_char, stream, hist_file_name,
Feval, 0, Qnil, Qnil, Qnil, Qnil);
unbind_to (count, Qnil);
! /* Run any eval-after-load forms for this file */
! if (NILP (Vpurify_flag))
! {
! Lisp_Object Qdo_after_load_evaluation
! = intern ("do-after-load-evaluation") ;
! if (!NILP (Ffboundp (Qdo_after_load_evaluation)))
! call1 (Qdo_after_load_evaluation, hist_file_name) ;
! else
! Fsignal (Qerror,
! Fcons (make_string
! ("Fload: can't find do-after-load-evaluation",
! 42), Qnil)) ;
! }
UNGCPRO;
if (saved_doc_string)
***************
*** 1385,1390 ****
--- 1401,1414 ----
GCPRO4 (sourcename, readfun, start, end);
+ /* Try to ensure sourcename is a truename, except whilst preloading. */
+ if (NILP (Vpurify_flag) && !NILP (sourcename)
+ && Ffile_name_absolute_p (sourcename))
+ {
+ Lisp_Object Qfile_truename = intern ("file-truename") ;
+ if (!NILP (Ffboundp (Qfile_truename)))
+ sourcename = call1 (Qfile_truename, sourcename) ;
+ }
LOADHIST_ATTACH (sourcename);
continue_reading_p = 1;
***************
*** 3982,3987 ****
--- 4006,4015 ----
Each alist element is a list that starts with a file name,
except for one element (optional) that starts with nil and describes
definitions evaluated from buffers not visiting files.
+
+ The file name is absolute and is the true file name (i.e. it doesn't
+ contain symbolic links) of the loaded file.
+
The remaining elements of each list are symbols defined as variables
and cons cells of the form `(provide . FEATURE)', `(require . FEATURE)',
`(defun . FUNCTION)', `(autoload . SYMBOL)', and `(t . SYMBOL)'.
Index: src/puresize.h
===================================================================
RCS file: /cvsroot/emacs/emacs/src/puresize.h,v
retrieving revision 1.86
diff -c -r1.86 puresize.h
*** src/puresize.h 22 Apr 2006 10:09:36 -0000 1.86
--- src/puresize.h 14 May 2006 09:51:44 -0000
***************
*** 43,49 ****
#endif
#ifndef BASE_PURESIZE
! #define BASE_PURESIZE (1205000 + SYSTEM_PURESIZE_EXTRA +
SITELOAD_PURESIZE_EXTRA)
#endif
/* Increase BASE_PURESIZE by a ratio depending on the machine's word size. */
--- 43,51 ----
#endif
#ifndef BASE_PURESIZE
! #define BASE_PURESIZE (1210000 + SYSTEM_PURESIZE_EXTRA +
SITELOAD_PURESIZE_EXTRA)
! /* was (1205000 + SYSTEM_PURESIZE_EXTRA + SITELOAD_PURESIZE_EXTRA). Increased
! for regexp-opt, ACM, 2006/5/13 */
#endif
/* Increase BASE_PURESIZE by a ratio depending on the machine's word size. */
--
>Alan.
- Clarification of eval-after-load [was: Problem mit symlinks, locate-library and load-history], Alan Mackenzie, 2006/05/10
- FIXED!! Re: Clarification of eval-after-load [was: Problem mit symlinks, locate-library and load-history],
Alan Mackenzie <=
- Re: FIXED!! Re: Clarification of eval-after-load [was: Problem mit symlinks, locate-library and load-history], Richard Stallman, 2006/05/15
- Re: FIXED!! Re: Clarification of eval-after-load [was: Problem mit symlinks, locate-library and load-history], Alan Mackenzie, 2006/05/21
- Re: FIXED!! Re: Clarification of eval-after-load [was: Problem mit symlinks, locate-library and load-history], Richard Stallman, 2006/05/21
- Re: FIXED!! Re: Clarification of eval-after-load [was: Problem mit symlinks, locate-library and load-history], Alan Mackenzie, 2006/05/23
- Re: FIXED!! Re: Clarification of eval-after-load [was: Problem mit symlinks, locate-library and load-history], Andreas Schwab, 2006/05/23
- Re: FIXED!! Re: Clarification of eval-after-load [was: Problem mit symlinks, locate-library and load-history], Alan Mackenzie, 2006/05/23
- Re: FIXED!! Re: Clarification of eval-after-load, Stefan Monnier, 2006/05/23