Compiler and runtime system ways in GHC

GHC can compile programs in different ways. For instance, a program might be compiled with profiling enabled (-prof), or for multithreaded execution (-threaded), or maybe making some debugging tools available (-debug, see Debugging/RuntimeSystem for a description).

There are two types of GHC ways, RTS-only ways and full ways.

  • Runtime system (RTS) ways affect the way that the runtime system is built. As an example, -threaded is a runtime system way. When you compile a program with -threaded, it will be linked to a (precompiled) version of the RTS with multithreading enabled.

Obviously, the compiler's RTS must have been built for this way (the threaded RTS is activated by default BTW). In customised builds, an RTS way can be added in the build configuration mk/ (see mk/, by adding its short name to the variable GhcRTSWays.

  • Full ways

Full compiler ways are ways which affect both the generated code and the runtime system that runs it.

The profiling way -prof is such a way. The machine code of a program compiled for profiling differs from a normal version's code by all code that gathers the profiling information, and the runtime system has additional functionality to access and report this information. Therefore, all libraries used in a profiling-enabled program need to also have profiling enabled, i.e. a separate library version for profiling needs to be installed to compile the program with prof. (If the library was installed without this profiling version, the program cannot be linked).

In customised builds, a full way is added in the build configuration mk/ by adding its tag to the variable GhcLibWays.

Available ways in a standard GHC

Ways are identified internally by a way name, and enabled by specific compilation flags. In addition, there are short names (tags) for the available ways, mainly used by the build system.

Here is a table of available ways in a standard GHC, as of May 2015.

Way flag Way name Tag Type Description
- - v Full (vanilla way) default
-threaded WayThreaded thr RTS multithreaded runtime system
-debug WayDebug debug RTS debugging, enables trace messages and extra checks
-prof WayProf p Full profiling, enables cost centre stacks and profiling reports
-eventlog WayEventLog l RTS Event logging (for ghc-events, threadscope, and EdenTV)
-dyn WayDyn dyn Full Dynamic linking

The standard (vanilla) way of GHC has a name (vanilla), but it could (probably?) even be switched off in a custom build if desired. Obviously, the libraries would still need to be built in the vanilla way for all RTS-only ways, so one would need GhcLibWays=v when building any other RTS-only way.

The code (see below) contains another way, for Glasgow parallel Haskell, which is currently unmaintained (WayPar).

Ways for parallel execution on clusters and multicores

The parallel Haskell runtime system for Eden (available from defines several RTS-only ways for Eden. All these ways execute the RTS in multiple instances with distributed heaps, they differ in the communication substrate (and consequently in the platform).

Way flag Way name Tag Type communication (OS)
-parpvm WayParPvm pp RTS PVM (Linux)
-parmpi WayParMPI pm RTS MPI (Linux)
-parcp WayParCp pc RTS OS-native shared memory (Windows/Linux)
-parms WayParMSlot ms RTS Windows mail slots (Windows)

Combining ways

The alert reader might have noticed that combinations like "threaded with dynamic linking" or "profiled with eventlog" are not covered in the table. Some ways can be used together (most prominently, debugging can be used together with any other way), others are mutually excluding each other (like profiling with eventlog).

The allowed combinations are defined inside the compiler, in compiler/main/DynFlags.hs. Which brings us to discussing some of the internals.

When compiling ghc, the available combinations are listed in mk/; as of 7.10.3:

thr         : threaded
thr_p       : threaded profiled
debug       : debugging (compile with -g for the C compiler, and -DDEBUG)
debug_p     : debugging profiled
thr_debug   : debugging threaded
thr_debug_p : debugging threaded profiled
l           : event logging
thr_l       : threaded and event logging

For example, to build both the profiling and the debug version of the profiling RTS (libHSrts_debug_p/lHSrts_debug_p), you can add

GhcRTSWays        += p debug_p

to your


Ways are defined in compiler/main/DynFlags.hs as a Haskell data structure Way.

Function dynamic_flags defines the actual flag strings for the ghc invocation (like -prof, -threaded), which activate the respective Way.

The short name tags for ways are defined in wayTag. The tags are used in the suffixes of *.o and *.a files for RTS and libraries, for instance *.p_o for profiling, *.l_o for eventlog.

A number of other functions in there customise behaviour depending on the ways. Note wayOptc which sets some options for the C compiler, like -DTRACING for the -eventlog way.

However, this is not the full truth. For instance, there is no -DDEBUG for the debug way here, but the RTS is full of #ifdef DEBUG.

In mk/, we find all the short names and all combinations enumerated, and some more options are defined here (WAY_*_HC_OPTS). These definitions are for the driver script, and pass on the right (long-name) options to the Haskell compiler to activate what is inside DynFlags (like -prof for WAY_p_HC_OPTS). Here we find WAY_debug_HC_OPTS= -static -optc-DDEBUG -ticky -DTICKY_TICKY so we can learn that ticky profiling is activated by compiling with debug.

(TODO be more precise on where the options from are used.)

Last modified 6 months ago Last modified on May 30, 2017 11:44:18 AM