guix/gnu/packages/patches/emacs-native-comp-fix-filenames.patch
Liliana Marie Prikler e2b04973fd
gnu: emacs: Don't hash file names in native compilation.
* gnu/packages/patches/emacs-native-comp-fix-filenames.patch: New file.
* gnu/local.mk (dist_patch_DATA): Register it here.
* gnu/packages/emacs.scm (emacs-minimal)[source]: Use it here.

Change-Id: I2b7f6b45742a985760f0097bb53910f068e3d8e5
2024-02-24 07:26:51 +01:00

338 lines
14 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.
In addition, this patch changes how native-comp-eln-load-path is
constructed. Upstream, an entry of the directory “../lisp” is added
supposedly for bootstrap only, but this directory appears to find its
way into the actual variable despite attempts to remove it by calling
startup--update-eln-cache.
The user-visible procedure startup-redirect-eln-cache is kept, as
packages may require it, but only pushes the new value now.
Index: emacs-29.2/src/comp.c
===================================================================
--- emacs-29.2.orig/src/comp.c
+++ emacs-29.2/src/comp.c
@@ -4396,26 +4396,17 @@ 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. */)
(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 +4414,55 @@ 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.
-
- '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))
- {
- 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 tail = Vload_path;
+ Lisp_Object name_len = Flength (filename);
- Lisp_Object lds_re_tail = loadsearch_re_list;
- FOR_EACH_TAIL (lds_re_tail)
+ FOR_EACH_TAIL_SAFE (tail)
{
- Lisp_Object match_idx =
- Fstring_match (XCAR (lds_re_tail), filename, Qnil, Qnil);
- if (BASE_EQ (match_idx, make_fixnum (0)))
+ Lisp_Object directory = Ffile_name_as_directory (XCAR (tail));
+ Lisp_Object len = Flength (directory);
+ if (XFIXNUM (name_len) < XFIXNUM (len))
+ continue;
+ else if (EQ (Qt, Fcompare_strings (filename, make_fixnum (0), len,
+ directory, make_fixnum (0), len,
+ Qnil)))
{
- filename =
- Freplace_match (build_string ("//"), Qt, Qt, filename, Qnil);
+ filename = Fsubstring (filename, 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 (file_name_absolute_p (filename)) /* no match in load-path */
+ 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 directory = Ffile_name_as_directory (XCAR (tail));
+ Lisp_Object len = Flength (directory);
+ if (XFIXNUM (name_len) < XFIXNUM (len))
+ continue;
+ else if (EQ (Qt, Fcompare_strings (filename, make_fixnum (0), len,
+ directory, make_fixnum (0), len,
+ Qnil)))
+ {
+ filename = Fsubstring (filename, 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 +4476,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;
@@ -4548,10 +4524,11 @@ the latter is supposed to be used by the
Lisp_Object lisp_preloaded =
Fgetenv_internal (build_string ("LISP_PRELOADED"), Qnil);
base_dir = Fexpand_file_name (Vcomp_native_version_dir, base_dir);
+ bool preloaded = comp_file_preloaded_p;
if (comp_file_preloaded_p
|| (!NILP (lisp_preloaded)
- && !NILP (Fmember (CALL1I (file-name-base, source_filename),
- Fmapcar (intern_c_string ("file-name-base"),
+ && !NILP (Fmember (CALL1I (file-name-sans-extension, source_filename),
+ Fmapcar (intern_c_string ("file-name-sans-extension"),
CALL1I (split-string, lisp_preloaded))))))
base_dir = Fexpand_file_name (build_string ("preloaded"), base_dir);
@@ -5863,10 +5840,7 @@ The last directory of this list is assum
the system *.eln files, which are the files produced when building
Emacs. */);
- /* Temporary value in use for bootstrap. We can't do better as
- `invocation-directory' is still unset, will be fixed up during
- dump reload. */
- Vnative_comp_eln_load_path = Fcons (build_string ("../native-lisp/"), Qnil);
+ Vnative_comp_eln_load_path = Qnil;
DEFVAR_LISP ("native-comp-enable-subr-trampolines",
Vnative_comp_enable_subr_trampolines,
Index: emacs-29.2/lisp/startup.el
===================================================================
--- emacs-29.2.orig/lisp/startup.el
+++ emacs-29.2/lisp/startup.el
@@ -545,9 +545,6 @@ DIRS are relative."
(defvar native-comp-jit-compilation)
(defvar native-comp-enable-subr-trampolines)
-(defvar startup--original-eln-load-path nil
- "Original value of `native-comp-eln-load-path'.")
-
(defun startup-redirect-eln-cache (cache-directory)
"Redirect the user's eln-cache directory to CACHE-DIRECTORY.
CACHE-DIRECTORY must be a single directory, a string.
@@ -558,22 +555,10 @@ to `user-emacs-directory'.
For best results, call this function in your early-init file,
so that the rest of initialization and package loading uses
the updated value."
- ;; Remove the original eln-cache.
- (setq native-comp-eln-load-path (cdr native-comp-eln-load-path))
- ;; Add the new eln-cache.
(push (expand-file-name (file-name-as-directory cache-directory)
user-emacs-directory)
native-comp-eln-load-path))
-(defun startup--update-eln-cache ()
- "Update the user eln-cache directory due to user customizations."
- ;; Don't override user customizations!
- (when (equal native-comp-eln-load-path
- startup--original-eln-load-path)
- (startup-redirect-eln-cache "eln-cache")
- (setq startup--original-eln-load-path
- (copy-sequence native-comp-eln-load-path))))
-
(defun normal-top-level ()
"Emacs calls this function when it first starts up.
It sets `command-line-processed', processes the command-line,
@@ -1362,12 +1347,6 @@ please check its value")
startup-init-directory)))
(setq early-init-file user-init-file)
- ;; Amend `native-comp-eln-load-path', since the early-init file may
- ;; have altered `user-emacs-directory' and/or changed the eln-cache
- ;; directory.
- (when (featurep 'native-compile)
- (startup--update-eln-cache))
-
;; If any package directory exists, initialize the package system.
(and user-init-file
package-enable-at-startup
@@ -1502,12 +1481,6 @@ please check its value")
startup-init-directory))
t)
- ;; Amend `native-comp-eln-load-path' again, since the early-init
- ;; file may have altered `user-emacs-directory' and/or changed the
- ;; eln-cache directory.
- (when (featurep 'native-compile)
- (startup--update-eln-cache))
-
(when (and deactivate-mark transient-mark-mode)
(with-current-buffer (window-buffer)
(deactivate-mark)))
Index: emacs-29.2/lisp/loadup.el
===================================================================
--- emacs-29.2.orig/lisp/loadup.el
+++ emacs-29.2/lisp/loadup.el
@@ -53,6 +53,14 @@
(setq redisplay--inhibit-bidi t)
(message "Dump mode: %s" dump-mode)
+;; Compensate for native-comp-eln-load-path being empty by Guix' default.
+(and (featurep 'native-compile)
+ dump-mode
+ (setq
+ native-comp-eln-load-path
+ (cons (expand-file-name "../native-lisp" invocation-directory)
+ native-comp-eln-load-path)
+ comp-file-preloaded-p t))
;; Add subdirectories to the load-path for files that might get
;; autoloaded when bootstrapping or running Emacs normally.
@@ -494,22 +502,20 @@ lost after dumping")))
(concat eln-dest-dir "native-lisp/" comp-native-version-dir "/"))
(maphash (lambda (_ cu)
(let* ((file (native-comp-unit-file cu))
- (preloaded (equal (substring (file-name-directory file)
- -10 -1)
- "preloaded"))
- (eln-dest-dir-eff (if preloaded
- (expand-file-name "preloaded"
- eln-dest-dir)
- eln-dest-dir)))
+ (native-lisp-needle
+ (regexp-quote (concat "native-lisp/"
+ comp-native-version-dir "/"))))
(native-comp-unit-set-file
cu
(cons
;; Relative filename from the installed binary.
- (file-relative-name (expand-file-name
- (file-name-nondirectory
- file)
- eln-dest-dir-eff)
- bin-dest-dir)
+ (file-relative-name
+ (expand-file-name
+ (save-match-data
+ (string-match native-lisp-needle file)
+ (substring file (match-end 0)))
+ eln-dest-dir)
+ bin-dest-dir)
;; Relative filename from the built uninstalled binary.
(file-relative-name file invocation-directory)))))
comp-loaded-comp-units-h)))
@@ -557,7 +563,9 @@ lost after dumping")))
(equal dump-mode "pdump"))
;; Don't enable this before bootstrap is completed, as the
;; compiler infrastructure may not be usable yet.
- (setq native-comp-enable-subr-trampolines t))
+ (setq native-comp-enable-subr-trampolines t
+ ;; We loaded everything we could.
+ comp-file-preloaded-p nil))
(message "Dumping under the name %s" output)
(condition-case ()
(delete-file output)
Index: emacs-29.2/src/Makefile.in
===================================================================
--- emacs-29.2.orig/src/Makefile.in
+++ emacs-29.2/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.