|
Table of Content
|
[up one level]
|
Higher level build descriptions
|
While SBuild relies on SCons and does share a lot with it, the SBuild build descriptions are very different than the native ones of SCons. They are still Python scripts. But they are descriptive in nature, vaguely similar in spirit to a description in XML. If they are "better" is subject to discussion and depends of the actual developer expectations.
A SBuild script is basically a list of target specifications (in short, target specs). These targets form a tree that we call the SBuild tree. We state that the Sbuild scripts are higher level because each node in this SBuild tree may corresponds and usually corresponds to a small Node tree at the Scons level, not to just one Node. The SBuild tree is smaller, it "aggregates" fragments of the SCons dependency tree.
[back to top]
|
Hierarchical builds
|
SBuild provides canned hierarchical builds. The developer places in target specifications a list of subtargets (more precisely, a list of queries to fetch subtargets) and then this target can be placed in higher level targets.
SCons already has features in the way of hierarchical builds. Some are similar (ex. hierachical builds can be, at choice, in several separate build scripts or in one and the same script) and some are different. For example, SBuild tree can be "grown upwards" without touching any existing script (think of a sconstruct instantly becoming a sconscript in a "higher" sconstruct elsewhere).
Also, SCons follows the error of make and encourages a tight link between the deployment structure of the product (what libraries) and the layout of the code base (the directory structure). That makes any change of the deployment so painful that it will be avoided forever. SBuild introduces unprecedented flexibility for designing several deployments from the same codebase.
All in all, we state that SBuild has more flexibility for the organization of targets into scripts. More explanation on the page presenting the syntax of the SBuild scripts.
[back to top]
|
Faster small builds
|
SCons traditional way to hierarchcal builds, the sconscript way, has a speed problem when what is desired is a small part in a large build. For example, a developer works on a source file and he wants to compile that file and nothing more. SCons makes him pay the price of a much larger check that what he wants. SBuild makes it easy to choose any desired smaller part and quickly build just that. This feature is put to work in the Eclipse plug-in, where the developer can compile one and only one file with a double click.
[back to top]
|
Variants
|
SBuild provides canned variants. They are basically an enumeration with a name and a documented list of allowed values. A target "has" a variant means that the variant id is listed in the target specification. Variant values can be changed from the command line of the build (among other ways) and the different flavors of the built files are stored in separate locations on disk. Adding or removing a variant to a target doesn't break the build. More on variants in the description of Sbuild concepts.
[back to top]
|
Ultra-minimal API
|
It was one of the design goals of SBuild to favor the style copy-paste-change for learning on the job. While we are not big time fans of this style (because all too often it means that developers do things not really knowing what they do), we have to aknowledge that this was, is and will be a very frequent use scenario among our developers.
To that purpose, the SBuild API has only a handfull of symbols. Here is the exhaustive list:
- sb.T() to introduce a target spec. A spec accepts a limited set of attributes, depending of a target typoe. The allowed types, their atributes and their explanation can be obtained as on-line help.
- sb.V() and sb.E() to introduce things that you can use in a target spec
- sb.vars.<id> and sb.tks.<id> to get access to registered variants and regitered toolkits (in order, for example, to put things conditionally in a target spec)
- <spec>.clone() method to save typing when making similar specs
The SBuild has also a trivial way to extend the API but, experience showed, that is rarely needed and rarely used. The mechanism is: put a Python function myfunc() in some place and then you can use it, as sb.myfunc(), in your build scripts. That is used, for example, to add something to all target in the current build script (reduce verbosity) or make sure that all of them have something (enforcement).
With this API, reading an existing script is usually all it takes to understand how to use the API. The rest of the learning curve (for build script authors at least) is provided by error messages. For example, "Target <id> of type <type> requires attribute <attr> to be specified", "Attribute <attr> is not understood for target <id> of type <type>"
[back to top]
|
GUI friendly
|
The descriptive nature of the SBuild build scripts makes it possible and easy to build a GUI on top of it. An outline view of a build script will show the list of targets (and not spend the time to build a dependency tree, for example). This is demonstrated in our Sbuild Eclipse plug-in.
Any build script is able to give on-line information, for example exhaustive list of attributes allowed in some spec, information that can be recovered and put to good use by the GUI. Also, a descriptive, non-procedural build description is friendly towards automatic generation by some wizard that the GUI may implement. These features are not yet in our Eclipse GUI.
[back to top]
|
SBuild packages
|
SBuild groups together related build script in what is called an SBuild pakage also named an SBuild project. An SBuild package is roughly just a directory with build scripts. Yet, this is a powerful mechanism to implement project-wide or product-wide convention and policies. Scripts in the same package share variants, user private settings, directory location conventions, API extension functions and even private complete toolkits.
[back to top]
|
Others advantages
|
- SBuild scripts are true Python scripts. They carry the file extension .py and they do that for a good reason. The SBuild is loaded (and indirectly SCons) by those scripts like any Python script would load any functionality provided to it. This has a few minor advantages, like easily taking advantage of Python development IDEs and lint-like checkers for Python code. At least one experienced Python programmer new to SCons tried first python sconstruct and got surprised :-)
- The command line of SBuild (meaning of the build scripts) has a few improvements over SCons. A trivial one (but that we deem important) is "do nothing when asked nothing". Any commit to disk is the result of a user explicit choice; the script by itself just lists information.
- Another advantage is the standard mechanism to change from the command line any target spec in the SBuild tree, without changing build scripts. Together with "direct args" (explained further below), this provides fast, in-place, experimental builds, yet safe builds, without chaotic proliferation of flavors.
[back to top]
|
Disadvantages
|
There is no doubt, SBuild scripts are more verbose than the SCons scripts. It is more striking for the school case examples. The minimal script to build an executable with SCons will be one line of code and the SBuild equivalent will be about 10 lines of code (there is a requirement to provide "doc string", there is some short boiler plate code at the top and the bottom of any script, etc.). But we like to believe that the readability of the build descriptions decreases slower for SBuild when the size of the system to be built scales up to real life projects.
[back to top]
|
More out of the box
|
SCons is such a wonderful engine. It was one goal of us to provide a feature rich build tool. We chose SCons for its "programmability" (among many other reasons) and then we made SBuild provide "more of almost everything" for our users.
[back to top]
|
SBuild toolkits
|
SBuild toolkits are a way to group together all the steps for a related build. For example the C/C++ toolkit would share nothing with the Java toolkit (other than SBuild generic code). This is SBuild attempt to install some structure in the SCons large pool of Tools and large Construction Environment. It is also an attempt to help with the toolchain support (by letting domain specialist focus on smaller part of the system; there will be different documented procedures to add new toolchains to different toolkits).
Toolkits don't provide only targets types. They also provide variants, directory conventions and the so-called toolkit parameters (example: lint_usage). Toolkit parameters can be changed from the command line (among others places) and are part of the on-line reference information. Toolkit parameters provide, among others, standard ways to pass direct command line arguments to individual executables (which would be otherwise subject of uncontrolled hacks).
[back to top]
|
More builders
|
SBuild saw several toolkits added over the years. Many of them are of limited interest. They compile data in some binary format specific to some product (and live in the SBuild package of that product). Some of them are of general interest (and live in SBuild) like the one for compiling Python source code. One toolkit worth mentioning is the "base", actually the set of target types provided by SBuild itself. Among them we have:
- The template expander: this one constructs a file out of a source template file and a set of values provided in the target spec
The arbitrary command line: this one wraps a command line (small technical detail: what to run is provided in a SBuild runner spec and that uses SCons Action(), not Command()).
The file concatenator: functionality similar to Unix cat.
The text encoding converter: this one is heavily used by us to convert to, from and between UTF-8 and UTF-16. It uses underneath the Python codecs module.
The copy target: this one provides some suggar around the Install() and InstallAs() SCons builders, like selecting sources with file patterns
The alias target: this one is just a Python list and it doesn't use the Alias() of SCons because that one cannot be passed as dependency to other targets (in SCons 0.96.1). For example, a linker will not accept an SCons alias node as source and automatically unfold the C object nodes in it. There is also a "symbolic alias" target that do use the SCons Alias().
There are a few others targets for this "base" toolkit that we wanted and needed but we didn't get to implement yet: the zip target, the wave file converter, the FTP uploader, the recursive sbuild target, etc. There are also, of course, many other target types in other toolkits.
[back to top]
|
More actions
|
There are several aspects related to actions that are a tiny bit better in SBuild. For example there is a command line option for the forced build and the build script authors don't need to care about it (only toolkit authors). Another aspect is the selective activation/deactivation of preactions.
One important action added by SBuild is ''running" a target. It is very practical for smoke testing any build. For any target, you can put in its spec a SBuild runner. For targets like built executables, SBuild makes one automatically. The sequence build_something.py -b followed by build_something.py -r is by far the most frequently used idiom at the command line.
[back to top]
|
Better introspection
|
We are proud with the capacity of SBuild to help developers new to a product to understand what they have under their hands (although they don't have at first the reflex to use these introspection features). Once a correct SBuild build description is available for a product, you can get all kind of information, from rather innocent (like statistics on lines of code) to very specific (like "where do I, porting engineer, have to touch the code, given this particular new target platform?").
- Reports: There is of course the list sources; yes, the trivial, the often lacking in other tools, the very frequently used listing of the full path to source files. For C/C++, there are a lot of other interesting listings like include directories, applied defines, exported symbols, etc.
- Searches: You can search the sources for a regular expression pattern. For C/C++ targets, you can include or not in the search the implicit dependencies and you can include or not the C/C++ comments. With respect to the "find in files" feature of your preferred IDE, this one searches, of course, only the files actually used in this particular flavor of this particular product.
- and some more. Some are inherited from SCons, like dumping the command lines, listing the output of the build, etc.
There is also a speed improvement involved here. For the majority of the inspection features, SBuild works on the SBuild target tree and doesn't construct the significantly larger SCons tree. This results in about one order of magnitude faster response. SBuild also dumps the info while traveling the tree and can also limit the tree when applying these actions. That furthers improves the (subjective) impression of speed.
You can list variants (this is border line between inspecting existing build descriptions and on-line reference information of SBuild). That means that you can learn what flavors you can build of this product. You can even ask SBuild to produce a shell script to capture (in shell environment settings) your favorite flavor for this build.
[back to top]
|
A lot reused and some lost
|
Note that a lot of features of SCons are "shamelessly" reused as such by SBuild. Among them are: the "keep going", the parallel builds, the what&why query, etc. And we, users of SBuild, of course, take profit of all the other strengths of SCons like very reliable build (never broken uselessly), very safe build (always consistent), etc.
It will be fair to say that all this pottery on top of SCons also looses some features. Most of that is because we didn't spend any time to surface them. Among these lost featured are: no Java toolkit yet, no Tex/Latex toolkit, no possibility to fetch code from Subversion and similar, no wink-in from repositories and no cached build etc. Also important, we conducted no reflection yet on how to integrate the autoconfiguration features that became available in SCons after we started SBuild.
[back to top]
|
C/C++ related additions
|
Most of the added value of SBuild is in the implementation of the C/C++ toolkit. Other than the features listed below, we had, of course, to add some new C/C++ toolchains. Next to about a dozen more or less obscure cross compilation toolchains (most based on the GCC and Cygwin), there are few noteworthy:
The Windows CE compilations (from Embedded Visual 3.0 for Windows CE 3.0 to Visual Studio 2005, no 2008 yet)
The Symbian builds for the simulator and ARM-based devices (still incomplete, no dynamic libraries for the device)
The Brew builds for the simulator and ARM-based devices (still incomplete, no resource compilation yet)
[back to top]
|
Separation of the target platform
|
Being part of an Embedded Software division, it was always paramount for us to separate the host platform and the target platform settings. SBuild C/C++ toolkit achieves that through three variants: tgtplatform, toolchain and bldopt. This is our answer to the same issue addressed by other tools (see the canned variants of Jam). This way a developer can easily run builds for different platforms (replacing tgtplatform=<this> with tgtplatform=<that> on the command line) and he can easily list the supported platforms (the list of allowed value for variant tgtplatform).
[back to top]
|
Preprocessor work
|
The C/C++ toolkit has a C preprocessor. Although rather primitive, it is useful for a lot of interesting checks and listings. For example, SBuild is able to show the actual tree of header file inclusion. Even more, it may check for you the reinclude guard supposed to be at the top of each header. SBuild is also able to spot and list expected "open defines" (conditional compilation tests where a define is expected to come/not come from the build description.)
[back to top]
|
Linker work
|
SBuild install a relation of "use" between compiled code. If one piece of code uses public headers of another piece of code, then these two pieces of code should be present in the same link. If not, the linker will most likely fail. But SBuild is failing sooner and it allows you to print out who is "using" who.
SBuild uses the SCons dynamic library abstraction and extends it a bit: the build description has lists of exported symbols (target platform independent but possibly changed by variants). This list can optionally be built by collecting exports from subtargets.
Finally, under some command line option, SBuild can build lists of symbols defined in a piece of C code, by inspecting the actual C object files. This works on both Unix and MS Windows and it will shout loud and clear if, for example, a function is defined in two places. This is useful when you are fighting a link-time masking bug.
[back to top]
|
Other C/C++ related
|
There are many other useful features in the C/C++ toolkit of SBuild:
- Smoke test deployment: as part of the build, SBuild maintains the so-called "copy directory", where executables and dynamic libraries are brought next to each other. This is not without some challenges and some risks but is very handy and very frequently used for testing.
- SLOC statistics: source lines of code, a vague measure of the men*months that went into a project/product
- C functions listing: The C/C++ toolkit has a (very primitive) C parser. It can list the C functions, the C macros and the begin and end line in the source file for them.
- Doxygen: We do build the on-line reference for our products with Doxygen under SBuild. The Doxyfile is generated, the images are generated (graphviz) but our setup lacks the proper scanner and quite some "out of date" situations go undetected. The forced build command line option (-B) comes to rescue.
- Binary data to C compiler (the bin2c target type): This is our builder to compile arbitrary binary data into C variables to be linked-in in the product. It is primitive, compared to Microsoft resources for example, but it works and it is portable.
- Special optimization levels: this is the ability to change the optimization for a few selected source files in a product with hundreds of files. It is used to not optimize some files that uncover bugs in the cross compiler. It is also useful to put debug information in only a few files, when the embedded platform doesn't have enough memory to hold a full debug build.
Some other features of the C/C++ toolkit are more advanced and they are discussed separately:
- Source concatenation: a mechanism to accelerate builds by reducing the number of times the C compiler is started
- Target platform "equivalence": a mechanism to find target platform specific places in the build scripts and to "shut them up" in one shot.
- C/C++ SDKs: a way to include in the build 3rd party precompiled code. Some SBuild SDK are not rebuildable and some are. Rebuildable SDKs are a kind of "on/off interrupts" in the dependency tree. This is a general mechanism that should be in SBuild, not in the C/C++ toolkit.
- Renaming builds: a mechanism to avoid name clashes in static linking of C code. We use it also to tolerate several historical versions of the same code in the same link.
[back to top] [up one level]
|
Copyright (c) 2008 Abalog Software BVBA. All rights reserved.
|