**************************************************************************
** title:      Build
** author:     Brian Frank
** created:    07 Jan 08
** copyright:  Copyright (c) 2008, Brian Frank and Andy Frank
** license:    Licensed under the Academic Free License version 3.0
**************************************************************************

Overview [#overview]
********************
Fantom comes bundled with its own standard build engine to promote
consistency and make sharing code easy.  Build scripts are normal
[Fantom scripts]`Fan#scripts` which subclass from `build::BuildScript`.
Characteristics of build scripts:

  - 'BuildScript' base class handles common functions like command
    line parsing, environment setup, and logging
  - Subclasses define *targets* which are things the build script
    can do such as "compile", "clean", or "test"
  - Targets are implemented as normal Fantom methods which can
    execute any procedural code needed using the APIs installed
  - The 'build' pod provides libraries of *tasks* which are designed
    to provide common chunks of functionality which can be composed
    to define targets
  - The 'build' pod provides a library of predefined 'BuildScript'
    classes to handle common scripts - one you will use all
    the time is [BuildPod]`build::BuildPod` used to build Fantom pods.

The build toolkit is designed to provide a consistent way to organize
build scripts - it doesn't provide a comprehensive library of
everything you might need to perform a build.  But by predefining
common scripts such as [BuildPod]`build::BuildPod` it reduces most
scripts down to purely declarative information.  When you do need the
power of custom code, you can implement it cleanly as normal Fantom code.

Example [#example]
******************
Let's create a build script called "buildtest.fan":

  using build

  class Build : BuildScript
  {
    @Target { help = "Compile everything" }
    Void compile() { log.info("Compile away!") }

    @Target { help = "Clean it all up" }
    Void clean() { log.info("Clean away!") }
  }

The script above defines two targets: compile and clean.  The targets are
annotated with the [@Target]`build::Target` facet. Set the help field
to a short summary.  To print the usage of this script use "-?":

  C:\dev\fan\src>buildtest -?
  usage:
    build [options] <target>*
  options:
    -? -help       Print usage summary
    -v             Verbose debug logging
    -dumpEnv       Debug dump of script env
  targets:
    compile*       Compile everything
    clean          Clean it all up

Note that the "compile" target is marked with an asterisk indicating
it is the default target because it is the first one declared. If we
invoke the script with no arguments the "compile" target is executed:

  C:\dev\fan\src>buildtest
  Compile away!
  BUILD SUCCESS [3ms]!

Or we can pass one or more targets as arguments:

  C:\dev\fan\src>buildtest clean
  Clean away!
  BUILD SUCCESS [2ms]!

  C:\dev\fan\src>buildtest clean compile
  Clean away!
  Compile away!
  BUILD SUCCESS [2ms]!

Note: see [Setup]`Setup` to configure your environment to run
scripts using just the script filename.

BuildScript [#BuildScript]
**************************
The [BuildScript]`build::BuildScript` is the base class for
all build scripts.  It provides many useful slots you will
find handy:

  - [log]`build::BuildScript.log`: standardized logging
  - [scriptFile]`build::BuildScript.scriptFile`: the file
    of the script itself
  - [scriptDir]`build::BuildScript.scriptDir`: the directory
    containing the script
  - [devHomeDir]`build::BuildScript.devHomeDir`: home directory
    of your development Fantom environment

Lifecycle [#lifecycle]
**********************
A build script lifecycle is composed of these steps:

  1. Base class constructor is run and will immediately setup the
     environment variables such as [log]`build::BuildScript.log` and
     [scriptFile]`build::BuildScript.scriptFile`.
  2. Your subclass constructor is run, which is where you
     can configure your own scripts fields.
  3. The [targets]`build::BuildScript.targets` callback
     is invoked to get the list of targets - most often you will
     let the default implementation build this list by searching
     for methods which implement the '@Target' facet.
  4. Command line parsed to find all the specified targets,
     if no targets specified then we use the first target from
     the 'targets' method..
  5. Each target method is invoked in the order specified
  6. If an exception is raised, the script fails and returns -1,
     otherwise 0 is returned.

Problems during the script should be reported via the
[BuildScript.log]`build::BuildScript.log`.  If an error is
encountered which should terminate the script, then throw
a [FatalBuildErr]`build::FatalBuildErr` via this pattern:

  throw fatal("I just can't go on!")

BuildPod [#buildPod]
********************
[BuildPod]`build::BuildPod` is the base class for build
scripts which build a Fantom pod.  The 'BuildPod' script defines
a bunch of fields to be filled in. Plus it predefines several
targets ready to use:

  - [compile]`build::BuildPod.compile`: recompiles Fantom code into
    a pod file along with all associated natives (JavaScript, Java, .NET)
  - [clean]`build::BuildPod.clean`: deletes all the intermediate
    and derived target files
  - [test]`build::BuildPod.test`: runs all tests declared by the pod
  - [full]`build::BuildPod.full`: clean, compile, test

By convention pod source directories are organized as follows:

  foo/
    build.fan
    fan/
      ClassAlpha.fan
      ClassBeta.fan
    java/
      ClassAlphaPeer.java
    js/
      ClassAlphaPeer.js
    dotnet/
      ClassAlphaPeer.cs
    test/
      TestClassAlpha.fan
      TestClassBeta.fan
    res/
      icon.png
      resource-file.txt

If you don't have tests or native code, then those directories
aren't included.  The build script for our directory structure
above would look like:

  // build.fan
  using build
  class Build : BuildPod
  {
    new make()
    {
      podName    = "foo"
      summary    = "Description of foo pod.  Foo is good."
      depends    = ["sys 1.0+", "bar 1.1+"]
      srcDirs    = [`fan/`, `test/`]
      javaDirs   = [`java/`]
      jsDirs     = [`js/`]
      dotnetDirs = [`dotnet/`]
      resDirs    = [`res/`]
    }
  }

Note that all the directories are specified as Uris relative
to the script directory.  If you don't have native code, you can
omit the 'javaDirs', 'dotnetDirs', and 'jsDirs' settings.
If you don't have resource files you can omit 'resDirs'.  See
[HelloWorld]`docIntro::HelloWorld#pod` for a simpler example.

Typically the pod's version is set by the build script's
[version]`build::BuildPod.version` field.  By default this is
set to the config property 'buildVersion' configured in
"etc/build/config.props".












