Opened 4 years ago

Last modified 3 years ago

#11378 new feature request

Use the compiler that built ghc for dynamic code loading, for cross-compiling

Reported by: ezyang Owned by:
Priority: lowest Milestone:
Component: Template Haskell Version: 7.11
Keywords: Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: #11470 Differential Rev(s):
Wiki Page:

Description

In a non cross-compiled stage 2 compiler, this coincides with what we do today, because the stage 1 implementation of GHC is the same as the stage 2 implementation. But in a cross-compiler, these are NOT the same: the cross-compiler's ghc library handles the package database in the target platform, whereas the compiler that built stage 2 (stage 1)'s ghc library handles the package database for the compiler's platform.

So, the correct architecture for supporting compiler plugins is that GHC should use the package-database/interface infrastructure from the compiler which built it (stage 1) to handle loading.

A few things to note:

  1. There is not a backwards-compatibility problem, because we can assume that stage 1 and stage 2 are built from the same codebase. In particular, this does NOT mean that TH/plugins start working on a stage 1 compiler. You have to have bootstrapped from the same codebase.
  2. Plugins (and even Template Haskell) have to be a bit more careful to take advantage of this. We cannot just assume that the package database for plugins is the same as the package database for compiling (revisiting #11244). Template Haskell is even trickier: we should NOT be allowed to use regular imports in splices; they have to go through TH_ONLY imports, c.f. #11377
  3. Can we actually link against the old version of ghc? Yes we can! All we need is (1) for it to have been built with a different IPID, and (2) to use module renaming to rename the relevant modules to a different module name, so that we can import them without a conflict.

Stepping back, there have been two approaches for dealing with the problem of Template Haskell/compiler plugins not reliably working:

  1. Run the code in an external process run in the target code, or
  2. Fix GHC to load code which is appropriately built for the bootstrap platform.

While (1) offers a more uniform environment for developers, (2) is absolutely necessary in some situations when you need to load code in the same address space as GHC, e.g. as mentioned in https://mail.haskell.org/pipermail/ghc-devs/2015-November/010478.html Thus, it seems worth pursuing both.

Change History (5)

comment:2 Changed 4 years ago by ezyang

comment:3 Changed 4 years ago by rwbarton

In current cross-compiling builds, the stage1 compiler is a cross-compiler and the stage2 compiler is a native compiler for the target. I think you're talking about a scenario in which the stage1 compiler is a native compiler for the build system and the stage2 compiler is a cross-compiler. Otherwise, ghc-stage2 couldn't possibly link against the stage1 ghc library since they are built for different platforms. Is that right?

If so, don't you have to also have to build all the libraries and the RTS twice. Once to be linked into the stage2 compiler which runs on the build system, and again to be linked into the executables that run on the target that are the output of the stage2 compiler. Similarly you have to detect the vagaries of both the host gcc, in order to build ghc-stage2, and the cross-compiling gcc, in order for ghc-stage2 to know how to build its output. Basically it seems like you have to do most of the work of #11470 anyways.

comment:4 Changed 3 years ago by shlevy

I don't think it's really most of the work, since we already need to know all of the relevant info about the host and the target to do cross-compiling at all, whereas #11470 requires info about arbitrary targets.

I think the best option here is to do a 3- or 4- stage compile for cross-compilation, where the last stage is optional:

3-stage: stage 1 is normal host-native stage 1, stage 2 runs on host and can target both host and target, stage 3 is a cross-compiled target-native GHC. This has the benefit of only requiring the stage 2 compiler to be around to do TH/plugins/ghci, but requires a single ghc binary to be able to target two architectures

4-stage: stage 1 and stage 2 are normal host-native stage 1 and stage 2, stage 3 runs on host and targets target, stage 4 is a cross-compiled target-native GHC. This has the benefit of not needing to teach a single compiler multiple targets, but you'd need to keep both stage 2 and stage 3 around if you wanted to do TH/plugins/ghci.

comment:5 Changed 3 years ago by shlevy

(and yes, in either case we need two versions of base etc.)

Note: See TracTickets for help on using tickets.