Subject: bug#72333: builtin native-compiled is loaded instead of emacs-packages

From: Simon Tournier <[email-masked]>
Date: Mon, 02 Sep 2024 20:55:15 +0200

Hi,

Alvin Hsu

Once bisecting, the first occurrence appears with:

        7a2fc32ba2cec79b087932f30d77751f9133d740
        CommitDate: Sun Jul 21 13:32:27 2024 +0200
        Parent:     bb1aea46e6 gnu: emacs-gnosis: Update to 0.3.2.

        gnu: emacs-magit: Update to 3.3.0-8.538cb2f

        * gnu/packages/emacs-xyz.scm (emacs-magit): Update to 3.3.0-8.538cb2f.

        A.o. it contains the fix for https://github.com/magit/magit/issues/4940 which is a showstopper.

        Change-Id: Id83a237d38c03a97f9f1043db4b8ba594521a2f7

This update of emacs-magit depends on transient-prefix-object, i.e., it
depends on a new version of transient.

--8<---------------cut here---------------start------------->8---
$ ag transient-prefix-object \
     $(guix time-machine -q --commit=7a2fc32ba2cec79b087932f30d77751f9133d740 -- build emacs-magit -S)
/gnu/store/fgcz4a4adhnrcxa541kdkn30f0hgn6c5-emacs-magit-3.3.0-8.538cb2f-checkout/lisp/magit-branch.el
213:              (oref (transient-prefix-object) scope)))
217:             (propertize (oref (transient-prefix-object) scope)
866:             (propertize (oref (transient-prefix-object) scope)
910:  (when-let* ((branch (oref (transient-prefix-object) scope))
918:    (magit-read-upstream-branch (oref (transient-prefix-object) scope)
922:  (magit-set-upstream-branch (oref (transient-prefix-object) scope) refname)
924:        (and-let* ((branch (oref (transient-prefix-object) scope))
931:  (let ((branch (oref (transient-prefix-object) scope)))

/gnu/store/fgcz4a4adhnrcxa541kdkn30f0hgn6c5-emacs-magit-3.3.0-8.538cb2f-checkout/lisp/magit-remote.el
73:              (oref (transient-prefix-object) scope)))
318:             (propertize (oref (transient-prefix-object) scope)
--8<---------------cut here---------------end--------------->8---

When the commit parent does not:

    $ ag transient-prefix-object \
        $(guix time-machine -q --commit=bb1aea46e6 -- build emacs-magit -S)

However, it should be an issue since emacs-transient is correctly
updated and correctly contains the requirements.

--8<---------------cut here---------------start------------->8---
$ ag transient-prefix-object \
     $(guix time-machine -q --commit=bb1aea46e6 -- build emacs-transient)
/gnu/store/8zwwwprv93shxjjfcc4a406gs9qgk58i-emacs-transient-0.7.2/share/emacs/site-lisp/transient-0.7.2/transient.el
1605:(defun transient-prefix-object ()
3044:               (format "levels > %s" (oref (transient-prefix-object) level))
3058:  (transient-set-value (transient-prefix-object)))
3066:  (transient-save-value (transient-prefix-object)))
3074:  (transient-reset-value (transient-prefix-object)))
3607:  (oref (transient-prefix-object) scope))
--8<---------------cut here---------------end--------------->8---

Therefore, the issue…

On Fri, 30 Aug 2024 at 18:33, Simon Tournier <[email-masked]> wrote:

> Why is emacs-transient not loaded?

…is something about loading Emacs Lisp code.

--8<---------------cut here---------------start------------->8---
$ guix time-machine -q --commit=bb1aea46e6 \
       -- shell emacs emacs-transient \
       -- emacs --batch --eval "(progn (require 'transient) (transient-prefix-object) (print \"done\"))"
 
Error: void-function (transient-prefix-object)
  mapbacktrace(#f(compiled-function (evald func args flags) #<bytecode 0x5d8e1c931aef1bf>))
  debug-early-backtrace()
  debug-early(error (void-function transient-prefix-object))
  (transient-prefix-object)
  (progn (require 'transient) (transient-prefix-object) (print "done"))
  command-line-1(("--eval" "(progn (require 'transient) (transient-prefix-object) (print \"done\"))"))
  command-line()
  normal-top-level()
Symbol’s function definition is void: transient-prefix-object
--8<---------------cut here---------------end--------------->8---

Compared to:

--8<---------------cut here---------------start------------->8---
$ guix time-machine -q --commit=bb1aea46e6 \
       -- shell emacs emacs-transient \
       -- emacs --batch --eval "(progn (load (locate-library \"transient\")) (transient-prefix-object) (print \"done\"))"

Loading /gnu/store/8zwwwprv93shxjjfcc4a406gs9qgk58i-emacs-transient-0.7.2/share/emacs/site-lisp/transient-0.7.2/transient.elc...

"done"
--8<---------------cut here---------------end--------------->8---

Now, if native compilation is not able to find .eln files then all work
as expected.

--8<---------------cut here---------------start------------->8---
$ guix time-machine -q --commit=bb1aea46e6 \
       -- shell emacs emacs-transient \
       -- emacs --batch --eval "(progn (setq native-comp-eln-load-path nil) (require 'transient) (transient-prefix-object) (print \"done\"))"
 
"done"
--8<---------------cut here---------------end--------------->8---

Other said, the bug is not about Magit or Transient but the bug is about
all native-compiled Emacs Lisp code that are part of builtin Emacs:
these are loaded and not the ones from packages if provided.

About the example of Org-mode, I guess ’org-version’ is not marked for
the compilation and that’s why it works in appearances.

Well, maybe that’s a bug known upstream (I have not checked) and maybe
this behaviour has already been reported for Guix.  In both cases,
that’s annoying because it means that emacs-packages are useless as
dependencies since builtin is always used instead.

Somehow, one solution would to not provide native-compilation of source
code that is developed outside the Emacs tree (transient, Magit, etc.)
and let user locally native-compile them.

Or another solution would to split ’native-comp-eln-load-path’.  Say one
folder for builtin code that we know is developed outside Emacs tree,
e.g., transient, Org, etc. And append them in EMACSNATIVELOADPATH by
default.  When a known package is provided by the user, the builtin path
is removed from EMACSNATIVELOADPATH (and the package path could be added
if emacs-build-system native-compile them).

Cheers,
simon