
It feels like something we would have to consider in lots of places,
#10871: Implement "fat" interface files which can be directly compiled without source -------------------------------------+------------------------------------- Reporter: ezyang | Owner: ezyang Type: feature request | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.11 Resolution: | Keywords: backpack Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by ezyang): Aha! SM, your latest comment pinpointed a misunderstanding. You said that "cabal install A B" must work whether or not "cabal install A" was done previously, thus fat interface files are not necessary. But in fact, even in the case of "cabal install A B", we use fat interfaces to compile an instantiated version of A: you will have to compile to a fat interface first, and THEN finish instantiating and finishing the compilation. Why is it set up this way? There were a confluence of reasons that pushed us in this direction: 1. We want GHC(i) to be able to compile Backpack code directly, without requiring Cabal in the loop. 2. Conversely, we don't want to bake Backpack support into cabal-install; if we do, then alternate package managers like Stack also have to port their own support. (A cabal-install which knows, in "cabal install A B", that A is instantiated with B, knows too much about Backpack for its own good!) 3. We always need to typecheck A by itself *anyway*, because it may be ill-typed in a way that you won't discover when you instantiate it. The canonical example is: {{{ unit A where signature A where data T = T signature B where data T module M where import qualified A import qualified B x = A.T :: B.T }}} A shouldn't type-check, because there is no reason to believe A.T and B.T are the same type. But if B implements A and B with the same T, it is actually possible to compile A instantiated with B. OK, let me answer some of the other questions more directly: like hs-boot files, a kind of tax on people who want to write build systems and tools that work with packages. I agree, it does make things more complicated. But you never have to interact with fat interfaces unless you want to build a Backpack package: they all go away once you instantiate things. So I think the complexity here is somewhat opt-in. It's the same deal with some sort of external core format: you don't have to deal with it unless you want to generate external core or compile it.
I wouldn't be surprised if there were tricky technical problems with implementing it fully too. What about core-to-core compiler plugins? What is the equivalent of ghc -M for fat interface files?
Core-to-core plugins run when compiling from hi-fat to hi; that should just work out of the box. As for ghc -M, fat interface files are "essentially" external core input files, i.e. they come with full information about their dependency structure. So you could just write ghc -M which would tell you what order to build hi-fat files in the same way you can do it for hs. (I have not implemented ghc -M, but I have implemented --make's analysis to work on fat interface fiels.)
This would mean that we couldn't have C code in a package that depends on something provided by a hole too. Maybe you don't want to support that use case, but given that without fat interfaces it would "just work", it seems a shame to lose it.
We are giving this up. But I am not losing too much sleep over it; the preprocessor for the C code would already have to know how to mangle the Haskell symbols to point to the right location. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/10871#comment:14 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler