Bootstrap
Overview
The Fan compiler is written in Fan itself - which presents a chicken and the egg problem. How do you compile the compiler without having a compiler? To solve this problem, the bootstrap process requires two Fan installations:
- rel: known good Fan installation (typically the last build)
- dev: development environment to build (probably pulled from hg)
By convention we structure our development directory tree like this:
dev/ rel/ bin/ lib/ ... fan/ bin/ lib/ src/ ...
The "rel" directory always contains the last released build. The "fan" directory contains our main development code branch. We call our top level directory "dev", but for the purposes of this discussion "fan" is the development directory.
Dev Home
By default the build assumes devHome to be the home directory of Fan installation. For example if you rebuild jfan, then the output goes into "devHome/lib/java/sys.jar". In the case of the rel installation we don't want this default because we will overwrite ourselves (which leads to some nasty problems). So you need to set the devHome property in "lib/sys.props" of your rel installation to reference the dev directory using a URI (not OS path):
fan.build.devHome=/C:/dev/fan/
If you forget to do this, then you will get a build error which looks something like this:
C:\dev\fan\src>jfan\build Error: Must update /lib/sys.props devHome for bootstrap build Error: Error initializing script [C:\dev\fan\src\jfan\build.fan] build::FatalBuildErr build::BuildScript.fatal (BuildScript.fan:429) ...
Substitutes
On a clean machine with only source code, we don't have any pods compiled such as sys
, build
, or compiler
. In order to run the build scripts to compile these pods, we need to use our rel installation.
Windows Substitutes
To make this all work seamlessly on Windows, the Fan launcher will look in "sys.props" to see if a substitute runtime should be used. For example in our environment we map the following scripts to use the rel installation.
// lib/sys.props of your *dev* directory fan.runtime.substitutes= \ /C:/dev/fan/src/buildall.fan = C:\\dev\\rel \ /C:/dev/fan/src/buildboot.fan = C:\\dev\\rel \ /C:/dev/fan/src/jfan/build.fan = C:\\dev\\rel \ /C:/dev/fan/src/sys/build.fan = C:\\dev\\rel \ /C:/dev/fan/src/compiler/build.fan = C:\\dev\\rel \ /C:/dev/fan/src/build/build.fan = C:\\dev\\rel
The launcher will check if any script being run matches one of those files. If a match is made, then it will route to the alternate runtime specified. Turn on launcher debugging to see exactly what is happening under the covers.
Note that the extension used to run the build scripts needs to match the substitutes defined in the "sys.props". If you set your pathext
to include ".fan", then Windows will pass the extension into the launcher. If you are running an alternate way you might need to explicitly specify the extension on your command line or change the extensions defined in "sys.props".
Unix Substitutes
Unix substitution is implemented by the bootstrap build scripts using the following shebang:
#! /usr/bin/env fansubstitute
The fansubstitute script explictly sets FAN_HOME to the value of the FAN_SUBSTITUTE variable before launching. So you will need to export FAN_SUBSTITUTE to reference your rel installation. And of course you have to run your scripts as executables so that the shebang takes effect.
Also note that building on Unix will skip any .NET targets.
JDK and .NET Tools
You need JDK 1.6 or greater to compile from source (only 1.5 is required for the Java runtime).
Version 2.0 or greater of .NET is required.
In order to compile from source you will need to setup some system properties to reference your JDK and .NET home directories:
fan.build.jdkHome=/C:/dev/tools/java/ fan.build.dotnetHome=/C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/
These paths should be formatted as file system Uris (not OS paths). These properties should be configured in "lib/sys.props" of both your rel and dev environments.
The .NET targets are automatically skipped if not running Windows. So you can ignore the .NET configuration on Unix platforms.
Buildall
The "buildall.fan" script is the top level build script for compiling the Fan distribution. We commonly run this command to rebuild everything and run tests on every pod:
buildall full test
The "buildall" script is executed by the rel substitute runtime and in turn launches two sub-scripts. The "buildboot.fan" script manages rebuilding the core runtime modules:
sys/build.fan jfan/build.fan nfan/build.fan compiler/build.fan compilerJava/build.fan build/build.fan
Once the bootstrap modules are compiled, the development environment is self hosting and can be used to compile the remainder of itself. This is done via the "buildpods.fan" script.
Dependencies
The bootstrap issue can cause some confusing dependency issues which are summarized here:
- The rel compiler will be generating the
sys
,compiler
, andbuild
pod files. This means that the rel compiler must be able to generate fcode that the dev runtime can read. It also means that the rel compiler must be able to read any new syntax used by dev versions ofsys
,compiler
, andbuild
. - The rel compiler will actually use the dev versions of the pods to resolve dependencies. For example dev compiler can reference new sys APIs defined in dev but not rel. Under the covers this works because the
compiler
andbuild
pod's build scripts specify a non-defaultdependsDir
.
Because of these restrictions, adding new language features and fcode changes require some careful planning.
Debugging
You can use the "dumpenv" build target to dump key aspects of your build script environment. You can run target on "buildall.fan", although a more concise report is to dumpenv on "buildboot.fan" and one of the non bootstrap pods like "testSys/build.fan".
On Windows you should see something like this:
C:\dev\fan\src>buildboot dumpenv --------------- scriptFile: /C:/dev/fan/src/buildboot.fan [build::BuildGroup] fanHome: /C:/dev/rel/ devHomeDir: /C:/dev/fan/ --------------- scriptFile: /C:/dev/fan/src/sys/build.fan [build::BuildPod] fanHome: /C:/dev/rel/ devHomeDir: /C:/dev/fan/ --------------- scriptFile: /C:/dev/fan/src/jfan/build.fan [build::BuildJava] fanHome: /C:/dev/rel/ devHomeDir: /C:/dev/fan/ javaHome: /C:/dev/tools/java/ --------------- scriptFile: /C:/dev/fan/src/nfan/build.fan [build::BuildCs] fanHome: /C:/dev/rel/ devHomeDir: /C:/dev/fan/ dotnetHome: /C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/ --------------- scriptFile: /C:/dev/fan/src/compiler/build.fan [build::BuildPod] fanHome: /C:/dev/rel/ devHomeDir: /C:/dev/fan/ --------------- scriptFile: /C:/dev/fan/src/compilerJava/build.fan [build::BuildPod] fanHome: /C:/dev/rel/ devHomeDir: /C:/dev/fan/ --------------- scriptFile: /C:/dev/fan/src/build/build.fan [build::BuildPod] fanHome: /C:/dev/rel/ devHomeDir: /C:/dev/fan/ C:\dev\fan\src>testSys\build dumpenv --------------- scriptFile: /C:/dev/fan/src/testSys/build.fan [build::BuildPod] fanHome: /c:/dev/fan/ devHomeDir: /c:/dev/fan/
Key things to note about your environment:
- all scripts should be using dev for devHomeDir
- bootbuild scripts should be using rel for fanHome
- non-bootbuild scripts like testSys should be using dev for fanHome
- verify javaHome for jfan/build.fan
- verify dotnetHome for nfan/build.fan (if running on Windows)
Summary
In summary, you want to make sure of a couple key things:
- setup your rel installation and never touch it (consider it readonly)
- ensure jdkHome and dotnetHome are configured in both rel and dev lib/sys.props
- ensure rel lib/sys.props devHome points to your dev installation
- make sure your substitutes are configured correctly:
- on Unix make sure your FAN_SUBSTITUTE env points to the rel installation
- on Windows make sure your dev lib/sys.props substitutes are configured
- only put dev bin your path and always run your scripts from the dev installation