1. Dumping out compiler intermediate structures

I think the order in which the options are listed is along the same line as the real order of the passes.

For example, ghc -ddump-to-file -ddump-asm a.hs would dump the assembly to file a.dump-asm.
The option "-ddump-to-file" tells ghc to dump to a file, instead of to stdout. This feature does not seem to be documented.


2. The runtime system

GHC compiles Haskell source code down to native code, and then links in necessary Haskell libraries (written in Haskell) and RTS (written in C and C--). To see what libraries are linked in, pass -v to ghc.

Therefore, the lifetime of a Haskell program roughly looks like this:

The C Runtime (CRT) gets started first, which passes control to main. For C programs, main is defined by programmers; while for Haskell programs, main is defined by RTS in rts/Main.c. Next, RTS is initialized by calling startupHaskell in RtsStartup.c. Eventually, the computation that resides in mainIO_closure (a macro defined in Prelude.h that resolves to &ZCMain_main_closure) is kicked off from real_main. The closure data structure is defined as StgClosure/HaskellObj in includes/RtsAPI.h and includes/Closures.h.

In fact, because RTS is C code, you can play with its Makefile to produce a libHSrts.a with debugging information in it. Then you can link your Haskell program with this library to walk through the source of RTS in gdb.

3. Static linking vs dynamic linking

The Haskell libraries are statically linked by default. In fact, shared Haskell libraries are only supported on Mac OS X. There are good reasons for that.

The C libraries are not statically linked by default. To produce a completely static binary, run ghc -optl-static -optl-pthread a.hs. Any string following "-optl" is passed to gcc for the final linking step. Without "-optl-pthread", you get errors like this:


wh5a@flitwick:/tmp$ ghc -optl-static a.hs
compilation IS NOT required
/usr/lib/gcc/i486-linux-gnu/4.2.3/../../../../lib/librt.a(timer_create.o): In function `timer_create':
(.text+0x111): undefined reference to `pthread_once'
/usr/lib/gcc/i486-linux-gnu/4.2.3/../../../../lib/librt.a(timer_create.o): In function `timer_create':
(.text+0x165): undefined reference to `pthread_attr_init'
/usr/lib/gcc/i486-linux-gnu/4.2.3/../../../../lib/librt.a(timer_create.o): In function `timer_create':
(.text+0x1ab): undefined reference to `pthread_attr_setdetachstate'
/usr/lib/gcc/i486-linux-gnu/4.2.3/../../../../lib/librt.a(timer_routines.o): In function `__start_helper_thread':
(.text+0x49): undefined reference to `pthread_attr_init'
/usr/lib/gcc/i486-linux-gnu/4.2.3/../../../../lib/librt.a(timer_routines.o): In function `__start_helper_thread':
(.text+0x5c): undefined reference to `pthread_attr_setstacksize'
/usr/lib/gcc/i486-linux-gnu/4.2.3/../../../../lib/librt.a(timer_routines.o): In function `__start_helper_thread':
(.text+0xab): undefined reference to `pthread_create'
/usr/lib/gcc/i486-linux-gnu/4.2.3/../../../../lib/librt.a(timer_routines.o): In function `__start_helper_thread':
(.text+0xde): undefined reference to `pthread_attr_destroy'
/usr/lib/gcc/i486-linux-gnu/4.2.3/../../../../lib/librt.a(timer_routines.o): In function `__start_helper_thread':
(.text+0xfa): undefined reference to `pthread_atfork'
/usr/lib/gcc/i486-linux-gnu/4.2.3/../../../../lib/librt.a(timer_routines.o): In function `timer_helper_thread':
(.text+0x19d): undefined reference to `pthread_exit'
/usr/lib/gcc/i486-linux-gnu/4.2.3/../../../../lib/librt.a(timer_routines.o): In function `timer_helper_thread':
(.text+0x1e5): undefined reference to `pthread_create'
/usr/lib/gcc/i486-linux-gnu/4.2.3/libgcc_eh.a(unwind-dw2.o): In function `uw_init_context_1':
(.text+0x1904): undefined reference to `pthread_once'
collect2: ld returned 1 exit status


Looking at the above error, you may think passing "-optl-lpthread" instead of "-optl-pthread" would help, too. But as you can see in the verbose mode, "-lpthread" is passed to gcc too early. Another way to work around this error is to pass "-threaded" to ghc, which automatically adds "-lpthread" to the end of gcc's command options because ghc knows you're using the threaded Haskell library.

For more advanced tricks, refer to the script "kernel/ldhouse" from the House project.