The build is based on Jakarta Ant. To build, cd to the build
subdirectory off the deployment project you wan to build from (for example
sand/apps/deploy/TaskHeapDemo/build), and type
ant. This will invoke the default "all" target.
The following terms are used in build discussions:
Primary build targets (from mainbuild.xml):
SAND project names must be unique. This provides for unique .jar file
names, build element identification, and other uses.
The primary goal of build processing is to produce a consistent result
with the minimum possible work. The build must be trustworthy
(produce a deployed executable in a reliable manner), and it should
provide maximum utility for common development situations. The build
should also be flexible enough to be adapted to uncommon situations.
A SAND build is distinguished by its use of generators. Metacoding affects all code in all projects in the dependency graph including the supporting platform project(s). Among other things, in the SAND build:
The SAND build is based on Jakarta Ant, and is therefore obviously
compatible with conventional static build systems, and extensible in
similar ways. It can also be extended through custom generators, which
provide broad development power at the source code level without
changes to the implementation language or modifications to code.
There are two major categories of build:
ant.
ant.
A full build is guaranteed to be safe, and you can return your system to
a source-only state by typing ant scrub.
The concept of an incremental build is straightforward: don't rebuild
the target unless the source has changed, make sure you do rebuild when you
have to. However in practice this involves some tradeoffs, the details of
which are best described through use cases and flag descriptions.
In general, the expectation is that both novice and advanced users will
simply type "ant" to take care of all build and deployment needs. The SAND
build should be smart enough to take care of everything without doing extra
work or otherwise annoying the developer.
Given the complexities that arise, it is unlikely the SAND build will
ever reach 100% of this goal, but we are shooting for 90% and doing the
work necessary to make that happen.
use case: forced recompilation
There are times when code needs to be recompiled, without the generators involved. Known examples include:
Forced recompilation is accomplished through the "clean" and "deepclean" targets, followed by the default "ant" call. There is no need for a separate compilation call, since the generators do not access the compiled files (see SandGenerator comments). However there is some additional overhead from checking this:
overhead = (S + N) * G * C Javadoc API documentation is a good thing, but developers whose tools support equal or better code navigation don't want to pay for this ovehead in their local environment. Javadoc behavior in the SAND build is controlled through a flag set as an Ant property:
If the ${generateJavadoc} is not defined, then "update" is
assumed. It is recommended that the property be set only in the
deployment build file, since it is a global property. To avoid
changes to the build.xml file, this property can also be set from an
environment variable.
Notes:
*.java relative to
*.class). So if you switch from "static" to "update"
you will need to rebuild the docs to catch interim changes.
By default java is compiled with debug=on. This can be
controlled through an Ant property:
Java linkage is done at compile time. That means that if class A
references class B, then whatever A knows about B at compile time is
what it goes with. If B is recompiled, A still thinks it is looking at the
same old B. Given that class loaders can cache stuff, there is even a
chance that A will find the old B at runtime. This can be very confusing
if you just changed B and are wondering how the devilish system can
possibly be ignoring your changes.
By recompiling A when B changes, you have a new A referencing a new B
and everything works the way you would expect. But rebuilding everything
every time is annoying, slow, and not always possible. Basically the build
system does it's best to manage the dependencies, but recompiling
everything each time would be prohibitively annoying for most users doing
incremental builds.
Note that problems due to compile time linkage don't manifest themselves
when building from scratch, so a typical reference build will not run into
these issues. If you are using a debugger, you may see what it is going on
relatively quickly, but rediscovering this behavior can be a time sink.
Each deployment or apps project contains a build
subdirectory with a build.xml file. When ant loads build.xml,
the mainbuild.xml include is processed, which provides the main
ant targets ("all", "clean", "deepclean", "scrub", "rebuild" etc).
These targets fall into two categories:
Both local and global targets call through to the sandbuild
task to manage the build process efficiently. The sandbuild
task is mapped to org.sandev.sandbuild.BridgeAnt2SAND, which
retrieves the
SandBuildDriver and
scope (LOCAL/GLOBAL), type
(STATIC/DYNAMIC/ALL), and mode (BUILD/CLEAN) for this
build run.
The SandBuildDriver serves as the central management point
for efficient SAND build processing. For a GLOBAL build,
SandBuildDriver calls the "sandproject" target in
the buildRoot, which (if defined) contains zero or more SAND build tasks:
org.sandev.sandbuild.RequiredProject)
tasks trigger the creation of new SandProject instances,
which are connected to the buildRoot in dependency order (possibly
replacing the buildRoot with an earlier project). Required project
declarations are processed recursively if not already recorded.
org.sandev.sandbuild.SandGenDecl) tasks
register a
SandGenerator to be run as part of the build.
org.sandev.sandbuild.SandEnvFile) tasks declare a
file as part of the runtime environment for the project.
The build tasks, and the dependency graph, are set up and then
processed. By convention, most build targets have a
corresponding clean target. The appropriate targets are
called depending on the build mode. At the time of this writing,
SandBuildDriver calls the following targets to process a
GLOBAL build (optional targets are shown in italics):
SandBuildDriver compiles the generators for each project
(as needed), placing the .class files into build/genclasses.
It then creates /build/env/projname_gen.jar
(as needed), and copies it into the build/env directory
off the build root. The generator source code is documented (according
to the generateJavadoc flag) and stored in the
build/genjavadoc directory of the owning project.
SandBuildDriver goes through the projects in dependency
order, calling the appropriate generators according to their declared
scope. The generators create or cleanup depending on the build mode.
Each generator is responsible for checking its own change status
and the status of its input to avoid doing unnecessary work.
platform/tools/build/build.xml). See that file for details.
For a LOCAL scope build, SandBuildDriver only affects the
driving project.