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

View File

@@ -1,160 +1,48 @@
# Beast scons file
#
#-------------------------------------------------------------------------------
from __future__ import absolute_import, division, print_function, unicode_literals
import ntpath
import copy
import os
import sys
import textwrap
#import re
#import json
#import urlparse
#import posixpath
#import string
#import subprocess
#import platform
#import itertools
#-------------------------------------------------------------------------------
def add_beast_to_path():
python_home = os.path.join(os.getcwd(), 'python')
if python_home not in sys.path:
sys.path.append(python_home)
# Format a name value pair
def print_nv_pair(n, v):
name = ("%s" % n.rjust(10))
sys.stdout.write("%s \033[94m%s\033[0m\n" % (name, v))
add_beast_to_path()
# Pretty-print values as a build configuration
def print_build_vars(env,var):
val = env.get(var, '')
from beast.env.AddCommonFlags import add_common_flags
from beast.env.AddUserEnv import add_user_env
from beast.env import Print
from beast.platform import GetEnvironment
from beast.util import Boost
from beast.util import File
from beast.util import Tests
if val and val != '':
name = ("%s" % var.rjust(10))
VARIANT_DIRECTORIES = {
'beast': ('bin', 'beast'),
'modules': ('bin', 'modules'),
}
wrapper = textwrap.TextWrapper()
wrapper.break_long_words = False
wrapper.break_on_hyphens = False
wrapper.width = 69
if type(val) is str:
lines = wrapper.wrap(val)
else:
lines = wrapper.wrap(" ".join(str(x) for x in val))
for line in lines:
print_nv_pair (name, line)
name = " "
def print_build_config(env):
config_vars = ['CC', 'CXX', 'CFLAGS', 'CCFLAGS', 'CPPFLAGS',
'CXXFLAGS', 'LIBPATH', 'LINKFLAGS', 'LIBS', 'BOOST_HOME']
sys.stdout.write("\nConfiguration:\n")
for var in config_vars:
print_build_vars(env,var)
print
def print_cmd_line(s, target, src, env):
target = (''.join([str(x) for x in target]))
source = (''.join([str(x) for x in src]))
name = target
print ' \033[94m' + name + '\033[0m'
#-------------------------------------------------------------------------------
# Returns the list of libraries needed by the test source file. This is
# accomplished by scanning the source file for a special comment line
# with this format, which must match exactly:
#
# // LIBS: <name>...
#
# path = path to source file
#
def get_libs(path):
prefix = '// LIBS:'
with open(path, 'rb') as f:
for line in f:
line = line.strip()
if line.startswith(prefix):
items = line.split(prefix, 1)[1].strip()
return [x.strip() for x in items.split(' ')]
# Returns the list of source modules needed by the test source file. This
#
# // MODULES: <module>...
#
# path = path to source file
#
def get_mods(path):
prefix = '// MODULES:'
with open(path, 'rb') as f:
for line in f:
line = line.strip()
if line.startswith(prefix):
items = line.split(prefix, 1)[1].strip()
items = [os.path.normpath(os.path.join(
os.path.dirname(path), x.strip())) for
x in items.split(' ')]
return items
# Build a stand alone executable that runs
# all the test suites in one source file
#
def build_test(env,path):
libs = get_libs(path)
mods = get_mods(path)
bin = os.path.basename(os.path.splitext(path)[0])
bin = os.path.join ("bin", bin)
srcs = ['beast/unit_test/tests/main.cpp']
srcs.append (path)
if mods:
srcs.extend (mods)
# All paths get normalized here, so we can use posix
# forward slashes for everything including on Windows
srcs = [os.path.normpath(os.path.join ('bin', x)) for x in srcs]
objs = [os.path.splitext(x)[0]+'.o' for x in srcs]
env_ = env
if libs:
env_.Append(LIBS = libs)
env_.Program (bin, srcs)
#-------------------------------------------------------------------------------
BOOST_LIBRARIES = 'boost_system',
MAIN_PROGRAM_FILE = 'beast/unit_test/tests/main.cpp'
DOTFILE = '~/.scons'
def main():
env = Environment()
File.validate_libraries(Boost.LIBPATH, BOOST_LIBRARIES)
defaults = GetEnvironment.get_environment(ARGUMENTS)
working = copy.deepcopy(defaults)
add_common_flags(defaults)
env['PRINT_CMD_LINE_FUNC'] = print_cmd_line
add_user_env(working, DOTFILE)
add_common_flags(working)
Print.print_build_config(working, defaults)
env.VariantDir (os.path.join ('bin', 'beast'), 'beast', duplicate=0)
env.VariantDir (os.path.join ('bin', 'modules'), 'modules', duplicate=0)
env = Environment(**working)
# Copy important os environment variables into env
if os.environ.get ('CC', None):
env.Replace (CC = os.environ['CC'])
if os.environ.get ('CXX', None):
env.Replace (CXX = os.environ['CXX'])
if os.environ.get ('PATH', None):
env.Replace (PATH = os.environ['PATH'])
# Set up boost variables
home = os.environ.get("BOOST_HOME", None)
if home is not None:
env.Prepend (CPPPATH = home)
env.Append (LIBPATH = os.path.join (home, 'stage', 'lib'))
# Set up flags
env.Append(CXXFLAGS = [
'-std=c++11',
'-frtti',
'-O3',
'-fno-strict-aliasing',
'-g'
])
for root, dirs, files in os.walk('.'):
for path in files:
path = os.path.join(root,path)
if (path.endswith(".test.cpp")):
build_test(env,path)
print_build_config (env)
for name, path in VARIANT_DIRECTORIES.items():
env.VariantDir(os.path.join(*path), name, duplicate=0)
env.Replace(PRINT_CMD_LINE_FUNC=Print.print_cmd_line)
Tests.run_tests(env, MAIN_PROGRAM_FILE, '.', '.test.cpp')
main()