Upstream hashes both the absolute file name and the content of a file to derive the name for the natively compiled files. This breaks the staged install used in guix, as any $GUIX_PROFILE is distinct from the build directory. It also breaks grafts, as hardcoded store file names get rewritten; thus changing the file hash. Index: emacs-29.1/src/comp.c =================================================================== --- emacs-29.1.orig/src/comp.c +++ emacs-29.1/src/comp.c @@ -4396,26 +4396,18 @@ DEFUN ("comp-el-to-eln-rel-filename", Fc Scomp_el_to_eln_rel_filename, 1, 1, 0, doc: /* Return the relative name of the .eln file for FILENAME. FILENAME must exist, and if it's a symlink, the target must exist. -If FILENAME is compressed, it must have the \".gz\" extension, -and Emacs must have been compiled with zlib; the file will be -uncompressed on the fly to hash its contents. -Value includes the original base name, followed by 2 hash values, -one for the file name and another for its contents, followed by .eln. */) +FILENAME is resolved relative to `load-path' and only the suffix of +the first matching path is kept. If FILENAME is not found to be relative +to any directory `load-path', it is used as-is to construct the return +value. Further, if the NATIVE_COMP_BOGUS_DIRS environment variable is set, +the first matching prefix mentioned in it will be stripped as well. */) (Lisp_Object filename) { CHECK_STRING (filename); - /* Resolve possible symlinks in FILENAME, so that path_hash below - always compares equal. (Bug#44701). */ - filename = Fexpand_file_name (filename, Qnil); - char *file_normalized = realpath (SSDATA (ENCODE_FILE (filename)), NULL); - if (file_normalized) - { - filename = DECODE_FILE (make_unibyte_string (file_normalized, - strlen (file_normalized))); - xfree (file_normalized); - } + Lisp_Object rel_name = filename; + filename = Fexpand_file_name (filename, Qnil); if (NILP (Ffile_exists_p (filename))) xsignal1 (Qfile_missing, filename); @@ -4423,64 +4415,53 @@ one for the file name and another for it filename = Fw32_long_file_name (filename); #endif - Lisp_Object content_hash = comp_hash_source_file (filename); - - if (suffix_p (filename, ".gz")) - filename = Fsubstring (filename, Qnil, make_fixnum (-3)); - - /* We create eln filenames with an hash in order to look-up these - starting from the source filename, IOW have a relation - - /absolute/path/filename.el + content -> - eln-cache/filename-path_hash-content_hash.eln. + Lisp_Object tail = Vload_path; + Lisp_Object name_len = Flength (filename); - 'dlopen' can return the same handle if two shared with the same - filename are loaded in two different times (even if the first was - deleted!). To prevent this scenario the source file content is - included in the hashing algorithm. - - As at any point in time no more then one file can exist with the - same filename, should be possible to clean up all - filename-path_hash-* except the most recent one (or the new one - being recompiled). - - As installing .eln files compiled during the build changes their - absolute path we need an hashing mechanism that is not sensitive - to that. For this we replace if match PATH_DUMPLOADSEARCH or - *PATH_REL_LOADSEARCH with '//' before computing the hash. */ - - if (NILP (loadsearch_re_list)) + FOR_EACH_TAIL_SAFE (tail) { - Lisp_Object sys_re = - concat2 (build_string ("\\`[[:ascii:]]+"), - Fregexp_quote (build_string ("/" PATH_REL_LOADSEARCH "/"))); - Lisp_Object dump_load_search = - Fexpand_file_name (build_string (PATH_DUMPLOADSEARCH "/"), Qnil); -#ifdef WINDOWSNT - dump_load_search = Fw32_long_file_name (dump_load_search); -#endif - loadsearch_re_list = list2 (sys_re, Fregexp_quote (dump_load_search)); - } - - Lisp_Object lds_re_tail = loadsearch_re_list; - FOR_EACH_TAIL (lds_re_tail) - { - Lisp_Object match_idx = - Fstring_match (XCAR (lds_re_tail), filename, Qnil, Qnil); - if (BASE_EQ (match_idx, make_fixnum (0))) + Lisp_Object len = Flength (XCAR (tail)); + if (XFIXNUM (name_len) < XFIXNUM (len)) + continue; + else if (EQ (Qt, Fcompare_strings (filename, make_fixnum (0), len, + XCAR (tail), make_fixnum (0), len, + Qnil))) { - filename = - Freplace_match (build_string ("//"), Qt, Qt, filename, Qnil); + filename = Fsubstring (filename, Fadd1 (len), Qnil); break; } } - Lisp_Object separator = build_string ("-"); - Lisp_Object path_hash = comp_hash_string (filename); - filename = concat2 (Ffile_name_nondirectory (Fsubstring (filename, Qnil, - make_fixnum (-3))), - separator); - Lisp_Object hash = concat3 (path_hash, separator, content_hash); - return concat3 (filename, hash, build_string (NATIVE_ELISP_SUFFIX)); + + if (Ffile_name_absolute_p (filename)) + filename = rel_name; + + Lisp_Object bogus_dirs = + Fgetenv_internal (build_string ("NATIVE_COMP_BOGUS_DIRS"), Qnil); + + if (!NILP (bogus_dirs)) + { + tail = CALL2I (split-string, bogus_dirs, build_string (":")); + + FOR_EACH_TAIL_SAFE (tail) + { + Lisp_Object len = Flength (XCAR (tail)); + if (XFIXNUM (name_len) < XFIXNUM (len)) + continue; + else if (EQ (Qt, Fcompare_strings (filename, make_fixnum (0), len, + XCAR (tail), make_fixnum (0), len, + Qnil))) + { + filename = Fsubstring (filename, Fadd1 (len), Qnil); + break; + } + } + } + + if (suffix_p (filename, ".gz")) + filename = Fsubstring (filename, Qnil, make_fixnum (-3)); + + return concat2(Fsubstring (filename, Qnil, make_fixnum (-3)), + build_string (NATIVE_ELISP_SUFFIX)); } DEFUN ("comp-el-to-eln-filename", Fcomp_el_to_eln_filename, @@ -4494,13 +4475,7 @@ If BASE-DIR is non-nil, use it as the di non-absolute BASE-DIR is interpreted as relative to `invocation-directory'. If BASE-DIR is omitted or nil, look for the first writable directory in `native-comp-eln-load-path', and use as BASE-DIR its subdirectory -whose name is given by `comp-native-version-dir'. -If FILENAME specifies a preloaded file, the directory for the .eln -file is the \"preloaded/\" subdirectory of the directory determined -as described above. FILENAME is considered to be a preloaded file if -the value of `comp-file-preloaded-p' is non-nil, or if FILENAME -appears in the value of the environment variable LISP_PRELOADED; -the latter is supposed to be used by the Emacs build procedure. */) +whose name is given by `comp-native-version-dir'. */) (Lisp_Object filename, Lisp_Object base_dir) { Lisp_Object source_filename = filename; @@ -4541,19 +4516,7 @@ the latter is supposed to be used by the if (!file_name_absolute_p (SSDATA (base_dir))) base_dir = Fexpand_file_name (base_dir, Vinvocation_directory); - - /* In case the file being compiled is found in 'LISP_PRELOADED' or - `comp-file-preloaded-p' is non-nil target for output the - 'preloaded' subfolder. */ - Lisp_Object lisp_preloaded = - Fgetenv_internal (build_string ("LISP_PRELOADED"), Qnil); base_dir = Fexpand_file_name (Vcomp_native_version_dir, base_dir); - if (comp_file_preloaded_p - || (!NILP (lisp_preloaded) - && !NILP (Fmember (CALL1I (file-name-base, source_filename), - Fmapcar (intern_c_string ("file-name-base"), - CALL1I (split-string, lisp_preloaded)))))) - base_dir = Fexpand_file_name (build_string ("preloaded"), base_dir); return Fexpand_file_name (filename, base_dir); } Index: emacs-29.1/src/Makefile.in =================================================================== --- emacs-29.1.orig/src/Makefile.in +++ emacs-29.1/src/Makefile.in @@ -553,6 +553,7 @@ shortlisp := $(filter-out ${shortlisp_fi ## We don't really need to sort, but may as well use it to remove duplicates. shortlisp := loaddefs.el loadup.el $(sort ${shortlisp}) export LISP_PRELOADED = ${shortlisp} +export NATIVE_COMP_BOGUS_DIRS lisp = $(addprefix ${lispsource}/,${shortlisp}) ## Construct full set of libraries to be linked.