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

[WIP] mingw-w64 for haskell cross compilation with ghc. #37254

Closed
wants to merge 44 commits into from

Conversation

angerman
Copy link
Contributor

Motivation for this change

This includes all the necessary changes to nixpkgs, that allow me to cross compile haskell to
windows via mingw-w64. It is not yet sufficient to allow cross compilation of Template Haskell.

Things done
  • Tested using sandboxing (nix.useSandbox on NixOS, or option build-use-sandbox in nix.conf on non-NixOS)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nox --run "nox-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Fits CONTRIBUTING.md.

@angerman angerman requested a review from peti as a code owner March 17, 2018 15:41
@angerman
Copy link
Contributor Author

/cc @Ericson2314

@@ -4,7 +4,7 @@
}:

# Prebuilt only does native
assert stdenv.targetPlatform == stdenv.hostPlatform;
# assert stdenv.targetPlatform == stdenv.hostPlatform;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While disabling this check, allows most of the cross compilation to succeed on macOS, I believe this is also the reason why we end up with mixed (build and target) packages in the stdenv eventually.

@@ -161,7 +175,11 @@ stdenv.mkDerivation rec {
# zsh and other shells are smart about `{ghc}` but bash isn't, and doesn't
# treat that as a unary `{x,y,z,..}` repetition.
postInstall = ''
paxmark m $out/lib/${name}/bin/${if targetPlatform != hostPlatform then "ghc" else "{ghc,haddock}"}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is motivated by the fact that we do not necessarily build haddock with quick flavours. As such we fall over trying to paxmark a file that does not exist.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good-- probably can collapse this to just {ghc,haddock} if we check for existence anyway.

"--with-strip=${stdenv.cc.bintools.targetPrefix}strip"
] ++ (if isHaLVM then [] else ["--hsc2hs-options=--cross-compile"]);
] ++ (if isHaLVM then [] else ["--hsc2hs-option=--cross-compile"
"--hsc2hs-option=--via-asm"]);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--via-asm is a rather recent feature in hsc2hs that is part of ghc > 8.4

@@ -12,7 +12,7 @@ let
"${targetPlatform.config}-";
in

assert targetPlatform.isDarwin;
assert stdenv.isDarwin;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could potentially also be the reason for the incorrect package set on darwin.

@bjornfor bjornfor added the 6.topic: cross-compilation Building packages on a different sort platform than than they will be run on label Mar 19, 2018

, version ? "8.5.20180118"
, ghcRevision ? "e1d4140be4d2a1508015093b69e1ef53516e1eb6"
, ghcSha256 ? "1gdcr10dd968d40qgljdwx9vfkva3yrvjm9a4nis7whaaac3ag58"
, ghcFlavour ? ""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to do ghcFlavour ? if targetPlatform != hostPlatform then "perf-cros" else ""

enableShared ? (targetPlatform == hostPlatform && !targetPlatform.isWindows)

, # Whetherto build terminfo.
enableTerminfo ? !targetPlatform.isWindows
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does terminfo/ncurses not work on windows?

If it was failing to find ncurses headers/libs see the fix on my musl PR (remove attempt to specify where to find them).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the case of cross compiling to windows, we don't want terminfo, the GHC build system disables terminfoin that case anyway.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It only disables it in some cross build "flavour"s, which we don't have to use as-is. Works for me building cross-aarch64-musl and such. Anyway sounds like you're saying windows in particular shouldn't use this, which I'll take your word for.

setupConfigureFlags+=" --extra-lib-dirs=$p/lib"
fi
done
${nativeGhcCommand}-pkg --${packageDbFlag}="$setupPackageConfDir" recache
Copy link
Member

@dtzWill dtzWill Mar 22, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@dtzWill
Copy link
Member

dtzWill commented Mar 22, 2018

If you're touching cctools, #37606 might have some useful bits.

enableShared ? true
#
# We don't do this by default if target != host, or if we target windows.
enableShared ? (targetPlatform == hostPlatform && !targetPlatform.isWindows)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that the description of this option is actually quite incorrect and misleading. Setting this to true has no effect on whether ghc builds shared libraries or not. Rather, it affects the code that's used by ghci to load compiled objects for interpretation. There's a good chance that this setting is completely ignored on Windows anyway. Could you please check whether the change you've made here is actually necessary?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enable* is about how the current package is linked. I think this does just that. That this also affects how GHCi works is just a side affect due to GHCi's fragile interpretation.

@dtzWill
Copy link
Member

dtzWill commented Apr 21, 2018

Beep boop, how's this going?

@angerman
Copy link
Contributor Author

angerman commented Apr 21, 2018

@dtzWill this does work as-is (I've used this to build dhall-json among others...). I did however get severely frustrated with the conditionals missing in cabal2nix generated cabal expressions. I did look into making cabal2nix generate better expressions, but learned that what I wanted was a bad fit for what cabal2nix does. And I don't want to disrupt any working solution in nix.

So I ended up writing Cabal2Nix, which really needs a better name. I now have hackage.nix, stackage.nix as well as some glue code in haskell.nix. This is pretty much work-in-progress. While it does allow me to build some trivial hs-hello package, it is nowhere near polished yet, and will likely see some additional changes.

I believe it will provide a much better basis for cross compilation haskell packages.

@Ericson2314
Copy link
Member

@angerman that sounds fascinating but I think your links are broken?

@angerman
Copy link
Contributor Author

# Add the setupHaskellDepends to a custom package-db,
# which ghc will be provided with.

for p in ${lib.escapeShellArgs setupHaskellDepends}; do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here propagated setup dependencies are not taken into account. That is, your pkgdb will contain only immediate setup dependencies but their transitive dependencies will not be in it, so it won’t compile.

configureSetup = buildHaskellPackages.setup { setupHs = ''
import Distribution.Simple
main = defaultMainWithHooks autoconfUserHooks
'';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inherit setupHaskellDepends, I guess.


phases = [ "buildPhase" ];

buildInputs = [ ghc ] ++ setupHaskellDepends;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think ghc should go to nativeBuildInputs.

@angerman angerman requested a review from nbp as a code owner June 8, 2018 15:46
Nix cc logic relies on passing /lib for each dependency as a library
search path.  This makes little sense for haskell packages, as their
libs are nested deeply in the /lib tree.  Also GHC will generate the
right library serach paths on its own from the package database
entries.

The larger issue though is that with one search path entry for each
library, and a similar one generated by GHC for each dependency
will eventually overflow the command line argument limits.

As such we do *not* put haskell libraries into $out anymore.
@angerman angerman closed this Jul 27, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants