X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/97bacf8c0530e5265db01fad127660a7ed33cfdb..09af58633c2a83b61dee86bcf3794122b101671a:/src/lread.c diff --git a/src/lread.c b/src/lread.c index 1f49be6e36..b8b9189719 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,37 @@ 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 emacs_close (fd); + } + 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) @@ -3537,7 +3574,7 @@ read_vector (Lisp_Object readcharfun, bool bytecodeflag) return vector; } -/* FLAG means check for ] to terminate rather than ) and . */ +/* FLAG means check for ']' to terminate rather than ')' and '.'. */ static Lisp_Object read_list (bool flag, Lisp_Object readcharfun) @@ -4128,10 +4165,6 @@ load_path_check (Lisp_Object lpath) } } -/* Record the value of load-path used at the start of dumping - so we can see if the site changed it later during dumping. */ -static Lisp_Object dump_path; - /* Return the default load-path, to be used if EMACSLOADPATH is unset. This does not include the standard site-lisp directories under the installation prefix (i.e., PATH_SITELOADSEARCH), @@ -4145,29 +4178,25 @@ static Lisp_Object dump_path; If purify-flag (ie dumping) just use PATH_DUMPLOADSEARCH. Otherwise use PATH_LOADSEARCH. - If !initialized, then just set dump_path and return PATH_DUMPLOADSEARCH. - If initialized, then if Vload_path != dump_path, return just Vload_path. - (Presumably the load-path has already been changed by something. - This can only be from a site-load file during dumping.) + If !initialized, then just return PATH_DUMPLOADSEARCH. + If initialized: If Vinstallation_directory is not nil (ie, running uninstalled): If installation-dir/lisp exists and not already a member, we must be running uninstalled. Reset the load-path to just installation-dir/lisp. (The default PATH_LOADSEARCH refers to the eventual installation directories. Since we are not yet installed, we should not use them, even if they exist.) - If installation-dir/lisp does not exist, just add dump_path at the - end instead. - Add installation-dir/leim (if exists and not already a member) at the front. + If installation-dir/lisp does not exist, just add + PATH_DUMPLOADSEARCH at the end instead. Add installation-dir/site-lisp (if !no_site_lisp, and exists and not already a member) at the front. If installation-dir != source-dir (ie running an uninstalled, out-of-tree build) AND install-dir/src/Makefile exists BUT install-dir/src/Makefile.in does NOT exist (this is a sanity - check), then repeat the above steps for source-dir/lisp, - leim and site-lisp. -*/ -Lisp_Object -load_path_default (bool ignore_existing) + check), then repeat the above steps for source-dir/lisp, site-lisp. */ + +static Lisp_Object +load_path_default (void) { Lisp_Object lpath = Qnil; const char *normal; @@ -4188,56 +4217,48 @@ load_path_default (bool ignore_existing) normal = NILP (Vpurify_flag) ? PATH_LOADSEARCH : PATH_DUMPLOADSEARCH; - /* In a dumped Emacs, we normally reset the value of Vload_path using - PATH_LOADSEARCH, since the value that was dumped uses lisp/ in - the source directory, instead of the path of the installed elisp - libraries. However, if it appears that Vload_path has already been - changed from the default that was saved before dumping, don't - change it further. Changes can only be due to EMACSLOADPATH, or - site-lisp files that were processed during dumping. */ if (initialized) { - if (!ignore_existing && NILP (Fequal (dump_path, Vload_path))) - { - /* Do not make any changes. */ - return Vload_path; - } - else - { #ifdef HAVE_NS - const char *loadpath = ns_load_path (); - lpath = decode_env_path (0, loadpath ? loadpath : normal, 0); + const char *loadpath = ns_load_path (); + lpath = decode_env_path (0, loadpath ? loadpath : normal, 0); #else - lpath = decode_env_path (0, normal, 0); + lpath = decode_env_path (0, normal, 0); #endif - if (!NILP (Vinstallation_directory)) + if (!NILP (Vinstallation_directory)) + { + Lisp_Object tem, tem1; + + /* Add to the path the lisp subdir of the installation + dir, if it is accessible. Note: in out-of-tree builds, + this directory is empty save for Makefile. */ + tem = Fexpand_file_name (build_string ("lisp"), + Vinstallation_directory); + tem1 = Ffile_accessible_directory_p (tem); + if (!NILP (tem1)) { - Lisp_Object tem, tem1; - - /* Add to the path the lisp subdir of the installation - dir, if it is accessible. Note: in out-of-tree builds, - this directory is empty save for Makefile. */ - tem = Fexpand_file_name (build_string ("lisp"), - Vinstallation_directory); - tem1 = Ffile_accessible_directory_p (tem); - if (!NILP (tem1)) + if (NILP (Fmember (tem, lpath))) { - if (NILP (Fmember (tem, lpath))) - { - /* We are running uninstalled. The default load-path - points to the eventual installed lisp, leim - directories. We should not use those now, even - if they exist, so start over from a clean slate. */ - lpath = list1 (tem); - } + /* We are running uninstalled. The default load-path + points to the eventual installed lisp directories. + We should not use those now, even if they exist, + so start over from a clean slate. */ + lpath = list1 (tem); } - else - /* That dir doesn't exist, so add the build-time - Lisp dirs instead. */ - lpath = nconc2 (lpath, dump_path); + } + else + /* That dir doesn't exist, so add the build-time + Lisp dirs instead. */ + { + Lisp_Object dump_path = + decode_env_path (0, PATH_DUMPLOADSEARCH, 0); + lpath = nconc2 (lpath, dump_path); + } - /* Add leim under the installation dir, if it is accessible. */ - tem = Fexpand_file_name (build_string ("leim"), + /* Add site-lisp under the installation dir, if it exists. */ + if (!no_site_lisp) + { + tem = Fexpand_file_name (build_string ("site-lisp"), Vinstallation_directory); tem1 = Ffile_accessible_directory_p (tem); if (!NILP (tem1)) @@ -4245,82 +4266,59 @@ load_path_default (bool ignore_existing) if (NILP (Fmember (tem, lpath))) lpath = Fcons (tem, lpath); } + } - /* Add site-lisp under the installation dir, if it exists. */ - if (!no_site_lisp) - { - tem = Fexpand_file_name (build_string ("site-lisp"), - Vinstallation_directory); - tem1 = Ffile_accessible_directory_p (tem); - if (!NILP (tem1)) - { - if (NILP (Fmember (tem, lpath))) - lpath = Fcons (tem, lpath); - } - } + /* If Emacs was not built in the source directory, + and it is run from where it was built, add to load-path + the lisp and site-lisp dirs under that directory. */ - /* If Emacs was not built in the source directory, - and it is run from where it was built, add to load-path - the lisp, leim and site-lisp dirs under that directory. */ + if (NILP (Fequal (Vinstallation_directory, Vsource_directory))) + { + Lisp_Object tem2; - if (NILP (Fequal (Vinstallation_directory, Vsource_directory))) + tem = Fexpand_file_name (build_string ("src/Makefile"), + Vinstallation_directory); + tem1 = Ffile_exists_p (tem); + + /* Don't be fooled if they moved the entire source tree + AFTER dumping Emacs. If the build directory is indeed + different from the source dir, src/Makefile.in and + src/Makefile will not be found together. */ + tem = Fexpand_file_name (build_string ("src/Makefile.in"), + Vinstallation_directory); + tem2 = Ffile_exists_p (tem); + if (!NILP (tem1) && NILP (tem2)) { - Lisp_Object tem2; - - tem = Fexpand_file_name (build_string ("src/Makefile"), - Vinstallation_directory); - tem1 = Ffile_exists_p (tem); - - /* Don't be fooled if they moved the entire source tree - AFTER dumping Emacs. If the build directory is indeed - different from the source dir, src/Makefile.in and - src/Makefile will not be found together. */ - tem = Fexpand_file_name (build_string ("src/Makefile.in"), - Vinstallation_directory); - tem2 = Ffile_exists_p (tem); - if (!NILP (tem1) && NILP (tem2)) - { - tem = Fexpand_file_name (build_string ("lisp"), - Vsource_directory); + tem = Fexpand_file_name (build_string ("lisp"), + Vsource_directory); - if (NILP (Fmember (tem, lpath))) - lpath = Fcons (tem, lpath); + if (NILP (Fmember (tem, lpath))) + lpath = Fcons (tem, lpath); - tem = Fexpand_file_name (build_string ("leim"), + if (!no_site_lisp) + { + tem = Fexpand_file_name (build_string ("site-lisp"), Vsource_directory); - - if (NILP (Fmember (tem, lpath))) - lpath = Fcons (tem, lpath); - - if (!no_site_lisp) + tem1 = Ffile_accessible_directory_p (tem); + if (!NILP (tem1)) { - tem = Fexpand_file_name (build_string ("site-lisp"), - Vsource_directory); - tem1 = Ffile_accessible_directory_p (tem); - if (!NILP (tem1)) - { - if (NILP (Fmember (tem, lpath))) - lpath = Fcons (tem, lpath); - } + if (NILP (Fmember (tem, lpath))) + lpath = Fcons (tem, lpath); } } - } /* Vinstallation_directory != Vsource_directory */ - - } /* if Vinstallation_directory */ + } + } /* Vinstallation_directory != Vsource_directory */ - } /* if dump_path == Vload_path */ + } /* if Vinstallation_directory */ } else /* !initialized */ { /* NORMAL refers to PATH_DUMPLOADSEARCH, ie the lisp dir in the source directory. We used to add ../lisp (ie the lisp dir in - the build directory) at the front here, but that caused trouble - because it was copied from dump_path into Vload_path, above, - when Vinstallation_directory was non-nil. It should not be - necessary, since in out of tree builds lisp/ is empty, save + the build directory) at the front here, but that should not + be necessary, since in out of tree builds lisp/ is empty, save for Makefile. */ lpath = decode_env_path (0, normal, 0); - dump_path = lpath; } #endif /* !CANNOT_DUMP */ @@ -4332,19 +4330,26 @@ init_lread (void) { /* First, set Vload_path. */ - /* We explicitly ignore EMACSLOADPATH when dumping. */ - if (NILP (Vpurify_flag) && egetenv ("EMACSLOADPATH")) + /* Ignore EMACSLOADPATH when dumping. */ +#ifdef CANNOT_DUMP + bool use_loadpath = true; +#else + bool use_loadpath = !NILP (Vpurify_flag); +#endif + + if (use_loadpath && egetenv ("EMACSLOADPATH")) { Vload_path = decode_env_path ("EMACSLOADPATH", 0, 1); /* Check (non-nil) user-supplied elements. */ load_path_check (Vload_path); - /* Replace any nil elements from the environment with the default. */ - if (!NILP (Fmemq (Qnil, Vload_path))) + /* If no nils in the environment variable, use as-is. + Otherwise, replace any nils with the default. */ + if (! NILP (Fmemq (Qnil, Vload_path))) { - Lisp_Object lpath = Vload_path; - Lisp_Object elem, default_lpath = load_path_default (1); + Lisp_Object elem, elpath = Vload_path; + Lisp_Object default_lpath = load_path_default (); /* Check defaults, before adding site-lisp. */ load_path_check (default_lpath); @@ -4361,11 +4366,11 @@ init_lread (void) Vload_path = Qnil; /* Replace nils from EMACSLOADPATH by default. */ - while (CONSP (lpath)) + while (CONSP (elpath)) { Lisp_Object arg[2]; - elem = XCAR (lpath); - lpath = XCDR (lpath); + elem = XCAR (elpath); + elpath = XCDR (elpath); arg[0] = Vload_path; arg[1] = NILP (elem) ? default_lpath : Fcons (elem, Qnil); Vload_path = Fappend (2, arg); @@ -4374,8 +4379,7 @@ init_lread (void) } else /* Vpurify_flag || !EMACSLOADPATH */ { - Lisp_Object lpath = Vload_path; - Vload_path = load_path_default (0); + Vload_path = load_path_default (); /* Check before adding site-lisp directories. The install should have created them, but they are not @@ -4383,11 +4387,8 @@ init_lread (void) Or we might be running before installation. */ load_path_check (Vload_path); - /* Add the site-lisp directories at the front, unless the - load-path has somehow already been changed (this can only be - from a site-load file during dumping?) from the dumped value. - FIXME? Should we ignore any dump_path changes? */ - if (initialized && !no_site_lisp && !NILP (Fequal (dump_path, lpath))) + /* Add the site-lisp directories at the front. */ + if (initialized && !no_site_lisp) { Lisp_Object sitelisp; sitelisp = decode_env_path (0, PATH_SITELOADSEARCH, 0); @@ -4668,6 +4669,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"); @@ -4692,8 +4704,6 @@ variables, this must be set in the first line of a file. */); DEFSYM (Qdir_ok, "dir-ok"); DEFSYM (Qdo_after_load_evaluation, "do-after-load-evaluation"); - staticpro (&dump_path); - staticpro (&read_objects); read_objects = Qnil; staticpro (&seen_list);