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
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.
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
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
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.
An action tells spank what action to perform. Valid actions are
build | Compiles and links a project |
rebuild | Cleans, compiles and links a project |
compile | Compiles the project sources |
link | Links the compiled files |
clean | Removes the target and temp-files |
export | Exports the project to the format given by the -exporter option |
Valid exporters are: sh (shell script) and makefile (make) | |
install | Compiles, links and installs a project |
fake-install | Fakes 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 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.
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
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.
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
Some libraries don't come with .pc files. To include these libraries in the spank build process there are two options
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 :)
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
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
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
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.
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.
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 | Description | Value |
---|---|---|
project | The project file(s) to load | path to and name of project file |
config | The config file(s) to load | path to and name of config file |
target | Name of build target binary | path to and name of target binary |
targettype | The type of target to produce | One of binary, lib-static and lib-shared |
sourcedir | Directory(ies) that contain source code (search is recursive, so src/test/1/hello.c will be included in the build) | directory name |
cflags | Custom compiler flags | compiler flags without preceding hyphen (if not addhyphen is set to false) |
template | Specifies a template to use | c, c++ or cs (c# through mono) |
ldflags | Custom linker flags | Linker flags without preceding hyphen (if not addhyphen is set to false) |
exclude | Exclude file name | A source file to exclude from the build |
rccheck | Method for checking if a file needs recompilation | pp (preprocessor), date or recursive (default) |
spankdefs | Whether to add the spank macros as compiler flags | true or false |
exporter | what exporter to use | makefile or sh (shell script) |
exportfile | Name of file to export to | |
lib | What pkg-config libs to include in the compile | name of a lib |
homedir | The spank home dir | A directory where spank lives (like ~/.spank) |
addhyphen | Whether to automatically prepend hyphens (-) before compiler and linker flags | true or false |
tmpdir | Directory to use for temporary storage | A directory |
include | Additional project files to include | a project file name |
sources | The search string to use when finding source files in the specified sourcedir | A search string (like “*.c”) |
Project Option | Description | Value |
---|---|---|
version | Project version | A version number |
name | Project name | The name of the project |
homepage | The project's homepage | An URL |
Author's email | An email address | |
author | Author's name | A name |
description | A description of the project | a string |
Project Option | Description | Value |
---|---|---|
pkg-config | command to use for invoking pkg-config | a command |
tar | command to use for invoking tar | a command |
ar | command to use for invoking ar | a command |
pp | Preprocessor command | a command that invokes the preprocessor |
inst_sudo | Command to use for sudo | A command |
compiler | The command to use for compiling | A command |
compilertype | The type of compiler | One of gcc or mcs (note clang or clang++ is type gcc) |
Project Option | Description | Value |
---|---|---|
prebuildscript | Scripts to execute before a build | Path to a script |
postbuildscript | Scripts to execute after a build | Path to a script |
oncleanscript | Scripts to execute on a clean action | Path to a script |
Project Option | Description | Value |
---|---|---|
help | Displays the help screen | true or false |
showconfig | Shows all config options if true | true or false |
verbosity | How verbose spank should be. The lower the number the more output. | 0 (debug), 1 (verbose), 2 (information), 3 (warnings), 4 (errors) |
stripsrc | Strip the directory from the output when compiling a file | true or false |
Project Option | Description | Value |
---|---|---|
installer | What installer to use. Only used when the action install is specified. | unix or deb |
inst_maintainer | Name of the project maintainer (used for packaging) | A name |
inst_maintainer_email | Email of the maintainer | an email address |
inst_prefix | Install prefix | A path (like /usr/local) |
inst_prescript | Script to perform before installation | A script |
inst_postscript | Script to perform after installation | A script |
inst_rmprescript | Script to perform on (before) removing (or removing of generated package) | A script |
inst_rmprescript | Script to perform after removing | A script |
inst_copy | Copy 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_mkdir | Make this directory on installation | A directory to create |
inst_arch | What architecture the installation or package is for | “host” → the build system's architecture, anything else will be used as the literal string |
Project Option | Description | Value |
---|---|---|
jobs | Number of jobs to use when building | A number |
Project Option | Description | Value |
---|---|---|
action | The current action to perform. Used internally, not very useful. | Don't use |