uvg266/SConstruct
Ari Koivula 4c3bbd4a35 Rewrite the SContruct.
- Works with new /strategy/ structure.
- Change architecture selection to use arch= instead of construction target.
2014-08-25 16:43:23 +03:00

237 lines
7.4 KiB
Python

""" SConstruct file fore building Kvazaar with Scons.
This is an additional cross platform way to build the program.
The main way is to use the Makefile and that is always kept up to date.
This mostly exists so it can be used with a custom SConscript file that
builds any old version of Kvazaar, ensuring that the compilation settings are
the same and any compilation from a specific version of Kvazaar will not
affect the comparison. The SConscript included in git version only compiles
the current version.
"""
import os
import platform
vars = Variables()
default_arch = 'amd64' if platform.machine().endswith('64') else 'x86'
vars.Add(EnumVariable('arch', 'Set target arch.', default_arch,
allowed_values=('x86', 'x64', 'amd64', 'ppc'),
map={'x64': 'amd64'}))
vars.Add(PathVariable('win32pthreads',
'Path to win32-pthreads dir.',
r'./../pthreads.2'))
vars.Add(PathVariable('copyto',
'Copy exe and required DLLs to this dir.',
'',
PathVariable.PathAccept))
vars.Add(BoolVariable('dump_env',
'Dump of construction environment to stdout.',
False))
vars.Add(BoolVariable('use_yasm',
'Use yasm.',
True))
# Visual studio needs the architecture to be set in this stage. It can not be
# modified later. Other tools ignore TARGET_ARCH.
# The variable substitution is done in the environment construction so $arch
# will not work here. Get the value manually.
arch = ARGUMENTS.get('arch', default_arch)
if arch == 'x64':
arch = 'amd64'
env = Environment(
variables=vars,
tools=['msvc', 'mslink', 'nasm'],
ENV={'PATH': os.environ['PATH']}, # to find yasm
TARGET_ARCH=arch, # for Visual Studio
AS='yasm',
)
Help("""
Example: 'scons arch=x64' to compile for amd64.
'scons --jobs=8' to compile in parallel.
""" + vars.GenerateHelpText(env))
if 'MSVS' in env:
compiler = 'msvs'
elif 'MSYSTEM' in os.environ:
compiler = 'mingw'
else:
compiler = 'gcc'
env['use_yasm'] = env['use_yasm'] and env['arch'] not in ('ppc',)
# pthreads_dll location for copyto
pthreads_dll = None
# Try and deal with all the remaining compiler specific differences that I
# really wish scons would handle.
if compiler in ('msvs',):
arch_dir = {'x86': r'x86', 'amd64': r'x64'}[env['arch']]
pthreads_dll = os.path.join(env['win32pthreads'], 'dll', arch_dir, 'pthreadVC2.dll')
env.Append(
CCFLAGS=r'/MD /Ox /GL /wd"4028"',
LINKFLAGS=r'/LTCG',
LIBPATH=r'#$win32pthreads\lib\\' + arch_dir,
LIBS=r'pthreadVC2',
CPPPATH=r'#$win32pthreads\include')
else:
env.MergeFlags('-O2 -pthread -lm -lrt -march=native')
if env['arch'] == 'x86':
env.MergeFlags('-m32')
elif env['arch'] == 'amd64':
env.MergeFlags('-m64')
# platform.system() lies on msys2, so just try to detect msys/mingw.
if 'MSYSTEM' in os.environ:
# __USE_MINGW_ANSI_STDIO required on mingw for printf to function.
env.MergeFlags('-D' + '__USE_MINGW_ANSI_STDIO=1')
# VS2010 linker and mingw64 need TMP.
if compiler in ('msvs', 'mingw'):
if 'TMP' in os.environ:
env['ENV']['TMP'] = os.environ['TMP']
env.MergeFlags('-I. -Iextras -Istrategies')
# Take comma separated list from 'D=' and pass them on to
# preprocessor as defines.
preprocessor_defines = ARGUMENTS.get('D', '')
if preprocessor_defines:
for define in preprocessor_defines.split(','):
env.MergeFlags('-D' + define)
# Declare build targets.
variant_dir = 'scons_build'
class EnvinronmentContainer(object):
"""Class for initializing and holding optimization environments.
As far as I know, making a separate environment is the only way to compile
different objects with different flags in scons. So this constructs all
the required environments.
Yasm is also its own environment although it's not strictly necessary.
It does however allow KVZ_COMPILE_ASM to only those files that require
it, avoiding a complete recompile.
"""
def __init__(self, env, compiler, arch):
# If optimization is not supported for arch, use default env.
self.env = env
self.sse2 = env
self.sse41 = env
self.avx = env
self.avx2 = env
self.altivec = env
self.asm = env
if compiler == 'msvs':
self.avx = env.Clone()
self.avx.Append(CCFLAGS='/arch:AVX')
self.avx2 = env.Clone()
self.avx2.Append(CCFLAGS='/arch:AVX2')
elif compiler in ('gcc',) and arch in ('x86', 'x64'):
self.sse2 = env.Clone()
self.sse2.Append(CCFLAGS='-msse2')
self.sse41 = env.Clone().Append(CCFLAGS='-msse4.1')
self.avx = env.Clone().Append(CCFLAGS='-mavx')
self.avx2 = env.Clone().Append(CCFLAGS='-mavx2')
elif compiler in ('gcc',) and arch in ('ppc'):
self.altivec = env.Clone().Append(CCFLAGS='-maltivec')
if env['use_yasm']:
self._init_yasm()
def _init_yasm(self):
self.asm = env.Clone()
self.asm.MergeFlags('-D' + 'KVZ_COMPILE_ASM')
# YASM flags for different architectures. The object file format and name
# mangling must be the same as used by the C compiler for that OS.
# Indexed by platform.system().
yasm_flags = {
'Windows': {
'x86': '-f win32 -DPREFIX -DHAVE_ALIGNED_STACK=0 ',
'amd64': '-f win64 -DHAVE_ALIGNED_STACK=1',
},
'Darwin': {
'x86': '-f macho32 -DPREFIX',
'amd64': '-f macho64 -DPREFIX',
},
'Linux': { # Flags for Unix-like.
'x86': '-f elf32',
'amd64': '-f elf64',
},
'all': { # Flags for all systems.
'x86': ' -I./src/extras -DARCH_X86_64=0 -m x86',
'amd64': ' -I./src/extras -DARCH_X86_64=1 -m amd64',
},
}
# Set yasm flags for OS and architecture.
target_yasm_flags = yasm_flags.get(platform.system(), yasm_flags['Linux'])
self.asm.Replace(ASFLAGS=target_yasm_flags[env['arch']])
self.asm.Append(ASFLAGS=yasm_flags['all'][env['arch']])
self.asm.Replace(AS='yasm')
envs = EnvinronmentContainer(env, compiler, env['arch'])
program = SConscript('src/SConscript',
exports={'envs': envs},
variant_dir=variant_dir,
duplicate=False)
# Copy exe and dll's to the path from 'copyto=' argument.
copy_dir = env['copyto']
if copy_dir:
env.Install(copy_dir, program)
if pthreads_dll:
env.Install(copy_dir, pthreads_dll)
env.Alias('copyto', copy_dir)
Default([program, 'copyto'])
else:
Default(program)
# Dumpo environment to stdout.
if env['dump_env']:
import difflib
def get_diff(orig_env, new_env):
return "\n".join(difflib.unified_diff(orig_env, new_env.Dump().splitlines(), n=0))
env_dump = env.Dump().splitlines()
print "== env"
print "\n".join(env_dump)
print "== diff env envs.sse2"
print get_diff(env_dump, envs.sse2)
print "== diff env envs.sse41"
print get_diff(env_dump, envs.sse41)
print "== diff env envs.avx"
print get_diff(env_dump, envs.avx)
print "== diff env envs.avx2"
print get_diff(env_dump, envs.avx2)
print "== diff env envs.altivec"
print get_diff(env_dump, envs.altivec)
print "== diff env envs.asm"
print get_diff(env_dump, envs.asm)