SCons generates and installs locally customized utility scripts

This commit is contained in:
Ray Speth 2011-12-14 03:53:39 +00:00
parent c27078d73a
commit 851eaf7040
9 changed files with 320 additions and 2 deletions

View file

@ -1,8 +1,10 @@
from buildutils import *
import subst
import platform, sys, os
env = Environment()
env = Environment(tools = ['default', 'textfile'])
env.AddMethod(RecursiveInstall)
subst.TOOL_SUBST(env)
# ******************************************************
# *** Set system-dependent defaults for some options ***
@ -102,7 +104,7 @@ if env['python_package'] in ('full', 'default'):
'numpy', ('numpy', 'numarray', 'numeric')),
PathVariable('python_array_home',
'Location for array package (e.g. if installed with --home)',
None, PathVariable.PathAccept),
'', PathVariable.PathAccept),
PathVariable('cantera_python_home', 'where to install the python package',
pyprefix, PathVariable.PathAccept)
)
@ -254,6 +256,7 @@ env['ct_tutdir'] = pjoin(env['prefix'], 'tutorials')
env['ct_docdir'] = pjoin(env['prefix'], 'doc')
env['ct_dir'] = env['prefix']
env['ct_mandir'] = pjoin(env['prefix'], 'man1')
env['ct_matlab_dir'] = pjoin(env['prefix'], 'matlab', 'toolbox')
# *********************
# *** Build Cantera ***
@ -343,6 +346,10 @@ SConscript('build/tools/SConscript')
inst = env.Install('$ct_datadir', mglob(env, pjoin('data','inputs'), 'cti', 'xml'))
installTargets.extend(inst)
# Install exp3to2.sh (used by some of the tests)
inst = env.Install('$ct_bindir', pjoin('bin', 'exp3to2.sh'))
installTargets.extend(inst)
### Meta-targets ###
build_cantera = Alias('build', buildTargets)
install_cantera = Alias('install', installTargets)

View file

@ -1,6 +1,7 @@
from glob import glob
import os
import shutil
import sys
from os.path import join as pjoin
class DefineDict(object):

207
subst.py Normal file
View file

@ -0,0 +1,207 @@
# File: subst.py
# Author: Brian A. Vanderburg II
# Purpose: A generic SCons file substitution mechanism
# Copyright: This file is placed in the public domain.
# URL: http://www.scons.org/wiki/GenericSubstBuilder
##############################################################################
# Requirements
##############################################################################
import re
from SCons.Script import *
import SCons.Errors
# Helper/core functions
##############################################################################
# Do the substitution
def _subst_file(target, source, env, pattern, replace):
# Read file
f = open(source, "rU")
try:
contents = f.read()
finally:
f.close()
# Substitute, make sure result is a string
def subfn(mo):
value = replace(env, mo)
if not SCons.Util.is_String(value):
raise SCons.Errors.UserError("Substitution must be a string.")
return value
contents = re.sub(pattern, subfn, contents)
# Write file
f = open(target, "wt")
try:
f.write(contents)
finally:
f.close()
# Determine which keys are used
def _subst_keys(source, pattern):
# Read file
f = open(source, "rU")
try:
contents = f.read()
finally:
f.close()
# Determine keys
keys = []
def subfn(mo):
key = mo.group("key")
if key:
keys.append(key)
return ''
re.sub(pattern, subfn, contents)
return keys
# Get the value of a key as a string, or None if it is not in the environment
def _subst_value(env, key):
# Why does "if key in env" result in "KeyError: 0:"?
try:
env[key]
except KeyError:
return None
# env.subst already returns a string even if it is stored as a number
# such as env['HAVE_XYZ'] = 1
return env.subst("${%s}" % key)
# Builder related functions
##############################################################################
# Builder action
def _subst_action(target, source, env):
# Substitute in the files
pattern = env["SUBST_PATTERN"]
replace = env["SUBST_REPLACE"]
for (t, s) in zip(target, source):
_subst_file(str(t), str(s), env, pattern, replace)
return 0
# Builder message
def _subst_message(target, source, env):
items = ["Substituting vars from %s to %s" % (s, t)
for (t, s) in zip(target, source)]
return "\n".join(items)
# Builder dependency emitter
def _subst_emitter(target, source, env):
pattern = env["SUBST_PATTERN"]
for (t, s) in zip(target, source):
# When building, if a variant directory is used and source files
# are being duplicated, the source file will not be duplicated yet
# when this is called, so the source node must be used instead of
# the duplicated node
path = s.srcnode().abspath
# Get keys used
keys = _subst_keys(path, pattern)
d = dict()
for key in keys:
value = _subst_value(env, key)
if not value is None:
d[key] = value
# Only the current target depends on this dictionary
Depends(t, SCons.Node.Python.Value(d))
return target, source
# Replace @key@ with the value of that key, and @@ with a single @
##############################################################################
_SubstFile_pattern = "@(?P<key>\w*?)@"
def _SubstFile_replace(env, mo):
key = mo.group("key")
if not key:
return "@"
value = _subst_value(env, key)
if value is None:
raise SCons.Errors.UserError("Error: key %s does not exist" % key)
return value
def SubstFile(env, target, source):
return env.SubstGeneric(target,
source,
SUBST_PATTERN=_SubstFile_pattern,
SUBST_REPLACE=_SubstFile_replace)
# A substitutor similar to config.h header substitution
# Supported patterns are:
#
# Pattern: #define @key@
# Found: #define key value
# Missing: /* #define key */
#
# Pattern: #define @key@ default
# Found: #define key value
# Missing: #define key default
#
# Pattern: #undef @key@
# Found: #define key value
# Missing: #undef key
#
# The "@" is used to that these defines can be used in addition to
# other defines that you do not desire to be replaced.
##############################################################################
_SubstHeader_pattern = "(?m)^(?P<space>\\s*?)(?P<type>#define|#undef)\\s+?@(?P<key>\w+?)@(?P<ending>.*?)$"
def _SubstHeader_replace(env, mo):
space = mo.group("space")
type = mo.group("type")
key = mo.group("key")
ending = mo.group("ending")
value = _subst_value(env, key)
if not value is None:
# If found it is always #define key value
return "%s#define %s %s" % (space, key, value)
# Not found
if type == "#define":
defval = ending.strip()
if defval:
# There is a default value
return "%s#define %s %s" % (space, key, defval)
else:
# There is no default value
return "%s/* #define %s */" % (space, key)
# It was #undef
return "%s#undef %s" % (space, key)
def SubstHeader(env, target, source):
return env.SubstGeneric(target,
source,
SUBST_PATTERN=_SubstHeader_pattern,
SUBST_REPLACE=_SubstHeader_replace)
# Create builders
##############################################################################
def TOOL_SUBST(env):
# The generic builder
subst = SCons.Action.Action(_subst_action, _subst_message)
env['BUILDERS']['SubstGeneric'] = Builder(action=subst,
emitter=_subst_emitter)
# Additional ones
env.AddMethod(SubstFile)
env.AddMethod(SubstHeader)

View file

@ -28,3 +28,38 @@ installTargets.extend(
# Copy man pages
inst = localenv.Install('$ct_mandir', mglob(localenv, 'man', '*'))
installTargets.extend(inst)
### Generate customized scripts ###
# 'setup_cantera'
v = sys.version_info
localenv['python_module_loc'] = pjoin(localenv['prefix'], 'lib', 'python%i.%i' % v[:2], 'site-packages')
target = localenv.SubstFile('setup_cantera', 'setup_cantera.in')
buildTargets.extend(target)
inst = localenv.Install('$ct_bindir','setup_cantera')
installTargets.append(inst)
# 'mixmaster'
if env['BUILD_PYTHON'] >= 2:
target = localenv.SubstFile('mixmaster', 'mixmaster.in')
buildTargets.extend(target)
inst = localenv.Install('$ct_bindir', 'mixmaster')
localenv.AddPostAction(inst, Chmod('$TARGET', 0755))
installTargets.extend(inst)
# 'ctnew'
target = localenv.SubstFile('ctnew', 'ctnew.in')
buildTargets.extend(target)
inst = localenv.Install('$ct_bindir', 'ctnew')
localenv.AddPostAction(inst, Chmod('$TARGET', 0755))
installTargets.extend(inst)
# 'ctpath.m', 'cantera_demos.m'
if env['matlab_toolbox'] == 'y':
target = localenv.SubstFile('ctpath.m', 'ctpath.m.in')
buildTargets.extend(target)
inst = localenv.Install(pjoin('$prefix','matlab'), target)
installTargets.extend(inst)
inst = localenv.Install(pjoin('$prefix','matlab'), 'cantera_demos.m')
installTargets.extend(inst)

4
tools/cantera_demos.m Normal file
View file

@ -0,0 +1,4 @@
ctpath;
cd ../demos/matlab;
run_examples;

9
tools/ctnew.in Normal file
View file

@ -0,0 +1,9 @@
#!/bin/sh
if test "x$1" = "x-f77"; then
cp @ct_templdir@/f77/*.* .
elif test "x$1" = "x-f90"; then
cp @ct_templdir@/f90/*.* .
else
cp @ct_templdir@/cxx/*.* .
fi

4
tools/ctpath.m.in Normal file
View file

@ -0,0 +1,4 @@
path('@ct_matlab_dir@', path)
path('@ct_matlab_dir@/1D', path)
setenv('PYTHON_CMD', '@python_cmd@')
setenv('PYTHONPATH', [getenv('PYTHONPATH'), ':@python_module_loc@'])

4
tools/mixmaster.in Normal file
View file

@ -0,0 +1,4 @@
#!@python_cmd@
from MixMaster import MixMaster
MixMaster()

47
tools/setup_cantera.in Normal file
View file

@ -0,0 +1,47 @@
#!/bin/sh
if [ -z $LD_LIBRARY_PATH ]; then
LD_LIBRARY_PATH=@ct_libdir@
else
LD_LIBRARY_PATH=@ct_libdir@:$LD_LIBRARY_PATH
fi
export LD_LIBRARY_PATH
PYTHON_CMD=@python_cmd@
export PYTHON_CMD
PATH=@ct_bindir@:$PATH
export PATH
if [ "@python_cmd@" != `which python` ]; then
alias ctpython=@python_cmd@
fi
if [ "@matlab_toolbox@" = "y" ]; then
if [ -z $MATLAB_PATH ]; then
MATLABPATH=@ct_matlab_dir@:@ct_matlab_dir@/1D
else
MATLABPATH=$MATLABPATH:@ct_matlab_dir@:@ct_matlab_dir@/1D
fi
export MATLABPATH
fi
if [ -z $PYTHONPATH ]; then
PYTHONPATH=@python_module_loc@
else
PYTHONPATH=@python_module_loc@:$PYTHONPATH
fi
if [ "@python_array_home@" != "" ]; then
PYTHONPATH=@python_array_home@:$PYTHONPATH
fi
export PYTHONPATH
## Uncomment this if you want to specify the tmp dir location where
## Cantera writes temporary files. The default is:
## (1) getenv("TMP")
## (2) getenv("TEMP")
## (3) "."
# CANTERA_TMPDIR=/fill/in
# export CANTERA_TMPDIR