1. Installation

1.1. Requirements

SBuild requires an working Java 6 Runtime. All other dependencies are bundled within the SBuild distribution ZIP file.

1.2. Download

You can download the latest stable SBuild distribution from the download page.

1.3. Installation

SBuild runs under all major operating systems, that have a Java 6 Runtime environment.

1.3.1. Linux

You should check, if your Linux distribution provides ready to install packages for SBuild, if so, you may want to install them in the specific way of your Linux distribution. For Gentoo Linux, you can find an ebuild for SBuild in lefous portage overlay.

If you used the installation procedure of you Linux distribution you were done here, else continue.

Unpack the ZIP file content into a directory of your choice, e.g. /opt/sbuild-0.7.1.

Make sure, the expanded file /opt/sbuild-0.7.1/bin/sbuild is executable, e.g. with chmod -x /opt/sbuild-0.7.1/bin/sbuild.

Add the binary directory (e.g. /opt/sbuild-0.7.1/bin/) to your search path: PATH=/opt/sbuild-0.7.1/bin:$PATH

1.3.2. Windows

Unpack the ZIP file content into an directory of your choice, e.g. C:\Program Files\sbuild-0.7.1. After unpacking, you should see the sub directories bin, lib and doc.

Add the environment variable SBUILD_HOME with the value of that directory, e.g. SBUILD_HOME=C:\Program Files\sbuild-0.7.1

Why is the SBUILD_HOME variable needed under Windows?

To be honest, we don’t know. Besides various Windows Command shell magic, we were not able to automatically infer the installation location of SBuild. Therefore we rely on the user to provide the location with the SBUILD_HOME variable.

If you know how to do that automatically, we would like to receive a new issue or even better pull request from you.

Add the path of the bin directory to the PATH variable: PATH=%SBUILD_HOME%\bin:%PATH%

Special Notes for Cygwin Users

If running sbuild under cygwin, you may see the following error message:

$ sbuild all
java.lang.NoClassDefFoundError: de/tototec/sbuild/runner/SBuildRunner
Caused by: java.lang.ClassNotFoundException: de.tototec.sbuild.runner.SBuildRunner
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
Could not find the main class: de.tototec.sbuild.runner.SBuildRunner.  Program will exit.
Exception in thread "main"

This is because cygwin does not execute the sbuild.bat file but the sbuild shell script. You may either call sbuild.bat directly, or delete the PATH/bin/sbuild file.

1.4. Check the installation

Open an new terminal window and execute the command: sbuild --version

You should see something like this:

Output of sbuild --version
$ sbuild --version
SBuild 0.7.1 (c) 2011 - 2013, ToToTec GbR, Tobias Roeser

Congratulations, you have successfully finished your SBuild installation.

1.5. Troubleshooting

If you went into trouble, you may want to search the fourms or create a new thread. If you found a bug please check, if there is already a ticket for it or create a new ticket.

2. First steps on the Commandline

SBuild’s main interface is a command line tool called sbuild. It supports various options and will receive the targets, you want to build, as parameter. When invoked, it searches for a build file SBuild.scala in the current directory, reads it and executes the requested targets.

2.1. Built-in Commandline Help

SBuild supports various commandline options. You can invokde sbuild with the --help or -h option, to get a list of all supported options and parameters with short descriptions.

Output of sbuild --help
bash$ sbuild --help
SBuild 0.7.1 (c) 2011 - 2013, ToToTec GbR, Tobias Roeser

Usage: sbuild [options] [parameter]

Options:
  --additional-buildfile,-F FILE  Add an additional buildfile into scope.
  --buildfile,-f FILE             The buildfile to use (default: SBuild.scala).
  --check                         Check targets for cycles and missing scheme
                                  handlers.
  --check-recursive               Check targets of this project and all its
                                  modules for cycles and missing scheme
                                  handlers.
  --clean                         Remove all generated output and caches. This
                                  will force a new compile of the buildfile.
                                  (This will not remove output generated by
                                  buildfiles.)
  --create-stub                   Create a new minimal SBuild.scala file to
                                  start with.
  --define,-D KEY=VALUE           Define or override properties. If VALUE is
                                  omitted it defaults to "true".
  --dependency-tree               Show dependency tree(s) and exit.
  --execution-plan                Show the execution plan and exit.
  --fsc                           Use the fast scala compiler (client/server).
                                  The fsc compiler of the correct Scala version
                                  must be installed.
  --help,-h                       Show this help screen.
  --jobs,-j N                     Allow processing N targets in parallel. Use 1
                                  to disable parallel and 0 to use
                                  <number-of-cpu-cores> threads.
  --just-clean                    Remove all generated output and caches without
                                  reading any buildfile. This will essentially
                                  remove the ".sbuild" directory in the current
                                  directory.
  --just-clean-recursive          Remove all generated output and caches without
                                  reading any buildfile. This will essentially
                                  remove the ".sbuild" directory in the current
                                  directory and all sub-directories, no matter,
                                  if sub-directories contain SBuild projects or
                                  not.
  --keep-going,-k                 Keep going when some targets can't be made.
  --list-available-plugins        List all plugins available (used and unused)
                                  by this project.
  --list-modules                  Show a list of modules involved in this
                                  project.
  --list-plugins                  List all plugins used by this project.
  --list-targets,-l               Show a list of targets defined in the current
                                  buildfile.
  --list-targets-recursive,-L     Show a list of targets defined in the current
                                  buildfile and all modules.
  --no-color                      Disable colored output.
  --no-fsc                        Do not try to use the fast scala compiler
                                  (client/server)
  --no-global                     Do not read global settings from <USER
                                  HOME>/.sbuildrc.
  -q,--quiet,--no-progress        Quiet mode. Don't show progress messages with
                                  progress in percent. (This will speed up
                                  SBuild initialization.)
  --repeat SECONDS                Repeat the requested action after the given
                                  time (in seconds), but not before the previous
                                  run was completed.
  --verbose,-v                    Be verbose when running.
  --version                       Show SBuild version.

Parameter:
  TARGETS  The target(s) to execute (in order).

2.2. The Buildfile

The buildfile contains all instructions and target descriptions and is typically written by the developer.

If sbuild does not found any buildfile, it will stop with an error message like this one:

bash $ sbuild

SBuild detected an failure in the project configuration or the build scripts.
Details: Project file '/tmp/example/SBuild.scala' does not exists

The relevant error message tells you, that the buildfile Sbuild.scala is required to proceed but was not found in the current directory.

2.2.1. Using an alternative Buildfile

To use another buildfile, you can use the --buildfile or -f option.

Using an alternative buildfile
bash$ sbuild -f MyBuild.scala

2.2.2. Creating a Buildfile stub

You you want to start a new SBuild project, you can use the --create-stub option, to let SBuild create a minial buildfile for you.

bash$ sbuild --create-stub

For an easy start you can instruct sbuild to create an minimal template file for you:

bash $ sbuild --create-stub

In case, you run sbuild --create-stub accidentally in a directory, where a buildfile already exists, SBuild will refuse to override it.

bash$ sbuild --create-stub

SBuild failed with an unexpected exception (SBuildException).
Details: File SBuild.scala already exists.

2.2.3. The Stub Buildfile

Here is the content of a Buildfile created with sbuild --create-stub.

import de.tototec.sbuild._

@version("0.7.1")
class SBuild(implicit _project: Project) {

  Target("phony:clean") exec {
    Path("target").deleteRecursive
  }

  Target("phony:hello") help "Greet me" exec {
    println("Hello you")
  }

}

This Buildfile contains the following information:

  • It requires SBuild 0.7.1 or newer

  • It contains two targets clean and hello

  • Both targets are phony, which means, they do not produce a single file but constitute some tasks, and both contain some custom actions.

You can customize the result of sbuild --create-stub by providing your own stub buildfile. To do this, you have to create a directory stub in the installation directory of SBuild (${SBUILD_HOME}) and place the template buildfile in that directory. If SBuild is run with the --create-stub, it will first search in that stub directory if it will find a file with the same name as the expected buildfile, namely SBuild.scala.

You can also provide more that one stub files with different names. To select a specific stub file, e.g. Setup.scala, run SBuild with sbuild --create-stub -f Setup.scala. Now SBuild will first search for a file named Setup.scala in the ${SBUILD_HOME}/sub directory. If one is found, this will be used as stub file, else the built-in default will be used. Finally, you will find the newly created stub file in the current directory.

2.3. Running SBuild

To execute one or more targets of a project, simple give the desired targets as parameters.

E.g. to execute the clean and the hello targets of the just created buildfile above, you will run sbuild clean hello. Following is the output of that command:

bash$ sbuild clean hello
Initializing project...
Compiling build script: /tmp/test/SBuild.scala...   (1)
[0%] Executing...
[0%] Executing target: clean   (2)
[50%] Finished target: clean after 4 msec
[50%] Executing target: hello
[50%] Greet me
Hello you
[100%] Finished target: hello after 0 msec
[100%] Execution finished. SBuild init time: 3,904 msec, Execution time: 57 msec   (3)
1 If SBuild never run before or if it detects, that the buildfile has changed, it will compile the buildfile, thus the output Compiling build script: ....
2 After compilation of the buildfile, it will execute the required targets and print what it is actual doing paired with a handy progress report.
3 At the end, you will see the Execution finished message and some little statistics.

In any subsequent run, compilation of the buildscript is not needed again and SBuild the execution of the requested targets start almost instantly.

bash$ sbuild clean hello
Initializing project...
[0%] Executing...
[0%] Executing target: clean
[50%] Finished target: clean after 2 msec
[50%] Executing target: hello
[50%] Greet me
Hello you
[100%] Finished target: hello after 0 msec
[100%] Execution finished. SBuild init time: 164 msec, Execution time: 55 msec

2.4. Built-in project exploration

SBuild has some handy options, which let you easily explore a project. Most of these options also have a "recursive" variant, which includes also all modules (sub projects) into the output.

The most frequently used options are:

--list-targets, -l

Show a list of targets defined in the current buildfile.

--list-targets-recursive

Show a list of targets defined in the current buildfile and all modules.

--list-modules

Show a list of modules involved in this project.

--list-plugins

List all plugins used by this project.

--list-available-plugins

List all plugins available (used and unused) by this project.

2.5. Project validation

TBD

2.6. Parallel execution

By default, SBuild will execute targets in parallel, to utilize the resources of modern multi-core hardware more efficiently. You can customize the number of simultaneously used threads with the --jobs or -j commandline option. With -j 1, you can disable the parallelization entirely and will also reduce the output slightly.

To use as much threads as your CPU has cores, you can use -j 0 (which is also the default) to instruct SBuild to auto-detect the used thread pool size.

To make a custom jobs setting permanent, you can add it to the ${HOME}/.sbuildrc file.

${HOME}/.sbuildrc
jobs=4

2.7. Failing the Build

When SBuild detects an execution failure in a target, it will interrupt all other parallel executing targets, print a error message with some details about the initially failed target and quit.

Sometimes, it is desirable to fail the build as late as possible and not stop at the moment the first target fails. Of course, the build can not be completed successfully, but some other targets may complete. In such scenarios, you can use the --keep-going or -k commandline option. When specified, SBuild tries to complete as much targets as possible before failing with a descriptive error message indicating which targets failed and which could not be completed because of unsatisfied dependencies.

2.8. Repetitive tasks

TBD

3. Writing Buildfiles

3.1. The Buildfile - the only true source

SBuild buildfiles are normal Scala source files. As such, they can be viewed and edited as any other text file with any text editor. Although an editor providing syntax highlighting and other Scala specific candy might be helpful.

The buildfile is the only place, where SBuild looks for description of your build!

To change the build and the SBuild behavior, you have thus only the option to change the buildfile or to make use of the various commandline options of sbuild.

3.2. Buildfile Preprocessing

SBuild buildfiles are Scala source files and must be compiled before SBuild can use them. This preprocessing is automatically done by SBuild, without any interaction from your site. Of course, the Scala compiler has no notion of SBuild plugins, libraries and includes, thus the buildfile must be preprocessed. SBuild will extract and interpret specific annotations before the buildfile is compiled and executed.

These are the special annotation, which are typically placed just before the build class SBuild.

@version

Specified the minimal SBuild version that is required for this buildfile. This annotation should be present in each buildfile. It will help detect version mismatches which otherwise might result in strange compile or runtime errors, which are comparatively hard to understand.

Example: @version("0.7.1")

If in doubt, use the version you are currently using.

@classpath

Additional plugins and libraries that should be used by this buildfile have to be declared here. Each given entry will be interpreted as a potentially plugin (see chapter Plugins), unless it is prefixed with raw:. If the entry is a plugin, SBuild will automatically scan it’s manifest and load it’s dependencies. All default SchemeHandler can be used here.

Example: @classpath("mvn:org.sbuild:org.sbuild.plugins.sbuildplugin:0.2.1", "mvn:org.apache.ant:ant:1.8.4")

@include

Here you can refer to additional Scala source files. These files will be compiled by SBuild with the same classpath as the buildfile. The compiled classes will be added to the classpath and can be directly used. All default SchemeHandler can be used here.

Example: @include("CommonSettings.scala")

3.3. SBuild Core API

The Core API of SBuild allows you to

  • create targets,

  • declare actions that should take place when a target gets executed,

  • define dependencies between targets,

  • interact with the environment,

  • run file operations

With a knowledge of the Core API, you have everything you need to write simple to complex buildfiles in an imperative style.

Please don’t stop here. With the use of Plugins you will be able to write much more concise and readable build script in a declarative fashion.

3.3.1. Targets

Targets are the central unit of work in SBuild. Each target has at least a name. This name is what you use on the SBuild commandline.

Targets can be of two kinds:

  • file targets - Targets, that are associated with a local file.

  • phony targets - Targets, not associated to any file representing some kind of action.

A buildfile with two targets, file.txt and action
import de.tototec.sbuild._

@version("0.7.1")
class SBuild(implicit _project: Project) {

  Target("file.txt") (1)

  Target("phony:action") (2)

}
1 A file target associated with the file file.txt in the project directory. The prefix file: is optional and was omitted.
2 A phony target with the name action. As it is not associated with any file it must be prefixed with phony:.

File-Targets represent a file in the local file system. If SBuild is requested to execute a file target (without dependencies), it will first check if that file already exists, and only if not, the target is run.

Phony-Targets represents some kind of action not resulting in a single local file. If SBuild is requested to execute a phony target, the target will always run. Of course, there are various mechanism to make that logic more clever, e.g. by making targets cacheable.

3.3.2. Executions

A plain target as seen above does not do anything when executed. That can be changed by assigning an execution block to a target.

A buildfile with two targets, file and action, both having an execution block
import de.tototec.sbuild._

@version("0.7.1")
class SBuild(implicit _project: Project) {

  Target("file.txt") exec { (1)
    import java.io._
    val target = Path("file.txt") (2)
    println(s"Created file: ${target}") (3)
    val ps = new PrintStream(target)
    ps.println("file content") (4)
    ps.close()
  }

  Target("phony:action") exec { (5)
    println("Action executed") (6)
  }

}
1 A definition of a file target file.txt with an execution block.
2 Here you see a way to use Path to construct a java.io.File relative to the project directory. This is not the most appropriate way in this situation, as you will see soon in the "Target Context" section.
3 The string "Created file: file.txt" will be printed to standard output stream.
4 The string file content is written into the file file.txt.
5 A definition of a phony target with an execution block.
6 The string "Action executed" will be printed to standard output stream.

The example above shows, how targets with execution blocks can be created.

3.3.3. Dependencies

Targets can also have dependencies.

TBD

3.3.4. Target Context

TBD

3.3.5. File operations

TBD

TBD

3.4. Using Plugins

TBD

3.5. Multi-Project Setups

TBD

3.6. Working with Include-Files

TBD

4. Advanced topics

4.1. Understanding SchemeHandler’s

TBD

4.2. Writing Plugins

4.2.1. Plugin API

TBD

4.2.2. Conventions

TBD

4.2.3. Plugin Classloading

TBD

5. Vision

5.1. The unimplemented parts

5.2. The eco system