Spank

Introduction

Spank is an easy to use build system, mainly created for Linux development using GCC. The goal is to create a build system that makes it easy to get up and running with a new project, and to keep the project file as small and to the point as possible.

Its homepage is available at http://grimnorth.se/~noname/spank

Concepts

Project Options

Project options affect the build or installation process of your project. This can be anything from the number of jobs to use in the build process, what files to include to what method to use to check if a file needs to be rebuilt. The project options can be set in the project.spank file, additional spank files included from project.spank, the config.spank file in ~/.spank/ or directly from the command line. Options specified from the command line takes precedence over any options from the files.

From the Command Line

Project options can be set from the command line as flags, -[-][PROJECT OPTION [VALUE]]. If value is omitted the project option will be set to true. If you wanted to change the target binary name for a build you could do so by invoking spank with:

spank -target mybinary2

From the Project File

Project files contain project options. By default spank reads any project file named project.spank or spank/project.spank in the current directory. The syntax for the project files are as follows:

# This is a comment
[project option] [value [value2 ["a third value" ...]]] # Some other comment
[project same option] [value4 [value[5 ...]]
[some other option] [value [value2 ...]]

A small syntax example with real values for better readability

# Still a comment
author "the dude" "some other dude" # also still a comment
author "some third dude" 4thdude
email  test@example.com

From the configuration file

The configuration file is a per user preference file located in ~/.spank/config.spank and uses the same syntax as the project files. Any project options put in this file will override the default value of the specified option.

Although any option can be set from the config file it is highly recommended that only options that affects only the local machine and builds are set. For instance specifying an alternative temp directory location or the number of jobs to build with makes sense to put in the configuration file.

Any option that would potentially break builds from/on other users/systems are considered harmful. Say that “lib sdl” is specified in the configuration file. Everything built on this machine is now linked with the SDL library. Now, say that you try and build your project that depends on SDL on some other machine. The build will fail since it's missing the SDL library. This is of course obvious, but mind what you put in the configuration file.

Actions

An action tells spank what action to perform. Valid actions are

buildCompiles and links a project
rebuildCleans, compiles and links a project
compileCompiles the project sources
linkLinks the compiled files
cleanRemoves the target and temp-files
exportExports the project to the format given by the -exporter option
Valid exporters are: sh (shell script) and makefile (make)
installCompiles, links and installs a project
fake-installFakes an install (prints the install procedure to screen instead of doing anything)

For instance invoking “spank build” builds the project in the current directory using the options specified in the project file

Templates

Templates are built in common standard configurations. At the moment of writing spank has three built in templates: c (default), c++ and cs (c# through mono). A template can be activated by setting the template option to one of the three templates. See below example about building a C++ project for more information.

A Simple Example

As an introductory example, say you have a C project consisting of 4 C source files and a header file. The project files are sorted like this:

.
|-- include
|   `-- header.h
|-- src
|   |-- a.c
|   |-- b.c
|   |-- c.c
|   `-- d.c
`-- project.spank

All the project options for spank is stored in a file called project.spank. It's the spank version of a makefile. A project.spank file for this project could look like this

target     mybinary
sourcedir  src

This project file will take all the C files in the directory src and compile them. After that it will link them together in the binary “mybinary”.

To build the project we invoke spank with the build action in the project directory.

spank build

The output will look like this:

Spank 0.9.2 GIT - Welcome to easy street.
Loading project file project.spank
Checking dependencies...
Preparing...
Compiling...
[  25 %] src/a.c
[  50 %] src/b.c
[  75 %] src/c.c
[ 100 %] src/d.c
Linking...
done building

Using Libs

More often than not when you're writing software you end up using one or more software libraries. Spank relies on the pkg-config software to handle library dependencies, compiler flags and linker flags. The project option for specifying libs is simply called “lib”. As an example, adding a dependency on the SDL library to the last example could look like this.

target     mybinary
sourcedir  src
lib        sdl

Additional libs can be appended to the same line (or on a separate line, it's still appended). If we wanted to add for instance SDL_image, it would look like this

target     mybinary
sourcedir  src
lib        sdl SDL_image

If you want to know the exact names of what libs pkg-config can handle on your system you can list all the libs with the command

pkg-config --list-all

Now if we try to compile the project but we're missing all or some of the libs the output will be

$ spank build
Spank 0.9.4 - Welcome to easy street.
Loading project file project.spank
Checking dependencies...
[ Error ] Missing library 'sdl'
[ Error ] Missing library 'SDL_image'

After installing the missing libs (in ubuntu with libsdl-image1.2-dev libsdl1.2-dev) there are no surprises or news in the output. The program just builds successfully like before, but if we inspect the commands executed with -verbosity 1 we can see that “`PKG_CONFIG_PATH=$PKG_CONFIG_PATH:.:spank pkg-config –cflags sdl SDL_image`” is appended to the gcc compile call for each file and that “`PKG_CONFIG_PATH=$PKG_CONFIG_PATH:.:spank pkg-config –libs sdl SDL_image`” has been added to the linker call.

Library Versions

To make the build depend on specific library versions the pkg-config syntax 'lib >= version' can be used. However, since we want spank to send the whole string to pkg-config (rather than first ”'lib”, then ”>=” and lastly “version'”) double quotes must be placed around the single quoted string. So, if for instance we want to check for SDL version 1.2 or higher we'd add (literlly, with all the single and double quotes) ” 'sdl >= 1.2' ”.

The project file would then look like this

target     mybinary
sourcedir  src
lib        "'sdl >= 1.2'" SDL_image

NOTE double and single quotes

Of course any valid combination of <, > and = can be used. Be careful with = though. If ” 'sdl = 1.2' ” is specified, 1.2.14 for instance won't work. Moreover != can be used to make sure a certain version isn't being used. A little more advanced example would be to look for “version 1.2 or higher, but not 1.3 or higher and not version 1.2.13” which would look like this: ” 'sdl >= 1.2 sdl < 1.3 sdl != 1.2.13' ”. In the config file it would look like this

target     mybinary
sourcedir  src
lib        "'sdl >= 1.2 sdl < 1.3 sdl != 1.2.13'" SDL_image

Libraries Without pkg-config (.pc) Files

Some libraries don't come with .pc files. To include these libraries in the spank build process there are two options

A. Make your own .pc-file

Spank adds the project directory and a subdirectory called spank to the pkg-config search path. You can make local pc-files for the project for libs you want to link with. Please refer to the pkg-config documentation on the syntax, or simply study some existing .pc-files (they're not terribly advanced). When you're done you can always send the library authors a copy of the file :)

B. Add the needed flags directly

The most straight forward option. Simply add any additional include directories with cflags I[directory] and the necessary linker flags with the ldflags option.

Continuing with our previous example and adding linking with sdl_gfx (which doesn't have a .pc file ಠ_ಠ) could look like this

target     mybinary
sourcedir  src
lib        sdl SDL_image
ldflags    lSDL_gfx

Building C++ Projects

To build a c++ project it's easiest to set the template option to c++ which sets sources to *.cpp and compiler to g++.

template   c++
target     mybinary
sourcedir  src

Writing Libraries

Spank can be used to build shared or static libraries, this is achieved by changing the option targettype to either lib-static or lib-shared.

targettype lib-static
target     mylibrary
sourcedir  src

Advanced Build Options

Spank does support some a bit more advanced build options such as configurations (almost) and script hooks. They've been added as they were needed in different projects.

Post/pre/clean build hooks

Sometimes you need to do stuff before and/or after builds to eg. assemble files and build roms for embedded systems. Say we have three scripts in the subdirectory scripts: assemble.sh - which assembles some platform specific startup code, buildrom.sh - that builds a system from the compiler output and cleanup.sh - which deletes the rom and assembly output.

Our project directory now looks like this

.
|-- include
|-- project.spank
|-- scripts
|   |-- assemble.sh
|   |-- buildrom.sh
|   `-- cleanup.sh
`-- src
    |-- a.c
    |-- b.c
    |-- c.c
    `-- d.c

We add the scripts using the options prebuildscript, postbuildscript and oncleanscript making the project file look like this

target     mybinary
sourcedir  src

prebuildscript   scripts/assemble.sh
postbuildscript  scripts/buildrom.sh
oncleanscript    scripts/cleanup.sh

Running spank rebuild will now produce the following output

$ spank rebuild
Spank 0.9.4 - Welcome to easy street.
Loading project file project.spank
Cleaning up assemblies and roms
done cleaning
Assembling files
Checking dependencies...
Preparing...
Compiling...
[  25 %] src/c.c
[  50 %] src/a.c
[  75 %] src/b.c
[ 100 %] src/d.c
Linking...
Building rom image
done rebuilding

Note the lines “Cleaning up assemblies and roms”, “Assembling files” and “Building rom image” which are produced by assemble.sh, buildrom.sh and cleanup.sh respectively.

Project Configurations

While spank doesn't support build configurations per se the behaviour can still be achived by using the include option. With the include option one project file can include another project file and append additional options to that. Moreover the shorthand “spank build [project]” specifying project files without the .spank extension can be used to build a specific “configuration”. If this method with multiple project files is used the alternative project file subdirectory spank/ can be used to tidy up the project root.

Say we wanted to make two project configurations, release and debug.

Debug builds with the -O0 -ggdb -DDEBUG compiler flags (disable optimizations, enable gdb debug symbols and define preprocessor macro: DEBUG). Release builds with the -O3 compiler flag (the highest optimization level, 3) and also strips the symbols from the executable

First we create the common project file for everything that applies to all configurations. We name it .inc rather than .spank to underline the fact that it's not meant to be built stand alone but only included in other projects.

spank/common.inc

# common project options
target     mybinary
sourcedir  src
cflags     Iinclude

The debug configuration file

spank/debug.spank

# debug configuration

include spank/common.inc

prebuildscript  "echo !!! THIS IS A DEBUG BUILD !!!"
cflags          O0 ggdb DDEBUG

The release configuration file

spank/release.spank

# release configuration

include spank/common.inc

prebuildscript   "echo !!! THIS IS A RELEASE BUILD !!!"
postbuildscript  "echo stripping target && strip $(target)"
cflags           O3

Note here that you can access other project options and also the system's environment variables using the $(OPTION) syntax. $(target) here means “mybinary”, which is specified in common.inc

By default spank loads project.spank or spank/project.spank. Here, to use the debug build as default, we include the debug project in project.spank

spank/project.spank

include spank/debug.spank

The directory structure now looks like this

.
|-- include
|-- spank
|   |-- common.inc
|   |-- debug.spank
|   |-- project.spank
|   `-- release.spank
`-- src
    |-- a.c
    |-- b.c
    |-- c.c
    `-- d.c

To build the default configuration (debug) spank is invoked as usual with its build action

$ spank build
Spank 0.9.4 - Welcome to easy street.
Loading project file spank/project.spank
Loading project file spank/debug.spank
Loading project file spank/common.inc
!!! THIS IS A DEBUG BUILD !!!
Checking dependencies...
Preparing...
Compiling...
[  25 %] src/c.c
[  50 %] src/a.c
[  75 %] src/b.c
[ 100 %] src/d.c
Linking...
done building

Note the verbose message about this being a debug build as specified in spank/debug.spank. It can also be observed that spank first loads spank/project.spank, which then loads spank/debug.spank which, in turn, loads spank/common.inc

To rebuild the project using the release settings spank can be invoked with the shorthand for alterative project file names (without the .spank extension): spank rebuild release

$ spank rebuild release
Spank 0.9.4 - Welcome to easy street.
Loading project file spank/release.spank
Loading project file spank/common.inc
done cleaning
!!! THIS IS A RELEASE BUILD !!!
Checking dependencies...
Preparing...
Compiling...
[  25 %] src/c.c
[  50 %] src/a.c
[  75 %] src/b.c
[ 100 %] src/d.c
Linking...
stripping target
done rebuilding

Note the message stating that this is indeed the release build configuration and that, since release(.spank) was requested project.spank is never loaded.

One could also explicitly rebuild with the debug configuration using spank rebuild debug

$ spank rebuild debug
Spank 0.9.4 - Welcome to easy street.
Loading project file spank/debug.spank
Loading project file spank/common.inc
done cleaning
!!! THIS IS A DEBUG BUILD !!!
Checking dependencies...
Preparing...
Compiling...
[  25 %] src/c.c
[  50 %] src/a.c
[  75 %] src/b.c
[ 100 %] src/d.c
Linking...
done rebuilding

The result is identical to not specifying debug, but the “dummy” project.spank file is never loaded.

It should also be noted that since common.ink doesn't have the .spank extension, it can't be explicitly built using spank rebuild common (which is a good thing).

Project Option Reference

General Project Settings

Project OptionDescriptionValue
projectThe project file(s) to loadpath to and name of project file
configThe config file(s) to loadpath to and name of config file
targetName of build target binarypath to and name of target binary
targettypeThe type of target to produceOne of binary, lib-static and lib-shared
sourcedirDirectory(ies) that contain source code (search is recursive, so src/test/1/hello.c will be included in the build)directory name
cflagsCustom compiler flagscompiler flags without preceding hyphen (if not addhyphen is set to false)
templateSpecifies a template to usec, c++ or cs (c# through mono)
ldflagsCustom linker flagsLinker flags without preceding hyphen (if not addhyphen is set to false)
excludeExclude file nameA source file to exclude from the build
rccheckMethod for checking if a file needs recompilationpp (preprocessor), date or recursive (default)
spankdefsWhether to add the spank macros as compiler flagstrue or false
exporterwhat exporter to usemakefile or sh (shell script)
exportfileName of file to export to
libWhat pkg-config libs to include in the compilename of a lib
homedirThe spank home dirA directory where spank lives (like ~/.spank)
addhyphenWhether to automatically prepend hyphens (-) before compiler and linker flagstrue or false
tmpdirDirectory to use for temporary storageA directory
includeAdditional project files to includea project file name
sourcesThe search string to use when finding source files in the specified sourcedirA search string (like “*.c”)

Project Information

Project OptionDescriptionValue
versionProject versionA version number
nameProject nameThe name of the project
homepageThe project's homepageAn URL
emailAuthor's emailAn email address
authorAuthor's nameA name
descriptionA description of the projecta string

Commands

Project OptionDescriptionValue
pkg-configcommand to use for invoking pkg-configa command
tarcommand to use for invoking tara command
arcommand to use for invoking ara command
ppPreprocessor commanda command that invokes the preprocessor
inst_sudoCommand to use for sudoA command
compilerThe command to use for compilingA command
compilertypeThe type of compilerOne of gcc or mcs (note clang or clang++ is type gcc)

Script Hooks

Project OptionDescriptionValue
prebuildscriptScripts to execute before a buildPath to a script
postbuildscriptScripts to execute after a buildPath to a script
oncleanscriptScripts to execute on a clean actionPath to a script

Output Options

Project OptionDescriptionValue
helpDisplays the help screentrue or false
showconfigShows all config options if truetrue or false
verbosityHow verbose spank should be. The lower the number the more output.0 (debug), 1 (verbose), 2 (information), 3 (warnings), 4 (errors)
stripsrcStrip the directory from the output when compiling a filetrue or false

Installation / package generation

Project OptionDescriptionValue
installerWhat installer to use. Only used when the action install is specified.unix or deb
inst_maintainerName of the project maintainer (used for packaging)A name
inst_maintainer_emailEmail of the maintaineran email address
inst_prefixInstall prefixA path (like /usr/local)
inst_prescriptScript to perform before installationA script
inst_postscriptScript to perform after installationA script
inst_rmprescriptScript to perform on (before) removing (or removing of generated package)A script
inst_rmprescriptScript to perform after removingA script
inst_copyCopy this file to a specified destination. Source and destination must be given in pairs (so never an odd number of values)a source and a destination
inst_mkdirMake this directory on installationA directory to create
inst_archWhat architecture the installation or package is for“host” → the build system's architecture, anything else will be used as the literal string

Build Settings

Project OptionDescriptionValue
jobsNumber of jobs to use when buildingA number

Internal / special

Project OptionDescriptionValue
actionThe current action to perform. Used internally, not very useful.Don't use
spank.txt · Last modified: 2011/02/10 21:37 by noname
Kleine Websites, die ein Wiki als CMS verwenden.de