cabal icon indicating copy to clipboard operation
cabal copied to clipboard

build Setup.hs with local compiler when cross-compiling

Open rwbarton opened this issue 10 years ago • 41 comments

I have a script that invokes cabal with --with-ghc=..., --with-ghc-pkg=..., --with-gcc=..., etc. for cross-compiling to Android. It works great for most packages, but fails for a package with Build-type: Custom, because it builds Setup.hs with the cross-compiler specified on the command-line, and then obviously it can't run dist/setup/setup because it's an ARM executable.

I can work around the issue by doing an ordinary cabal configure with no --with-ghc=... options first, then doing a cabal install with my cross-compiler script, because the second invocation uses the cached dist/setup/setup from the first one. But that's a hack, obviously, and annoying to do when the package I'm installing is a dependency of the one I actually want.

What I would like is a separate set of options for specifying the program configuration to use to build Setup.hs; or at least an option to tell cabal to just use the ones on my path. I found that using defaultSetupScriptOptions for setupScriptOptions in configure and performInstallations seemed to do the trick for me, to give an idea of what I want to happen, though I haven't tested the resulting libraries. I couldn't determine whether there is already a way to achieve the same effect through command-line options.

rwbarton avatar Sep 09 '13 03:09 rwbarton

What would be an appropriate name for such an option? --host-compiler?

23Skidoo avatar Sep 09 '13 21:09 23Skidoo

I was imagining a series of options like --with-host-compiler, --with-host-PROGRAM to specify the compiler and program configuration to use for building Setup.hs. (And possibly in the future for building modules to be loaded by Template Haskell?)

rwbarton avatar Sep 09 '13 23:09 rwbarton

Apparently the Haskell-iPhone people are working around this by patching packages to use build-type: Simple. See the thread http://www.haskell.org/pipermail/iphone/2012-December/000180.html and some of the patches at https://github.com/kaoskorobase/ghc-ios-cabal-scripts/tree/master/patches, like lifted-base and syb.

rwbarton avatar Sep 23 '13 18:09 rwbarton

Yeah, this is also a pain point for me. I work around it by just running ghc Setup.hs and copying the result over the one produced by cabal and re-running, but it's a pain.

singpolyma avatar Oct 01 '14 17:10 singpolyma

Another possibility, which seems to be sufficient for most cases, would be to allow "build-type" to exist within "if" branches, so that, for example:

if os(HaLVM) || os(iOS) Build-Type: Simple else Build-Type: Custom

I was considering looking into a patch to do this, which seemed like it might be simpler, as long as the if cases were restricted to non-computed things (like os()).

acw avatar Oct 25 '14 00:10 acw

if os(HaLVM) || os(iOS)
Build-Type: Simple
else
Build-Type: Custom

This is a bad idea IMO, since it requires all package authors to modify their .cabal files.

23Skidoo avatar Oct 25 '14 00:10 23Skidoo

I think that rwbarton is right with his idea.

What about adding flags along the line of '--with-build-ghc' --with-target-ghc? We could let '--with-ghc' be a shorthand for passing both '--with-build-ghc' and '--with-target-ghc' with the same value. We could even make it illegal to pass a combination of old and new flags without breaking compatibility.

Additionally we could allow for additional config file entries.

Is anyone working on this? Otherwise I will go ahead and try to implement a proposal...

sheyll avatar Oct 29 '14 21:10 sheyll

@sheyll To my knowledge, no-one is working on this.

I think we only need a --with-build-PROGRAM flag for all built-in programs (maybe only GHC initially). By default, Cabal will use the GHC specified with -w for everything, but if --with-build-ghc is provided, it will compile Setup.hs with it. Ditto for other programs.

I imagine that we would have a new section in the config file for this stuff, akin to program-locations:

cross-compilation
    build-ghc-location: /path/to/build-ghc
    build-gcc-location: /path/to/build-gcc
    [...]

23Skidoo avatar Oct 29 '14 21:10 23Skidoo

@23Skidoo Ok it seems to be consensus that additional flags are useful. I will simply start with "--with-build-PROGRAM" for ghc and ghc-pkg and we'll see how it flows from there.

sheyll avatar Oct 29 '14 21:10 sheyll

Ok .. I now have a draft for code review, located here: https://github.com/sheyll/cabal/commit/06c2501e48608024c1d80887c485c4596b8cf9e3

sheyll avatar Nov 02 '14 14:11 sheyll

Thanks sheyll. This is great stuff and just what I need right now to take the pain out of cross building packages (PowerPC as well as ARM). Though I don't feel qualified to comment on your changes in detail will take them for a spin soon.

jms19 avatar Nov 14 '14 11:11 jms19

hey wait

this was only a prototype, the real thing is in the making.. I do not guarantee it works. I am currently rewriting it using a different approach and also with tests etc..

would you mind making me some kind docker recipe for your cross compiling setup so I can test that locally?

wbr Sven Am 14.11.2014 12:28 schrieb "jms19" [email protected]:

Thanks sheyll. This is great stuff and just what I need right now to take the pain out of cross building packages (PowerPC as well as ARM). Though I don't feel qualified to comment on your changes in detail will take them for a spin soon.

— Reply to this email directly or view it on GitHub https://github.com/haskell/cabal/issues/1493#issuecomment-63048410.

sheyll avatar Nov 14 '14 11:11 sheyll

I should have said I am very new to Haskell, even more so to cabal (a week or two) and the term docker has me reaching for Google. I am off the ground with cross compilers though and have gained some knowledge that might be used to improve https://ghc.haskell.org/trac/ghc/wiki/CrossCompilation and friends.

jms19 avatar Nov 14 '14 11:11 jms19

I just wanted to let you know I continue to work on this now,

Do you think this issue could be assigned to me, to indicate that work is going on there?

I have done a fork of this repo a while ago, but I rebase it regularily, so it should not be too painful to merge when it is done.

I must admit I am surprised by the sophistication of the cabal internals, and coming from industry rather than academia I appreciate the pragmatic approaches chosen, although I have struggled with the fact that I had to touch so many different places for the intended changes; but this might as well have todo with me having the urge to make the changes as test-covered as possible and follow the boy-scout-rule.

I'd rather take some more time than leave a mess that just makes other maybe more important changes more expensive

sheyll avatar Dec 13 '14 15:12 sheyll

Do you think this issue could be assigned to me, to indicate that work is going on there?

It looks like you need to be a member of the Haskell organization on GitHub for me to be able to do that.

23Skidoo avatar Dec 13 '14 15:12 23Skidoo

@sheyll any progress lately? I would be willing to test it out if you have something working.

I want to cross-compile a cabal sandbox on a x86_64 server for use on an arm laptop, so I need Setup.hs compiled with the host compiler, then ./setup configure run with the (target) arm cross-compiler. Is the proposal to have this look like cabal install -w arm-ghc --with-build-ghc=ghc package? I feel cabal install --with-target-ghc=arm-ghc package would be more natural in my case.

I understand my setup isn't widely adopted, but I thought I'd mention it.

jarlg avatar Dec 26 '14 22:12 jarlg

I will make an experimental version on the fork I have in my github account, and notify you here. Maybe what's there works, but I have not test-covered or implemented all affected parts yet, go ahead and try. To answer your question: yes. Oh and happy new year.

sheyll avatar Jan 01 '15 16:01 sheyll

Hey, what's the status on this? Is there anything we can do to accelerate this getting into mainline?

acw avatar May 09 '15 00:05 acw

hi I will look into it in the next couple of days, I have a fork on github that contains the current state if anyone is interested. I remember that I added some unit test and todo comments to be able to pick up the work where I had to stop. Basically it was working, but the design approach taken did not feel too good.

Wbr Sven Am 09.05.2015 02:13 schrieb "Adam Wick" [email protected]:

Hey, what's the status on this? Is there anything we can do to accelerate this getting into mainline?

— Reply to this email directly or view it on GitHub https://github.com/haskell/cabal/issues/1493#issuecomment-100397283.

sheyll avatar May 12 '15 04:05 sheyll

In https://github.com/haskell/cabal/issues/3882 @ezyang and I talked about turning Setup.hs into its own component? That probably dovetails with this nicely so setup components can be solved separately against the host compile / host-specific packager?

Ericson2314 avatar Oct 27 '16 21:10 Ericson2314

Setup as a component itself could help, but I am not sure how it relates to @sheyll's patch. @sheyll I just added you to the Cabal team so that you can assign yourself this ticket.

ezyang avatar Oct 27 '16 22:10 ezyang

OK I gave the patch a read through. This isn't going to be sufficient for getting new-build to use these capabilities.

Maybe it would make sense to do things in this order:

  1. Refactor SetupWrapper so that Setup can be built as its own component and then invoked separately after the fact
  2. Refactor new-build so that it supports "mixed GHC" plans; i.e., some components are built using the host GHC and some are built with the target
  3. Now, to make Custom setup work on a cross-compile, we just note that the Custom setup is built with the host compiler

ezyang avatar Oct 27 '16 22:10 ezyang

@ezyang heh I actually missed the link to that patch reading through, I was just commenting on the issue in principle. Your plan there looks very good to me: "mixed GHC" plans should hopefully just a be a further decoupling of setup depends on normal depends solving.

Ericson2314 avatar Oct 27 '16 22:10 Ericson2314

Merged! Thanks!

acw avatar Dec 08 '16 16:12 acw

Ok, to do this the Right Way™, I think I want to change the type of qualifiers. Note the comment on setup about nesting. Well, this applies equally well to exe deps too, and because packages can constrain on exe version, when cross compiling or bootstrapping this matters.

[expansio ad absurdum: Let's say somebody wants to bootstrap across 5 platforms (and platform-specific compilers), oh my! A build-tool-depends or setup exe running on platform n is built on platform n-1. Let's also say a bunch of packages have various platform-conditional deps/flags/whatever. Well, we need to keep track of have many exe deps deep we are to know which compiler+platform to use. They must be configured separately!]

Thus, I propose instead

type Qualifier = [QualifyingEdge]

data QualifierEdge
  = QualBase PackageName
  | QualExe { from :: PackageName, to :: QualExeTarget }

-- | May just use `Maybe PackageName` in practice
data QualExeTarget = TargetExe PackageName | TargetOwnSetup

Now, there is also a good argument in that comment about the search space growing too large. Well, I propose that after we build the deps we "prune" all qualifier paths accordingly. There are two options I see for this pruning. Let n be the number of compilers/platforms passed in, and m be the number of exe edges in the qualifier path. Then the options are:

  • filter all but the first n QualExes, leaving a shorter list
  • take the last or first element (whatever matches today) along with min n m saying which compiler+platform to resolve against.

How does this sound?

Ericson2314 avatar Jan 16 '17 21:01 Ericson2314

For reference, the commits that reverted infinite qualifiers are 37978a6c61ffaf09d424e4d6ac73b333eb978b77 (fix) and 3d2ad8e0a9ffc4db40719e046583a9da0fe5316b (test). I am not entirely sure why @edsko decided to change the package path structure, as oppose to teach the solver how to prune things, but I think that if you are working on this patch, it is more likely to work if you keep the qualifiers finite, because it is not known what changes you would have to make to the solver to prune qualifier paths.

So, sure: in principle, someone might cross compile over five platforms. But are they actually going to in practice? How would they even say that they wanted to cross compile over five platforms?

ezyang avatar Jan 19 '17 17:01 ezyang

@ezyang well in practice there would probably only be two, but I think the code is clearer using a list and supporting arbitrary.

Ericson2314 avatar Jan 26 '17 02:01 Ericson2314

Also BTW in https://github.com/Ericson2314/cabal/tree/cross-solve I have that change to qualifier, with prune just doing at most one exe/setup dep because there is no cross support yet.

CC @grayjay

Ericson2314 avatar Jan 26 '17 02:01 Ericson2314

I just took a quick look, and I think it looks similar to the qualifiers that cabal had before #3220. So I would want to make sure that a new implementation handles the issues that led to #3220 before increasing the depth. Other than that, I think that the structure of the qualifiers looks good.

How would the solver know which compiler to use for each executable? Would it always be specified by the user?

grayjay avatar Jan 27 '17 08:01 grayjay

@grayjay the difference is the prune function---it limits the number of QualExes and there can already be only one QualBase, thus the length of the path must be finite. [I forgot to use prune too on user-specified constraints, but those are also finite and worst-case just wouldn't apply, so less harm there.]

How would the solver know which compiler to use for each executable? Would it always be specified by the user?

Specifying a single compiler/platform, or single cross and native compiler/platform, generalizes into specifying a list of compilers/platforms----whatever the user-facing interface would be, this is how things would be stored internally. Then, simply take the number of QualExes in the qualifier, and that is the index for compilers/platforms.

FWIW I am doing some very similar changes with nixpkgs atm, and documenting the new world in https://github.com/NixOS/nixpkgs/blob/master/doc/cross-compilation.xml . That may of interest, but probably not yet.

Ericson2314 avatar Jan 27 '17 17:01 Ericson2314