2014-02-19 14:51:13 +00:00
|
|
|
""" SConstruct file fore building Kvazaar with Scons.
|
|
|
|
|
2014-08-19 15:12:04 +00:00
|
|
|
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.
|
2014-02-19 14:51:13 +00:00
|
|
|
|
2014-08-19 15:12:04 +00:00
|
|
|
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.
|
2014-02-19 14:51:13 +00:00
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
import os
|
|
|
|
import platform
|
|
|
|
|
2014-08-19 15:12:04 +00:00
|
|
|
|
|
|
|
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))
|
2014-02-19 14:51:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
# Visual studio needs the architecture to be set in this stage. It can not be
|
2014-08-19 15:12:04 +00:00
|
|
|
# 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',
|
2014-02-19 14:51:13 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2014-08-19 15:12:04 +00:00
|
|
|
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
|
2014-02-19 14:51:13 +00:00
|
|
|
|
|
|
|
# Try and deal with all the remaining compiler specific differences that I
|
2014-08-19 15:12:04 +00:00
|
|
|
# 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')
|
2014-02-19 14:51:13 +00:00
|
|
|
else:
|
2014-08-19 15:12:04 +00:00
|
|
|
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')
|
|
|
|
|
2014-05-07 15:49:49 +00:00
|
|
|
|
|
|
|
# VS2010 linker and mingw64 need TMP.
|
2014-08-19 15:12:04 +00:00
|
|
|
if compiler in ('msvs', 'mingw'):
|
|
|
|
if 'TMP' in os.environ:
|
|
|
|
env['ENV']['TMP'] = os.environ['TMP']
|
2014-02-19 14:51:13 +00:00
|
|
|
|
2014-08-19 15:12:04 +00:00
|
|
|
env.MergeFlags('-I. -Iextras -Istrategies')
|
|
|
|
|
|
|
|
# Take comma separated list from 'D=' and pass them on to
|
|
|
|
# preprocessor as defines.
|
2014-04-25 08:44:13 +00:00
|
|
|
preprocessor_defines = ARGUMENTS.get('D', '')
|
|
|
|
if preprocessor_defines:
|
2014-08-19 15:12:04 +00:00
|
|
|
for define in preprocessor_defines.split(','):
|
|
|
|
env.MergeFlags('-D' + define)
|
2014-02-19 14:51:13 +00:00
|
|
|
|
|
|
|
# Declare build targets.
|
2014-08-19 15:12:04 +00:00
|
|
|
variant_dir = 'scons_build'
|
|
|
|
|
2014-02-19 14:51:13 +00:00
|
|
|
|
2014-08-19 15:12:04 +00:00
|
|
|
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,
|
2014-02-19 14:51:13 +00:00
|
|
|
duplicate=False)
|
|
|
|
|
|
|
|
|
2014-08-19 15:12:04 +00:00
|
|
|
# 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'])
|
2014-02-19 14:51:13 +00:00
|
|
|
else:
|
2014-08-19 15:12:04 +00:00
|
|
|
Default(program)
|
|
|
|
|
2014-02-19 14:51:13 +00:00
|
|
|
|
2014-08-19 15:12:04 +00:00
|
|
|
# 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)
|
|
|
|
|