Plan 9 from Bell Labs’s /usr/web/sources/contrib/fernan/nhc98/docs/implementation-notes/build-system

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


                         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.




Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.