nhc98's build system
The build system for nhc98 is based on the standard 'make' utility,
with a hand-built 'configure' script to patch up differences
between machines and prepare various other scripts before building.
We additionally use 'hmake' for some components (where all the files
are in Haskell), because it works out the dependencies automatically
and saves us some effort as developers.
Source tree layout
The source tree is laid out as follows:
docs/ -- you are here
include/ -- standard interface files (and runtime C includes)
lib/ -- final location for executables and libraries
$(MACHINE)/ -- separated by architecture
man/ -- manual pages
script/ -- shell script drivers for all the tools
src/
compiler98/ -- the compiler proper, called nhc98comp
greencard/ -- a Haskell-C-code interfacing tool
hmake/ -- automatic make tool for Haskell
hp2graph/ -- convert raw heap profile to PostScript graph
interpreter/ -- 'hmake interactive', simulates Hugs
libraries/ -- will contain the extended standard library set
prelude/ -- prelude + current standard libraries
Prelude/
List/
Char/
...
runtime/ -- runtime support all written in C
Kernel/ -- cmdline args, interpreter, GC, tables
Builtin/ -- implementations of primitives
Mk/ -- auxiliaries for building heap values
Integer/ -- multi-precision Integer library
tracer/ -- extra runtime support and tools for tracing
runtime/ -- rts extensions for tracing
ui/ -- java browser (hat-trail)
hat/ -- textual hat tools (-observe, -detect, -stack, etc)
hood/ -- java browser for HOOD library
targets/ -- temporary build location for objects, executables, etc.
$(MACHINE)/ -- subdir for each architecture
obj/ -- ordinary object files
hmake/
compiler98/
runtime/
prelude/
...
objp/ -- heap profiling object files
runtime/
prelude/
objt/ -- time profiling object files
runtime/
prelude/
objT/ -- tracing object files
runtime/
prelude/
The build system is designed to allow multiple builds on different
machine architectures to proceed in parallel from the same (shared)
source tree. The tool 'script/harch' is used to determine a canonical
name for each architecture, and in many places this is assigned
to the variable $(MACHINE). For instance, common values might be
"ix86-Linux", or "sparc-solaris2". All architecture-specific files
are kept separate from the sources and from each other, usually by
the creation of a directory named for the architecture. So, you will
find directories like
lib/ix86-Linux
targets/ix86-Linux
src/prelude/ix86-Linux
in various places.
During the build, all object files are created under the 'targets'
directory, in a tree structure that largely mimics the structure of
the source tree. Eventually, at the end of each component's build
cycle, the final executables (or combined object archives) are moved
to the 'lib' directory.
Makefiles
In every source directory, there is both a Makefile and a Makefile.inc.
Every Makefile issues a command to include the corresponding
Makefile.inc. The primary purpose of each Makefile.inc is simply to
include the Makefile.inc from the enclosing directory - and hence,
eventually the top-level Makefile.inc. The top-level Makefile.inc
contains various configuration options that can be overridden once
for the whole tree - many of these options are in fact sourced from
environment variables set in the file lib/$(MACHINE)/config.
The top-level Makefile has many useful "dummy" targets like 'compiler',
'tracer', 'prelude' etc. These essentially call 'make' recursively
in the appropriate directories. Often, they also leave a zero-length
dummy file in the targets/$(MACHINE) directory, as a quick check for
later 'make' invocations to know whether a component is already built.
Sometimes you will find it necessary to remove one or two of these
dummy files if you want to force 'make' to build a component again.
In general, each subdirectory Makefile has six main targets:
all -- build the component
install -- build the component and install in lib/$(MACHINE)
fromC -- build the component from .c bootstrap files
cfiles -- create .c bootstrap files
clean -- remove object files
realclean -- remove object files and .hi files
Note that 'make install' in a subdirectory copies components into
the lib/$(MACHINE) directory *within* the build tree. Only the
top-level Makefile can do the final install from the build tree into
a system-wide location.
Ways
Nhc98 has facilities for heap profiling, time profiling, and tracing,
and each of these requires the runtime system and prelude/libraries
to be built in a slightly different way. From the top-level Makefile,
the variable $(CFG) is set to 'p' 't' or 'T' to indicate the way for
a recursive call of 'make' in the runtime or prelude subdirectory.
The tools (i.e. anything except the runtime and prelude) can be built
with any Haskell'98 compiler. This is indicated to a recursive call of
'make' by setting the $(HC) environment variable.
|