Move environment set up to site_scons
This commit is contained in:
parent
b9a582caf4
commit
2f1c86a793
5 changed files with 148 additions and 163 deletions
176
SConstruct
176
SConstruct
|
@ -6,122 +6,10 @@
|
||||||
#
|
#
|
||||||
# Eryn Wells <eryn@erynwells.me>
|
# Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# DEFAULT CONFIGURATION VALUES
|
|
||||||
#
|
|
||||||
|
|
||||||
# Settings for the default toolchain binaries. Setting these overrides the
|
|
||||||
# defaults, provided your the given binary exists.
|
|
||||||
CC = None
|
|
||||||
CXX = None
|
|
||||||
AS = None
|
|
||||||
LINK = 'clang++'
|
|
||||||
|
|
||||||
CCFLAGS = ['-Wall', '-Wextra', '-pedantic']
|
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# BUILD STUFF BELOW HERE
|
|
||||||
#
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import os.path
|
|
||||||
import sys
|
|
||||||
import SCons.Errors
|
|
||||||
|
|
||||||
|
import erw
|
||||||
|
|
||||||
def which(program):
|
|
||||||
def is_executable(path):
|
|
||||||
return os.path.exists(path) and os.access(path, os.X_OK)
|
|
||||||
|
|
||||||
path, name = os.path.split(program)
|
|
||||||
if path:
|
|
||||||
if is_executable(program):
|
|
||||||
return program
|
|
||||||
else:
|
|
||||||
pathext = [''] + os.environ.get('PATHEXT', '').split(os.pathsep)
|
|
||||||
for path in os.environ.get('PATH', '').split(os.pathsep):
|
|
||||||
exe = os.path.join(path, program)
|
|
||||||
for ext in pathext:
|
|
||||||
candidate = exe + ext
|
|
||||||
if is_executable(candidate):
|
|
||||||
return candidate
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_bool_argument(arg):
|
|
||||||
try:
|
|
||||||
return bool(int(arg))
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
if arg in ('False', 'FALSE', 'false', ''):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def set_toolchain_binary(env, var, user_binary, binaries=()):
|
|
||||||
if user_binary and which(user_binary):
|
|
||||||
env[var] = user_binary
|
|
||||||
return
|
|
||||||
for c in binaries:
|
|
||||||
if which(c):
|
|
||||||
env[var] = c
|
|
||||||
break
|
|
||||||
|
|
||||||
common_env = Environment()
|
|
||||||
set_toolchain_binary(common_env, 'CC', CC, ('clang', 'gcc'))
|
|
||||||
set_toolchain_binary(common_env, 'CXX', CXX, ('clang++', 'g++'))
|
|
||||||
set_toolchain_binary(common_env, 'AS', AS)
|
|
||||||
set_toolchain_binary(common_env, 'LINK', LINK)
|
|
||||||
|
|
||||||
|
|
||||||
def verbose_build_cmds():
|
|
||||||
def generate_comstr(action):
|
|
||||||
return '{:>25}: $TARGET'.format(action)
|
|
||||||
common_env['ARCOMSTR'] = generate_comstr('Archiving')
|
|
||||||
common_env['ASCOMSTR'] = generate_comstr('Assembling')
|
|
||||||
common_env['ASPPCOMSTR'] = generate_comstr('Assembling')
|
|
||||||
common_env['CCCOMSTR'] = generate_comstr('Building (C)')
|
|
||||||
common_env['CXXCOMSTR'] = generate_comstr('Building (C++)')
|
|
||||||
common_env['LINKCOMSTR'] = generate_comstr('Linking')
|
|
||||||
common_env['RANLIBCOMSTR'] = generate_comstr('Indexing')
|
|
||||||
common_env['SHCCCOMSTR'] = generate_comstr('Building (C, Shared)')
|
|
||||||
common_env['SHCXXCOMSTR'] = generate_comstr('Building (C++, Shared)')
|
|
||||||
common_env['SHLINKCOMSTR'] = generate_comstr('Linking (Shared)')
|
|
||||||
|
|
||||||
|
|
||||||
def succinct_build_cmds():
|
|
||||||
def generate_comstr(action):
|
|
||||||
return ' [{:^6}] $TARGET'.format(action)
|
|
||||||
common_env['ARCOMSTR'] = generate_comstr('AR')
|
|
||||||
common_env['ASCOMSTR'] = generate_comstr('AS')
|
|
||||||
common_env['ASPPCOMSTR'] = generate_comstr('AS')
|
|
||||||
common_env['CCCOMSTR'] = generate_comstr('CC')
|
|
||||||
common_env['CXXCOMSTR'] = generate_comstr('CXX')
|
|
||||||
common_env['LINKCOMSTR'] = generate_comstr('LINK')
|
|
||||||
common_env['RANLIBCOMSTR'] = generate_comstr('RANLIB')
|
|
||||||
common_env['SHCCCOMSTR'] = generate_comstr('SHCC')
|
|
||||||
common_env['SHCXXCOMSTR'] = generate_comstr('SHCXX')
|
|
||||||
common_env['SHLINKCOMSTR'] = generate_comstr('SHLINK')
|
|
||||||
|
|
||||||
|
|
||||||
BUILD_CMDS = get_bool_argument(ARGUMENTS.get('BUILD_CMDS', False))
|
|
||||||
if not BUILD_CMDS:
|
|
||||||
verbose_build_cmds()
|
|
||||||
|
|
||||||
# Separate environment for building libraries because they often don't use the
|
|
||||||
# same CCFLAGS I do.
|
|
||||||
lib_env = common_env.Clone()
|
|
||||||
|
|
||||||
common_env.Append(CCFLAGS=CCFLAGS)
|
|
||||||
common_env.Append(CFLAGS=['-std=c99'])
|
|
||||||
common_env.Append(CXXFLAGS=['-std=c++11'])
|
|
||||||
|
|
||||||
# Add color error messages for clang
|
|
||||||
if sys.stdout.isatty():
|
|
||||||
if 'clang' in common_env['CC'] or 'clang' in common_env['CXX']:
|
|
||||||
common_env.Append(CCFLAGS=['-fcolor-diagnostics'])
|
|
||||||
|
|
||||||
BUILD_DIR = Dir('#build')
|
BUILD_DIR = Dir('#build')
|
||||||
LIB_DIR = Dir('#lib')
|
LIB_DIR = Dir('#lib')
|
||||||
|
@ -129,82 +17,44 @@ SRC_DIR = Dir('#src')
|
||||||
TEST_DIR = Dir('#test')
|
TEST_DIR = Dir('#test')
|
||||||
|
|
||||||
|
|
||||||
def create_env(name, appends=None):
|
def do_sconscript(env, src_dir, out_dir):
|
||||||
output_dir = BUILD_DIR.Dir(name)
|
|
||||||
env = common_env.Clone()
|
|
||||||
# Standard env extensions.
|
|
||||||
env.Append(CPPPATH=[SRC_DIR])
|
|
||||||
# Custom env stuff.
|
|
||||||
env['__name'] = name
|
|
||||||
if appends:
|
|
||||||
for k, v in appends.iteritems():
|
|
||||||
if k.startswith('='):
|
|
||||||
env[k[1:]] = v
|
|
||||||
else:
|
|
||||||
env.Append(**{k: v})
|
|
||||||
return env
|
|
||||||
|
|
||||||
|
|
||||||
def do_sconscript(env, build_env, src_dir, out_dir):
|
|
||||||
sconscript = src_dir.File('SConscript')
|
sconscript = src_dir.File('SConscript')
|
||||||
print 'Reading {}'.format(sconscript)
|
print 'Reading {}'.format(sconscript)
|
||||||
# Swapping env and build_env here is a bit wacky. Doing so means that env is
|
# Swapping env and build_env here is a bit wacky. Doing so means that env is
|
||||||
# always the Environment that the SConscript should be building with, while
|
# always the Environment that the SConscript should be building with, while
|
||||||
# build_env is the Environment we're using to put everything together.
|
# build_env is the Environment we're using to put everything together.
|
||||||
env.SConscript(sconscript,
|
env.SConscript(sconscript,
|
||||||
{'env': build_env, 'build_env': env},
|
{'env': env.Clone(), 'build_env': env},
|
||||||
variant_dir=out_dir)
|
variant_dir=out_dir)
|
||||||
|
|
||||||
|
BUILD_CMDS = get_bool_argument(ARGUMENTS.get('BUILD_CMDS', False))
|
||||||
debug_env = create_env('debug', {
|
MODE = ARGUMENTS.get('MODE', None)
|
||||||
'CPPDEFINES': ['NDEBUG'],
|
|
||||||
'CCFLAGS': ['-O0', '-g'],
|
|
||||||
})
|
|
||||||
|
|
||||||
beta_env = create_env('beta', {
|
|
||||||
'CPPDEFINES': ['NDEBUG'],
|
|
||||||
'CCFLAGS': ['-O3', '-g'],
|
|
||||||
})
|
|
||||||
|
|
||||||
release_env = create_env('release', {
|
|
||||||
'CPPDEFINES': ['NRELEASE'],
|
|
||||||
'CCFLAGS': ['-O3']
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
modes = {
|
modes = {
|
||||||
'debug': debug_env,
|
'debug': erw.DebugEnvironment(succinct=not BUILD_CMDS),
|
||||||
'beta': beta_env,
|
'beta': erw.BetaEnvironment(succinct=not BUILD_CMDS),
|
||||||
'release': release_env,
|
'release': erw.ReleaseEnvironment(succinct=not BUILD_CMDS),
|
||||||
}
|
}
|
||||||
|
|
||||||
mode = ARGUMENTS.get('MODE', None)
|
for mode in (MODE.split(',') if MODE else ['debug']):
|
||||||
build_modes = []
|
|
||||||
if mode:
|
|
||||||
# If MODE=foo is specified, build only that mode.
|
|
||||||
build_modes.append(mode)
|
|
||||||
else:
|
|
||||||
build_modes = ['debug']
|
|
||||||
|
|
||||||
for mode in build_modes:
|
|
||||||
try:
|
try:
|
||||||
env = modes[mode]
|
env = modes[mode]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
print 'Skipping invalid mode: {}'.format(mode)
|
print 'Skipping invalid mode: {}'.format(mode)
|
||||||
break
|
break
|
||||||
|
|
||||||
out_dir = BUILD_DIR.Dir(env['__name'])
|
out_dir = BUILD_DIR.Dir(env['_name'])
|
||||||
|
|
||||||
# Process all lib dirs.
|
# Process all lib dirs.
|
||||||
for lib in os.listdir(LIB_DIR.abspath):
|
for lib in os.listdir(LIB_DIR.abspath):
|
||||||
lib_out_dir = out_dir.Dir('lib').Dir(lib)
|
lib_out_dir = out_dir.Dir('lib').Dir(lib)
|
||||||
do_sconscript(env, lib_env, LIB_DIR.Dir(lib), lib_out_dir)
|
do_sconscript(env, LIB_DIR.Dir(lib), lib_out_dir)
|
||||||
env.Append(LIBPATH=[lib_out_dir])
|
env.Append(LIBPATH=[lib_out_dir])
|
||||||
|
|
||||||
# Get source files.
|
# Get source files.
|
||||||
src_out_dir = out_dir.Dir('src')
|
src_out_dir = out_dir.Dir('src')
|
||||||
do_sconscript(env, env, SRC_DIR, src_out_dir)
|
do_sconscript(env, SRC_DIR, src_out_dir)
|
||||||
env.Append(LIBPATH=[src_out_dir])
|
env.Append(LIBPATH=[src_out_dir])
|
||||||
|
|
||||||
# Get test binaries.
|
# Get test binaries.
|
||||||
do_sconscript(env, env, TEST_DIR, out_dir.Dir('test'))
|
do_sconscript(env, TEST_DIR, out_dir.Dir('test'))
|
||||||
|
|
1
site_scons/.gitignore
vendored
Normal file
1
site_scons/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.pyc
|
84
site_scons/erw.py
Normal file
84
site_scons/erw.py
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
# erw.py
|
||||||
|
# Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import SCons.Environment
|
||||||
|
|
||||||
|
import paths
|
||||||
|
|
||||||
|
#
|
||||||
|
# Environments
|
||||||
|
#
|
||||||
|
|
||||||
|
class Environment(SCons.Environment.Environment):
|
||||||
|
'''
|
||||||
|
Default SCons environment for building things.
|
||||||
|
'''
|
||||||
|
|
||||||
|
def __init__(self, name, modern=True, paranoid=True, colorful=True, succinct=True, **kwargs):
|
||||||
|
# Use clang if its available.
|
||||||
|
kwargs.setdefault('CC', self._toolchain_binary(('clang', 'gcc')))
|
||||||
|
kwargs.setdefault('CXX', self._toolchain_binary(('clang++', 'g++')))
|
||||||
|
kwargs.setdefault('LINK', self._toolchain_binary(('clang++')))
|
||||||
|
|
||||||
|
super(Environment, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
self['_name'] = name
|
||||||
|
|
||||||
|
# Modern C/C++
|
||||||
|
if modern:
|
||||||
|
self.Append(CFLAGS=['-std=c99'])
|
||||||
|
self.Append(CXXFLAGS=['-std=c++11'])
|
||||||
|
|
||||||
|
# Paranoid C/C++
|
||||||
|
if paranoid:
|
||||||
|
self.Append(CCFLAGS=['-Wall', '-Wextra', '-pedantic'])
|
||||||
|
|
||||||
|
# Colorful C/C++
|
||||||
|
if colorful and sys.stdout.isatty():
|
||||||
|
if 'clang' in self['CC'] or 'clang' in self['CXX']:
|
||||||
|
self.Append(CCFLAGS=['-fcolor-diagnostics'])
|
||||||
|
|
||||||
|
self['ARCOMSTR'] = self._comstr('Archiving', succinct)
|
||||||
|
self['ASCOMSTR'] = self._comstr('Assembling', succinct)
|
||||||
|
self['ASPPCOMSTR'] = self._comstr('Assembling', succinct)
|
||||||
|
self['CCCOMSTR'] = self._comstr('Building (C)', succinct)
|
||||||
|
self['CXXCOMSTR'] = self._comstr('Building (C++)', succinct)
|
||||||
|
self['LINKCOMSTR'] = self._comstr('Linking', succinct)
|
||||||
|
self['RANLIBCOMSTR'] = self._comstr('Indexing', succinct)
|
||||||
|
self['SHCCCOMSTR'] = self._comstr('Building (C, Shared)', succinct)
|
||||||
|
self['SHCXXCOMSTR'] = self._comstr('Building (C++, Shared)', succinct)
|
||||||
|
self['SHLINKCOMSTR'] = self._comstr('Linking (Shared)', succinct)
|
||||||
|
|
||||||
|
def _toolchain_binary(self, binaries):
|
||||||
|
for b in binaries:
|
||||||
|
if b and paths.which(b):
|
||||||
|
return b
|
||||||
|
|
||||||
|
def _comstr(self, action, succinct=True):
|
||||||
|
if succinct:
|
||||||
|
return '{:>25}: $TARGET'.format(action)
|
||||||
|
else:
|
||||||
|
return ' [{:^6}] $TARGET'.format(action)
|
||||||
|
|
||||||
|
|
||||||
|
class DebugEnvironment(Environment):
|
||||||
|
def __init__(self, name='debug', **kwargs):
|
||||||
|
super(DebugEnvironment, self).__init__(name, **kwargs)
|
||||||
|
self.Append(CPPDEFINES=['NDEBUG'])
|
||||||
|
self.Append(CCFLAGS=['-O0', '-g'])
|
||||||
|
|
||||||
|
|
||||||
|
class BetaEnvironment(Environment):
|
||||||
|
def __init__(self, name='beta', **kwargs):
|
||||||
|
super(BetaEnvironment, self).__init__(name, **kwargs)
|
||||||
|
self.Append(CPPDEFINES=['NDEBUG'])
|
||||||
|
self.Append(CCFLAGS=['-O3', '-g'])
|
||||||
|
|
||||||
|
|
||||||
|
class ReleaseEnvironment(Environment):
|
||||||
|
def __init__(self, name='release', **kwargs):
|
||||||
|
super(ReleaseEnvironment, self).__init__(name, **kwargs)
|
||||||
|
self.Append(CPPDEFINES=['NRELEASE'])
|
||||||
|
self.Append(CCFLAGS=['-O3'])
|
30
site_scons/paths.py
Normal file
30
site_scons/paths.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# paths.py
|
||||||
|
# Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
|
||||||
|
def is_executable(path):
|
||||||
|
return os.path.exists(path) and os.access(path, os.X_OK)
|
||||||
|
|
||||||
|
|
||||||
|
def which(program):
|
||||||
|
'''
|
||||||
|
Look for `program` in system path and return the full path to that binary if
|
||||||
|
it is found. Otherwise, return `None`.
|
||||||
|
'''
|
||||||
|
path, name = os.path.split(program)
|
||||||
|
if path:
|
||||||
|
if is_executable(program):
|
||||||
|
return program
|
||||||
|
else:
|
||||||
|
pathext = [''] + os.environ.get('PATHEXT', '').split(os.pathsep)
|
||||||
|
for path in os.environ.get('PATH', '').split(os.pathsep):
|
||||||
|
exe = os.path.join(path, program)
|
||||||
|
for ext in pathext:
|
||||||
|
candidate = exe + ext
|
||||||
|
if is_executable(candidate):
|
||||||
|
return candidate
|
||||||
|
return None
|
||||||
|
|
20
site_scons/site_init.py
Normal file
20
site_scons/site_init.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# site_init.py
|
||||||
|
# Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
|
import erw
|
||||||
|
|
||||||
|
#
|
||||||
|
# Argument utils
|
||||||
|
#
|
||||||
|
|
||||||
|
def get_bool_argument(arg):
|
||||||
|
'''
|
||||||
|
Convert the given argument value to a bool. True values are any integer that
|
||||||
|
is considered true by Python, and any string value that isn't a
|
||||||
|
capitalization variant of the word "false".
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
return bool(int(arg))
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
return str(arg).lower() != 'false'
|
Loading…
Add table
Add a link
Reference in a new issue