Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposing another implementation of lisp-modules #155851

Closed
Uthar opened this issue Jan 20, 2022 · 74 comments
Closed

Proposing another implementation of lisp-modules #155851

Uthar opened this issue Jan 20, 2022 · 74 comments
Assignees
Labels
0.kind: bug Something is broken

Comments

@Uthar
Copy link
Contributor

Uthar commented Jan 20, 2022

Hi!

I made a small nix library (nix-cl), for working with ASDF and Quicklisp, which has been working great for me recently. The code is still a mess but I want to show it to you and see if it sparks interest.

Basically I think it could replace the current lisp-modules and provide a number of benefits.

If you'd like to test it out you should use direnv or source .envrc to get the examples working. (Have to set NIX_PATH).
(Also worth noting, I think that nixpkgs doesn't provide Clasp but it worked with my own version.)

I had these problems with lisp-modules - please correct me if I'm wrong here:

  • Had to read the source to find how to run a lisp wrapper (common-lisp.sh) - no documentation
  • It leaks FASL's into $HOME Common Lisp compilation files (fasl) are not being used #142604
  • Hard to work with Quicklisp (have to build everything ahead of time, which is slow): Reusing quicklisp-to-nix #150941
  • CFFI doesn't work on ABCL (the one library that I know of which requires a .jar in the CLASSPATH)
  • Can't have multiple lisps in one nix-shell because a lisp-with-packages is achieved by putting the libraries themselves in buildInputs and running the generic common-lisp.sh
  • Doesn't support ASDF systems where .asd is not in the root directory (e.g. jzon)

Which are improved in nix-cl:

  • Has some documentation on how to run a ${lisp}WithPackages
  • CL_SOURCE_REGISTRY, ASDF_OUTPUT_TRANSLATIONS are set in a granular way, per package
  • It generates nix expressions for everything in quicklisp, which works well because of Nix's laziness. One can then just pick what they want from that.
  • Can declare Java libraries for ABCL
  • abclWithPackages/cclWithPackages/eclWithPackages/sbclWithPackages etc. makes it possible to have multiple lisps in one nix-shell
  • Works for asd's not in root by using "//" suffix to CL_SOURCE_REGISTRY (cool feature of ASDF - manual)
  • Easy to package things not in quicklisp. Minimal package is pname,version,src.

There are issues with it still where I haven't had the need to fix them:

  • CLASSPATH handling assumes /share/java/*.jar (from fetchMavenArtifact)
  • Haven't handled the case where the manually defined packages could use the quicklisp-imported ones as dependencies (worked around by just copying the code to manual packages)
  • Java jars are included unnecessarily in non-java lisp wrappers
  • Weird prefix for libs beginning with a number (e.g. _3d-vectors)

@7c6f434c

@Uthar Uthar added the 0.kind: bug Something is broken label Jan 20, 2022
@7c6f434c
Copy link
Member

Copying manually the generated definitions for anything that depends on them sounds pretty bad (in the context of Nyxt being packaged like a non-Quicklisp package that depends on large amounts of whatever)…

Is compilation supposed to happen for all the stuff in withPackages at once?

@Uthar
Copy link
Contributor Author

Uthar commented Jan 20, 2022

yeah it's all pre-compiled at once

when it comes to compilatioin, there was another problems that I had:

  • cl-unicode generates files during compilation, which failed when ASDF output is set to storeDir. Workaround was to compile first into pwd, then use $out of that as an $src of the next build

@Uthar
Copy link
Contributor Author

Uthar commented Jan 20, 2022

I haven't had problems with copying generated definitions. They are almost the same as the manually specified ones, with the exception that when building a system like cl-async-util which definition of is in cl-async.asd, a file cl-async-util.asd is created first. asd's other than the name of the system being built are removed to prevent runtime references to uncompiled sytems, so without such a hack systems like this cl-async-util were unloadable.

Now that I think about it it would have to be the same for the manual package, but I haven't had such a package yet. So in that case the ql imported things is just a way to save a lot of typing.

@7c6f434c
Copy link
Member

I have nothing against some special-case workarounds; I somewhat like the idea of binary cache compatibility, though.

About copying: it's trivial, but it needs some integration with mass updates for manual packages with tons of dependencies.

@Uthar
Copy link
Contributor Author

Uthar commented Jan 20, 2022

Hmmm I understand, that is problematic

interaction between the imported and manual packages is kind of tricky

Maybe I could load the quicklisp packages without rewriting their dependency trees at first, then load the manual packages and provide quicklisp imports as additional libraries. Just to break the current inter-dependency. Then go through the resulting thing and do whatever such as prefer manual libs to ql. Then build that derivation

@7c6f434c
Copy link
Member

Maybe a generator could do all the copying before use, though.

@Uthar
Copy link
Contributor Author

Uthar commented Jan 20, 2022

Are you thinking about a separate script that updates the file containing the manual packages? That could work . Or even a separate file, "ql-deps.nix" or something to keep the manual file clean

@7c6f434c
Copy link
Member

Basically how the current Lisp infrastructure just generates the Quicklisp data once as a nix file, yes.

@Uthar
Copy link
Contributor Author

Uthar commented Jan 21, 2022

the case where the manually defined packages could use the quicklisp-imported ones as dependencies

Added that in Uthar/nix-cl@a0eb90a

It was pretty productive because I could remove most of my package code and just reuse the QL generated things. So thanks a lot for this suggestion @7c6f434c!

For example, to pin the version of dexador which has these dependencies (lispLibs):

alexandria babel bordeaux-threads chipz chunga cl+ssl
cl-base64 cl-cookie cl-ppcre fast-http fast-io quri
trivial-features trivial-gray-streams trivial-mimes uiop usocket

this code in packages.nix works:

dexador = build-asdf-system {
  inherit (ql.dexador) pname lispLibs;
  version = "20220115";
  src = builtins.fetchTarball {
    url = "https://github.com/fukamachi/dexador/archive/03aaadf18b3cdcfa625627587951fa956bdf490f.tar.gz";
    sha256 = "0hwmzw9l2iqg4v0x59h4amr8bxmxdpc9nd8a3k6xji8g7v25idxw";
  };
};

Later on, it will simply pick up updates to its dependencies from the quicklisp generated file. At the same time, anything that depends on dexador, either QL-imported or declared manually, will now use this version of it.

Though now it's redundant with the extras mechanism in ql.nix. Meaning some customizations can be done in either ql.nix or packages.nix. Hmmm not sure what to do about that. Myself I would keep non-QL packages in packages.nix, and trivial fixes to QL packages (addded native library etc.) in ql.nix.

@7c6f434c
Copy link
Member

7c6f434c commented Jan 21, 2022 via email

@Uthar
Copy link
Contributor Author

Uthar commented Jan 21, 2022

I do directly read the quicklisp dependency data, then do some merging on it in the importer to capture dependencies of dependencies etc.

Most stuff that I tried building this way just worked - in case of problems a common one was a dependency on a "slashy" system. I ignore those in the importer because to it, a unit of granularity is the system, not the .asd file (that's why these files are created as necessary) - but "slashy" systems belong to the "root-name-part.asd" file. At the time I didn't know how to handle that, but maybe there is a way.

One of the cool things that I'm thinking about would be the ability to run Nix builds of the entire Quicklisp on Nix orgs' Hydra servers - probably a gazillion bugs would be uncovered. At least for sbcl/ccl where they have pretty fast compilers (?) Not really sure how that would look from resoures/political side.

Could you expand some more about the precompilation concept? If the concern is recompiling all libs for each wrapper, then that's not the case - the lisp packages themselves get compiled once (sbclPackages), then any lisp wrappers (sbclWithPackages) reuse that without recompiling anything (they just put together a wrapper shell script). Sorry, maybe I didn't understand your previous question correctly so the answer could be misleading.

@Uthar
Copy link
Contributor Author

Uthar commented Jan 21, 2022

My current workaround for slashy systems is to add them to the systems list of the thing that is being depended on. So, nyxt depends on iolib/pathname then I set iolib.systems to [ "iolib" "iolib/pathname" ]

@7c6f434c
Copy link
Member

7c6f434c commented Jan 21, 2022 via email

@7c6f434c
Copy link
Member

7c6f434c commented Jan 21, 2022 via email

@Uthar
Copy link
Contributor Author

Uthar commented Jan 21, 2022

There have been Quicklisp releases in the past with some more interesting problems in dependency data (which is where quicklisp-to-nix takes its motivation).

That's interesting. I only imported the QL releases 2021-12-30 and 2021-08-07 (that one had a bug with a missing dependency of clml). But the newer one removed quite some packages.

Even now CCL doesn't build 100% of lispPackages. SBCL might be doable. Quicklisp is actually somewhat small, so running everything on SBCL will probably end up doable even locally. And as we monotonically grow the set of packages we grab, just maxing it would not be that much of a surprise…

Hmm you're right. I could actually try building the whole of QL locally using SBCL (Currently that's 4310 packages). Or maybe start with the subset that's in lispPackages currently to compare both implementations.

Presumably, if you already grab the tarballs in the generator, you can as well unpack them and obtain the list of such systems, right?

That could be an option, but Quicklisp's systems.txt already contains those systems in the third column. I just skipped them for now for lack of a better idea. On the other hand, with 2021-12-30, nyxt seems to have a dependency on iolib/pathname that's undeclared in systems.txt. I have to check whether QL info even includes such systems in the dependencies column.

The problem for me was to somehow make slashy systems work with load-system. The reason that's problematic is:

  1. There can only be one foo system in a unique foo.asd file
  2. ASDF looks up foo/<...>'s in that same foo.asd

So in effect it "packs" a bunch of systems into a single .asd file, which is completely against what nix-cl understands.

There is the possiblity to simply always build every slashy subsystem of a system. But that could possibly add unnecessary dependencies in cases the slashy systems won't be used. Because real libraries use the foo/bar form, I don't see a possibility to generate some unique names from that either, unless patching ASDF itself. So maybe the "add slashy systems on an as-needed basis" approach is fine after all?

@Uthar
Copy link
Contributor Author

Uthar commented Jan 21, 2022

OK, I'll build the systems in quicklisp-to-nix-systems.txt using nix-cl and post an update.

@7c6f434c
Copy link
Member

I think the massive numbers of missed dependencies were quite long ago now.

slashy systems have yet another annoying habit of creating circular dependencies between .asd files, yeah.

@Uthar
Copy link
Contributor Author

Uthar commented Jan 22, 2022

Results for quicklisp-to-nix-systems.txt:

 SBCL: 252/252
  CCL: 249/252
  ECL: 234/252
 ABCL: 210/252
Clasp: 202/252

Gonna do the same for things in pkgs.lispPackages

@7c6f434c
Copy link
Member

From a glance, looks about right.

@Uthar
Copy link
Contributor Author

Uthar commented Jan 23, 2022

Status of lispPackages for SBCL and CCL:

SBCL: 379/384
 CCL: 375/384

Things that don't build are the slashy systems:

cl-postgres_slash_tests
cxml_slash_test
s-sql_slash_tests
simple-date_slash_postgres-glue
xpath_slash_test

And, additionally for CCL, three packages that are explicitly SBCL-only

nyxt
stumpwm
woo

Plus varjo, which has a CCL-specific bug upstream: cbaggers/varjo#243 - fixed but not yet in Quicklisp.

I would propose another solution to the slashy systems problem. On branch overridable-drv, I stole overridePythonAttrs from python-packages.nix and made it into overrideLispAttrs. So slashy-systems could now be built in an ad-hoc way.

Here's a cl-postgres+cl-postgres/tests:

sbclPackages.cl-postgres.overrideLispAttrs (old: {
  systems = old.systems ++ [ "cl-postgres/tests" ];
  lispLibs = old.lispLibs ++ [ sbclPackages.fiveam ];
})

This could even be used when a certain package depends on some slashy systems, to provide the dependency in an "anonymous" way - without cluttering the original sbclPackages.cl-postgres.

Given their "optionality" nature this seems pretty reasonable to me - what do you think?

@Uthar
Copy link
Contributor Author

Uthar commented Jan 23, 2022

Got a question about this line
This is what I had to do to make nyxt work for me, but not sure if this should be hard-coded like that? Maybe it's just a thing of my particular DE/setup?

@7c6f434c
Copy link
Member

7c6f434c commented Jan 23, 2022 via email

@7c6f434c
Copy link
Member

Hm, we do not seem to need this now. Does building an older version still need it in your setup?

@Uthar
Copy link
Contributor Author

Uthar commented Jan 23, 2022

I get the error with webkitgtk-2.34.4 (using nixpkgs master) , but only a warning with webkitgtk-2.32.3 (some old commit, ~20.09) when that variable is not set.

@7c6f434c
Copy link
Member

Hm, probably not DE-specific (not sure what their sandbox wants though)

@Uthar
Copy link
Contributor Author

Uthar commented Jan 23, 2022

To be precise, this is what happens:

  1. webkitgtk-2.34.4
** (nyxt:1097805): ERROR **: 15:18:18.273: Unable to configure xdg-desktop-portal access in the WebKit sandbox: GApplication is required.
<WARN> [15:18:18] Warning: Error on GTK thread: The value
  :INVALID-CODE-OBJECT-AT-PC
is not of type
  FUNCTION

** (process:1097805): ERROR (recursed) **: Unable to configure xdg-desktop-portal access in the WebKit sandbox: GApplication is required.fatal error encountered in SBCL pid 1097805 tid 1097819:
SIGABRT received.

   0: fp=0x2 pc=0x7fbbf4f08baa Foreign function gsignal
  1. webkitgtk-2.32.3

** (nyxt:1097629): WARNING **: 15:18:03.123: GApplication is required for xdg-desktop-portal access in the WebKit sandbox. Actions that require xdg-desktop-portal will be broken.

** (nyxt:1097629): WARNING **: 15:18:03.141: GApplication is required for xdg-desktop-portal access in the WebKit sandbox. Actions that require xdg-desktop-portal will be broken.

@7c6f434c
Copy link
Member

Ah, that might be dependent on having something installed in the profile, possibly via DE in system path…

Re: slashy systems — I think current generation logic defaults to including these systems and blocking the problematic ones. Maybe it's better to keep that approach?

@Uthar
Copy link
Contributor Author

Uthar commented Jan 23, 2022

Posting rest of CL implementations for completeness (lispPackages):

  ECL: 351/384
 ABCL: 322/384
Clasp: 288/384

@Uthar Uthar mentioned this issue Apr 24, 2022
13 tasks
@Uthar
Copy link
Contributor Author

Uthar commented Apr 29, 2022

We can change which .asd files get loaded, but once an .asd file get loaded, all systems from the file are going to get loaded from this file. And this is probably hard to work around.

Tested it a little bit, here are some results. I used:

 lispPackages_new.sbclWithPackages (p: 
   [ p.cl-async-base 
     p.cl-async-util 
     p.cl-async 
   ])

as an example, because all three contain the defsystem forms of each other, they were just copied to create the "missing" .asds.

* (require 'asdf)
("ASDF" "asdf" "UIOP" "uiop")

* (asdf:load-system 'cl-async-util)
T

* (asdf:system-source-directory 'cl-async-util)
#P"/nix/store/a66qzg4qgppbq1c9hwgl1hjy7gfxndc0-cl-async-util-20211020-git/"

* (asdf:load-system 'cl-async-base)
T

* (asdf:system-source-directory 'cl-async-util)
#P"/nix/store/a66qzg4qgppbq1c9hwgl1hjy7gfxndc0-cl-async-util-20211020-git/"
* (asdf:system-source-directory 'cl-async-base)
#P"/nix/store/x541kcj7sgv46vj5vr7832i76f3jz7km-cl-async-base-20211020-git/"

* (asdf:load-system 'cl-async)
T

* (asdf:system-source-directory 'cl-async)
#P"/nix/store/i386bh1i2c2aq9icd4nahi717f4dj9n9-cl-async-20211020-git/"
* (asdf:system-source-directory 'cl-async-base)
#P"/nix/store/x541kcj7sgv46vj5vr7832i76f3jz7km-cl-async-base-20211020-git/"
* (asdf:system-source-directory 'cl-async-util)
#P"/nix/store/a66qzg4qgppbq1c9hwgl1hjy7gfxndc0-cl-async-util-20211020-git/"

It breaks though when trying to load cl-async two times in a row, which is... weird:

* (require 'asdf)
("ASDF" "asdf" "UIOP" "uiop")
* (asdf:load-system 'cl-async)
T
* (asdf:load-system 'cl-async)
debugger invoked on a SB-INT:SIMPLE-FILE-ERROR in thread
#<THREAD "main thread" RUNNING {1004B88463}>:
  Error opening #P"/nix/store/x541kcj7sgv46vj5vr7832i76f3jz7km-cl-async-base-20211020-git/src/util/package-tmpGHU3ALSV.fasl":

    Read-only file system
0]

(invoke-restart 'ASDF:CLEAR-CONFIGURATION-AND-RETRY) makes it load, but no idea what are the consequences now.

@7c6f434c
Copy link
Member

7c6f434c commented Apr 29, 2022 via email

@teu5us
Copy link

teu5us commented Jun 15, 2022

Just tried this in 22.05. Besides the fact, that cl-async won't load the second time, it also breaks the same way when I require it the first time

@7c6f434c
Copy link
Member

I think require passes through to ASDF so it is not surprising the results are the same…

@teu5us
Copy link

teu5us commented Jun 17, 2022

It does, but it won't load cl-async even once unlike load-system

@7c6f434c
Copy link
Member

7c6f434c commented Jun 17, 2022 via email

@hraban
Copy link
Member

hraban commented Oct 18, 2022

I'm having problems with cl-async, though I can't exactly pin-point the problem because I'm no expert in neither asdf nor nix at this point.

Demo of failing build: https://github.com/hraban/nix-lisppackages-new-demo

Is this how you're supposed to use it? Specifically it's package cl-async that causes the problem. Other packages like alexandria work fine.

Full build error:

$ nix-build --arg pkgs "import /my/local/nixpkgs-master {}"
this derivation will be built:
  /nix/store/q5jjrwvnl6xw51dv9gzh8ppddf9qcdwy-demo-0.0.1.drv
building '/nix/store/q5jjrwvnl6xw51dv9gzh8ppddf9qcdwy-demo-0.0.1.drv'...
unpacking sources
unpacking source archive /nix/store/ij6b6n6xhllyjqlwxxa6awbzshnkjrsy-nix-lisppackages-new-demo
source root is nix-lisppackages-new-demo
patching sources
configuring
no configure script, doing nothing
building
WARNING: System definition file #P"/nix/store/snf7f23hcrzwsinb3d9zy0yknhb54f0v-cl-async-20211020-git/cl-async.asd" contains definition for system "cl-async-base". Please only define "cl-async" and secondary systems with a name starting with "cl-async/" (e.g. "cl-async/test") in that file.
WARNING: System definition file #P"/nix/store/snf7f23hcrzwsinb3d9zy0yknhb54f0v-cl-async-20211020-git/cl-async.asd" contains definition for system "cl-async-util". Please only define "cl-async" and secondary systems with a name starting with "cl-async/" (e.g. "cl-async/test") in that file.
WARNING: redefining DEFTYPE type to be a class: CL-ASYNC:SOCKET-CLOSED
WARNING: redefining DEFTYPE type to be a class: CL-ASYNC:TCP-EOF
WARNING: redefining DEFTYPE type to be a class: CL-ASYNC:TCP-INFO
WARNING: redefining DEFTYPE type to be a class: CL-ASYNC:TCP-ERROR
WARNING: redefining DEFTYPE type to be a class: CL-ASYNC:TCP-RESET
WARNING: redefining DEFTYPE type to be a class: CL-ASYNC:TCP-TIMEOUT
WARNING: redefining DEFTYPE type to be a class: CL-ASYNC:TCP-REFUSED
WARNING: redefining DEFTYPE type to be a class: CL-ASYNC:TCP-ACCEPT-ERROR
; compiling file "/nix/store/ij6b6n6xhllyjqlwxxa6awbzshnkjrsy-nix-lisppackages-new-demo/src/package.lisp" (written 01 JAN 1970 12:00:01 AM):

; wrote /private/tmp/nix-build-demo-0.0.1.drv-0/nix-lisppackages-new-demo/src/package-tmpGHU3ALSV.fasl
; compilation finished in 0:00:00.007
; compiling file "/nix/store/ij6b6n6xhllyjqlwxxa6awbzshnkjrsy-nix-lisppackages-new-demo/src/demo.lisp" (written 01 JAN 1970 12:00:01 AM):

; wrote /private/tmp/nix-build-demo-0.0.1.drv-0/nix-lisppackages-new-demo/src/demo-tmpAAURSO1.fasl
; compilation finished in 0:00:00.001
WARNING: System definition file #P"/nix/store/snf7f23hcrzwsinb3d9zy0yknhb54f0v-cl-async-20211020-git/cl-async.asd" contains definition for system "cl-async-base". Please only define "cl-async" and secondary systems with a name starting with "cl-async/" (e.g. "cl-async/test") in that file.
WARNING: System definition file #P"/nix/store/snf7f23hcrzwsinb3d9zy0yknhb54f0v-cl-async-20211020-git/cl-async.asd" contains definition for system "cl-async-util". Please only define "cl-async" and secondary systems with a name starting with "cl-async/" (e.g. "cl-async/test") in that file.
WARNING: redefining DEFTYPE type to be a class: CL-ASYNC:SOCKET-CLOSED
WARNING: redefining DEFTYPE type to be a class: CL-ASYNC:TCP-EOF
WARNING: redefining DEFTYPE type to be a class: CL-ASYNC:TCP-INFO
WARNING: redefining DEFTYPE type to be a class: CL-ASYNC:TCP-ERROR
WARNING: redefining DEFTYPE type to be a class: CL-ASYNC:TCP-RESET
WARNING: redefining DEFTYPE type to be a class: CL-ASYNC:TCP-TIMEOUT
WARNING: redefining DEFTYPE type to be a class: CL-ASYNC:TCP-REFUSED
WARNING: redefining DEFTYPE type to be a class: CL-ASYNC:TCP-ACCEPT-ERROR
WARNING: System definition file #P"/nix/store/h20fjqggj7mlzjd9rnbq3rvnszqfd8a8-cl-async-base-20211020-git/cl-async-base.asd" contains definition for system "cl-async-util". Please only define "cl-async-base" and secondary systems with a name starting with "cl-async-base/" (e.g. "cl-async-base/test") in that file.
WARNING: System definition file #P"/nix/store/h20fjqggj7mlzjd9rnbq3rvnszqfd8a8-cl-async-base-20211020-git/cl-async-base.asd" contains definition for system "cl-async". Please only define "cl-async-base" and secondary systems with a name starting with "cl-async-base/" (e.g. "cl-async-base/test") in that file.
Unhandled SB-INT:SIMPLE-FILE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING
                                                {10010800A3}>:
  Error opening #P"/nix/store/h20fjqggj7mlzjd9rnbq3rvnszqfd8a8-cl-async-base-20211020-git/src/util/package-tmpGHU3ALSV.fasl":

    Permission denied

Backtrace for: #<SB-THREAD:THREAD "main thread" RUNNING {10010800A3}>
0: (SB-DEBUG::DEBUGGER-DISABLED-HOOK #<SB-INT:SIMPLE-FILE-ERROR "Error opening ~S" {1001D10CE3}> #<unused argument> :QUIT T)
1: (SB-DEBUG::RUN-HOOK *INVOKE-DEBUGGER-HOOK* #<SB-INT:SIMPLE-FILE-ERROR "Error opening ~S" {1001D10CE3}>)
2: (INVOKE-DEBUGGER #<SB-INT:SIMPLE-FILE-ERROR "Error opening ~S" {1001D10CE3}>)
3: (ERROR SB-INT:SIMPLE-FILE-ERROR :PATHNAME #P"/nix/store/h20fjqggj7mlzjd9rnbq3rvnszqfd8a8-cl-async-base-20211020-git/src/util/package-tmpGHU3ALSV.fasl" :MESSAGE "Permission denied" :FORMAT-CONTROL "Error opening ~S" :FORMAT-ARGUMENTS (#P"/nix/store/h20fjqggj7mlzjd9rnbq3rvnszqfd8a8-cl-async-base-20211020-git/src/util/package-tmpGHU3ALSV.fasl"))
4: (SB-IMPL::FILE-PERROR #P"/nix/store/h20fjqggj7mlzjd9rnbq3rvnszqfd8a8-cl-async-base-20211020-git/src/util/package-tmpGHU3ALSV.fasl" 13 "Error opening ~S" #P"/nix/store/h20fjqggj7mlzjd9rnbq3rvnszqfd8a8-cl-async-base-20211020-git/src/util/package-tmpGHU3ALSV.fasl")
5: (SB-IMPL::%OPEN-ERROR #P"/nix/store/h20fjqggj7mlzjd9rnbq3rvnszqfd8a8-cl-async-base-20211020-git/src/util/package-tmpGHU3ALSV.fasl" 13 NIL :CREATE)
6: (OPEN #P"/nix/store/h20fjqggj7mlzjd9rnbq3rvnszqfd8a8-cl-async-base-20211020-git/src/util/package-tmpGHU3ALSV.fasl" :DIRECTION :IO :ELEMENT-TYPE :DEFAULT :IF-EXISTS NIL :IF-DOES-NOT-EXIST :CREATE :EXTERNAL-FORMAT :UTF-8 :CLASS SB-SYS:FD-STREAM)
7: (UIOP/STREAM:CALL-WITH-TEMPORARY-FILE #<FUNCTION (FLET "BEFORE234" :IN UIOP/STREAM::GET-TEMPORARY-FILE) {534FA74B}> :WANT-STREAM-P NIL :WANT-PATHNAME-P T :DIRECTION :IO :KEEP T :AFTER NIL :DIRECTORY #P"/nix/store/h20fjqggj7mlzjd9rnbq3rvnszqfd8a8-cl-async-base-20211020-git/src/util/" :TYPE "fasl" :PREFIX "package-tmp" :SUFFIX NIL :ELEMENT-TYPE NIL :EXTERNAL-FORMAT NIL)
8: (UIOP/LISP-BUILD:COMPILE-FILE* #P"/nix/store/h20fjqggj7mlzjd9rnbq3rvnszqfd8a8-cl-async-base-20211020-git/src/util/package.lisp" :OUTPUT-FILE #P"/nix/store/h20fjqggj7mlzjd9rnbq3rvnszqfd8a8-cl-async-base-20211020-git/src/util/package.fasl" :EXTERNAL-FORMAT :UTF-8 :WARNINGS-FILE NIL)
9: (ASDF/LISP-ACTION:PERFORM-LISP-COMPILATION #<ASDF/LISP-ACTION:COMPILE-OP > #<ASDF/LISP-ACTION:CL-SOURCE-FILE "cl-async-util" "src/util/package">)
10: ((SB-PCL::EMF ASDF/ACTION:PERFORM) #<unused argument> #<unused argument> #<ASDF/LISP-ACTION:COMPILE-OP > #<ASDF/LISP-ACTION:CL-SOURCE-FILE "cl-async-util" "src/util/package">)
11: ((LAMBDA NIL :IN ASDF/ACTION:CALL-WHILE-VISITING-ACTION))
12: ((:METHOD ASDF/ACTION:PERFORM-WITH-RESTARTS :AROUND (T T)) #<ASDF/LISP-ACTION:COMPILE-OP > #<ASDF/LISP-ACTION:CL-SOURCE-FILE "cl-async-util" "src/util/package">) [fast-method]
13: ((:METHOD ASDF/PLAN:PERFORM-PLAN (T)) #<ASDF/PLAN:SEQUENTIAL-PLAN {1004F6E873}>) [fast-method]
14: ((FLET SB-C::WITH-IT :IN SB-C::%WITH-COMPILATION-UNIT))
15: ((:METHOD ASDF/PLAN:PERFORM-PLAN :AROUND (T)) #<ASDF/PLAN:SEQUENTIAL-PLAN {1004F6E873}>) [fast-method]
16: ((:METHOD ASDF/OPERATE:OPERATE (ASDF/OPERATION:OPERATION ASDF/COMPONENT:COMPONENT)) #<ASDF/OPERATE:BUILD-OP > #<ASDF/SYSTEM:SYSTEM "demo"> :PLAN-CLASS NIL :PLAN-OPTIONS NIL) [fast-method]
17: ((SB-PCL::EMF ASDF/OPERATE:OPERATE) #<unused argument> #<unused argument> #<ASDF/OPERATE:BUILD-OP > #<ASDF/SYSTEM:SYSTEM "demo">)
18: ((LAMBDA NIL :IN ASDF/OPERATE:OPERATE))
19: ((:METHOD ASDF/OPERATE:OPERATE :AROUND (T T)) #<ASDF/OPERATE:BUILD-OP > #<ASDF/SYSTEM:SYSTEM "demo">) [fast-method]
20: ((SB-PCL::EMF ASDF/OPERATE:OPERATE) #<unused argument> #<unused argument> ASDF/OPERATE:BUILD-OP "demo")
21: ((LAMBDA NIL :IN ASDF/OPERATE:OPERATE))
22: ((:METHOD ASDF/OPERATE:OPERATE :AROUND (T T)) ASDF/OPERATE:BUILD-OP "demo") [fast-method]
23: (ASDF/SESSION:CALL-WITH-ASDF-SESSION #<FUNCTION (LAMBDA NIL :IN ASDF/OPERATE:OPERATE) {1004F6528B}> :OVERRIDE T :KEY NIL :OVERRIDE-CACHE T :OVERRIDE-FORCING NIL)
24: ((LAMBDA NIL :IN ASDF/OPERATE:OPERATE))
25: (ASDF/SESSION:CALL-WITH-ASDF-SESSION #<FUNCTION (LAMBDA NIL :IN ASDF/OPERATE:OPERATE) {1004EE5AEB}> :OVERRIDE NIL :KEY NIL :OVERRIDE-CACHE NIL :OVERRIDE-FORCING NIL)
26: ((:METHOD ASDF/OPERATE:OPERATE :AROUND (T T)) ASDF/OPERATE:BUILD-OP "demo") [fast-method]
27: (ASDF/OPERATE:MAKE "demo")
28: (SB-INT:SIMPLE-EVAL-IN-LEXENV (ASDF/OPERATE:MAKE "demo") #<NULL-LEXENV>)
29: (EVAL-TLF (ASDF/OPERATE:MAKE "demo") 4 NIL)
30: ((LABELS SB-FASL::EVAL-FORM :IN SB-INT:LOAD-AS-SOURCE) (ASDF/OPERATE:MAKE "demo") 4)
31: ((LAMBDA (SB-KERNEL:FORM &KEY :CURRENT-INDEX &ALLOW-OTHER-KEYS) :IN SB-INT:LOAD-AS-SOURCE) (ASDF/OPERATE:MAKE "demo") :CURRENT-INDEX 4)
32: (SB-C::%DO-FORMS-FROM-INFO #<FUNCTION (LAMBDA (SB-KERNEL:FORM &KEY :CURRENT-INDEX &ALLOW-OTHER-KEYS) :IN SB-INT:LOAD-AS-SOURCE) {100105664B}> #<SB-C::SOURCE-INFO {1001056613}> SB-C::INPUT-ERROR-IN-LOAD)
33: (SB-INT:LOAD-AS-SOURCE #<SB-SYS:FD-STREAM for "file /private/tmp/nix-build-demo-0.0.1.drv-0/nix-lisppackages-new-demo/build.lisp" {1001050D03}> :VERBOSE NIL :PRINT NIL :CONTEXT "loading")
34: ((LABELS SB-FASL::LOAD-STREAM-1 :IN LOAD) #<SB-SYS:FD-STREAM for "file /private/tmp/nix-build-demo-0.0.1.drv-0/nix-lisppackages-new-demo/build.lisp" {1001050D03}> NIL)
35: (SB-FASL::CALL-WITH-LOAD-BINDINGS #<FUNCTION (LABELS SB-FASL::LOAD-STREAM-1 :IN LOAD) {618782B}> #<SB-SYS:FD-STREAM for "file /private/tmp/nix-build-demo-0.0.1.drv-0/nix-lisppackages-new-demo/build.lisp" {1001050D03}> NIL #<SB-SYS:FD-STREAM for "file /private/tmp/nix-build-demo-0.0.1.drv-0/nix-lisppackages-new-demo/build.lisp" {1001050D03}>)
36: (LOAD #<SB-SYS:FD-STREAM for "file /private/tmp/nix-build-demo-0.0.1.drv-0/nix-lisppackages-new-demo/build.lisp" {1001050D03}> :VERBOSE NIL :PRINT NIL :IF-DOES-NOT-EXIST :ERROR :EXTERNAL-FORMAT :DEFAULT)
37: ((FLET SB-IMPL::LOAD-SCRIPT :IN SB-IMPL::PROCESS-SCRIPT) #<SB-SYS:FD-STREAM for "file /private/tmp/nix-build-demo-0.0.1.drv-0/nix-lisppackages-new-demo/build.lisp" {1001050D03}>)
38: ((FLET SB-UNIX::BODY :IN SB-IMPL::PROCESS-SCRIPT))
39: ((FLET "WITHOUT-INTERRUPTS-BODY-11" :IN SB-IMPL::PROCESS-SCRIPT))
40: (SB-IMPL::PROCESS-SCRIPT "build.lisp")
41: (SB-IMPL::TOPLEVEL-INIT)
42: ((FLET SB-UNIX::BODY :IN SB-IMPL::START-LISP))
43: ((FLET "WITHOUT-INTERRUPTS-BODY-3" :IN SB-IMPL::START-LISP))
44: (SB-IMPL::%START-LISP)

unhandled condition in --disable-debugger mode, quitting
;
; compilation unit aborted
;   caught 1 fatal ERROR condition
error: builder for '/nix/store/q5jjrwvnl6xw51dv9gzh8ppddf9qcdwy-demo-0.0.1.drv' failed with exit code 1;
       last 10 log lines:
       > 40: (SB-IMPL::PROCESS-SCRIPT "build.lisp")
       > 41: (SB-IMPL::TOPLEVEL-INIT)
       > 42: ((FLET SB-UNIX::BODY :IN SB-IMPL::START-LISP))
       > 43: ((FLET "WITHOUT-INTERRUPTS-BODY-3" :IN SB-IMPL::START-LISP))
       > 44: (SB-IMPL::%START-LISP)
       >
       > unhandled condition in --disable-debugger mode, quitting
       > ;
       > ; compilation unit aborted
       > ;   caught 1 fatal ERROR condition
       For full logs, run 'nix log /nix/store/q5jjrwvnl6xw51dv9gzh8ppddf9qcdwy-demo-0.0.1.drv'.

The problem seems to be that cl-async.asd defines cl-async-base and cl-async-util, the latter including the former, but somehow when something (?) in the final build step tries to load cl-async-util, it tries to load it from cl-async-base's dir, where cl-async-util hasn't been compiled, which causes it to try and create the .fasl there, which fails. I don't really know where to go from here, unfortunately.

My system:

$ nix-shell -p nix-info --run "nix-info -m"
 - system: `"x86_64-darwin"`
 - host os: `Darwin 21.6.0, macOS 10.16`
 - multi-user?: `yes`
 - sandbox: `no`
 - version: `nix-env (Nix) 2.11.1`
 - channels(root): `"nixpkgs"`
 - nixpkgs: `/nix/var/nix/profiles/per-user/root/channels/nixpkgs`

In my local nixpkgs-master checkout, I have cherry-picked two extra commits to make sbcl work:


Thought I'd share this here as this case study might be of interest in the larger scheme of things. Happy to move it to a separate issue.

@hraban
Copy link
Member

hraban commented Oct 19, 2022

Update: I think I fixed it. Could anyone interested, please have a look and tell me if this is sane? #196818

@hraban
Copy link
Member

hraban commented Oct 20, 2022

@Uthar looking at imported.nix, it seems individual packages are split up into their constituent systems, each available as top-level packages in nix. E.g. cl-async-util and cl-async-base, which are basically local to cl-async, are both exposed alongside it. Do you know why this is? I can't import them via e.g. quicklisp; they show up in (ql:system-apropos "cl-async") but if you try to (ql:quickload "cl-async-util") you get an error.

It seems to be these packages in particular that cause grief, so I was wondering what the rationale was for making them all top-level, nix managed dependencies.

@Uthar
Copy link
Contributor Author

Uthar commented Oct 20, 2022

Hi @hraban
I'm cooking some rice now, I will get back to you here

@Uthar
Copy link
Contributor Author

Uthar commented Oct 20, 2022

Try like this

--- a/default.nix
+++ b/default.nix
@@ -13,9 +13,4 @@ let
     lisp = "${pkgs.sbcl}/bin/sbcl --script";
     dontStrip = true;
   };
-in
-asdf-only.overrideAttrs (final: prev: {
-  buildPhase = prev.buildPhase + ''
-    ${prev.lisp} build.lisp
-  '';
-})
+in asdf-only

@Uthar
Copy link
Contributor Author

Uthar commented Oct 20, 2022

E.g. cl-async-util and cl-async-base, which are basically local to cl-async, are both exposed alongside it. Do you know why this is?

I made systems exist in their own .asd file to ensure that there is always a single <package>.asd file in the asdf source registry. otherwise it's ambiguous from which one to load .

I think that asdf started warning about this some time ago, which caused a huge drama

@Uthar
Copy link
Contributor Author

Uthar commented Oct 20, 2022

in particular to work around this problem:

Let's say a project contains foo.asd and bar.asd. One packages foo as a nix package and places it into the immutable /nix/store. Now loading foo works fine. Later on, one might want to package bar as well. One puts both store paths in the source registry. Now ASDF will, depending on which system appears first in CL_SOURCE_REGISTRY, either try to load foo from {bar}/foo.asd or from {foo}/foo.asd, and, load bar from either {bar}/bar.asd or {foo}/bar.asd. In the {bar} case, foo fails and bar succeeds and In the {foo} case, foo succeeds and bar fails. This is because {foo} only contains the fasls of foo, and vice versa. Now loading triggers a write attempt to /nix/store to compile the missing fasls.

@hraban
Copy link
Member

hraban commented Oct 20, 2022

cl-async-base and cl-async-util are both defined in cl-async.asd, not in their own .asd files. They're "private" packages, internal to cl-async, and shouldn't really be exposed as top-level. See the discussion in #196818 .

@Uthar
Copy link
Contributor Author

Uthar commented Oct 20, 2022

yeah that could be better because of less source duplication, but it was easier to write quicklisp importing for me like this

@Uthar
Copy link
Contributor Author

Uthar commented Oct 20, 2022

because of less special cases

@Uthar
Copy link
Contributor Author

Uthar commented Nov 7, 2022

What do you think if it was possible to use Lisp packages like this?

sbcl.pkgs.alexandria
sbcl.withPackages (ps: [ ps.alexandria ])

@Uthar
Copy link
Contributor Author

Uthar commented Nov 10, 2022

I'm also thinking about something like this in all-packages.nix

  lispImplementations = callPackage ../development/lisp-modules-new {};
  inherit (lispImplementations) abcl ccl clisp clasp ecl sbcl;

let me know of any thoughts

@Uthar
Copy link
Contributor Author

Uthar commented Nov 11, 2022

Now that I think about the slashy systems problem, if there is a way to asdf:load-system without compiling the .lisp files, that would maybe solve it? Do you know of such a way?

To me it seems that asdf is simply hard-coded to compile every .lisp file, unfortunately.

@7c6f434c
Copy link
Member

What asdf:load-system even is if not something to compile and load every source file?

@Uthar
Copy link
Contributor Author

Uthar commented Nov 15, 2022

It could just load the files, there could be asdf:load-and-compile-system to both load and compile

@7c6f434c
Copy link
Member

I wonder if the most proper solution available would be just to provide ASDF a function for compiled output location that tries next to the source file, in the current build output, and in $HOME-stored cache in that order…

@Uthar
Copy link
Contributor Author

Uthar commented Nov 15, 2022

Recently I read the python infrastructure in nixpkgs. Now what I'm thinking to do is to make secondary systems optional via overlays. So that we can still keep the fasls in /nix/store.

{

# Instead of:
sbcl-with-foo-and-bar = sbcl.withPackages (ps: [ ps.foo ps.bar_slash_baz ]);

# Use overlays:
sbcl' = sbcl.override {
  packageOverlays = self: super: {
    bar = super.bar.overrideLispAttrs (old: {
      systems = old.systems ++ [ "bar/baz" ];
    });
  };
};
sbcl-with-foo-and-bar = sbcl'.withPackages (ps: [ ps.foo ps.bar ]);

}

@Uthar
Copy link
Contributor Author

Uthar commented Apr 4, 2023

see #218870

@Uthar Uthar closed this as completed Apr 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
0.kind: bug Something is broken
Projects
None yet
Development

No branches or pull requests

6 participants