Improvements to scons build for beast.

* Common code extracted to Python directories.
* Read ~/.scons file for scons environment defaults.
* Override scons settings with shell environment variables.
* New "tags" for debug, nodebug, optimize, nooptimize builds.
* Universal platform detection.
* Default value of environment variables set through prefix dictionaries.
* Check for correct Boost value and fail otherwise.
* Extract git describe --tags into a preprocesor variable, -DTIP_BRANCH
* More colors - blue for unchanged defaults, green for changed defaults, red for error.
* Contain unit tests for non-obvious stuff.
* Check to see that boost libraries have been built.
* Right now, we accept both .dylib and .a versions but it'd be easy to enforce .a only.
This commit is contained in:
Tom Ritchford
2014-04-09 15:33:34 -04:00
committed by Vinnie Falco
parent 4a3176e3a0
commit 6b0cec1189
29 changed files with 701 additions and 150 deletions

11
python/beast/env/AddCommonFlags.py vendored Normal file
View File

@@ -0,0 +1,11 @@
from __future__ import absolute_import, division, print_function, unicode_literals
from beast.util import Boost
from beast.util import Git
def add_common_flags(env):
git_flag = '-DTIP_BRANCH="%s"' % Git.describe()
env['CPPFLAGS'] = '%s %s' % (env['CPPFLAGS'], git_flag)
env['CPPPATH'].insert(0, Boost.CPPPATH)
env['LIBPATH'].append(Boost.LIBPATH)
env['BOOST_HOME'] = Boost.CPPPATH

38
python/beast/env/AddUserEnv.py vendored Normal file
View File

@@ -0,0 +1,38 @@
from __future__ import absolute_import, division, print_function, unicode_literals
import os
import shlex
from beast.env.ReadEnvFile import read_env_file
from beast.util.String import is_string
from beast.util.Terminal import warn
_BAD_VARS_ERROR = """
the following variables appearing in %s were not understood:
%s"""
def add_user_env(env, dotfile, print=print):
df = os.path.expanduser(dotfile)
try:
with open(df, 'r') as f:
dotvars = read_env_file(f.read())
except IOError:
if os.path.exists(df):
warn("Dotfile %s exists but can't be read." % dotfile, print)
dotvars = {}
bad_names = []
for name, value in dotvars.items():
if name in env:
if is_string(env[name]):
env[name] = value
else:
env[name] = shlex.split(value)
else:
bad_names.append(name)
if bad_names:
error = _BAD_VARS_ERROR % (dotfile, '\n '.join(bad_names))
warn(error, print)
for name, default in env.items():
env[name] = os.environ.get(name, default)

41
python/beast/env/Print.py vendored Normal file
View File

@@ -0,0 +1,41 @@
from __future__ import absolute_import, division, print_function, unicode_literals
import textwrap
from beast.util import String
from beast.util import Terminal
FIELD_WIDTH = 10
LINE_WIDTH = 69
EMPTY_NAME = ' ' * FIELD_WIDTH
TEXT_WRAPPER = textwrap.TextWrapper(
break_long_words=False,
break_on_hyphens=False,
width=LINE_WIDTH,
)
DISPLAY_EMPTY_ENVS = True
def print_build_vars(name, value, same, print=print):
"""Pretty-print values as a build configuration."""
name = '%s' % name.rjust(FIELD_WIDTH)
color = Terminal.blue if same else Terminal.green
for line in TEXT_WRAPPER.wrap(String.stringify(value, ' ')):
print(' '.join([name, color(line)]))
name = EMPTY_NAME
def print_cmd_line(s, target, source, env):
print(EMPTY_NAME + Terminal.blue(String.stringify(target)))
def print_build_config(env, original, print=print):
print('\nConfiguration:')
for name, value in env.items():
if value or DISPLAY_EMPTY_ENVS:
same = (value == original[name])
if not same:
print('"%s" != "%s"' % (value, original[name]))
print_build_vars(name, value, same, print=print)
print()

34
python/beast/env/ReadEnvFile.py vendored Normal file
View File

@@ -0,0 +1,34 @@
from __future__ import absolute_import, division, print_function, unicode_literals
import json
import re
from beast.util import String
from beast.util.Terminal import warn
ENV_LINE_MATCH = re.compile(r'(?: export \s+)? \s* ([^=\s]*) \s* = (.*)',
re.VERBOSE)
def read_env_file(data, print=print):
try:
return json.loads(data)
except ValueError:
pass
bad_lines = []
results = {}
for number, raw_line in enumerate(data.splitlines()):
line = String.remove_comment(raw_line).strip()
if line:
match = ENV_LINE_MATCH.match(line)
if match:
name, value = match.groups()
results[name.strip()] = String.remove_quotes(value.strip())
else:
bad_lines.append([number, raw_line])
if bad_lines:
warn("Didn't understand the following environment file lines:", print)
for number, line in bad_lines:
print('%d. >>> %s' % (number + 1, line))
return results

51
python/beast/env/ReadEnvFile_test.py vendored Normal file
View File

@@ -0,0 +1,51 @@
from __future__ import absolute_import, division, print_function, unicode_literals
from unittest import TestCase
from beast.env.ReadEnvFile import read_env_file
from beast.util import Terminal
Terminal.CAN_CHANGE_COLOR = False
JSON = """
{
"FOO": "foo",
"BAR": "bar bar bar",
"CPPFLAGS": "-std=c++11 -frtti -fno-strict-aliasing -DWOMBAT"
}"""
ENV = """
# An env file.
FOO=foo
export BAR="bar bar bar"
CPPFLAGS=-std=c++11 -frtti -fno-strict-aliasing -DWOMBAT
# export BAZ=baz should be ignored.
"""
RESULT = {
'FOO': 'foo',
'BAR': 'bar bar bar',
'CPPFLAGS': '-std=c++11 -frtti -fno-strict-aliasing -DWOMBAT',
}
BAD_ENV = ENV + """
This line isn't right.
NO SPACES IN NAMES="valid value"
"""
class test_ReadEnvFile(TestCase):
def test_read_json(self):
self.assertEqual(read_env_file(JSON), RESULT)
def test_read_env(self):
self.assertEqual(read_env_file(ENV), RESULT)
def test_read_env_error(self):
errors = []
self.assertEqual(read_env_file(BAD_ENV, errors.append), RESULT)
self.assertEqual(errors, [
"WARNING: Didn't understand the following environment file lines:",
"11. >>> This line isn't right.",
'12. >>> NO SPACES IN NAMES="valid value"'])

17
python/beast/env/Tags.py vendored Normal file
View File

@@ -0,0 +1,17 @@
from __future__ import absolute_import, division, print_function, unicode_literals
from beast.util.Terminal import warn
_TAGS = frozenset(['debug', 'optimize'])
def _to_tag(name, value):
return '%s%s' % ('' if value else 'no', name)
def get_tags(arguments, print=print):
result = {}
bad_tags = set(arguments) - _TAGS
if bad_tags:
warn("don't understand tags " + ' '.join(bad_tags), print=print)
debug = result.get('debug', True)
optimize = result.get('optimize', not debug)
return _to_tag('debug', debug), _to_tag('optimize', optimize)

0
python/beast/env/__init__.py vendored Normal file
View File