mirror of
https://github.com/Cantera/cantera.git
synced 2025-02-25 18:55:29 -06:00
Check for a system copy of Eigen, and if that is not found, install Eigen's headers with the Cantera headers. Add the header 'eigen_dense.h' to provide a single header to include from other locations.
1607 lines
61 KiB
Python
1607 lines
61 KiB
Python
"""
|
|
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 <action>, 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
|
|
"""
|
|
|
|
from buildutils import *
|
|
|
|
if not COMMAND_LINE_TARGETS:
|
|
# Print usage help
|
|
print __doc__
|
|
sys.exit(0)
|
|
|
|
valid_commands = ('build','clean','install','uninstall',
|
|
'help','msi','samples','sphinx','doxygen','dump')
|
|
|
|
for command in COMMAND_LINE_TARGETS:
|
|
if command not in valid_commands and not command.startswith('test'):
|
|
print 'ERROR: unrecognized command line target: %r' % command
|
|
sys.exit(0)
|
|
|
|
extraEnvArgs = {}
|
|
|
|
if 'clean' in COMMAND_LINE_TARGETS:
|
|
removeDirectory('build')
|
|
removeDirectory('stage')
|
|
removeDirectory('.sconf_temp')
|
|
removeFile('.sconsign.dblite')
|
|
removeFile('include/cantera/base/config.h')
|
|
removeDirectory('include/cantera/ext')
|
|
removeFile('ext/f2c_libs/arith.h')
|
|
removeFile('interfaces/cython/cantera/_cantera.cpp')
|
|
removeFile('interfaces/cython/setup2.py')
|
|
removeFile('interfaces/cython/setup3.py')
|
|
removeFile('interfaces/python_minimal/setup.py')
|
|
removeFile('config.log')
|
|
removeDirectory('doc/sphinx/matlab/examples')
|
|
removeDirectory('doc/sphinx/matlab/tutorials')
|
|
removeDirectory('doc/sphinx/matlab/code-docs')
|
|
removeDirectory('doc/sphinx/cython/examples')
|
|
removeDirectory('interfaces/cython/Cantera.egg-info')
|
|
removeDirectory('interfaces/python_minimal/Cantera_minimal_.egg-info')
|
|
for name in os.listdir('interfaces/cython/cantera/data/'):
|
|
if name != '__init__.py':
|
|
removeFile('interfaces/cython/cantera/data/' + name)
|
|
for name in os.listdir('interfaces/cython/cantera/test/data/'):
|
|
if name != '__init__.py':
|
|
removeFile('interfaces/cython/cantera/test/data/' + name)
|
|
for name in os.listdir('.'):
|
|
if name.endswith('.msi'):
|
|
removeFile(name)
|
|
for name in os.listdir('site_scons/'):
|
|
if name.endswith('.pyc'):
|
|
removeFile('site_scons/' + name)
|
|
for name in os.listdir('site_scons/site_tools/'):
|
|
if name.endswith('.pyc'):
|
|
removeFile('site_scons/site_tools/' + name)
|
|
for name in os.listdir('interfaces/python_minimal/cantera'):
|
|
if name != '__init__.py':
|
|
removeFile('interfaces/python_minimal/cantera/' + name)
|
|
removeFile('interfaces/matlab/toolbox/cantera_shared.dll')
|
|
removeFile('interfaces/matlab/Contents.m')
|
|
removeFile('interfaces/matlab/ctpath.m')
|
|
for name in os.listdir('interfaces/matlab/toolbox'):
|
|
if name.startswith('ctmethods.'):
|
|
removeFile('interfaces/matlab/toolbox/' + name)
|
|
|
|
print 'Done removing output files.'
|
|
|
|
if COMMAND_LINE_TARGETS == ['clean']:
|
|
# Just exit if there's nothing else to do
|
|
sys.exit(0)
|
|
else:
|
|
Alias('clean', [])
|
|
|
|
# ******************************************************
|
|
# *** Set system-dependent defaults for some options ***
|
|
# ******************************************************
|
|
|
|
print 'INFO: SCons is using the following Python interpreter:', sys.executable
|
|
|
|
opts = Variables('cantera.conf')
|
|
|
|
windows_compiler_options = []
|
|
if os.name == 'nt':
|
|
# On Windows, target the same architecture as the current copy of Python,
|
|
# unless the user specified another option.
|
|
if '64 bit' in sys.version:
|
|
target_arch = 'amd64'
|
|
else:
|
|
target_arch = 'x86'
|
|
|
|
# Make an educated guess about the right default compiler
|
|
if which('g++') and not which('cl.exe'):
|
|
defaultToolchain = 'mingw'
|
|
else:
|
|
defaultToolchain = 'msvc'
|
|
|
|
windows_compiler_options.extend([
|
|
('msvc_version',
|
|
"""Version of Visual Studio to use. The default is the newest
|
|
installed version. Specify '12.0' for Visual Studio 2013 or '14.0'
|
|
for Visual Studio 2015.""",
|
|
''),
|
|
('target_arch',
|
|
"""Target architecture. The default is the same
|
|
architecture as the installed version of Python.""",
|
|
target_arch)])
|
|
opts.AddVariables(*windows_compiler_options)
|
|
|
|
pickCompilerEnv = Environment()
|
|
opts.Update(pickCompilerEnv)
|
|
|
|
if pickCompilerEnv['msvc_version']:
|
|
defaultToolchain = 'msvc'
|
|
|
|
windows_compiler_options.append(EnumVariable(
|
|
'toolchain',
|
|
"""The preferred compiler toolchain.""",
|
|
defaultToolchain, ('msvc', 'mingw', 'intel')))
|
|
opts.AddVariables(windows_compiler_options[-1])
|
|
opts.Update(pickCompilerEnv)
|
|
|
|
if pickCompilerEnv['toolchain'] == 'msvc':
|
|
toolchain = ['default']
|
|
if pickCompilerEnv['msvc_version']:
|
|
extraEnvArgs['MSVC_VERSION'] = pickCompilerEnv['msvc_version']
|
|
print 'INFO: Compiling with MSVC', (pickCompilerEnv['msvc_version'] or
|
|
pickCompilerEnv['MSVC_VERSION'])
|
|
|
|
elif pickCompilerEnv['toolchain'] == 'mingw':
|
|
toolchain = ['mingw', 'f90']
|
|
extraEnvArgs['F77'] = None
|
|
# Next line fixes http://scons.tigris.org/issues/show_bug.cgi?id=2683
|
|
extraEnvArgs['WINDOWS_INSERT_DEF'] = 1
|
|
|
|
elif pickCompilerEnv['toolchain'] == 'intel':
|
|
toolchain = ['intelc'] # note: untested
|
|
|
|
extraEnvArgs['TARGET_ARCH'] = pickCompilerEnv['target_arch']
|
|
print 'INFO: Compiling for architecture:', pickCompilerEnv['target_arch']
|
|
print 'INFO: Compiling using the following toolchain(s):', repr(toolchain)
|
|
|
|
else:
|
|
toolchain = ['default']
|
|
|
|
env = Environment(tools=toolchain+['textfile', 'subst', 'recursiveInstall', 'wix'],
|
|
ENV={'PATH': os.environ['PATH']},
|
|
toolchain=toolchain,
|
|
**extraEnvArgs)
|
|
|
|
env['OS'] = platform.system()
|
|
env['OS_BITS'] = int(platform.architecture()[0][:2])
|
|
if 'cygwin' in env['OS'].lower():
|
|
env['OS'] = 'Cygwin' # remove Windows version suffix
|
|
|
|
# Fixes a linker error in Windows
|
|
if os.name == 'nt' and 'TMP' in os.environ:
|
|
env['ENV']['TMP'] = os.environ['TMP']
|
|
|
|
# Fixes issues with Python subprocesses. See http://bugs.python.org/issue13524
|
|
if os.name == 'nt':
|
|
env['ENV']['SystemRoot'] = os.environ['SystemRoot']
|
|
|
|
# Needed for Matlab to source ~/.matlab7rc.sh
|
|
if 'HOME' in os.environ:
|
|
env['ENV']['HOME'] = os.environ['HOME']
|
|
|
|
# Fix an issue with Unicode sneaking into the environment on Windows
|
|
if os.name == 'nt':
|
|
for key,val in env['ENV'].iteritems():
|
|
env['ENV'][key] = str(val)
|
|
|
|
if 'FRAMEWORKS' not in env:
|
|
env['FRAMEWORKS'] = []
|
|
|
|
add_RegressionTest(env)
|
|
|
|
class defaults: pass
|
|
|
|
if os.name == 'posix':
|
|
defaults.prefix = '/usr/local'
|
|
defaults.boostIncDir = ''
|
|
env['INSTALL_MANPAGES'] = True
|
|
elif os.name == 'nt':
|
|
defaults.prefix = pjoin(os.environ['ProgramFiles'], 'Cantera')
|
|
defaults.boostIncDir = ''
|
|
env['INSTALL_MANPAGES'] = False
|
|
else:
|
|
print "Error: Unrecognized operating system '%s'" % os.name
|
|
sys.exit(1)
|
|
|
|
compiler_options = [
|
|
('CXX',
|
|
'The C++ compiler to use.',
|
|
env['CXX']),
|
|
('CC',
|
|
"""The C compiler to use. This is only used to compile CVODE.""",
|
|
env['CC'])]
|
|
opts.AddVariables(*compiler_options)
|
|
opts.Update(env)
|
|
|
|
defaults.cxxFlags = ''
|
|
defaults.ccFlags = ''
|
|
defaults.noOptimizeCcFlags = '-O0'
|
|
defaults.optimizeCcFlags = '-O3'
|
|
defaults.debugCcFlags = '-g'
|
|
defaults.noDebugCcFlags = ''
|
|
defaults.debugLinkFlags = ''
|
|
defaults.noDebugLinkFlags = ''
|
|
defaults.warningFlags = '-Wall'
|
|
|
|
if 'gcc' in env.subst('$CC'):
|
|
defaults.optimizeCcFlags += ' -Wno-inline'
|
|
if env['OS'] == 'Cygwin':
|
|
# See http://stackoverflow.com/questions/18784112
|
|
defaults.cxxFlags = '-std=gnu++0x'
|
|
else:
|
|
defaults.cxxFlags = '-std=c++0x'
|
|
|
|
elif env['CC'] == 'cl': # Visual Studio
|
|
defaults.cxxFlags = ['/EHsc']
|
|
defaults.ccFlags = ['/MD', '/nologo',
|
|
'/D_SCL_SECURE_NO_WARNINGS', '/D_CRT_SECURE_NO_WARNINGS']
|
|
defaults.debugCcFlags = '/Zi /Fd${TARGET}.pdb'
|
|
defaults.noOptimizeCcFlags = '/Od /Ob0'
|
|
defaults.optimizeCcFlags = '/O2'
|
|
defaults.debugLinkFlags = '/DEBUG'
|
|
defaults.warningFlags = '/W3'
|
|
|
|
elif 'icc' in env.subst('$CC'):
|
|
defaults.cxxFlags = '-std=c++0x'
|
|
defaults.ccFlags = '-vec-report0 -diag-disable 1478'
|
|
defaults.warningFlags = '-Wcheck'
|
|
|
|
elif 'clang' in env.subst('$CC'):
|
|
defaults.ccFlags = '-fcolor-diagnostics'
|
|
defaults.cxxFlags = '-std=c++11'
|
|
|
|
else:
|
|
print "WARNING: Unrecognized C compiler '%s'" % env['CC']
|
|
|
|
if env['OS'] in ('Windows', 'Darwin'):
|
|
defaults.threadFlags = ''
|
|
else:
|
|
defaults.threadFlags = '-pthread'
|
|
|
|
defaults.fsLayout = 'compact' if env['OS'] == 'Windows' else 'standard'
|
|
defaults.env_vars = 'LD_LIBRARY_PATH,PYTHONPATH'
|
|
|
|
defaults.python_prefix = '$prefix' if env['OS'] != 'Windows' else ''
|
|
|
|
# Transform lists into strings to keep cantera.conf clean
|
|
for key,value in defaults.__dict__.items():
|
|
if isinstance(value, (list, tuple)):
|
|
defaults.__dict__[key] = ' '.join(value)
|
|
|
|
# **************************************
|
|
# *** Read user-configurable options ***
|
|
# **************************************
|
|
|
|
# This check prevents requiring root permissions to build when the
|
|
# installation directory is not writable by the current user.
|
|
if 'install' in COMMAND_LINE_TARGETS:
|
|
installPathTest = PathVariable.PathIsDirCreate
|
|
else:
|
|
installPathTest = PathVariable.PathAccept
|
|
|
|
config_options = [
|
|
PathVariable(
|
|
'prefix',
|
|
'Set this to the directory where Cantera should be installed.',
|
|
defaults.prefix, installPathTest),
|
|
EnumVariable(
|
|
'python_package',
|
|
"""If you plan to work in Python, or you want to use the graphical
|
|
MixMaster application, then you need the 'full' Cantera Python
|
|
Package. If, on the other hand, you will only use Cantera from
|
|
some other language (e.g. MATLAB or Fortran 90/95) and only need
|
|
Python to process .cti files, then you only need a 'minimal'
|
|
subset of the package (actually, only two files). The default
|
|
behavior is to build the Python package if the required
|
|
prerequisites (numpy) are installed.""",
|
|
'default', ('new', 'full', 'minimal', 'none', 'default')),
|
|
PathVariable(
|
|
'python_cmd',
|
|
"""Cantera needs to know where to find the Python interpreter. If
|
|
PYTHON_CMD is not set, then the configuration process will use the
|
|
same Python interpreter being used by SCons.""",
|
|
sys.executable),
|
|
PathVariable(
|
|
'python_array_home',
|
|
"""If numpy was installed using the --home option, set this to
|
|
the home directory for numpy.""",
|
|
'', PathVariable.PathAccept),
|
|
PathVariable(
|
|
'python_prefix',
|
|
"""Use this option if you want to install the Cantera Python package to
|
|
an alternate location. On Unix-like systems, the default is the same
|
|
as the $prefix option. If this option is set to the empty string (the
|
|
default on Windows), then the Package will be installed to the system
|
|
default 'site-packages' directory. To install to the current user's
|
|
site-packages directory, use 'python_prefix=USER'.""",
|
|
defaults.python_prefix, PathVariable.PathAccept),
|
|
EnumVariable(
|
|
'python3_package',
|
|
"""Controls whether or not the Python 3 module will be built. By
|
|
default, the module will be built if the Python 3 interpreter can
|
|
be found.""",
|
|
'default', ('y','n','default')),
|
|
PathVariable(
|
|
'python3_cmd',
|
|
""" The name (full path if necessary) of the Python 3 interpreter.
|
|
Required to build the Python 3 module.""",
|
|
'python3', PathVariable.PathAccept),
|
|
PathVariable(
|
|
'python3_array_home',
|
|
""""If numpy was installed to a custom location (e.g. using the --home
|
|
option, set this to the directory for numpy.""",
|
|
'', PathVariable.PathAccept),
|
|
PathVariable(
|
|
'python3_prefix',
|
|
"""Use this option if you want to install the Cantera Python 3 package to
|
|
an alternate location. On Unix-like systems, the default is the same
|
|
as the $prefix option. If this option is set to the empty string (the
|
|
default on Windows), then the Package will be installed to the system
|
|
default 'site-packages' directory. To install to the current user's
|
|
site-packages directory, use 'python3_prefix=USER'.""",
|
|
defaults.python_prefix, PathVariable.PathAccept),
|
|
EnumVariable(
|
|
'matlab_toolbox',
|
|
"""This variable controls whether the Matlab toolbox will be built. If
|
|
set to 'y', you will also need to set the value of the 'matlab_path'
|
|
variable. If set to 'default', the Matlab toolbox will be built if
|
|
'matlab_path' is set.""",
|
|
'default', ('y', 'n', 'default')),
|
|
PathVariable(
|
|
'matlab_path',
|
|
"""Path to the Matlab install directory. This should be the directory
|
|
containing the 'extern', 'bin', etc. subdirectories. Typical values
|
|
are: "C:/Program Files/MATLAB/R2011a" on Windows,
|
|
"/Applications/MATLAB_R2011a.app" on OS X, or
|
|
"/opt/MATLAB/R2011a" on Linux.""",
|
|
'', PathVariable.PathAccept),
|
|
EnumVariable(
|
|
'f90_interface',
|
|
"""This variable controls whether the Fortran 90/95 interface will be
|
|
built. If set to 'default', the builder will look for a compatible
|
|
Fortran compiler in the $PATH, and compile the Fortran 90 interface
|
|
if one is found.""",
|
|
'default', ('y', 'n', 'default')),
|
|
PathVariable(
|
|
'FORTRAN',
|
|
"""The Fortran (90) compiler. If unspecified, the builder will look for
|
|
a compatible compiler (gfortran, ifort, g95) in the $PATH.""",
|
|
'', PathVariable.PathAccept),
|
|
('FORTRANFLAGS',
|
|
'Compilation options for the Fortran (90) compiler.',
|
|
'-O3'),
|
|
BoolVariable(
|
|
'coverage',
|
|
"""Enable collection of code coverage information with gcov.
|
|
Available only when compiling with gcc.""",
|
|
False),
|
|
BoolVariable(
|
|
'doxygen_docs',
|
|
"""Build HTML documentation for the C++ interface using Doxygen.""",
|
|
False),
|
|
BoolVariable(
|
|
'sphinx_docs',
|
|
"""Build HTML documentation for the Python module using Sphinx.""",
|
|
False),
|
|
PathVariable(
|
|
'sphinx_cmd',
|
|
"""Command to use for building the Sphinx documentation.""",
|
|
'sphinx-build', PathVariable.PathAccept),
|
|
EnumVariable(
|
|
'system_eigen',
|
|
"""Select whether to use Eigen from a system installation ('y'), from
|
|
a git submodule ('n'), or to decide automatically ('default').""",
|
|
'default', ('default', 'y', 'n')),
|
|
EnumVariable(
|
|
'system_sundials',
|
|
"""Select whether to use Sundials from a system installation ('y'), from
|
|
a git submodule ('n'), or to decide automatically ('default').
|
|
Specifying 'sundials_include' or 'sundials_libdir' changes the
|
|
default to 'y'.""",
|
|
'default', ('default', 'y', 'n')),
|
|
PathVariable(
|
|
'sundials_include',
|
|
"""The directory where the Sundials header files are installed. This
|
|
should be the directory that contains the "cvodes", "nvector", etc.
|
|
subdirectories. Not needed if the headers are installed in a
|
|
standard location, e.g. /usr/include.""",
|
|
'', PathVariable.PathAccept),
|
|
PathVariable(
|
|
'sundials_libdir',
|
|
"""The directory where the sundials static libraries are installed.
|
|
Not needed if the libraries are installed in a standard location,
|
|
e.g. /usr/lib.""",
|
|
'', PathVariable.PathAccept),
|
|
('blas_lapack_libs',
|
|
"""Cantera comes with Fortran (or C) versions of those parts of BLAS and
|
|
LAPACK it requires. But performance may be better if you use a version
|
|
of these libraries optimized for your machine hardware. If you want to
|
|
use your own libraries, set blas_lapack_libs to the the list of
|
|
libraries that should be passed to the linker, separated by commas,
|
|
e.g. "lapack,blas" or "lapack,f77blas,cblas,atlas".""",
|
|
''),
|
|
PathVariable('blas_lapack_dir',
|
|
"""Directory containing the libraries specified by 'blas_lapack_libs'.""",
|
|
'', PathVariable.PathAccept),
|
|
EnumVariable(
|
|
'lapack_names',
|
|
"""Set depending on whether the procedure names in the specified
|
|
libraries are lowercase or uppercase. If you don't know, run 'nm' on
|
|
the library file (e.g. 'nm libblas.a').""",
|
|
'lower', ('lower','upper')),
|
|
BoolVariable(
|
|
'lapack_ftn_trailing_underscore', '', True),
|
|
BoolVariable(
|
|
'lapack_ftn_string_len_at_end', '', True),
|
|
EnumVariable(
|
|
'system_googletest',
|
|
"""Select whether to use gtest from system installation ('y'), from a
|
|
git submodule ('n'), or to decide automatically ('default').""",
|
|
'default', ('default', 'y', 'n')),
|
|
('env_vars',
|
|
"""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'.""",
|
|
defaults.env_vars),
|
|
('cxx_flags',
|
|
"""Compiler flags passed to the C++ compiler only. Separate multiple
|
|
options with spaces, e.g. cxx_flags='-g -Wextra -O3 --std=c++11'""",
|
|
defaults.cxxFlags),
|
|
('cc_flags',
|
|
'Compiler flags passed to both the C and C++ compilers, regardless of optimization level',
|
|
defaults.ccFlags),
|
|
('thread_flags',
|
|
'Compiler and linker flags for POSIX multithreading support.',
|
|
defaults.threadFlags),
|
|
BoolVariable(
|
|
'optimize',
|
|
"""Enable extra compiler optimizations specified by the
|
|
"optimize_flags" variable, instead of the flags specified by the
|
|
"no_optimize_flags" variable.""",
|
|
True),
|
|
('optimize_flags',
|
|
'Additional compiler flags passed to the C/C++ compiler when optimize=yes.',
|
|
defaults.optimizeCcFlags),
|
|
('no_optimize_flags',
|
|
'Additional compiler flags passed to the C/C++ compiler when optimize=no.',
|
|
defaults.noOptimizeCcFlags),
|
|
BoolVariable(
|
|
'debug',
|
|
"""Enable compiler debugging symbols.""",
|
|
True),
|
|
('debug_flags',
|
|
'Additional compiler flags passed to the C/C++ compiler when debug=yes.',
|
|
defaults.debugCcFlags),
|
|
('no_debug_flags',
|
|
'Additional compiler flags passed to the C/C++ compiler when debug=no.',
|
|
defaults.noDebugCcFlags),
|
|
('debug_linker_flags',
|
|
'Additional options passed to the linker when debug=yes.',
|
|
defaults.debugLinkFlags),
|
|
('no_debug_linker_flags',
|
|
'Additional options passed to the linker when debug=no.',
|
|
defaults.noDebugLinkFlags),
|
|
('warning_flags',
|
|
"""Additional compiler flags passed to the C/C++ compiler to enable
|
|
extra warnings. Used only when compiling source code that part of
|
|
Cantera (e.g. excluding code in the 'ext' directory).""",
|
|
defaults.warningFlags),
|
|
('extra_inc_dirs',
|
|
'Additional directories to search for header files (colon-separated list).',
|
|
''),
|
|
('extra_lib_dirs',
|
|
'Additional directories to search for libraries (colon-separated list).',
|
|
''),
|
|
PathVariable(
|
|
'boost_inc_dir',
|
|
'Location of the Boost header files.',
|
|
defaults.boostIncDir, PathVariable.PathAccept),
|
|
BoolVariable(
|
|
'build_with_f2c',
|
|
"""For external procedures written in Fortran 77, both the
|
|
original F77 source code and C source code generated by the
|
|
'f2c' program are included. Set this to "n" if you want to
|
|
build Cantera using the F77 sources in the ext directory.""",
|
|
True),
|
|
PathVariable(
|
|
'stage_dir',
|
|
""" Directory relative to the Cantera source directory to be
|
|
used as a staging area for building e.g. a Debian
|
|
package. If specified, 'scons install' will install files
|
|
to 'stage_dir/prefix/...' instead of installing into the
|
|
local filesystem.""",
|
|
'',
|
|
PathVariable.PathAccept),
|
|
BoolVariable(
|
|
'VERBOSE',
|
|
"""Create verbose output about what scons is doing.""",
|
|
False),
|
|
BoolVariable(
|
|
'renamed_shared_libraries',
|
|
"""If this option is turned on, the shared libraries that are created
|
|
will be renamed to have a "_shared" extension added to their base name.
|
|
If not, the base names will be the same as the static libraries.
|
|
In some cases this simplifies subsequent linking environments with
|
|
static libraries and avoids a bug with using valgrind with
|
|
the -static linking flag.""",
|
|
True),
|
|
EnumVariable(
|
|
'layout',
|
|
"""The layout of the directory structure. 'standard' installs files to
|
|
several subdirectories under 'prefix', e.g. $prefix/bin,
|
|
$prefix/include/cantera, $prefix/lib. This layout is best used in
|
|
conjunction with 'prefix'='/usr/local'. 'compact' puts all installed
|
|
files in the subdirectory define by 'prefix'. This layout is best for
|
|
with a prefix like '/opt/cantera'. 'debian' installs to the stage
|
|
directory in a layout used for generating Debian packages.""",
|
|
defaults.fsLayout, ('standard','compact','debian')),
|
|
]
|
|
|
|
opts.AddVariables(*config_options)
|
|
opts.Update(env)
|
|
opts.Save('cantera.conf', env)
|
|
|
|
if 'help' in COMMAND_LINE_TARGETS:
|
|
### Print help about configuration options and exit.
|
|
print """
|
|
**************************************************
|
|
* Configuration options for building Cantera *
|
|
**************************************************
|
|
|
|
The following options can be passed to SCons to customize the Cantera
|
|
build process. They should be given in the form:
|
|
|
|
scons build option1=value1 option2=value2
|
|
|
|
Variables set in this way will be stored in the 'cantera.conf' file and reused
|
|
automatically on subsequent invocations of scons. Alternatively, the
|
|
configuration options can be entered directly into 'cantera.conf' before
|
|
running 'scons build'. The format of this file is:
|
|
|
|
option1 = 'value1'
|
|
option2 = 'value2'
|
|
|
|
**************************************************
|
|
"""
|
|
|
|
for opt in opts.options:
|
|
print '\n'.join(formatOption(env, opt))
|
|
sys.exit(0)
|
|
|
|
if 'doxygen' in COMMAND_LINE_TARGETS:
|
|
env['doxygen_docs'] = True
|
|
if 'sphinx' in COMMAND_LINE_TARGETS:
|
|
env['sphinx_docs'] = True
|
|
|
|
valid_arguments = (set(opt[0] for opt in windows_compiler_options) |
|
|
set(opt[0] for opt in compiler_options) |
|
|
set(opt[0] for opt in config_options))
|
|
for arg in ARGUMENTS:
|
|
if arg not in valid_arguments:
|
|
print 'Encountered unexpected command line argument: %r' % arg
|
|
sys.exit(1)
|
|
|
|
# Require a StrictVersion-compatible version
|
|
env['cantera_version'] = "2.3.0a2"
|
|
ctversion = StrictVersion(env['cantera_version'])
|
|
# MSI versions do not support pre-release tags
|
|
env['cantera_msi_version'] = '.'.join(str(x) for x in ctversion.version)
|
|
env['cantera_short_version'] = '.'.join(str(x) for x in ctversion.version[:2])
|
|
|
|
# Print values of all build options:
|
|
print "Configuration variables read from 'cantera.conf' and command line:"
|
|
for line in open('cantera.conf'):
|
|
print ' ', line.strip()
|
|
print
|
|
|
|
# ********************************************
|
|
# *** Configure system-specific properties ***
|
|
# ********************************************
|
|
|
|
# Copy in external environment variables
|
|
if env['env_vars'] == 'all':
|
|
env['ENV'].update(os.environ)
|
|
if 'PYTHONHOME' in env['ENV']:
|
|
del env['ENV']['PYTHONHOME']
|
|
elif env['env_vars']:
|
|
for name in listify(env['env_vars']):
|
|
if name in os.environ:
|
|
env['ENV'][name] = os.environ[name]
|
|
elif name not in defaults.env_vars:
|
|
print 'WARNING: failed to propagate environment variable', repr(name)
|
|
print ' Edit cantera.conf or the build command line to fix this.'
|
|
|
|
env['extra_inc_dirs'] = [d for d in env['extra_inc_dirs'].split(':') if d]
|
|
env['extra_lib_dirs'] = [d for d in env['extra_lib_dirs'].split(':') if d]
|
|
|
|
env.Append(CPPPATH=env['extra_inc_dirs'],
|
|
LIBPATH=env['extra_lib_dirs'])
|
|
|
|
if env['CC'] == 'cl':
|
|
# embed manifest file
|
|
env['LINKCOM'] = [env['LINKCOM'],
|
|
'if exist ${TARGET}.manifest mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;1']
|
|
env['SHLINKCOM'] = [env['SHLINKCOM'],
|
|
'if exist ${TARGET}.manifest mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;2']
|
|
|
|
if env['boost_inc_dir']:
|
|
env.Append(CPPPATH=env['boost_inc_dir'])
|
|
|
|
if env['blas_lapack_dir']:
|
|
env.Append(LIBPATH=[env['blas_lapack_dir']])
|
|
|
|
if env['system_sundials'] in ('y','default'):
|
|
if env['sundials_include']:
|
|
env.Append(CPPPATH=[env['sundials_include']])
|
|
env['system_sundials'] = 'y'
|
|
if env['sundials_libdir']:
|
|
env.Append(LIBPATH=[env['sundials_libdir']])
|
|
env['system_sundials'] = 'y'
|
|
|
|
# BLAS / LAPACK configuration
|
|
if env['blas_lapack_libs'] != '':
|
|
env['blas_lapack_libs'] = env['blas_lapack_libs'].split(',')
|
|
env['BUILD_BLAS_LAPACK'] = False
|
|
elif env['OS'] == 'Darwin':
|
|
env['blas_lapack_libs'] = []
|
|
env['BUILD_BLAS_LAPACK'] = False
|
|
env.Append(FRAMEWORKS=['Accelerate'])
|
|
else:
|
|
# External BLAS/LAPACK were not given, so we need to compile them
|
|
env['BUILD_BLAS_LAPACK'] = True
|
|
env['blas_lapack_libs'] = [] # built into libcantera
|
|
|
|
# ************************************
|
|
# *** Compiler Configuration Tests ***
|
|
# ************************************
|
|
|
|
def CheckStatement(context, function, includes=""):
|
|
context.Message('Checking for %s... ' % function)
|
|
src = """
|
|
%(include)s
|
|
int main(int argc, char** argv) {
|
|
%(func)s;
|
|
return 0;
|
|
}
|
|
""" % {'func':function, 'include':includes}
|
|
result = context.TryCompile(src, '.cpp')
|
|
context.Result(result)
|
|
return result
|
|
|
|
conf = Configure(env, custom_tests={'CheckStatement': CheckStatement})
|
|
|
|
# Set up compiler options before running configuration tests
|
|
env['CXXFLAGS'] = listify(env['cxx_flags'])
|
|
env['CCFLAGS'] = listify(env['cc_flags']) + listify(env['thread_flags'])
|
|
env['LINKFLAGS'] += listify(env['thread_flags'])
|
|
env['CPPDEFINES'] = {}
|
|
|
|
env['warning_flags'] = listify(env['warning_flags'])
|
|
|
|
if env['optimize']:
|
|
env['CCFLAGS'] += listify(env['optimize_flags'])
|
|
env.Append(CPPDEFINES=['NDEBUG'])
|
|
else:
|
|
env['CCFLAGS'] += listify(env['no_optimize_flags'])
|
|
|
|
if env['debug']:
|
|
env['CCFLAGS'] += listify(env['debug_flags'])
|
|
env['LINKFLAGS'] += listify(env['debug_linker_flags'])
|
|
else:
|
|
env['CCFLAGS'] += listify(env['no_debug_flags'])
|
|
env['LINKFLAGS'] += listify(env['no_debug_linker_flags'])
|
|
|
|
if env['coverage']:
|
|
if 'gcc' in env.subst('$CC'):
|
|
env.Append(CCFLAGS=['-fprofile-arcs', '-ftest-coverage'])
|
|
env.Append(LINKFLAGS=['-fprofile-arcs', '-ftest-coverage'])
|
|
|
|
else:
|
|
print 'Error: coverage testing is only available with GCC.'
|
|
exit(0)
|
|
|
|
if env['toolchain'] == 'mingw':
|
|
env.Append(LINKFLAGS=['-static-libgcc', '-static-libstdc++'])
|
|
|
|
def config_error(message):
|
|
print 'ERROR:', message
|
|
if env['VERBOSE']:
|
|
print '*' * 25, 'Contents of config.log:', '*' * 25
|
|
print open('config.log').read()
|
|
print '*' * 28, 'End of config.log', '*' * 28
|
|
else:
|
|
print "See 'config.log' for details."
|
|
sys.exit(1)
|
|
|
|
# First, a sanity check:
|
|
if not conf.CheckCXXHeader('cmath', '<>'):
|
|
config_error('The C++ compiler is not correctly configured.')
|
|
|
|
# Check for fmt library and checkout submodule if needed
|
|
if not os.path.exists('ext/fmt/fmt/format.h'):
|
|
if not os.path.exists('.git'):
|
|
config_error('fmt is missing. Install source in ext/fmt.')
|
|
|
|
try:
|
|
code = subprocess.call(['git','submodule','update','--init',
|
|
'--recursive','ext/fmt'])
|
|
except Exception:
|
|
code = -1
|
|
if code:
|
|
config_error('fmt submodule checkout failed.\n'
|
|
'Try manually checking out the submodule with:\n\n'
|
|
' git submodule update --init --recursive ext/fmt\n')
|
|
|
|
# Check for googletest and checkout submodule if needed
|
|
if env['system_googletest'] in ('y', 'default'):
|
|
if conf.CheckCXXHeader('gtest/gtest.h', '""'):
|
|
env['system_googletest'] = True
|
|
elif env['system_googletest'] == 'y':
|
|
config_error('Expected system installation of Googletest, but it '
|
|
'could not be found.')
|
|
|
|
if env['system_googletest'] in ('n', 'default'):
|
|
env['system_googletest'] = False
|
|
if not os.path.exists('ext/googletest/include/gtest/gtest.h'):
|
|
if not os.path.exists('.git'):
|
|
config_error('Googletest is missing. Install source in ext/googletest.')
|
|
|
|
try:
|
|
code = subprocess.call(['git','submodule','update','--init',
|
|
'--recursive','ext/googletest'])
|
|
except Exception:
|
|
code = -1
|
|
if code:
|
|
config_error('Googletest not found and submodule checkout failed.\n'
|
|
'Try manually checking out the submodule with:\n\n'
|
|
' git submodule update --init --recursive ext/googletest\n')
|
|
|
|
# Check for Eigen and checkout submodule if needed
|
|
if env['system_eigen'] in ('y', 'default'):
|
|
if conf.CheckCXXHeader('Eigen/Dense', '<>'):
|
|
env['system_eigen'] = True
|
|
elif env['system_eigen'] == 'y':
|
|
config_error('Expected system installation of Eigen, but it '
|
|
'could not be found.')
|
|
|
|
if env['system_eigen'] in ('n', 'default'):
|
|
env['system_eigen'] = False
|
|
if not os.path.exists('ext/eigen/Eigen/Dense'):
|
|
if not os.path.exists('.git'):
|
|
config_error('Eigen is missing. Install Eigen in ext/eigen.')
|
|
|
|
try:
|
|
code = subprocess.call(['git','submodule','update','--init',
|
|
'--recursive','ext/eigen'])
|
|
except Exception:
|
|
code = -1
|
|
if code:
|
|
config_error('Eigen not found and submodule checkout failed.\n'
|
|
'Try manually checking out the submodule with:\n\n'
|
|
' git submodule update --init --recursive ext/eigen\n')
|
|
|
|
|
|
def get_expression_value(includes, expression):
|
|
s = ['#include ' + i for i in includes]
|
|
s.extend(('#define Q(x) #x',
|
|
'#define QUOTE(x) Q(x)',
|
|
'#include <iostream>',
|
|
'int main(int argc, char** argv) {',
|
|
' std::cout << %s << std::endl;' % expression,
|
|
' return 0;',
|
|
'}\n'))
|
|
return '\n'.join(s)
|
|
|
|
env['HAS_TIMES_H'] = conf.CheckCHeader('sys/times.h', '""')
|
|
env['HAS_UNISTD_H'] = conf.CheckCHeader('unistd.h', '""')
|
|
|
|
boost_version_source = get_expression_value(['<boost/version.hpp>'], 'BOOST_LIB_VERSION')
|
|
retcode, boost_lib_version = conf.TryRun(boost_version_source, '.cpp')
|
|
env['BOOST_LIB_VERSION'] = boost_lib_version.strip()
|
|
|
|
import SCons.Conftest, SCons.SConf
|
|
context = SCons.SConf.CheckContext(conf)
|
|
ret = SCons.Conftest.CheckLib(context,
|
|
['sundials_cvodes'],
|
|
header='#include "cvodes/cvodes.h"',
|
|
language='C++',
|
|
call='CVodeCreate(CV_BDF, CV_NEWTON);',
|
|
autoadd=False,
|
|
extra_libs=env['blas_lapack_libs'])
|
|
if ret:
|
|
# CheckLib returns False to indicate success
|
|
if env['system_sundials'] == 'default':
|
|
env['system_sundials'] = 'n'
|
|
elif env['system_sundials'] == 'y':
|
|
config_error('Expected system installation of Sundials, but it could '
|
|
'not be found.')
|
|
elif env['system_sundials'] == 'default':
|
|
env['system_sundials'] = 'y'
|
|
|
|
|
|
# Checkout Sundials submodule if needed
|
|
if (env['system_sundials'] == 'n' and
|
|
not os.path.exists('ext/sundials/include/cvodes/cvodes.h')):
|
|
if not os.path.exists('.git'):
|
|
config_error('Sundials is missing. Install source in ext/sundials.')
|
|
|
|
try:
|
|
code = subprocess.call(['git','submodule','update','--init',
|
|
'--recursive','ext/sundials'])
|
|
except Exception:
|
|
code = -1
|
|
if code:
|
|
config_error('Sundials not found and submodule checkout failed.\n'
|
|
'Try manually checking out the submodule with:\n\n'
|
|
' git submodule update --init --recursive ext/sundials\n')
|
|
|
|
|
|
env['NEED_LIBM'] = not conf.CheckLibWithHeader(None, 'math.h', 'C',
|
|
'double x; log(x);', False)
|
|
env['LIBM'] = ['m'] if env['NEED_LIBM'] else []
|
|
|
|
if env['system_sundials'] == 'y':
|
|
for subdir in ('sundials','nvector','cvodes','ida'):
|
|
removeDirectory('include/cantera/ext/'+subdir)
|
|
|
|
# Determine Sundials version
|
|
sundials_version_source = get_expression_value(['"sundials/sundials_config.h"'],
|
|
'QUOTE(SUNDIALS_PACKAGE_VERSION)')
|
|
retcode, sundials_version = conf.TryRun(sundials_version_source, '.cpp')
|
|
if retcode == 0:
|
|
config_error("Failed to determine Sundials version.")
|
|
sundials_version = sundials_version.strip(' "\n')
|
|
|
|
# Ignore the minor version, e.g. 2.4.x -> 2.4
|
|
env['sundials_version'] = '.'.join(sundials_version.split('.')[:2])
|
|
if env['sundials_version'] not in ('2.4','2.5','2.6'):
|
|
print """ERROR: Sundials version %r is not supported.""" % env['sundials_version']
|
|
sys.exit(1)
|
|
print """INFO: Using system installation of Sundials version %s.""" % sundials_version
|
|
|
|
#Determine whether or not Sundials was built with BLAS/LAPACK
|
|
if LooseVersion(env['sundials_version']) < LooseVersion('2.6'):
|
|
# In Sundials 2.4 / 2.5, SUNDIALS_BLAS_LAPACK is either 0 or 1
|
|
sundials_blas_lapack = get_expression_value(['"sundials/sundials_config.h"'],
|
|
'SUNDIALS_BLAS_LAPACK')
|
|
retcode, has_sundials_lapack = conf.TryRun(sundials_blas_lapack, '.cpp')
|
|
if retcode == 0:
|
|
config_error("Failed to determine Sundials BLAS/LAPACK.")
|
|
env['has_sundials_lapack'] = int(has_sundials_lapack.strip())
|
|
else:
|
|
# In Sundials 2.6, SUNDIALS_BLAS_LAPACK is either defined or undefined
|
|
env['has_sundials_lapack'] = conf.CheckDeclaration('SUNDIALS_BLAS_LAPACK',
|
|
'#include "sundials/sundials_config.h"', 'C++')
|
|
|
|
# In the case where a user is trying to link Cantera to an external BLAS/LAPACK
|
|
# library, but Sundials was configured without this support, print a Warning.
|
|
if not env['has_sundials_lapack'] and not env['BUILD_BLAS_LAPACK']:
|
|
print ('WARNING: External BLAS/LAPACK has been specified for Cantera '
|
|
'but Sundials was built without this support.')
|
|
else: # env['system_sundials'] == 'n'
|
|
print """INFO: Using private installation of Sundials version 2.6."""
|
|
env['sundials_version'] = '2.6'
|
|
env['has_sundials_lapack'] = int(not env['BUILD_BLAS_LAPACK'])
|
|
|
|
|
|
# Try to find a working Fortran compiler:
|
|
env['FORTRANSYSLIBS'] = []
|
|
fortran_libs = {'gfortran':'gfortran', 'g95':'f95'}
|
|
def check_fortran(compiler, expected=False):
|
|
if which(compiler) is not None:
|
|
lib = fortran_libs.get(compiler)
|
|
if lib:
|
|
have_lib = conf.CheckLib(lib)
|
|
if have_lib:
|
|
env.Append(FORTRANSYSLIBS=lib)
|
|
env['FORTRAN'] = compiler
|
|
return True
|
|
else:
|
|
print ("WARNING: Unable to use '%s' to compile the Fortran "
|
|
"interface because the library '%s' could not be found." %
|
|
(compiler, lib))
|
|
else:
|
|
env['FORTRAN'] = compiler
|
|
return True
|
|
elif expected:
|
|
print "ERROR: Couldn't find specified Fortran compiler: '%s'" % compiler
|
|
sys.exit(1)
|
|
|
|
return False
|
|
|
|
if env['f90_interface'] in ('y','default'):
|
|
foundF90 = False
|
|
if env['FORTRAN']:
|
|
foundF90 = check_fortran(env['FORTRAN'], True)
|
|
|
|
for compiler in ('gfortran', 'ifort', 'g95'):
|
|
if foundF90:
|
|
break
|
|
foundF90 = check_fortran(compiler)
|
|
|
|
if foundF90:
|
|
print "INFO: Using '%s' to build the Fortran 90 interface" % env['FORTRAN']
|
|
env['f90_interface'] = 'y'
|
|
else:
|
|
if env['f90_interface'] == 'y':
|
|
print "ERROR: Couldn't find a suitable Fortran compiler to build the Fortran 90 interface."
|
|
sys.exit(1)
|
|
else:
|
|
env['f90_interface'] = 'n'
|
|
print "INFO: Skipping compilation of the Fortran 90 interface."
|
|
|
|
if 'gfortran' in env['FORTRAN']:
|
|
env['FORTRANMODDIRPREFIX'] = '-J'
|
|
elif 'g95' in env['FORTRAN']:
|
|
env['FORTRANMODDIRPREFIX'] = '-fmod='
|
|
elif 'ifort' in env['FORTRAN']:
|
|
env['FORTRANMODDIRPREFIX'] = '-module '
|
|
|
|
env['F77'] = env['F90'] = env['F95'] = env['F03'] = env['FORTRAN']
|
|
env['F77FLAGS'] = env['F90FLAGS'] = env['F95FLAGS'] = env['F03FLAGS'] = env['FORTRANFLAGS']
|
|
|
|
env['FORTRANMODDIR'] = '${TARGET.dir}'
|
|
|
|
env = conf.Finish()
|
|
|
|
if env['VERBOSE']:
|
|
print '-------------------- begin config.log --------------------'
|
|
print open('config.log').read()
|
|
print '--------------------- end config.log ---------------------'
|
|
|
|
env['python_cmd_esc'] = quoted(env['python_cmd'])
|
|
|
|
# Python 2 Package Settings
|
|
cython_min_version = LooseVersion('0.19')
|
|
env['install_python2_action'] = ''
|
|
if env['python_package'] == 'new':
|
|
env['python_package'] = 'full' # Allow 'new' as a synonym for 'full'
|
|
warnNoPython = False
|
|
|
|
# The directory within the source tree which will contain the Python 2 module
|
|
env['pythonpath_build2'] = Dir('build/python2').abspath
|
|
|
|
if env['python_package'] in ('full','default'):
|
|
if 'PYTHONPATH' in env['ENV']:
|
|
env['pythonpath_build2'] += os.path.pathsep + env['ENV']['PYTHONPATH']
|
|
|
|
# Check for Cython:
|
|
try:
|
|
import Cython
|
|
cython_version = LooseVersion(Cython.__version__)
|
|
print 'INFO: Using Cython version {0}.'.format(cython_version)
|
|
except ImportError:
|
|
cython_version = LooseVersion('0.0.0')
|
|
|
|
if cython_version < cython_min_version:
|
|
message = ("Cython not found or incompatible version: "
|
|
"Found {0} but {1} or newer is required.".format(cython_version, cython_min_version))
|
|
if env['python_package'] == 'full':
|
|
print("ERROR: " + message)
|
|
sys.exit(1)
|
|
else:
|
|
warnNoPython = True
|
|
env['python_package'] = 'minimal'
|
|
print ("WARNING: " + message)
|
|
|
|
# Test to see if we can import the specified array module
|
|
if env['python_array_home']:
|
|
sys.path.append(env['python_array_home'])
|
|
try:
|
|
import numpy as np
|
|
try:
|
|
env['python_array_include'] = np.get_include()
|
|
except AttributeError:
|
|
print """WARNING: Couldn't find include directory for NumPy."""
|
|
env['python_array_include'] = ''
|
|
|
|
except ImportError:
|
|
if env['python_package'] == 'full':
|
|
print """ERROR: Couldn't find include directory for NumPy."""
|
|
sys.exit(1)
|
|
else:
|
|
print ("""WARNING: Not building the Python package """
|
|
""" because NumPy could not be found.""")
|
|
warnNoPython = True
|
|
env['python_package'] = 'minimal'
|
|
|
|
if warnNoPython:
|
|
env['python_package'] = 'minimal'
|
|
else:
|
|
env['python_package'] = 'full'
|
|
print """INFO: Building the full Python 2 package."""
|
|
|
|
try:
|
|
import site
|
|
env['python_usersitepackages'] = site.getusersitepackages()
|
|
except AttributeError: # getusersitepackages is only in Python 2.7+
|
|
env['python_usersitepackages'] = '<user site-packages directory>'
|
|
|
|
# Check for 3to2. See http://pypi.python.org/pypi/3to2
|
|
if env['python_package'] == 'full':
|
|
try:
|
|
if env['OS'] == 'Windows':
|
|
python_dir = os.path.dirname(which(env['python_cmd']))
|
|
threetotwo_cmd = pjoin(python_dir, 'Scripts', '3to2')
|
|
ret = getCommandOutput(env['python_cmd'], threetotwo_cmd, '-l')
|
|
else:
|
|
ret = getCommandOutput('3to2', '-l')
|
|
except OSError:
|
|
ret = ''
|
|
if 'print' in ret:
|
|
env['python_convert_examples'] = True
|
|
else:
|
|
env['python_convert_examples'] = False
|
|
print """WARNING: Couldn't find '3to2'. Python examples will not work correctly."""
|
|
|
|
else:
|
|
env['python_array_include'] = ''
|
|
env['python_module_loc'] = ''
|
|
|
|
# Python 3 Package Settings
|
|
if env['python3_package'] in ('y', 'default'):
|
|
# The directory within the source tree which will contain the Python 3 module
|
|
env['pythonpath_build3'] = Dir('build/python3').abspath
|
|
if 'PYTHONPATH' in env['ENV']:
|
|
env['pythonpath_build3'] += os.path.pathsep + env['ENV']['PYTHONPATH']
|
|
|
|
# See if we can execute the Python 3 interpreter
|
|
try:
|
|
script = '\n'.join(("from distutils.sysconfig import *",
|
|
"import site",
|
|
"print(get_python_version())",
|
|
"try:",
|
|
" print(site.getusersitepackages())",
|
|
"except AttributeError:",
|
|
" print(site.USER_SITE)"))
|
|
info = getCommandOutput(env['python3_cmd'], '-c', script)
|
|
(env['python3_version'],
|
|
env['python3_usersitepackages']) = info.splitlines()[-2:]
|
|
except OSError:
|
|
info = False
|
|
|
|
if not info:
|
|
if env['python3_package'] == 'default':
|
|
print ('INFO: Not building the Python 3 package because the Python '
|
|
'3 interpreter %r could not be found.' % env['python3_cmd'])
|
|
env['python3_package'] = 'n'
|
|
else:
|
|
print ('ERROR: Could not execute the Python 3 interpreter %r.' %
|
|
env['python3_cmd'])
|
|
sys.exit(1)
|
|
else:
|
|
print 'INFO: Building Python package for Python {0}'.format(env['python3_version'])
|
|
env['python3_package'] = 'y'
|
|
|
|
|
|
# Matlab Toolbox settings
|
|
if env['matlab_path'] != '' and env['matlab_toolbox'] == 'default':
|
|
env['matlab_toolbox'] = 'y'
|
|
|
|
if env['matlab_toolbox'] == 'y':
|
|
matPath = env['matlab_path']
|
|
if matPath == '':
|
|
print """ERROR: Unable to build the Matlab toolbox because 'matlab_path' has not been set."""
|
|
sys.exit(1)
|
|
|
|
if env['blas_lapack_libs']:
|
|
print ('ERROR: The Matlab toolbox is incompatible with external BLAS '
|
|
'and LAPACK libraries. Unset blas_lapack_libs (e.g. "scons '
|
|
'build blas_lapack_libs=") in order to build the Matlab '
|
|
'toolbox, or set matlab_toolbox=n to use the specified BLAS/'
|
|
'LAPACK libraries and skip building the Matlab toolbox.')
|
|
sys.exit(1)
|
|
|
|
if not (os.path.isdir(matPath) and
|
|
os.path.isdir(pjoin(matPath, 'extern'))):
|
|
print """ERROR: Path set for 'matlab_path' is not correct."""
|
|
print """ERROR: Path was: '%s'""" % matPath
|
|
sys.exit(1)
|
|
|
|
|
|
# **********************************************
|
|
# *** Set additional configuration variables ***
|
|
# **********************************************
|
|
|
|
# Directories where things will be after actually being installed. These
|
|
# variables are the ones that are used to populate header files, scripts, etc.
|
|
env['ct_installroot'] = env['prefix']
|
|
env['ct_libdir'] = pjoin(env['prefix'], 'lib')
|
|
env['ct_bindir'] = pjoin(env['prefix'], 'bin')
|
|
env['ct_incdir'] = pjoin(env['prefix'], 'include', 'cantera')
|
|
env['ct_incroot'] = pjoin(env['prefix'], 'include')
|
|
|
|
if env['layout'] == 'compact':
|
|
env['ct_datadir'] = pjoin(env['prefix'], 'data')
|
|
env['ct_sampledir'] = pjoin(env['prefix'], 'samples')
|
|
env['ct_mandir'] = pjoin(env['prefix'], 'man1')
|
|
env['ct_matlab_dir'] = pjoin(env['prefix'], 'matlab', 'toolbox')
|
|
else:
|
|
env['ct_datadir'] = pjoin(env['prefix'], 'share', 'cantera', 'data')
|
|
env['ct_sampledir'] = pjoin(env['prefix'], 'share', 'cantera', 'samples')
|
|
env['ct_mandir'] = pjoin(env['prefix'], 'share', 'man', 'man1')
|
|
env['ct_matlab_dir'] = pjoin(env['prefix'], 'lib', 'cantera', 'matlab', 'toolbox')
|
|
|
|
# Always set the stage directory before building an MSI installer
|
|
if 'msi' in COMMAND_LINE_TARGETS:
|
|
COMMAND_LINE_TARGETS.append('install')
|
|
env['stage_dir'] = 'stage'
|
|
env['prefix'] = '.'
|
|
env['PYTHON_INSTALLER'] = 'binary'
|
|
elif env['layout'] == 'debian':
|
|
COMMAND_LINE_TARGETS.append('install')
|
|
env['stage_dir'] = 'stage/cantera'
|
|
env['PYTHON_INSTALLER'] = 'debian'
|
|
env['INSTALL_MANPAGES'] = False
|
|
else:
|
|
env['PYTHON_INSTALLER'] = 'direct'
|
|
|
|
|
|
addInstallActions = ('install' in COMMAND_LINE_TARGETS or
|
|
'uninstall' in COMMAND_LINE_TARGETS)
|
|
|
|
# Directories where things will be staged for package creation. These
|
|
# variables should always be used by the Install(...) targets
|
|
if env['stage_dir']:
|
|
instRoot = pjoin(os.getcwd(), env['stage_dir'],
|
|
stripDrive(env['prefix']).strip('/\\'))
|
|
for k in ('python_prefix', 'python3_prefix'):
|
|
if env[k]:
|
|
env[k] = pjoin(os.getcwd(), env['stage_dir'],
|
|
stripDrive(env[k]).strip('/\\'))
|
|
else:
|
|
env[k] = pjoin(os.getcwd(), env['stage_dir'])
|
|
else:
|
|
instRoot = env['prefix']
|
|
|
|
if env['layout'] == 'debian':
|
|
base = pjoin(os.getcwd(), 'debian')
|
|
|
|
env['inst_libdir'] = pjoin(base, 'cantera-dev', 'usr', 'lib')
|
|
env['inst_incdir'] = pjoin(base, 'cantera-dev', 'usr', 'include', 'cantera')
|
|
env['inst_incroot'] = pjoin(base, 'cantera-dev', 'usr' 'include')
|
|
|
|
env['inst_bindir'] = pjoin(base, 'cantera-common', 'usr', 'bin')
|
|
env['inst_datadir'] = pjoin(base, 'cantera-common', 'usr', 'share', 'cantera', 'data')
|
|
env['inst_docdir'] = pjoin(base, 'cantera-common', 'usr', 'share', 'cantera', 'doc')
|
|
env['inst_sampledir'] = pjoin(base, 'cantera-common', 'usr', 'share', 'cantera', 'samples')
|
|
env['inst_mandir'] = pjoin(base, 'cantera-common', 'usr', 'share', 'man', 'man1')
|
|
|
|
env['inst_matlab_dir'] = pjoin(base, 'cantera-matlab',
|
|
'usr', 'lib', 'cantera', 'matlab', 'toolbox')
|
|
|
|
env['inst_python_bindir'] = pjoin(base, 'cantera-python', 'usr', 'bin')
|
|
env['python_prefix'] = pjoin(base, 'cantera-python', 'usr')
|
|
env['python3_prefix'] = pjoin(base, 'cantera-python3', 'usr')
|
|
else:
|
|
env['inst_libdir'] = pjoin(instRoot, 'lib')
|
|
env['inst_bindir'] = pjoin(instRoot, 'bin')
|
|
env['inst_python_bindir'] = pjoin(instRoot, 'bin')
|
|
env['inst_incdir'] = pjoin(instRoot, 'include', 'cantera')
|
|
env['inst_incroot'] = pjoin(instRoot, 'include')
|
|
|
|
if env['layout'] == 'compact':
|
|
env['inst_matlab_dir'] = pjoin(instRoot, 'matlab', 'toolbox')
|
|
env['inst_datadir'] = pjoin(instRoot, 'data')
|
|
env['inst_sampledir'] = pjoin(instRoot, 'samples')
|
|
env['inst_docdir'] = pjoin(instRoot, 'doc')
|
|
env['inst_mandir'] = pjoin(instRoot, 'man1')
|
|
else: # env['layout'] == 'standard'
|
|
env['inst_matlab_dir'] = pjoin(instRoot, 'lib', 'cantera', 'matlab', 'toolbox')
|
|
env['inst_datadir'] = pjoin(instRoot, 'share', 'cantera', 'data')
|
|
env['inst_sampledir'] = pjoin(instRoot, 'share', 'cantera', 'samples')
|
|
env['inst_docdir'] = pjoin(instRoot, 'share', 'cantera', 'doc')
|
|
env['inst_mandir'] = pjoin(instRoot, 'share', 'man', 'man1')
|
|
|
|
# **************************************
|
|
# *** Set options needed in config.h ***
|
|
# **************************************
|
|
|
|
configh = {}
|
|
|
|
configh['CANTERA_VERSION'] = quoted(env['cantera_version'])
|
|
configh['CANTERA_SHORT_VERSION'] = quoted(env['cantera_short_version'])
|
|
|
|
# Conditional defines
|
|
def cdefine(definevar, configvar, comp=True, value=1):
|
|
if env.get(configvar) == comp:
|
|
configh[definevar] = value
|
|
else:
|
|
configh[definevar] = None
|
|
|
|
# Need to test all of these to see what platform.system() returns
|
|
configh['SOLARIS'] = 1 if env['OS'] == 'Solaris' else None
|
|
configh['DARWIN'] = 1 if env['OS'] == 'Darwin' else None
|
|
cdefine('NEEDS_GENERIC_TEMPL_STATIC_DECL', 'OS', 'Solaris')
|
|
|
|
if env['python_package'] == 'none' and env['python3_package'] == 'n':
|
|
configh['HAS_NO_PYTHON'] = 1
|
|
else:
|
|
configh['HAS_NO_PYTHON'] = None
|
|
|
|
configh['SUNDIALS_VERSION'] = env['sundials_version'].replace('.','')
|
|
|
|
if env.get('has_sundials_lapack') and not env['BUILD_BLAS_LAPACK']:
|
|
configh['SUNDIALS_USE_LAPACK'] = 1
|
|
else:
|
|
configh['SUNDIALS_USE_LAPACK'] = 0
|
|
|
|
cdefine('LAPACK_FTN_STRING_LEN_AT_END', 'lapack_ftn_string_len_at_end')
|
|
cdefine('LAPACK_FTN_TRAILING_UNDERSCORE', 'lapack_ftn_trailing_underscore')
|
|
cdefine('FTN_TRAILING_UNDERSCORE', 'lapack_ftn_trailing_underscore')
|
|
cdefine('LAPACK_NAMES_LOWERCASE', 'lapack_names', 'lower')
|
|
configh['CT_USE_LAPACK'] = 0 if env['BUILD_BLAS_LAPACK'] else 1
|
|
cdefine('CT_USE_SYSTEM_EIGEN', env['system_eigen'])
|
|
|
|
config_h = env.Command('include/cantera/base/config.h',
|
|
'include/cantera/base/config.h.in',
|
|
ConfigBuilder(configh))
|
|
env.AlwaysBuild(config_h)
|
|
env['config_h_target'] = config_h
|
|
|
|
# *********************
|
|
# *** Build Cantera ***
|
|
# *********************
|
|
|
|
# Some options to speed up SCons
|
|
env.SetOption('max_drift', 2)
|
|
env.SetOption('implicit_cache', True)
|
|
|
|
buildTargets = []
|
|
libraryTargets = [] # objects that go in the Cantera library
|
|
installTargets = []
|
|
sampleTargets = []
|
|
|
|
def build(targets):
|
|
""" Wrapper to add target to list of build targets """
|
|
buildTargets.extend(targets)
|
|
return targets
|
|
|
|
def buildSample(*args, **kwargs):
|
|
""" Wrapper to add target to list of samples """
|
|
targets = args[0](*args[1:], **kwargs)
|
|
sampleTargets.extend(targets)
|
|
return targets
|
|
|
|
def install(*args, **kwargs):
|
|
""" Wrapper to add target to list of install targets """
|
|
if not addInstallActions:
|
|
return
|
|
if len(args) == 2:
|
|
inst = env.Install(*args, **kwargs)
|
|
else:
|
|
inst = args[0](*args[1:], **kwargs)
|
|
|
|
installTargets.extend(inst)
|
|
return inst
|
|
|
|
|
|
env.SConsignFile()
|
|
|
|
env.Prepend(CPPPATH=[],
|
|
LIBPATH=[Dir('build/lib')])
|
|
|
|
# preprocess input files (cti -> xml)
|
|
convertedInputFiles = set()
|
|
for cti in mglob(env, 'data/inputs', 'cti'):
|
|
build(env.Command('build/data/%s' % cti.name, cti.path,
|
|
Copy('$TARGET', '$SOURCE')))
|
|
outName = os.path.splitext(cti.name)[0] + '.xml'
|
|
convertedInputFiles.add(outName)
|
|
build(env.Command('build/data/%s' % outName, cti.path,
|
|
'$python_cmd_esc interfaces/cython/cantera/ctml_writer.py $SOURCE $TARGET'))
|
|
|
|
|
|
# Copy input files which are not present as cti:
|
|
for xml in mglob(env, 'data/inputs', 'xml'):
|
|
dest = pjoin('build','data',xml.name)
|
|
if xml.name not in convertedInputFiles:
|
|
build(env.Command(dest, xml.path, Copy('$TARGET', '$SOURCE')))
|
|
|
|
if addInstallActions:
|
|
# Put headers in place
|
|
headerBase = 'include/cantera'
|
|
install(env.RecursiveInstall, '$inst_incdir', 'include/cantera')
|
|
|
|
# Data files
|
|
install('$inst_datadir', mglob(env, 'build/data', 'cti', 'xml'))
|
|
|
|
|
|
### List of libraries needed to link to Cantera ###
|
|
linkLibs = ['cantera']
|
|
|
|
### List of shared libraries needed to link applications to Cantera
|
|
linkSharedLibs = ['cantera_shared']
|
|
|
|
if env['system_sundials'] == 'y':
|
|
env['sundials_libs'] = ['sundials_cvodes', 'sundials_ida', 'sundials_nvecserial']
|
|
linkLibs.extend(('sundials_cvodes', 'sundials_ida', 'sundials_nvecserial'))
|
|
linkSharedLibs.extend(('sundials_cvodes', 'sundials_ida', 'sundials_nvecserial'))
|
|
else:
|
|
env['sundials_libs'] = []
|
|
|
|
# Add LAPACK and BLAS to the link line
|
|
if env['blas_lapack_libs']:
|
|
linkLibs.extend(env['blas_lapack_libs'])
|
|
linkSharedLibs.extend(env['blas_lapack_libs'])
|
|
|
|
if not env['build_with_f2c']:
|
|
linkLibs.extend(env['FORTRANSYSLIBS'])
|
|
linkSharedLibs.append(env['FORTRANSYSLIBS'])
|
|
|
|
# Store the list of needed static link libraries in the environment
|
|
env['cantera_libs'] = linkLibs
|
|
env['cantera_shared_libs'] = linkSharedLibs
|
|
if not env['renamed_shared_libraries']:
|
|
env['cantera_shared_libs'] = linkLibs
|
|
|
|
# Add targets from the SConscript files in the various subdirectories
|
|
Export('env', 'build', 'libraryTargets', 'install', 'buildSample')
|
|
|
|
# ext needs to come before src so that libraryTargets is fully populated
|
|
VariantDir('build/ext', 'ext', duplicate=0)
|
|
SConscript('build/ext/SConscript')
|
|
|
|
# Fortran needs to come before src so that libraryTargets is fully populated
|
|
if env['f90_interface'] == 'y':
|
|
VariantDir('build/src/fortran/', 'src/fortran', duplicate=1)
|
|
SConscript('build/src/fortran/SConscript')
|
|
|
|
VariantDir('build/src', 'src', duplicate=0)
|
|
SConscript('build/src/SConscript')
|
|
|
|
if env['python3_package'] == 'y' or env['python_package'] == 'full':
|
|
SConscript('interfaces/cython/SConscript')
|
|
|
|
if env['python_package'] == 'minimal':
|
|
SConscript('interfaces/python_minimal/SConscript')
|
|
|
|
if env['CC'] != 'cl':
|
|
VariantDir('build/platform', 'platform/posix', duplicate=0)
|
|
SConscript('build/platform/SConscript')
|
|
|
|
if env['matlab_toolbox'] == 'y':
|
|
SConscript('build/src/matlab/SConscript')
|
|
|
|
if env['doxygen_docs'] or env['sphinx_docs']:
|
|
SConscript('doc/SConscript')
|
|
|
|
if 'samples' in COMMAND_LINE_TARGETS or addInstallActions:
|
|
VariantDir('build/samples', 'samples', duplicate=0)
|
|
sampledir_excludes = ['\\.o$', '^~$', '\\.in', 'SConscript']
|
|
SConscript('build/samples/cxx/SConscript')
|
|
|
|
# Install C++ samples
|
|
install(env.RecursiveInstall, '$inst_sampledir/cxx',
|
|
'samples/cxx', exclude=sampledir_excludes)
|
|
|
|
if env['f90_interface'] == 'y':
|
|
SConscript('build/samples/f77/SConscript')
|
|
SConscript('build/samples/f90/SConscript')
|
|
|
|
# install F90 / F77 samples
|
|
install(env.RecursiveInstall, '$inst_sampledir/f77',
|
|
'samples/f77', sampledir_excludes)
|
|
install(env.RecursiveInstall, '$inst_sampledir/f90',
|
|
'samples/f90', sampledir_excludes)
|
|
|
|
### Meta-targets ###
|
|
build_samples = Alias('samples', sampleTargets)
|
|
|
|
def postBuildMessage(target, source, env):
|
|
print "*******************************************************"
|
|
print "Compilation completed successfully.\n"
|
|
print "- To run the test suite, type 'scons test'."
|
|
if os.name == 'nt':
|
|
print "- To install, type 'scons install'."
|
|
print "- To create a Windows MSI installer, type 'scons msi'."
|
|
else:
|
|
print "- To install, type '[sudo] scons install'."
|
|
print "*******************************************************"
|
|
|
|
finish_build = env.Command('finish_build', [], postBuildMessage)
|
|
env.Depends(finish_build, buildTargets)
|
|
build_cantera = Alias('build', finish_build)
|
|
|
|
Default('build')
|
|
|
|
def postInstallMessage(target, source, env):
|
|
if env['python_package'] == 'none':
|
|
env['python_module_loc'] = 'NONE'
|
|
|
|
if env['python3_package'] == 'y':
|
|
env['python3_example_loc'] = pjoin(env['python3_module_loc'], 'cantera', 'examples')
|
|
|
|
env['python_example_loc'] = pjoin(env['python_module_loc'], 'cantera', 'examples')
|
|
|
|
env['matlab_sample_loc'] = pjoin(env['ct_sampledir'], 'matlab')
|
|
env['matlab_ctpath_loc'] = pjoin(env['ct_matlab_dir'], 'ctpath.m')
|
|
print """
|
|
Cantera has been successfully installed.
|
|
|
|
File locations:
|
|
|
|
applications %(ct_bindir)s
|
|
library files %(ct_libdir)s
|
|
C++ headers %(ct_incroot)s
|
|
samples %(ct_sampledir)s
|
|
data files %(ct_datadir)s""" % env,
|
|
|
|
if env['python_package'] == 'full':
|
|
print """
|
|
Python 2 package (cantera) %(python_module_loc)s
|
|
Python 2 samples %(python_example_loc)s""" % env,
|
|
elif warnNoPython:
|
|
print """
|
|
#################################################################
|
|
WARNING: the Cantera Python package was not installed because
|
|
the prerequisites (Cython and NumPy) could not be found.
|
|
#################################################################"""
|
|
|
|
if env['python3_package'] == 'y':
|
|
print """
|
|
Python 3 package (cantera) %(python3_module_loc)s
|
|
Python 3 samples %(python3_example_loc)s""" % env,
|
|
|
|
if env['matlab_toolbox'] == 'y':
|
|
print """
|
|
Matlab toolbox %(ct_matlab_dir)s
|
|
Matlab samples %(matlab_sample_loc)s
|
|
|
|
An m-file to set the correct matlab path for Cantera is at:
|
|
|
|
%(matlab_ctpath_loc)s
|
|
""" % env,
|
|
|
|
if os.name != 'nt':
|
|
print """
|
|
setup script %(ct_bindir)s/setup_cantera
|
|
|
|
The setup script configures the environment for Cantera. It is recommended that
|
|
you run this script by typing:
|
|
|
|
source %(ct_bindir)s/setup_cantera
|
|
|
|
before using Cantera, or else include its contents in your shell login script.
|
|
""" % env
|
|
else:
|
|
print ''
|
|
|
|
finish_install = env.Command('finish_install', [], postInstallMessage)
|
|
env.Depends(finish_install, installTargets)
|
|
install_cantera = Alias('install', finish_install)
|
|
|
|
### Uninstallation
|
|
def getParentDirs(path, top=True):
|
|
head,tail = os.path.split(path)
|
|
if head == os.path.abspath(env['prefix']):
|
|
return [path]
|
|
elif not tail:
|
|
if head.endswith(os.sep):
|
|
return []
|
|
else:
|
|
return [head]
|
|
elif top:
|
|
return getParentDirs(head, False)
|
|
else:
|
|
return getParentDirs(head, False) + [path]
|
|
|
|
# Files installed by SCons
|
|
allfiles = FindInstalledFiles()
|
|
|
|
# Files installed by the Python installer(s)
|
|
pyFiles = ['build/python2-installed-files.txt',
|
|
'build/python3-installed-files.txt']
|
|
|
|
for filename in pyFiles:
|
|
if os.path.exists(filename):
|
|
with open(filename, 'r') as f:
|
|
file_list = f.readlines()
|
|
|
|
install_base = os.path.dirname(file_list[0].strip())
|
|
if os.path.exists(install_base):
|
|
not_listed_files = [s for s in os.listdir(install_base) if not any(s in j for j in file_list)]
|
|
for f in not_listed_files:
|
|
f = pjoin(install_base, f)
|
|
if not os.path.isdir(f) and os.path.exists(f):
|
|
allfiles.append(File(f))
|
|
for f in file_list:
|
|
f = f.strip()
|
|
if not os.path.isdir(f) and os.path.exists(f):
|
|
allfiles.append(File(f))
|
|
|
|
# After removing files (which SCons keeps track of),
|
|
# remove any empty directories (which SCons doesn't track)
|
|
def removeDirectories(target, source, env):
|
|
# Get all directories where files are installed
|
|
alldirs = set()
|
|
for f in allfiles:
|
|
alldirs.update(getParentDirs(f.path))
|
|
if env['layout'] == 'compact':
|
|
alldirs.add(os.path.abspath(env['prefix']))
|
|
# Sort in order of decreasing directory length so that empty subdirectories
|
|
# will be removed before their parents are checked.
|
|
alldirs = sorted(alldirs, key=lambda x: -len(x))
|
|
|
|
# Don't remove directories that probably existed before installation,
|
|
# even if they are empty
|
|
keepDirs = ['local/share', 'local/lib', 'local/include', 'local/bin',
|
|
'man/man1', 'dist-packages', 'site-packages']
|
|
for d in alldirs:
|
|
if any(d.endswith(k) for k in keepDirs):
|
|
continue
|
|
if os.path.isdir(d) and not os.listdir(d):
|
|
os.rmdir(d)
|
|
|
|
uninstall = env.Command("uninstall", None, Delete(allfiles))
|
|
env.AddPostAction(uninstall, Action(removeDirectories))
|
|
|
|
### Windows MSI Installer ###
|
|
if 'msi' in COMMAND_LINE_TARGETS:
|
|
def build_wxs(target, source, env):
|
|
import wxsgen
|
|
wxs = wxsgen.WxsGenerator(env['stage_dir'],
|
|
short_version=env['cantera_short_version'],
|
|
full_version=env['cantera_msi_version'],
|
|
x64=env['TARGET_ARCH']=='amd64',
|
|
includeMatlab=env['matlab_toolbox']=='y')
|
|
wxs.make_wxs(str(target[0]))
|
|
|
|
wxs_target = env.Command('build/wix/cantera.wxs', [], build_wxs)
|
|
env.AlwaysBuild(wxs_target)
|
|
|
|
env.Append(WIXLIGHTFLAGS=['-ext', 'WixUIExtension'])
|
|
msi_target = env.WiX('cantera.msi', ['build/wix/cantera.wxs'])
|
|
env.Depends(wxs_target, installTargets)
|
|
env.Depends(msi_target, wxs_target)
|
|
build_msi = Alias('msi', msi_target)
|
|
|
|
### Tests ###
|
|
if any(target.startswith('test') for target in COMMAND_LINE_TARGETS):
|
|
env['testNames'] = []
|
|
env['test_results'] = env.Command('test_results', [], testResults.printReport)
|
|
|
|
# Tests written using the gtest framework, the Python unittest module,
|
|
# or the Matlab xunit package.
|
|
VariantDir('build/test', 'test', duplicate=0)
|
|
SConscript('build/test/SConscript')
|
|
|
|
# Regression tests
|
|
SConscript('test_problems/SConscript')
|
|
|
|
if 'test-help' in COMMAND_LINE_TARGETS:
|
|
print '\n*** Available tests ***\n'
|
|
for name in env['testNames']:
|
|
print 'test-%s' % name
|
|
sys.exit(0)
|
|
|
|
Alias('test', env['test_results'])
|
|
|
|
### Dump (debugging SCons)
|
|
if 'dump' in COMMAND_LINE_TARGETS:
|
|
import pprint
|
|
# Typical usage: 'scons build dump'
|
|
print 'os.environ:\n', pprint.pprint(dict(os.environ))
|
|
print 'env.Dump():\n', env.Dump()
|
|
sys.exit(0)
|