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

Near-impossible to specify extra-libraries not existing in Nixpkgs #198

Open
JaSpa opened this issue Sep 14, 2023 · 1 comment
Open

Near-impossible to specify extra-libraries not existing in Nixpkgs #198

JaSpa opened this issue Sep 14, 2023 · 1 comment

Comments

@JaSpa
Copy link

JaSpa commented Sep 14, 2023

Problem description

The repository JaSpa/haskell-flakes-with-extra-libraries demonstrates the problem.

I want to write a Haskell executable depending on the gvc library distributed with Graphviz. To instruct GHC/cabal about the link-time requirement I add extra-libraries: gvc to the package description in example.cabal.

Main.hs contains a simple executable which calls two functions from the mentioned library and prints their results. The script run-outside-of-nix.sh demonstrates that the executable is functional. It uses the global GHC/cabal and Graphviz obtained through nix.

Broken haskell-flakes setup

Building through the bare-bones haskell-flakes setup does not work (complete error message below). It complains about a required argument gvc which was not provided. But this makes sense. cabal2nix translates the extra-libraries: gvc into an argument { …, gvc }: … but there is no gvc package in Nixpkgs.

nix error message
error: anonymous function at /nix/store/95jn322pl7yhy3ggz04qrcvhgl33y0bc-cabal2nix-example/default.nix:1:1 called without required argument 'gvc'

       at /nix/store/2ayipj5kgy67231fvbl8agsl591kanw8-source/pkgs/development/haskell-modules/make-package-set.nix:97:40:

           96|       # this wraps the `drv` function to add `scope` and `overrideScope` to the result.
           97|       drvScope = allArgs: ensureAttrs (drv allArgs) // {
             |                                        ^
           98|         inherit scope;
(use '--show-trace' to show detailed location information)
cabal2nix output
{ mkDerivation, base, gvc, lib }:
mkDerivation {
  pname = "example";
  version = "0.1.0.0";
  src = ./.;
  isLibrary = false;
  isExecutable = true;
  executableHaskellDepends = [ base ];
  executableSystemDepends = [ gvc ];
  license = "unknown";
  mainProgram = "example";
}

Working ordinary Nixpkgs setup

I defined a flake package “ordinary” in flake.nix which demonstrates that this is not a problem when using the ordinary Nixpkgs infrastructure: callCabal2nix is called with the argument { gvc = pkgs.graphviz; }. nix-build .#ordinary succeeds and produces a runnable binary.

Workaround

There exists a workaround. It is possible to define gvc as an alias for Graphviz using a Nixpkgs overlay. This exists commented out in flake.nix. Enabling these lines allows the haskell-flakes package to build successfully. However, using Nixpkgs overlays is quite un-ergonomic in conjunction with flake-parts.

{
    _module.args.pkgs = import inputs.nixpkgs {
      inherit system;
      overlays = [
        (final: prev: {gvc = final.graphviz;})
      ];
    };
    haskellProjects.default = {};
}

Achieving this through haskell-flakes

Is there a way to achieve this using haskell-flakes? I tried various incantations using either packages or settings but ultimately I don't think this can work with the current version.

(root: self.callCabal2nix name root { })

The empty { } argument is the place where the { gvc = pkgs.graphviz; } would have to appear.

There are two ways I can imagine how this might work in the future: packages.<name>.custom could specify any kind of package. These packages don't go through callCabal2nix/callHackage but instead are added to the package set as-is. Instead of adding a “global” alias for Graphviz it could then be scoped to haskellProjects:

{
    haskellProjects.default = {
        packages = {
            gvc.custom = pkgs.graphviz;
        };
    };
}

However, this still is quite coarse. Maybe instead there could be a new setting args which takes the place of { } mentioned above. (It's unclear to me if this would fit with haskell-flakes architecture.)

{
    haskellProjects.default = {
        settings.example.args = {
            gvc = pkgs.graphviz;
        };
    };
}
@srid
Copy link
Owner

srid commented Sep 14, 2023

I think it is worth solving the more general problem here -- by allowing the user to pass any arguments (default being {}) to callCabal2nix. Perhaps like this:

    haskellProjects.default = {
        packages.example.source = {
          cabal2nix-args = {
            gvc = pkgs.graphviz;
          };
       };
    };

Note that source is an overloaded option ― it can be either a source path or hackage version.

then
log.traceDebug "${name}.callCabal2nix ${cfg.source}"
(build-haskell-package name cfg.source)
else
log.traceDebug "${name}.callHackage ${cfg.source}"
(self.callHackage name cfg.source { });
in

As you can see above, we call callCabal2nix only in the former case, and thus this option cabal2nix-args makes sense only in that context. So we want to figure out the API first, before implementing it (the implementation itself should be straightforward). Let's also consider this in the context of a potential 3rd overloaded type, hackage-direct.

cc @roberth in case I missed anything.

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