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

Customize ("fixup") Lisp packages before building? #9

Open
lukego opened this issue Oct 4, 2022 · 29 comments
Open

Customize ("fixup") Lisp packages before building? #9

lukego opened this issue Oct 4, 2022 · 29 comments

Comments

@lukego
Copy link
Collaborator

lukego commented Oct 4, 2022

I am looking for a way to customize the set of Lisp package derivations before they are built. Is this supported in the API? Or else how might we support it?

For example I would like to add a failureHook so that broken packages will be "built" into debug information.

I tried to do it like this:

let pkgs = import nixpkgs {};
    baseLispPackages = pkgs.lispPackages_new.sbclPackages;
    updateDerivation = d: d.overrideAttrs (o: {
      failureHook = ''
          ...
        '';
    });
    lispPackages = builtins.mapAttrs (n: v: updateDerivation v) baseLispPackages;
    pkg = builtins.getAttr lispPackage lispPackages;
    in

but I don't think this works because the modified derivations will include references to old unmodified definitions of their dependencies. Somehow I need to have the updated derivations all refer to each other.

I have a few ideas of how to approach this...

  1. Add an API function to return Lisp package definitions as attribute sets so that they can be modified before calling build-asdf-system.
  2. Make Lisp package definitions into functions that are called with callPackage to resolve their dependencies before creating their derivation.
  3. Stealing some clever ideas from other languages' packagings...

But I'm not sure which approach makes sense so I'd be glad for some advice.

@Uthar
Copy link
Owner

Uthar commented Oct 6, 2022

There's no such API now,
I don't have any advice , but I will put it on my brain's to-do list :)

There is a similiar thing when overriding dependencies of Quicklisp imported packages with manually specified ones:

nix-cl/packages.nix

Lines 50 to 52 in 60dbe8f

# Makes it so packages imported from Quicklisp can be re-used as
# lispLibs ofpackages in this file.
ql = quicklispPackagesFor { inherit lisp; fixup = fixupFor packages; };

@Uthar
Copy link
Owner

Uthar commented Oct 6, 2022

They have an example with Python packages on the wiki https://nixos.wiki/wiki/Overlays#Python_Packages_Overlay

@lukego
Copy link
Collaborator Author

lukego commented Oct 11, 2022

@Uthar I suspect that we need to make some changes to the structure of the packages if we want to do python-style overlays. I wrote some thoughts at NixOS/nixpkgs#193754 (comment). Do you agree @Uthar or do I misunderstand?

@Uthar
Copy link
Owner

Uthar commented Oct 11, 2022

It sounds good to make it callPackage friendly. It will also be more in-line with other code in nixpkgs, like the pythonPackages.
I don't know how to do this though and have no alternative idea for now.

@lukego
Copy link
Collaborator Author

lukego commented Oct 11, 2022

Thanks for the sanity-check. I'll see if I can make a proof-of-concept to understand the topic better. I am still figuring out how the various nixpkgs overriding mechanisms really work.

@Uthar
Copy link
Owner

Uthar commented Nov 10, 2022

hmm maybe changing the api a little bit, from sbclPackages -> sbcl.pkgs will make it easier, then one could just sbcl.overrideAttrs -> packageOverrides like the python example

@Uthar
Copy link
Owner

Uthar commented Nov 10, 2022

maybe a mkLisp function that "adds" pkgs attr set and withPackages function to sbcl

@Uthar
Copy link
Owner

Uthar commented Nov 11, 2022

We should check out lib.makeScope:

Make a set of packages with a common scope. All packages called         
with the provided `callPackage' will be evaluated with the same         
arguments. Any package in the set may depend on any other. The          
`overrideScope'` function allows subsequent modification of the package 
set in a consistent way, i.e. all packages in the set will be           
called with the overridden packages. The package sets may be            
hierarchical: the packages in the set are called with the scope         
provided by `newScope' and the set provides a `newScope' attribute      
which can form the parent scope for later package sets.         

@Uthar
Copy link
Owner

Uthar commented Nov 11, 2022

@lukego Do you want to test your use case again on the scope branch?

Example from nix-cl git repo:

$ nix repl
Welcome to Nix 2.11.1. Type :? for help.

nix-repl> :lf .                      
Added 13 variables.

nix-repl> lib.sbclPackages.bordeaux-threads.lispLibs
[ «derivation /nix/store/sd4zrcywjca98v34r6p71i6lvd1r0i1m-alexandria-20220707-git.drv» ]

nix-repl> lib.sbclPackages.alexa                    
lib.sbclPackages.alexa                        lib.sbclPackages.alexandria_plus
lib.sbclPackages.alexa-tests                  lib.sbclPackages.alexandria_plus_slash_tests
lib.sbclPackages.alexandria                   lib.sbclPackages.alexandria_slash_tests
nix-repl> lib.sbclPackages.alexandria
«derivation /nix/store/sd4zrcywjca98v34r6p71i6lvd1r0i1m-alexandria-20220707-git.drv»

nix-repl> :lf nixpkgs
Added 14 variables.

nix-repl> pkgs = legacyPackages.x86_64-linux

nix-repl> :lf .                                      
Added 13 variables.

nix-repl> new = lib.sbclPackages.overrideScope' (self: super: { alexandria = pkgs.hello; })

nix-repl> new.bordeaux-threads.lispLibs
[ «derivation /nix/store/qcvlk255x98i46cg9vphkdw5pghrizsh-hello-2.12.1.drv» ]

nix-repl> 

@Uthar
Copy link
Owner

Uthar commented Nov 13, 2022

BTW i have documented this new and experimental mechanism in the docs: https://github.com/Uthar/nix-cl/blob/f5290469cc32046617b8debc110efd8650bf8978/doc/api.md

@lukego
Copy link
Collaborator Author

lukego commented Nov 14, 2022

@Uthar How do I pull in this change when I'm working with nixpkgs lispPackages_new?

I'd like to git merge or git cherry-pick but I guess that doesn't work because you are working in a stand-alone repo rather than a fork/branch of nixpkgs, which is what I'm doing?

@Uthar
Copy link
Owner

Uthar commented Nov 14, 2022

yeah both are completely separate

@lukego
Copy link
Collaborator Author

lukego commented Nov 14, 2022

So which one should I use and when? what's the idea?

@Uthar
Copy link
Owner

Uthar commented Nov 14, 2022

I think it would be nice to rm -rf lisp-modules-new and replace with nix-cl, but the api should stabilize a bit first

In nix-cl there's experiments and new stuff and the lisp-modules-new in nixpkgs was ALSO merged as an experiment, so pretty much nothing is stable

@Uthar
Copy link
Owner

Uthar commented Nov 14, 2022

I would just use the nix-cl api because it will probably replace lisp-modules-new

@lukego
Copy link
Collaborator Author

lukego commented Nov 14, 2022

Someday I'd love to read a blog entry or something about the evolution and relationship between ql2nix and lisp-modules and lisp-modules-new and nix-cl... :-) but thanks for the tip, I'll look into migrating onto nix-cl.

@Uthar
Copy link
Owner

Uthar commented Nov 14, 2022

in general I would like something like:

nix build nixpkgs#sbcl.pkgs.alexandria

Just like there are:

nix build nixpkgs#python310.pkgs.pika
nix build nixpkgs#emacs.pkgs.magit

@Uthar
Copy link
Owner

Uthar commented Nov 14, 2022

Of course it's all extremely experimental and can break day by day, until the lisp-modules itself in nixpkgs is replaced with a stable version

@lukego
Copy link
Collaborator Author

lukego commented Nov 14, 2022

Of course

Ahem :-) Here on the outside I have no idea whatsoever what is experimental/working/stable/deprecated/obsolete/etc. Any guidance is greatly appreciated. I have been trying to contribute to lisp-modules-new on upstream nixpkgs and I thought this was The Way Forward and something that you were developing and maintaining.

Now it sounds like nix-cl is a better option for me but at the same time I'd like to get stuff done so an API that's silently changing from day to day doesn't necessarily sound like much fun for me...?

@Uthar
Copy link
Owner

Uthar commented Nov 14, 2022

But That's where the fun is (-:

@Uthar
Copy link
Owner

Uthar commented Nov 14, 2022

but really, i think I'll wait maybe a month and then ask the Lisp guy on nixpkgs to replace it all the way, because now there are overlays, it's fast, overrides etc

@lukego
Copy link
Collaborator Author

lukego commented Nov 14, 2022

There is definitely a lot more of this brand of fun in my life since I started using Nix 😂

@lukego
Copy link
Collaborator Author

lukego commented Nov 14, 2022

Sounds awesome! I'll take nix-cl for a spin soon.

@Uthar
Copy link
Owner

Uthar commented Nov 14, 2022

There is definitely a lot more of this brand of fun in my life since I started using Nix

Yeah, Haskellers eat API breakage for breakfast :-D They're used to it

@lukego
Copy link
Collaborator Author

lukego commented Nov 14, 2022

I haven't done much with Haskell. Smalltalk is my usual benchmark for software being either "alpha" or "obsolete" with almost nothing in between :) "Burn the diskpacks and git repos!"

@lukego
Copy link
Collaborator Author

lukego commented Nov 14, 2022

Question:

The README has instructions for "Build a lisp with packages" but it's based on running inside the nix-cl repo working directory. How would I do this from another repository?

Specifically I'd like to have an external repo with a nix expression that builds a custom Lisp development environment e.g. with all of the Kons-9 dependencies.

Today I'm doing this by referencing <nixpkgs> and using lispPackages_new from there in a shell.nix file: https://github.com/lukego/kons-9/blob/actions/shell.nix but what's the nix-cl way to solve this problem?

@Uthar
Copy link
Owner

Uthar commented Nov 14, 2022

you can do something like this in Nix

let

  nix-cl = builtins.getFlake "github:uthar/nix-cl";

  sbcl = nix-cl.packages.${builtins.currentSystem}.sbcl;

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

Or with flakes, put it in inputs:

{
  description = "test";
  inputs.nix-cl.url = "github:uthar/nix-cl";
  outputs = { self, nixpkgs, nix-cl } : {
  };
}

Or with nix CLI

nix build github:uthar/nix-cl#sbcl.pkgs.alexandria

Oh, the readme example is broken, now I see (sbcl should be pakages.${builtins.currentSystem}.sbcl

@Uthar
Copy link
Owner

Uthar commented Nov 14, 2022

For your case I would use the following flake, and run nix develop

{
  description = "Lisp development environment";

  inputs.nix-cl.url = "github:uthar/nix-cl";

  outputs = { self, nixpkgs, flake-utils, nix-cl }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
        lisps = nix-cl.packages.${system};
        sbcl = lisps.sbcl.withPackages (ps: with ps; [
          closer-mop
          trivial-main-thread
          trivial-backtrace
          cffi
          cl-opengl
          cl-glu
          cl-glfw3
          origin
        ]);
      in {
        
        devShells.default = pkgs.mkShell {
          buildInputs = [
            sbcl
          ];
        };
        
      });
}

@Uthar
Copy link
Owner

Uthar commented Nov 14, 2022

You can also pass compile time and run time flags to the lisp:

...
        pkgs = nixpkgs.legacyPackages.${system};
        lisps = nix-cl.packages.${system};
        init = pkgs.writeText "init.lisp" ''
          (pushnew :foo *features*)
          (format t "hello world~%")
        '';
        sbcl = lisps.sbcl.override {
          spec = {
            pkg = lisps.sbcl;
            faslExt = "fasl";
            asdf = lisps.sbcl.pkgs.alexandria.asdf;
            flags = "--dynamic-space-size 8092 --load ${init}";
          };
        };
        sbcl' = sbcl.withPackages (ps: with ps; [
...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants