ASDF:UPGRADE-ASDF leaves UIOP system definition broken
It appears that asdf:upgrade-asdf
can leave the UIOP system definition in a broken state. A side effect of this (and how I noticed it) is that a dependency such as (:version "uiop" "3.3.2")
is very difficult to satisfy on SBCL if you follow the recommended install procedure.
Example using SBCL (ships with ASDF 3.3.1) and asdf cloned to ~/common-lisp/asdf/
:
sbcl --noinform --no-userinit --no-sysinit --eval '(require :asdf)' --eval '(asdf:upgrade-asdf)' --eval '(format t "UIOP system version: ~S~%" (asdf:component-version (asdf:find-system "uiop")))' --eval '(format t "UIOP:*UIOP-VERSION*: ~S~%" uiop:*uiop-version*)' --quit
UIOP system version: "3.3.1"
UIOP:*UIOP-VERSION*: "3.3.5.3"
Compared with:
sbcl --noinform --no-userinit --no-sysinit --eval '(require :asdf)' --eval '(asdf:find-system "uiop")' --eval '(asdf:upgrade-asdf)' --eval '(format t "UIOP system version: ~S~%" (asdf:component-version (asdf:find-system "uiop")))' --eval '(format t "UIOP:*UIOP-VERSION*: ~S~%" uiop:*uiop-version*)' --quit
WARNING: redefining ASDF/INTERFACE::CALL-WITHOUT-REDEFINITION-WARNINGS in DEFUN
UIOP system version: "3.3.5.3"
UIOP:*UIOP-VERSION*: "3.3.5.3"
The only difference is that in the second there's a call to (asdf:find-system "uiop")
before ASDF is upgraded.
In addition to the version number being broken, things like system-relative-pathname
and basically anything else you can do with a system object are broken in the first example.
Here's what I think is happening in the first case:
-
upgrade-asdf
performs a(load-system "asdf")
. - It seems that since 3.3, the asdf system no longer depends on UIOP directly. Instead, its files are transcluded into the asdf/driver system.
- UIOP's sources are loaded via the asdf/driver system, so uiop really is v3.3.5.3 like
*uiop-version*
claims. - Any further calls to
(find-system "uiop")
silently ignore uiop.asd since its version is not strictly greater than ASDF's version https://gitlab.common-lisp.net/asdf/asdf/-/blob/ecd378670b3dd3dba476e9d3110f831b81b2c16e/find-system.lisp#L147. Instead, the original preloaded UIOP system that came from(require "asdf")
is returned.
The second case bypasses this because (find-system "uiop")
does not trigger an ASDF upgrade. So ASDF successfully finds and registers uiop.asd, replacing the preloaded system.
I see three options to fix this:
- Have
upgrade-asdf
do something like(if-let ((uiop (find-system "uiop" nil))) (load-system uiop))
before loading asdf. I really don't want to do this. - Allow
find-system
to return a system for UIOP so long as the found system is at least as new as the currently loaded version. - Fix things up so that https://gitlab.common-lisp.net/asdf/asdf/-/blob/1a69ba6c6cd6dedaf9f923dbb3dfc2bab29aeb18/footer.lisp#L23 causes the preloaded systems to be re-registered. I believe this doesn't work currently because
ensure-preloaded-system-registered
short-circuits if the system to be registered is already registered, even if there's a version mismatch.
Now that I've written this all down, I think 3 is the best way to go, with 2 as a close second. 3 in isolation would make the version number on the system object correct, but everything else would remain blank. This means things like system-relative-pathname
wouldn't work for UIOP, but it's highly unlikely people are currently using that.
In any case, chalk up another example for #83 (closed).