Non-haskell dependencies
CMCDragonkai opened this issue · comments
The proper way to bring in non-haskell dependencies when using cabal2nix
is to again use package.yaml
. This means we don't add dependencies directly into the default.nix
.
For example to bring in clang
. We need to add it to the build-tools
or system-build-tools
in the package.yaml
.
Note that system-build-tools
is what it should be at the latest version of hpack
. On older versions it's build-tools
. The change was added here: sol/hpack@c1d4ba7 This can be added like:
build-tools:
- clang
system-build-tools:
- clang
Then you update the cabal.nix
and also the cabal file using cabal2nix
and hpack
. And then you should see clang
appear in both the buildInputs of default.nix
and shell.nix
.
This gist is important as well: https://gist.github.com/CMCDragonkai/8b5cc041cea4a7e45a9cb89f849eaaf8
Especially if you're doing separate compilation of C files using just gcc
inside the nix-shell
.
For non-haskell dependencies that are libraries. Apparently the proper way is to put down in package.yaml
:
extra-libraries:
- libmnl
- libnftnl
- linuxHeaders
This will put the dependency into librarySystemDepends
which mean it will be available in both nix-build and nix-shell.
It also automatically makes cabal configure
try to find these libraries. However I have not figured out how to resolve this since cabal then fails to compile. I'm guessing I'm missing something else that requires to refer to these libraries.
Ok I found the problem: NixOS/cabal2nix#413
Basically Cabal/Hpack expects that extra-libraries
refers to actual C libraries that will be linked.
So if you state extra-libraries: libmnl
, it will actually try to link to -llibmnl
. However this is problematic, because often the name of the library to be linked is something different like -lmnl
. So -llibmnl
will result in an error.
But if we change to -lmnl
, the problem is that cabal2nix
will generate a cabal.nix
that wants mnl
as a package attribute. And in nixpkgs, the package is called libmnl
.
So what does cabal2nix do? It maintains a mapping of common library names to the package names in Nixpkgs.
This means we have to request them to maintain these mappings everytime we meet a dependency that isn't mapped already. However... as a stop-gap, we can fill in these mappings ourselves when we load the cabal.nix
. So we use extra-libraries: mnl
and then when importing the cabal.nix
, we have to put mnl = pkgs.libmnl;
.
drv = haskellPackages.callPackage (import ./cabal.nix) { mnl = libmnl; };
BTW, Nix puts these C dependencies in NIX_CFLAGS_COMPILE
. Not sure what else is here.
However this doesn't solve the problem for things like linuxHeaders
which are just include files with no corresponding thing to link to, since we just may need it.
Do note if using the callPackage pattern, you need to make sure to overwrite the parameter in default.nix to be a top level package, if there are name conflicts between the top level package name and another haskell package name.
The #24 takes over from #23. #23 shows an example of how to use CPP to put compile time macros into the Haskell program. So I'm going to close that one, but it is still useful reference for everybody in case they need a compile time macro. @DrFacepalm @nzhang-zh @Zachaccino
Solved this for Haskell Demo.
But in general there is 2 solutions:
A. You consider project to be a Haskell dependency (something distributed on hackage)
B. You consider the project to be a standard package (something that is on Nix)
In the A side, you must keep default.nix
a callpackage derivation.
In the B side, you can dispense with that requirement, make default.nix
something that can use stdenv.mkDerivation
, and then you are using a Haskell project within it.
B may be relevant if there's a lot of non-Haskell stuff, a multi-language and many dependency project.
If you are doing B, you will end up using the haskellPackages.callPackage
which will be whatever haskell compiler is considered the "default" compiler for that package set.