|Version 16 (modified by 10 years ago) (diff),|
[ Up: Commentary ]
The compilation pipeline
When GHC compiles a module, it calls other programs, and generates a series of intermediate files. Here's a summary of the process.
We start with
Foo.lhs, the "l" specifing whether literate style is being used.
- Run the unlit pre-processor,
unlit, to remove the literate markup, generating
unlitprocessor is a C program kept in
- Run the C preprocessor,
-cppis specified), generating
- Run the compiler itself. This does not start a separate process; it's just a call to a Haskell function. This step always generates an interface file
Foo.hi, and depending on what flags you give, it also generates a compiled file:
- Assembly code: flag
- C code: flag
- C-- mode: flag
Foo.cmm, believed not to work
- Assembly code: flag
- In the
-fviaCcase, run the C compiler, followed by the Evil Mangler, generating
-fsplit-objsis in force, run the splitter on
Foo.s. This splits
Foo.sinto lots of small files,
Foo/Foo2.s, etc. The idea is that the static linker will thereby avoid linking dead code.
- Run the assembler on
-fsplit-objsin in force, on each individual assembly file.
An interface file supports separate compilation by recording the information gained by compiling
M.hs in its interface file
M.hi. Morally speaking, the interface file
M.hi is part of the object file
M.o; it's like a super symbol-table for
Interface files are kept in binary, GHC-specific format. The format of these files changes with each GHC release, but not with patch-level releases. The format of an interface file can be determined by examining
compiler/iface/IfaceType. An informal description of a particular file, suitable for a person (not for machine parsing), can be found thus:
ghc --show-iface M.hi
Here are some of the things stored in an interface file
- A list of what
- The types of exported functions, definition of exported types, and so on.
- Version information, used to drive the smart recompilation checker.
- The strictness, arity, and unfolding of exported functions. This is crucial for cross-module optimisation; but it is only included when you compile with