cabal2nix
cabal2nix copied to clipboard
cabal2nix does not generate framework dependencies on macOS
The streamly cabal file has the following stanza:
library
if os(darwin)
frameworks: Cocoa
include-dirs: src/Streamly/Internal
c-sources: src/Streamly/Internal/Data/Time/Darwin.c
, src/Streamly/Internal/FileSystem/Event/Darwin.m
exposed-modules:
Streamly.Internal.FileSystem.Event.Darwin
When cabal2nix is used on this file it does not generate a Cocoa framework dependency, therefore the nix-shell fails. After adding the dependency manually it works.
How to reproduce:
$ git clone https://github.com/composewell/streamly.git
$ cd streamly
$ mv benchmark/streamly-benchmarks.cabal benchmark/streamly-benchmarks.cabal.bak
$ rm default.nix
$ cabal2nix --shell . > shell.nix
$ cabal build streamly
The build will fail because of Cocoa framework dependency.
We have added the dependency manually in the shell derivation:
buildInputs =
if builtins.currentSystem == "x86_64-darwin"
then [nixpkgs.darwin.apple_sdk.frameworks.Cocoa]
else [];
I'm pretty sure this is due to a limitation in which we parse cabal files, i. e. we can't resolve flags at all. I'd have to check what the state is here precisely atm, but this may be hard to fix unfortunately.
The trouble is also that even if we would resolve flags, we'd have to translate the logic involving of these flags to nix code which definitely is non-trivial (and probably why this wasn't implemented in the first place).
I think such parsing already exists, its probably a small bug. I am saying that based on the fact that the fsnotify package has this in the cabal file:
if os(windows)
CPP-Options: -DOS_Win32
Other-Modules: System.FSNotify.Win32
, System.Win32.FileNotify
, System.Win32.Notify
Build-Depends: Win32
Hs-Source-Dirs: win-src
else
if os(darwin)
CPP-Options: -DOS_Mac
Other-Modules: System.FSNotify.OSX
Build-Depends: hfsevents >= 0.1.3
And cabal2nix generates this:
$ cabal2nix .
{ mkDerivation, async, base, bytestring, containers, directory
, filepath, hfsevents, lib, random, tasty, tasty-hunit, temporary
, text, time, unix-compat
}:
mkDerivation {
pname = "fsnotify";
version = "0.3.0.1";
src = ./.;
revision = "1";
editedCabalFile = "1pa9pa0kflkqlb4dysagy0aihn452hmf6wwlsr7fp4ygg86m7fsq";
libraryHaskellDepends = [
async base bytestring containers directory filepath hfsevents text
time unix-compat
];
hfsevents is under the os(darwin) conditional just like in the case I reported in this issue. But it is still correctly parsed and we get a dependency on hfsevents.
For the streamly-0.8.0 package cabal2nix does not generate the framework dependency which is under a similar conditional:
streamly-0.8.0 $ cabal2nix .
{ mkDerivation, atomic-primops, base, containers, deepseq
, directory, exceptions, fusion-plugin-types, ghc-prim, heaps, lib
, lockfree-queue, monad-control, mtl, network, primitive
, transformers, transformers-base
}:
mkDerivation {
pname = "streamly";
version = "0.8.0";
src = ./.;
libraryHaskellDepends = [
atomic-primops base containers deepseq directory exceptions
fusion-plugin-types ghc-prim heaps lockfree-queue monad-control mtl
network primitive transformers transformers-base
];
homepage = "https://streamly.composewell.com";
description = "Dataflow programming and declarative concurrency";
license = lib.licenses.bsd3;
}
However, it does recognize a build-depends under the same conditional. If I add a build-depends entry under that conditional it recognizes it, it only does not recognize the frameworks stanza.
I don't see any build-depends being included despite under a conditional, can you elaborate?
I don't see any
build-dependsbeing included despite under a conditional, can you elaborate?
hfsevents in the example above is under if os(darwin) but the output of cabal2nix includes it.
Yeah, you're right. I've checked for real this time and cabal2nix completely ignores frameworks. This makes sense since cabal2nix doesn't factor the host platform into account at all, so adding framework bindings would cause problems on all non darwin platforms (meaning evaluation would fail).
There are probably multiple approaches to fix this, but it is definitely a non-trivial problem which is connected to a larger (design) issue of cabal2nix.
It does recognize the frameworks stanza outside a conditional. For example it emits the following for hfsevents.cabal:
mkDerivation {
pname = "hfsevents";
version = "0.1.6";
src = ./.;
libraryHaskellDepends = [ base bytestring cereal mtl text unix ];
librarySystemDepends = [ Cocoa ];
libraryToolDepends = [ CoreServices ];
For the conditional case, can't it emit something like this?:
if builtins.currentSystem == "x86_64-darwin"
then [Cocoa]
else [];
hfsevents has a hard coded post processing filter which adds the framework:
https://github.com/NixOS/cabal2nix/blob/3d9f69c17bbb82546d747906a83dbf0c2ddfa0d5/src/Distribution/Nixpkgs/Haskell/FromCabal/PostProcess.hs#L351-L357
Unfortunately emitting conditionals is not as simple as you are outlining — we need to consider cross compilation as well. Also we'd need to parse and understand the Cabal conditionals in the first place…
Ah, I did not know that it has been special cased for hfsevents.
I did another experiment. In the streamly package, I added a Haskell dependency under the conditional:
if os(darwin)
build-depends: streaming
frameworks: Cocoa
And cabal2nix seems to parse the conditional and generate a proper dependency on "streaming":
mkDerivation {
pname = "streamly";
version = "0.8.0";
src = ./.;
libraryHaskellDepends = [
atomic-primops base containers deepseq directory exceptions
fusion-plugin-types ghc-prim heaps lockfree-queue monad-control mtl
network primitive streaming transformers transformers-base
];
So it seems parsing of cabal conditionals is present.
Its only about generating nix expressions that are portable.