SCons
SCons is a general-purpose build system that does not rely on Makefiles to build software. SCons is written in Python, and handles all building and linking itself.
As far as build systems go, SCons is very non-uniform. It provides a common framework for developers to write build scripts, but the build scripts themselves can vary drastically. Some developers add subcommands like:
$ scons clean
$ scons build
$ scons test
$ scons install
Others don’t add any subcommands. Some have configuration options that can be specified through variables on the command line. Others don’t.
Phases
As previously mentioned, SCons allows developers to add subcommands like
build
and install
, but by default, installation usually looks like:
$ scons
$ scons install
To facilitate this, the SConsBuilder
and SconsPackage
base classes provide the
following phases:
build
- build the packageinstall
- install the package
Package developers often add unit tests that can be invoked with
scons test
or scons check
. Spack provides a test
method
to handle this. Since we don’t know which one the package developer
chose, the test
method does nothing by default, but can be easily
overridden like so:
def test(self):
scons("check")
Important files
SCons packages can be identified by their SConstruct
files. These
files handle everything from setting up subcommands and command-line
options to linking and compiling.
One thing to look for is the EnsureSConsVersion
function:
EnsureSConsVersion(2, 3, 0)
This means that SCons 2.3.0 is the earliest release that will work.
You should specify this in a depends_on
statement.
Build system dependencies
At the bare minimum, packages that use the SCons build system need a
scons
dependency. Since this is always the case, the SConsPackage
base class already contains:
depends_on("scons", type="build")
If you want to specify a particular version requirement, you can override this in your package:
depends_on("scons@2.3.0:", type="build")
Finding available options
The first place to start when looking for a list of valid options to
build a package is scons --help
. Some packages like
kahip
don’t bother overwriting the default SCons help message, so this isn’t
very useful, but other packages like
serf
print a list of valid command-line variables:
$ scons --help
scons: Reading SConscript files ...
Checking for GNU-compatible C compiler...yes
scons: done reading SConscript files.
PREFIX: Directory to install under ( /path/to/PREFIX )
default: /usr/local
actual: /usr/local
LIBDIR: Directory to install architecture dependent libraries under ( /path/to/LIBDIR )
default: $PREFIX/lib
actual: /usr/local/lib
APR: Path to apr-1-config, or to APR's install area ( /path/to/APR )
default: /usr
actual: /usr
APU: Path to apu-1-config, or to APR's install area ( /path/to/APU )
default: /usr
actual: /usr
OPENSSL: Path to OpenSSL's install area ( /path/to/OPENSSL )
default: /usr
actual: /usr
ZLIB: Path to zlib's install area ( /path/to/ZLIB )
default: /usr
actual: /usr
GSSAPI: Path to GSSAPI's install area ( /path/to/GSSAPI )
default: None
actual: None
DEBUG: Enable debugging info and strict compile warnings (yes|no)
default: False
actual: False
APR_STATIC: Enable using a static compiled APR (yes|no)
default: False
actual: False
CC: Command name or path of the C compiler
default: None
actual: gcc
CFLAGS: Extra flags for the C compiler (space-separated)
default: None
actual:
LIBS: Extra libraries passed to the linker, e.g. "-l<library1> -l<library2>" (space separated)
default: None
actual: None
LINKFLAGS: Extra flags for the linker (space-separated)
default: None
actual:
CPPFLAGS: Extra flags for the C preprocessor (space separated)
default: None
actual: None
Use scons -H for help about command-line options.
More advanced packages like
cantera
use scons --help
to print a list of subcommands:
$ scons --help
scons: Reading SConscript files ...
SCons build script for Cantera
Basic usage:
'scons help' - print a description of user-specifiable options.
'scons build' - Compile Cantera and the language interfaces using
default options.
'scons clean' - Delete files created while building Cantera.
'[sudo] scons install' - Install Cantera.
'[sudo] scons uninstall' - Uninstall Cantera.
'scons test' - Run all tests which did not previously pass or for which the
results may have changed.
'scons test-reset' - Reset the passing status of all tests.
'scons test-clean' - Delete files created while running the tests.
'scons test-help' - List available tests.
'scons test-NAME' - Run the test named "NAME".
'scons <command> dump' - Dump the state of the SCons environment to the
screen instead of doing <command>, e.g.
'scons build dump'. For debugging purposes.
'scons samples' - Compile the C++ and Fortran samples.
'scons msi' - Build a Windows installer (.msi) for Cantera.
'scons sphinx' - Build the Sphinx documentation
'scons doxygen' - Build the Doxygen documentation
You’ll notice that cantera provides a scons help
subcommand. Running
scons help
prints a list of valid command-line variables.
Passing arguments to scons
Now that you know what arguments the project accepts, you can add them to
the package build phase. This is done by overriding build_args
like so:
def build_args(self, spec, prefix):
args = [
f"PREFIX={prefix}",
f"ZLIB={spec['zlib'].prefix}",
]
if spec.satisfies("+debug"):
args.append("DEBUG=yes")
else:
args.append("DEBUG=no")
return args
SConsPackage
also provides an install_args
function that you can
override to pass additional arguments to scons install
.
Compiler wrappers
By default, SCons builds all packages in a separate execution environment,
and doesn’t pass any environment variables from the user environment.
Even changes to PATH
are not propagated unless the package developer
does so.
This is particularly troublesome for Spack’s compiler wrappers, which depend on environment variables to manage dependencies and linking flags. In many cases, SCons packages are not compatible with Spack’s compiler wrappers, and linking must be done manually.
First of all, check the list of valid options for anything relating to environment variables. For example, cantera has the following option:
* env_vars: [ string ]
Environment variables to propagate through to SCons. Either the
string "all" or a comma separated list of variable names, e.g.
"LD_LIBRARY_PATH,HOME".
- default: "LD_LIBRARY_PATH,PYTHONPATH"
In the case of cantera, using env_vars=all
allows us to use
Spack’s compiler wrappers. If you don’t see an option related to
environment variables, try using Spack’s compiler wrappers by passing
spack_cc
, spack_cxx
, and spack_fc
via the CC
, CXX
,
and FC
arguments, respectively. If you pass them to the build and
you see an error message like:
Spack compiler must be run from Spack! Input 'SPACK_PREFIX' is missing.
you’ll know that the package isn’t compatible with Spack’s compiler
wrappers. In this case, you’ll have to use the path to the actual
compilers, which are stored in self.compiler.cc
and friends.
Note that this may involve passing additional flags to the build to
locate dependencies, a task normally done by the compiler wrappers.
serf is an example of a package with this limitation.
External documentation
For more information on the SCons build system, see: http://scons.org/documentation.html