From 1f41ee56ace98fe0d5f288c97ddb73870befed45 Mon Sep 17 00:00:00 2001 From: Glenn Morris Date: Tue, 17 Dec 2013 19:21:48 -0800 Subject: [PATCH] Add load-prefer-newer option, to load .el if newer than .elc * src/lread.c (Fload): Pass load_prefer_newer to openp. Don't bother checking mtime if openp already did it. (openp): Add `newer' argument, to check all suffixes and find the newest file. (syms_of_lread) : New option. * src/callproc.c (call_process): * src/charset.c (load_charset_map_from_file): * src/emacs.c (init_cmdargs): * src/image.c (x_create_bitmap_from_file, x_find_image_file): * src/lisp.h (openp): * lread.c (Flocate_file_internal): * src/process.c (Fformat_network_address): * src/sound.c (Fplay_sound_internal): * src/w32.c (check_windows_init_file): * src/w32proc.c (sys_spawnve): Update for new arg spec of openp. * lisp/Makefile.in (BYTE_COMPILE_FLAGS): Set load-prefer-newer to t. * etc/NEWS: Mention this. Fixes: debbugs:2061 --- etc/NEWS | 5 ++ lisp/ChangeLog | 6 +++ lisp/Makefile.in | 3 +- lisp/cus-start.el | 1 + src/ChangeLog | 16 ++++++ src/callproc.c | 2 +- src/charset.c | 20 ++++---- src/emacs.c | 2 +- src/image.c | 4 +- src/lisp.h | 2 +- src/lread.c | 121 ++++++++++++++++++++++++++++++++-------------- src/process.c | 2 +- src/sound.c | 2 +- src/w32.c | 5 +- src/w32proc.c | 5 +- 15 files changed, 138 insertions(+), 58 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 0977accff3..4ab3cd3138 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -807,6 +807,11 @@ for something (not just adding elements to it), it ought not to affect you. * Lisp Changes in Emacs 24.4 +** New option `load-prefer-newer', if non-nil, means that when both +.el and .elc versions of a file exist, rather than `load' always +choosing the .elc version, it will choose whichever is newer +(unless you explicitly specify one or the other). + ** New function get-pos-property. ** New hook `pre-redisplay-function'. diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 126f10ae79..435581799b 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,7 @@ +2013-12-18 Glenn Morris + + * Makefile.in (BYTE_COMPILE_FLAGS): Set load-prefer-newer to t. + 2013-12-18 Le Wang * comint.el (comint-previous-matching-input-from-input): Retain @@ -9,6 +13,8 @@ 2013-12-18 Glenn Morris + * cus-start.el (load-prefer-newer): New option. + * mail/emacsbug.el (report-emacs-bug): Only mention enable-multibyte-characters if non-standard. diff --git a/lisp/Makefile.in b/lisp/Makefile.in index 2ac2f3e8d6..39452edcbf 100644 --- a/lisp/Makefile.in +++ b/lisp/Makefile.in @@ -88,7 +88,8 @@ AUTOGEN_VCS = \ BIG_STACK_DEPTH = 2200 BIG_STACK_OPTS = --eval "(setq max-lisp-eval-depth $(BIG_STACK_DEPTH))" -BYTE_COMPILE_FLAGS = $(BIG_STACK_OPTS) $(BYTE_COMPILE_EXTRA_FLAGS) +# Set load-prefer-newer for the benefit of the non-bootstrappers. +BYTE_COMPILE_FLAGS = $(BIG_STACK_OPTS) --eval '(setq load-prefer-newer t)' $(BYTE_COMPILE_EXTRA_FLAGS) # Files to compile before others during a bootstrap. This is done to # speed up the bootstrap process. They're ordered by size, so we use diff --git a/lisp/cus-start.el b/lisp/cus-start.el index 8e94e85f84..32013b7112 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -312,6 +312,7 @@ Leaving \"Default\" unchecked is equivalent with specifying a default of ;; :format "%[Current dir?%] %v" ;; (const :tag " current dir" nil) ;; (directory :format "%v")))) + (load-prefer-newer lisp boolean "24.4") ;; minibuf.c (enable-recursive-minibuffers minibuffer boolean) (history-length minibuffer diff --git a/src/ChangeLog b/src/ChangeLog index 5933f145b4..937b5c7c4c 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,21 @@ 2013-12-18 Glenn Morris + * lread.c (Fload): Pass load_prefer_newer to openp. + Don't bother checking mtime if openp already did it. + (openp): Add `newer' argument, to check all suffixes + and find the newest file. + (syms_of_lread) : New option. (Bug#2061) + * callproc.c (call_process): + * charset.c (load_charset_map_from_file): + * emacs.c (init_cmdargs): + * image.c (x_create_bitmap_from_file, x_find_image_file): + * lisp.h (openp): + * lread.c (Flocate_file_internal): + * process.c (Fformat_network_address): + * sound.c (Fplay_sound_internal): + * w32.c (check_windows_init_file): + * w32proc.c (sys_spawnve): Update for new arg spec of openp. + * emacs.c (standard_args) [HAVE_NS]: Remove -disable-font-backend. 2013-12-17 Eli Zaretskii diff --git a/src/callproc.c b/src/callproc.c index b44f680b35..0d30fe549e 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -465,7 +465,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, int ok; GCPRO3 (buffer, current_dir, error_file); - ok = openp (Vexec_path, args[0], Vexec_suffixes, &path, make_number (X_OK)); + ok = openp (Vexec_path, args[0], Vexec_suffixes, &path, make_number (X_OK), 0); UNGCPRO; if (ok < 0) report_file_error ("Searching for program", args[0]); diff --git a/src/charset.c b/src/charset.c index 2ef060228e..1e14475f11 100644 --- a/src/charset.c +++ b/src/charset.c @@ -1,13 +1,15 @@ /* Basic character set support. - Copyright (C) 2001-2013 Free Software Foundation, Inc. - Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007, 2008, 2009, 2010, 2011 - National Institute of Advanced Industrial Science and Technology (AIST) - Registration Number H14PRO021 - Copyright (C) 2003, 2004 - National Institute of Advanced Industrial Science and Technology (AIST) - Registration Number H13PRO009 +Copyright (C) 2001-2013 Free Software Foundation, Inc. + +Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, + 2005, 2006, 2007, 2008, 2009, 2010, 2011 + National Institute of Advanced Industrial Science and Technology (AIST) + Registration Number H14PRO021 + +Copyright (C) 2003, 2004 + National Institute of Advanced Industrial Science and Technology (AIST) + Registration Number H13PRO009 This file is part of GNU Emacs. @@ -493,7 +495,7 @@ load_charset_map_from_file (struct charset *charset, Lisp_Object mapfile, count = SPECPDL_INDEX (); record_unwind_protect_nothing (); specbind (Qfile_name_handler_alist, Qnil); - fd = openp (Vcharset_map_path, mapfile, suffixes, NULL, Qnil); + fd = openp (Vcharset_map_path, mapfile, suffixes, NULL, Qnil, 0); fp = fd < 0 ? 0 : fdopen (fd, "r"); if (!fp) { diff --git a/src/emacs.c b/src/emacs.c index 89e04b12b4..791e0524e1 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -424,7 +424,7 @@ init_cmdargs (int argc, char **argv, int skip_args, char *original_pwd) { Lisp_Object found; int yes = openp (Vexec_path, Vinvocation_name, - Vexec_suffixes, &found, make_number (X_OK)); + Vexec_suffixes, &found, make_number (X_OK), 0); if (yes == 1) { /* Add /: to the front of the name diff --git a/src/image.c b/src/image.c index e1c6e5df3c..85f29329bd 100644 --- a/src/image.c +++ b/src/image.c @@ -327,7 +327,7 @@ x_create_bitmap_from_file (struct frame *f, Lisp_Object file) } /* Search bitmap-file-path for the file, if appropriate. */ - if (openp (Vx_bitmap_file_path, file, Qnil, &found, make_number (R_OK)) < 0) + if (openp (Vx_bitmap_file_path, file, Qnil, &found, make_number (R_OK), 0) < 0) return -1; filename = SSDATA (found); @@ -2242,7 +2242,7 @@ x_find_image_file (Lisp_Object file) Vx_bitmap_file_path); /* Try to find FILE in data-directory/images, then x-bitmap-file-path. */ - fd = openp (search_path, file, Qnil, &file_found, Qnil); + fd = openp (search_path, file, Qnil, &file_found, Qnil, 0); if (fd == -1) file_found = Qnil; diff --git a/src/lisp.h b/src/lisp.h index 1e68b152df..e53d25b3fc 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -3791,7 +3791,7 @@ LOADHIST_ATTACH (Lisp_Object x) Vcurrent_load_list = Fcons (x, Vcurrent_load_list); } extern int openp (Lisp_Object, Lisp_Object, Lisp_Object, - Lisp_Object *, Lisp_Object); + Lisp_Object *, Lisp_Object, int); extern Lisp_Object string_to_number (char const *, int, bool); extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object), Lisp_Object); diff --git a/src/lread.c b/src/lread.c index 2bada06f2a..c24af0cf9c 100644 --- a/src/lread.c +++ b/src/lread.c @@ -1129,7 +1129,7 @@ Return t if the file exists and loads successfully. */) } } - fd = openp (Vload_path, file, suffixes, &found, Qnil); + fd = openp (Vload_path, file, suffixes, &found, Qnil, load_prefer_newer); UNGCPRO; } @@ -1252,29 +1252,36 @@ Return t if the file exists and loads successfully. */) #ifdef DOS_NT fmode = "rb"; #endif /* DOS_NT */ - result = stat (SSDATA (efound), &s1); - if (result == 0) - { - SSET (efound, SBYTES (efound) - 1, 0); - result = stat (SSDATA (efound), &s2); - SSET (efound, SBYTES (efound) - 1, 'c'); - } - if (result == 0 - && timespec_cmp (get_stat_mtime (&s1), get_stat_mtime (&s2)) < 0) - { - /* Make the progress messages mention that source is newer. */ - newer = 1; + /* openp already checked for newness, no point doing it again. + FIXME would be nice to get a message when openp + ignores suffix order due to load_prefer_newer. */ + if (!load_prefer_newer) + { + result = stat (SSDATA (efound), &s1); + if (result == 0) + { + SSET (efound, SBYTES (efound) - 1, 0); + result = stat (SSDATA (efound), &s2); + SSET (efound, SBYTES (efound) - 1, 'c'); + } - /* If we won't print another message, mention this anyway. */ - if (!NILP (nomessage) && !force_load_messages) - { - Lisp_Object msg_file; - msg_file = Fsubstring (found, make_number (0), make_number (-1)); - message_with_string ("Source file `%s' newer than byte-compiled file", - msg_file, 1); - } - } + if (result == 0 + && timespec_cmp (get_stat_mtime (&s1), get_stat_mtime (&s2)) < 0) + { + /* Make the progress messages mention that source is newer. */ + newer = 1; + + /* If we won't print another message, mention this anyway. */ + if (!NILP (nomessage) && !force_load_messages) + { + Lisp_Object msg_file; + msg_file = Fsubstring (found, make_number (0), make_number (-1)); + message_with_string ("Source file `%s' newer than byte-compiled file", + msg_file, 1); + } + } + } /* !load_prefer_newer */ UNGCPRO; } } @@ -1413,7 +1420,7 @@ directories, make sure the PREDICATE function returns `dir-ok' for them. */) (Lisp_Object filename, Lisp_Object path, Lisp_Object suffixes, Lisp_Object predicate) { Lisp_Object file; - int fd = openp (path, filename, suffixes, &file, predicate); + int fd = openp (path, filename, suffixes, &file, predicate, 0); if (NILP (predicate) && fd >= 0) emacs_close (fd); return file; @@ -1440,11 +1447,14 @@ static Lisp_Object Qdir_ok; nil is stored there on failure. If the file we find is remote, return -2 - but store the found remote file name in *STOREPTR. */ + but store the found remote file name in *STOREPTR. + + If NEWER is true, try all SUFFIXes and return the result for the + newest file that exists. Does not apply to remote files. */ int openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, - Lisp_Object *storeptr, Lisp_Object predicate) + Lisp_Object *storeptr, Lisp_Object predicate, int newer) { ptrdiff_t fn_size = 100; char buf[100]; @@ -1453,9 +1463,11 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, ptrdiff_t want_length; Lisp_Object filename; struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6; - Lisp_Object string, tail, encoded_fn; + Lisp_Object string, tail, encoded_fn, save_string; ptrdiff_t max_suffix_len = 0; int last_errno = ENOENT; + struct timespec save_mtime; + int save_fd = 0; CHECK_STRING (str); @@ -1556,17 +1568,18 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, if (exists) { - /* We succeeded; return this descriptor and filename. */ - if (storeptr) - *storeptr = string; - UNGCPRO; - return -2; + /* We succeeded; return this descriptor and filename. */ + if (storeptr) + *storeptr = string; + UNGCPRO; + return -2; } } else { int fd; const char *pfn; + struct stat st; encoded_fn = ENCODE_FILE (string); pfn = SSDATA (encoded_fn); @@ -1597,7 +1610,6 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, } else { - struct stat st; int err = (fstat (fd, &st) != 0 ? errno : S_ISDIR (st.st_mode) ? EISDIR : 0); if (err) @@ -1611,12 +1623,36 @@ openp (Lisp_Object path, Lisp_Object str, Lisp_Object suffixes, if (fd >= 0) { - /* We succeeded; return this descriptor and filename. */ - if (storeptr) - *storeptr = string; - UNGCPRO; - return fd; + if (newer) + { + struct timespec mtime = get_stat_mtime (&st); + + if (!save_fd || timespec_cmp (save_mtime, mtime) < 0) + { + if (save_fd) emacs_close (save_fd); + save_fd = fd; + save_mtime = mtime; + save_string = string; + } + } + else + { + /* We succeeded; return this descriptor and filename. */ + if (storeptr) + *storeptr = string; + UNGCPRO; + return fd; + } } + + /* No more suffixes. Return the newest. */ + if (newer && save_fd && ! CONSP (XCDR (tail))) + { + if (storeptr) + *storeptr = save_string; + UNGCPRO; + return save_fd; + } } } if (absolute) @@ -4632,6 +4668,17 @@ variables, this must be set in the first line of a file. */); Vold_style_backquotes = Qnil; DEFSYM (Qold_style_backquotes, "old-style-backquotes"); + DEFVAR_BOOL ("load-prefer-newer", load_prefer_newer, + doc: /* Non-nil means `load' prefers the newest version of a file. +This applies when a filename suffix is not explicitly specified and +`load' is trying various possible suffixes (see `load-suffixes' and +`load-file-rep-suffixes'). Normally, it stops at the first file +that exists. If this option is non-nil, it checks all suffixes and +uses whichever file is newest. +Note that if you customize this, obviously it will not affect files +that are loaded before your customizations are read! */); + load_prefer_newer = 0; + /* Vsource_directory was initialized in init_lread. */ DEFSYM (Qcurrent_load_list, "current-load-list"); diff --git a/src/process.c b/src/process.c index dac4b14dce..bef1e6d68f 100644 --- a/src/process.c +++ b/src/process.c @@ -1530,7 +1530,7 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */) tem = Qnil; GCPRO4 (name, program, buffer, current_dir); - openp (Vexec_path, program, Vexec_suffixes, &tem, make_number (X_OK)); + openp (Vexec_path, program, Vexec_suffixes, &tem, make_number (X_OK), 0); UNGCPRO; if (NILP (tem)) report_file_error ("Searching for program", program); diff --git a/src/sound.c b/src/sound.c index f8c6b48305..e84f7415cd 100644 --- a/src/sound.c +++ b/src/sound.c @@ -1332,7 +1332,7 @@ Internal use only, use `play-sound' instead. */) { /* Open the sound file. */ current_sound->fd = openp (list1 (Vdata_directory), - attrs[SOUND_FILE], Qnil, &file, Qnil); + attrs[SOUND_FILE], Qnil, &file, Qnil, 0); if (current_sound->fd < 0) sound_perror ("Could not open sound file"); diff --git a/src/w32.c b/src/w32.c index 159085e7f5..dde74bfcdd 100644 --- a/src/w32.c +++ b/src/w32.c @@ -1,5 +1,6 @@ /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API. - Copyright (C) 1994-1995, 2000-2013 Free Software Foundation, Inc. + +Copyright (C) 1994-1995, 2000-2013 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -8602,7 +8603,7 @@ check_windows_init_file (void) need to ENCODE_FILE here, but we do need to convert the file names from UTF-8 to ANSI. */ init_file = build_string ("term/w32-win"); - fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil); + fd = openp (Vload_path, init_file, Fget_load_suffixes (), NULL, Qnil, 0); if (fd < 0) { Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil); diff --git a/src/w32proc.c b/src/w32proc.c index 7d4fb9825f..2b583efba5 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -1,5 +1,6 @@ /* Process support for GNU Emacs on the Microsoft Windows API. - Copyright (C) 1992, 1995, 1999-2013 Free Software Foundation, Inc. + +Copyright (C) 1992, 1995, 1999-2013 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -1592,7 +1593,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) program = build_string (cmdname); full = Qnil; GCPRO1 (program); - openp (Vexec_path, program, Vexec_suffixes, &full, make_number (X_OK)); + openp (Vexec_path, program, Vexec_suffixes, &full, make_number (X_OK), 0); UNGCPRO; if (NILP (full)) { -- 2.20.1