__STDC_FORMAT_MACROS is needed to enable PRIi64. __STDC_FORMAT_MACROS must be set before including any headers, so when PCH is used, it must be set on the command line.
1251 lines
42 KiB
Python
1251 lines
42 KiB
Python
#SConstruct
|
|
|
|
# needed imports
|
|
import sys
|
|
import os
|
|
import SCons.Util
|
|
|
|
def message(program,msg):
|
|
print "%s: %s" % (program.program_message_prefix, msg)
|
|
|
|
# endianess-checker
|
|
def checkEndian():
|
|
if ARGUMENTS.has_key('endian'):
|
|
r = ARGUMENTS['endian']
|
|
if r == "little" or r == "big":
|
|
return r
|
|
raise SCons.Errors.UserError("Unknown endian value: %s" % r)
|
|
import struct
|
|
array = struct.pack('cccc', '\x01', '\x02', '\x03', '\x04')
|
|
i = struct.unpack('i', array)
|
|
if i == struct.unpack('<i', array):
|
|
return "little"
|
|
elif i == struct.unpack('>i', array):
|
|
return "big"
|
|
return "unknown"
|
|
|
|
class ConfigureTests:
|
|
class Collector:
|
|
def __init__(self):
|
|
self.tests = []
|
|
def __call__(self,f):
|
|
self.tests.append(f.__name__)
|
|
return f
|
|
_implicit_test = Collector()
|
|
_custom_test = Collector()
|
|
implicit_tests = _implicit_test.tests
|
|
custom_tests = _custom_test.tests
|
|
comment_not_supported = '/* not supported */'
|
|
__flags_Werror = {k:['-Werror'] for k in ['CFLAGS', 'CXXFLAGS']}
|
|
__empty_main_program = 'int a();int a(){return 0;}'
|
|
def __init__(self,msgprefix,user_settings):
|
|
self.msgprefix = msgprefix
|
|
self.user_settings = user_settings
|
|
self.successful_flags = {}
|
|
self.__repeated_tests = {}
|
|
self.__automatic_compiler_tests = {
|
|
'.c': self.check_cc_works,
|
|
}
|
|
@classmethod
|
|
def describe(cls,name):
|
|
f = getattr(cls, name)
|
|
if f.__doc__:
|
|
lines = f.__doc__.rstrip().split('\n')
|
|
if lines[-1].startswith("help:"):
|
|
return lines[-1][5:]
|
|
return None
|
|
def _may_repeat(f):
|
|
def wrap(self,*args,**kwargs):
|
|
try:
|
|
return self.__repeated_tests[f.__name__]
|
|
except KeyError as e:
|
|
pass
|
|
r = f(self,*args,**kwargs)
|
|
self.__repeated_tests[f.__name__] = r
|
|
return r
|
|
wrap.__name__ = 'repeat-wrap:' + f.__name__
|
|
wrap.__doc__ = f.__doc__
|
|
return wrap
|
|
def _check_forced(self,context,name):
|
|
return getattr(self.user_settings, 'sconf_%s' % name)
|
|
def _check_macro(self,context,macro_name,macro_value,test,**kwargs):
|
|
r = self.Compile(context, text="""
|
|
#define {macro_name} {macro_value}
|
|
{test}
|
|
""".format(macro_name=macro_name, macro_value=macro_value, test=test), **kwargs)
|
|
if r:
|
|
context.sconf.Define(macro_name, macro_value)
|
|
else:
|
|
context.sconf.Define(macro_name, self.comment_not_supported)
|
|
def __compiler_test_already_done(self,context):
|
|
pass
|
|
def Compile(self,context,text,msg,ext='.c',successflags={},skipped=None,successmsg=None,failuremsg=None):
|
|
self.__automatic_compiler_tests.pop(ext, self.__compiler_test_already_done)(context)
|
|
context.Message('%s: checking %s...' % (self.msgprefix, msg))
|
|
if skipped is not None:
|
|
context.Result('(skipped){skipped}'.format(skipped=skipped))
|
|
return
|
|
frame = None
|
|
try:
|
|
1//0
|
|
except ZeroDivisionError:
|
|
frame = sys.exc_info()[2].tb_frame.f_back
|
|
while frame is not None:
|
|
co_name = frame.f_code.co_name
|
|
if co_name[0:6] == 'check_':
|
|
forced = self._check_forced(context, co_name[6:])
|
|
if forced is not None:
|
|
context.Result('(forced){forced}'.format(forced='yes' if forced else 'no'))
|
|
return forced
|
|
break
|
|
frame = frame.f_back
|
|
env_flags = {k: context.env[k][:] for k in successflags.keys()}
|
|
context.env.Append(**successflags)
|
|
caller_modified_env_flags = {k: context.env[k][:] for k in self.__flags_Werror.keys()}
|
|
# Always pass -Werror
|
|
context.env.Append(**self.__flags_Werror)
|
|
# Force verbose output to sconf.log
|
|
cc_env_strings = {}
|
|
for k in ['CCCOMSTR', 'CXXCOMSTR']:
|
|
try:
|
|
cc_env_strings[k] = context.env[k]
|
|
del context.env[k]
|
|
except KeyError:
|
|
pass
|
|
r = context.TryCompile(text + '\n', ext)
|
|
# Restore potential quiet build options
|
|
context.env.Replace(**cc_env_strings)
|
|
context.Result((successmsg if r else failuremsg) or r)
|
|
# On success, revert to base flags + successflags
|
|
# On failure, revert to base flags
|
|
if r:
|
|
context.env.Replace(**caller_modified_env_flags)
|
|
for (k,v) in successflags.items():
|
|
self.successful_flags.setdefault(k, []).extend(v)
|
|
else:
|
|
context.env.Replace(**env_flags)
|
|
return r
|
|
@_may_repeat
|
|
@_implicit_test
|
|
def check_cc_works(self,context):
|
|
"""
|
|
help:assume C compiler works
|
|
"""
|
|
if not self.Compile(context, text=self.__empty_main_program, msg='whether C compiler works'):
|
|
raise SCons.Errors.StopError("C compiler does not work.")
|
|
@_custom_test
|
|
def check_attribute_format_arg(self,context):
|
|
"""
|
|
help:assume compiler supports __attribute__((format_arg))
|
|
"""
|
|
macro_name = '__attribute_format_arg(A)'
|
|
macro_value = '__attribute__((format_arg(A)))'
|
|
self._check_macro(context,macro_name=macro_name,macro_value=macro_value,test="""
|
|
char*a(char*)__attribute_format_arg(1);
|
|
""", msg='for function __attribute__((format_arg))')
|
|
@_custom_test
|
|
def check_attribute_format_printf(self,context):
|
|
"""
|
|
help:assume compiler supports __attribute__((format(printf)))
|
|
"""
|
|
macro_name = '__attribute_format_printf(A,B)'
|
|
macro_value = '__attribute__((format(printf,A,B)))'
|
|
self._check_macro(context,macro_name=macro_name,macro_value=macro_value,test="""
|
|
int a(char*,...)__attribute_format_printf(1,2);
|
|
int b(char*)__attribute_format_printf(1,0);
|
|
""", msg='for function __attribute__((format(printf)))')
|
|
@_custom_test
|
|
def check_attribute_used(self,context):
|
|
"""
|
|
help:assume compiler supports __attribute__((used))
|
|
"""
|
|
macro_name = '__attribute_used'
|
|
macro_value = '__attribute__((used))'
|
|
self._check_macro(context,macro_name=macro_name,macro_value=macro_value,test="""
|
|
static void a()__attribute_used;
|
|
static void a(){}
|
|
""", msg='for function __attribute__((used))')
|
|
|
|
class LazyObjectConstructor:
|
|
def __lazy_objects(self,name,source):
|
|
try:
|
|
return self.__lazy_object_cache[name]
|
|
except KeyError as e:
|
|
def __strip_extension(self,name):
|
|
return os.path.splitext(name)[0]
|
|
value = []
|
|
extra = {}
|
|
if self.user_settings.pch:
|
|
extra['CXXFLAGS'] = self.env['CXXFLAGS'] + ['-include', str(self.env._dxx_pch_node[0])[:-4]]
|
|
for s in source:
|
|
if isinstance(s, str):
|
|
s = {'source': [s]}
|
|
transform_target = s.get('transform_target', __strip_extension)
|
|
for srcname in s['source']:
|
|
t = transform_target(self, srcname)
|
|
o = self.env.StaticObject(target='%s%s%s' % (self.user_settings.builddir, t, self.env["OBJSUFFIX"]), source=srcname, **extra)
|
|
if self.user_settings.pch:
|
|
self.env.Depends(o, self.env._dxx_pch_node)
|
|
value.append(o)
|
|
self.__lazy_object_cache[name] = value
|
|
return value
|
|
|
|
@staticmethod
|
|
def create_lazy_object_getter(sources):
|
|
name = repr(sources)
|
|
return lambda s: s.__lazy_objects(name, sources)
|
|
|
|
@classmethod
|
|
def create_lazy_object_property(cls,sources):
|
|
return property(cls.create_lazy_object_getter(sources))
|
|
|
|
def __init__(self):
|
|
self.__lazy_object_cache = {}
|
|
|
|
class FilterHelpText:
|
|
def __init__(self):
|
|
self.visible_arguments = []
|
|
def FormatVariableHelpText(self, env, opt, help, default, actual, aliases):
|
|
if not opt in self.visible_arguments:
|
|
return ''
|
|
l = []
|
|
if default is not None:
|
|
if isinstance(default, str) and not default.isalnum():
|
|
default = '"%s"' % default
|
|
l.append("default: {default}".format(default=default))
|
|
actual = getattr(self, opt, None)
|
|
if actual is not None:
|
|
if isinstance(actual, str) and not actual.isalnum():
|
|
actual = '"%s"' % actual
|
|
l.append("current: {current}".format(current=actual))
|
|
return " {opt:13} {help}".format(opt=opt, help=help) + (" [" + "; ".join(l) + "]" if l else '') + '\n'
|
|
|
|
class DXXCommon(LazyObjectConstructor):
|
|
__shared_program_instance = [0]
|
|
__endian = checkEndian()
|
|
@property
|
|
def program_message_prefix(self):
|
|
return '%s.%d' % (self.PROGRAM_NAME, self.program_instance)
|
|
# Settings which affect how the files are compiled
|
|
class UserBuildSettings:
|
|
# Paths for the Videocore libs/includes on the Raspberry Pi
|
|
RPI_DEFAULT_VC_PATH='/opt/vc'
|
|
default_OGLES_LIB = 'GLES_CM'
|
|
_default_prefix = '/usr/local'
|
|
def default_builddir(self):
|
|
builddir_prefix = self.builddir_prefix
|
|
builddir_suffix = self.builddir_suffix
|
|
default_builddir = builddir_prefix or ''
|
|
if builddir_prefix is not None or builddir_suffix is not None:
|
|
fields = [
|
|
self.host_platform,
|
|
os.path.basename(self.CC) if self.CC else None,
|
|
]
|
|
compiler_flags = '\n'.join((getattr(self, attr) or '') for attr in ['CPPFLAGS', 'CFLAGS'])
|
|
if compiler_flags:
|
|
# Mix in CRC of CFLAGS to get reasonable uniqueness
|
|
# when flags are changed. A full hash is
|
|
# unnecessary here.
|
|
import binascii
|
|
crc = binascii.crc32(compiler_flags)
|
|
if crc < 0:
|
|
crc = crc + 0x100000000
|
|
fields.append('{:08x}'.format(crc))
|
|
fields.append(''.join(a[1] if getattr(self, a[0]) else (a[2] if len(a) > 2 else '')
|
|
for a in (
|
|
('debug', 'dbg'),
|
|
('profiler', 'prf'),
|
|
('editor', 'ed'),
|
|
('opengl', 'ogl', 'sdl'),
|
|
('opengles', 'es'),
|
|
('raspberrypi', 'rpi'),
|
|
)))
|
|
default_builddir += '-'.join([f for f in fields if f])
|
|
if builddir_suffix is not None:
|
|
default_builddir += builddir_prefix
|
|
return default_builddir
|
|
def default_memdebug(self):
|
|
return self.debug
|
|
# automatic setup for raspberrypi
|
|
def default_opengles(self):
|
|
if self.raspberrypi:
|
|
return True
|
|
return False
|
|
def selected_OGLES_LIB(self):
|
|
if self.raspberrypi:
|
|
return 'GLESv2'
|
|
return self.default_OGLES_LIB
|
|
def __default_DATA_DIR(self):
|
|
return self.prefix + '/share/games/' + self._program.target
|
|
@staticmethod
|
|
def _generic_variable(key,help,default):
|
|
return (key, help, default)
|
|
@staticmethod
|
|
def _enum_variable(key,help,default,allowed_values):
|
|
return EnumVariable(key, help, default, allowed_values)
|
|
def _options(self):
|
|
return (
|
|
{
|
|
'variable': BoolVariable,
|
|
'arguments': [
|
|
('sconf_%s' % name[6:], None, ConfigureTests.describe(name) or ('assume result of %s' % name)) for name in ConfigureTests.implicit_tests + ConfigureTests.custom_tests if name[0] != '_'
|
|
],
|
|
},
|
|
{
|
|
'variable': BoolVariable,
|
|
'arguments': (
|
|
('raspberrypi', False, 'build for Raspberry Pi (automatically sets opengles and opengles_lib)'),
|
|
),
|
|
},
|
|
{
|
|
'variable': self._generic_variable,
|
|
'arguments': (
|
|
('rpi_vc_path', self.RPI_DEFAULT_VC_PATH, 'directory for RPi VideoCore libraries'),
|
|
('opengles_lib', self.selected_OGLES_LIB, 'name of the OpenGL ES library to link against'),
|
|
('prefix', self._default_prefix, 'installation prefix directory (Linux only)'),
|
|
('sharepath', self.__default_DATA_DIR, 'directory for shared game data (Linux only)'),
|
|
('pch', None, 'pre-compile headers used this many times'),
|
|
),
|
|
},
|
|
{
|
|
'variable': BoolVariable,
|
|
'arguments': (
|
|
('debug', False, 'build DEBUG binary which includes asserts, debugging output, cheats and more output'),
|
|
('memdebug', self.default_memdebug, 'build with malloc tracking'),
|
|
('profiler', False, 'profiler build'),
|
|
('opengl', True, 'build with OpenGL support'),
|
|
('opengles', self.default_opengles, 'build with OpenGL ES support'),
|
|
('asm', False, 'build with ASSEMBLER code (only with opengl=0, requires NASM and x86)'),
|
|
('editor', False, 'include editor into build (!EXPERIMENTAL!)'),
|
|
('sdlmixer', True, 'build with SDL_Mixer support for sound and music (includes external music support)'),
|
|
('ipv6', False, 'enable IPv6 compability'),
|
|
('use_udp', True, 'enable UDP support'),
|
|
('use_tracker', True, 'enable Tracker support (requires UDP)'),
|
|
('verbosebuild', False, 'print out all compiler/linker messages during building'),
|
|
),
|
|
},
|
|
{
|
|
'variable': self._generic_variable,
|
|
'arguments': (
|
|
('CHOST', os.environ.get('CHOST'), 'CHOST of output'),
|
|
('CC', os.environ.get('CC'), 'C compiler command'),
|
|
('CXX', os.environ.get('CXX'), 'C++ compiler command'),
|
|
('CFLAGS', os.environ.get('CFLAGS'), 'C compiler flags'),
|
|
('CPPFLAGS', os.environ.get('CPPFLAGS'), 'C preprocessor flags'),
|
|
('CXXFLAGS', os.environ.get('CXXFLAGS'), 'C++ compiler flags'),
|
|
('LDFLAGS', os.environ.get('LDFLAGS'), 'Linker flags'),
|
|
('LIBS', os.environ.get('LIBS'), 'Libraries to link'),
|
|
('PKG_CONFIG', os.environ.get('PKG_CONFIG'), 'PKG_CONFIG to run (Linux only)'),
|
|
('RC', os.environ.get('RC'), 'Windows resource compiler command'),
|
|
('extra_version', None, 'text to append to version, such as VCS identity'),
|
|
),
|
|
},
|
|
{
|
|
'variable': self._enum_variable,
|
|
'arguments': (
|
|
('host_platform', None, 'cross-compile to specified platform', {'allowed_values' : ['win32', 'darwin', 'linux']}),
|
|
),
|
|
},
|
|
{
|
|
'variable': self._generic_variable,
|
|
'arguments': (
|
|
('builddir_prefix', None, 'prefix to generated build directory'),
|
|
('builddir_suffix', None, 'suffix to generated build directory'),
|
|
# This must be last so that default_builddir will
|
|
# have access to other properties.
|
|
('builddir', self.default_builddir, 'build in specified directory'),
|
|
),
|
|
},
|
|
)
|
|
@staticmethod
|
|
def _names(name,prefix):
|
|
# Mask out the leading underscore form.
|
|
return [('%s_%s' % (p, name)) for p in prefix if p]
|
|
def __init__(self,program=None):
|
|
self._program = program
|
|
def register_variables(self,prefix,variables):
|
|
self.known_variables = []
|
|
for grp in self._options():
|
|
variable = grp['variable']
|
|
for opt in grp['arguments']:
|
|
(name,value,help) = opt[0:3]
|
|
kwargs = opt[3] if len(opt) > 3 else {}
|
|
names = self._names(name, prefix)
|
|
for n in names:
|
|
if n not in variables.keys():
|
|
variables.Add(variable(key=n, help=help, default=None, **kwargs))
|
|
if name not in variables.keys():
|
|
filtered_help.visible_arguments.append(name)
|
|
variables.Add(variable(key=name, help=help, default=None if callable(value) else value, **kwargs))
|
|
self.known_variables.append((names + [name], value))
|
|
def read_variables(self,variables,d):
|
|
for (namelist,value) in self.known_variables:
|
|
for n in namelist:
|
|
try:
|
|
value = d[n]
|
|
break
|
|
except KeyError as e:
|
|
pass
|
|
if callable(value):
|
|
value = value()
|
|
setattr(self, namelist[-1], value)
|
|
if self.builddir != '' and self.builddir[-1:] != '/':
|
|
self.builddir += '/'
|
|
def clone(self):
|
|
clone = DXXCommon.UserBuildSettings(None)
|
|
for grp in clone._options():
|
|
for o in grp['arguments']:
|
|
name = o[0]
|
|
value = getattr(self, name)
|
|
setattr(clone, name, value)
|
|
return clone
|
|
class UserInstallSettings:
|
|
def _options(self):
|
|
return (
|
|
{
|
|
'variable': self._generic_variable,
|
|
'arguments': (
|
|
('DESTDIR', None, 'installation stage directory'),
|
|
('program_name', None, 'name of built program'),
|
|
),
|
|
},
|
|
{
|
|
'variable': BoolVariable,
|
|
'arguments': (
|
|
('register_install_target', True, 'report install target to SCons core'),
|
|
),
|
|
},
|
|
)
|
|
class UserSettings(UserBuildSettings,UserInstallSettings):
|
|
def _options(self):
|
|
return DXXCommon.UserBuildSettings._options(self) + DXXCommon.UserInstallSettings._options(self)
|
|
# Base class for platform-specific settings processing
|
|
class _PlatformSettings:
|
|
tools = None
|
|
ogllibs = ''
|
|
osasmdef = None
|
|
platform_sources = []
|
|
platform_objects = []
|
|
__pkg_config_sdl = {}
|
|
def __init__(self,program,user_settings):
|
|
self.__program = program
|
|
self.user_settings = user_settings
|
|
@property
|
|
def env(self):
|
|
return self.__program.env
|
|
def find_sdl_config(self,program,env):
|
|
if program.user_settings.PKG_CONFIG:
|
|
pkgconfig = program.user_settings.PKG_CONFIG
|
|
else:
|
|
if program.user_settings.CHOST:
|
|
pkgconfig = '%s-pkg-config' % program.user_settings.CHOST
|
|
else:
|
|
pkgconfig = 'pkg-config'
|
|
cmd = '%s --cflags --libs sdl' % pkgconfig
|
|
try:
|
|
flags = self.__pkg_config_sdl[cmd]
|
|
except KeyError as e:
|
|
if (program.user_settings.verbosebuild != 0):
|
|
message(program, "reading SDL settings from `%s`" % cmd)
|
|
self.__pkg_config_sdl[cmd] = env.backtick(cmd)
|
|
flags = self.__pkg_config_sdl[cmd]
|
|
env.MergeFlags(flags)
|
|
# Settings to apply to mingw32 builds
|
|
class Win32PlatformSettings(_PlatformSettings):
|
|
tools = ['mingw']
|
|
osdef = '_WIN32'
|
|
osasmdef = 'win32'
|
|
def adjust_environment(self,program,env):
|
|
env.Append(CPPDEFINES = ['_WIN32', 'HAVE_STRUCT_TIMEVAL', 'WIN32_LEAN_AND_MEAN'])
|
|
class DarwinPlatformSettings(_PlatformSettings):
|
|
osdef = '__APPLE__'
|
|
def __init__(self,program,user_settings):
|
|
DXXCommon._PlatformSettings.__init__(self,program,user_settings)
|
|
user_settings.asm = 0
|
|
def adjust_environment(self,program,env):
|
|
env.Append(CPPDEFINES = ['HAVE_STRUCT_TIMESPEC', 'HAVE_STRUCT_TIMEVAL', '__unix__'])
|
|
env.Append(CPPPATH = [os.path.join(program.srcdir, '../physfs'), os.path.join(os.getenv("HOME"), 'Library/Frameworks/SDL.framework/Headers'), '/Library/Frameworks/SDL.framework/Headers'])
|
|
env.Append(FRAMEWORKS = ['ApplicationServices', 'Carbon', 'Cocoa', 'SDL'])
|
|
if (self.user_settings.opengl == 1) or (self.user_settings.opengles == 1):
|
|
env.Append(FRAMEWORKS = ['OpenGL'])
|
|
env.Append(FRAMEWORKPATH = [os.path.join(os.getenv("HOME"), 'Library/Frameworks'), '/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks'])
|
|
env['LIBPATH'] = '../physfs/build/Debug'
|
|
# Settings to apply to Linux builds
|
|
class LinuxPlatformSettings(_PlatformSettings):
|
|
osdef = '__LINUX__'
|
|
osasmdef = 'elf'
|
|
__opengl_libs = ['GL', 'GLU']
|
|
__pkg_config_sdl = {}
|
|
def __init__(self,program,user_settings):
|
|
DXXCommon._PlatformSettings.__init__(self,program,user_settings)
|
|
if (user_settings.opengles == 1):
|
|
self.ogllibs = [ user_settings.opengles_lib, 'EGL']
|
|
else:
|
|
self.ogllibs = self.__opengl_libs
|
|
def adjust_environment(self,program,env):
|
|
env.Append(CPPDEFINES = ['__LINUX__', 'HAVE_STRUCT_TIMESPEC', 'HAVE_STRUCT_TIMEVAL'])
|
|
|
|
def __init__(self):
|
|
LazyObjectConstructor.__init__(self)
|
|
self.sources = []
|
|
self.__shared_program_instance[0] += 1
|
|
self.program_instance = self.__shared_program_instance[0]
|
|
|
|
@staticmethod
|
|
def _collect_pch_candidates(target,source,env):
|
|
for t in target:
|
|
scanner = t.get_source_scanner(source[0])
|
|
path = t.get_build_scanner_path(scanner)
|
|
deps = scanner(source[0], env, scanner.path(env))
|
|
for d in deps:
|
|
ds = str(d)
|
|
env.__dxx_pch_candidates[ds] = env.__dxx_pch_candidates.get(ds, 0) + 1
|
|
return (target, source)
|
|
|
|
@staticmethod
|
|
def write_pch_inclusion_file(target, source, env):
|
|
with open(str(target[0]), 'wt') as f:
|
|
f.write('/* BEGIN PCH GENERATED FILE\n * Threshold=%u\n */\n' % env.__dxx_pch_inclusion_count)
|
|
for (name,count) in env.__dxx_pch_candidates.items():
|
|
if count >= env.__dxx_pch_inclusion_count:
|
|
f.write('#include "%s"\t/* %u */\n' % (name, count))
|
|
env.Depends(target, name)
|
|
f.write('/* END PCH GENERATED FILE */\n')
|
|
|
|
def create_pch_node(self,dirname):
|
|
dirname = os.path.join(self.user_settings.builddir, dirname)
|
|
target = os.path.join(dirname, 'pch.h.gch')
|
|
source = os.path.join(dirname, 'pch.cpp')
|
|
self.env._dxx_pch_node = self.env.StaticObject(target=target, source=source, CXXFLAGS=self.env['CXXFLAGS'] + ['-x', 'c++-header'])
|
|
self.env.__dxx_pch_candidates = {}
|
|
self.env.__dxx_pch_inclusion_count = int(self.user_settings.pch)
|
|
self.env['BUILDERS']['StaticObject'].add_emitter('.cpp', self._collect_pch_candidates)
|
|
self.env.Command(source, None, self.write_pch_inclusion_file)
|
|
|
|
def prepare_environment(self):
|
|
# Prettier build messages......
|
|
if (self.user_settings.verbosebuild == 0):
|
|
builddir = self.user_settings.builddir if self.user_settings.builddir != '' else '.'
|
|
self.env["CCCOMSTR"] = "Compiling %s %s $SOURCE" % (self.target, builddir)
|
|
self.env["CXXCOMSTR"] = "Compiling %s %s $SOURCE" % (self.target, builddir)
|
|
self.env["LINKCOMSTR"] = "Linking %s $TARGET" % self.target
|
|
self.env["ARCOMSTR"] = "Archiving $TARGET ..."
|
|
self.env["RANLIBCOMSTR"] = "Indexing $TARGET ..."
|
|
|
|
# Use -Wundef to catch when a shared source file includes a
|
|
# shared header that misuses conditional compilation. Use
|
|
# -Werror=undef to make this fatal. Both are needed, since
|
|
# gcc 4.5 silently ignores -Werror=undef. On gcc 4.5, misuse
|
|
# produces a warning. On gcc 4.7, misuse produces an error.
|
|
self.env.Append(CCFLAGS = ['-Wall', '-Wundef', '-Werror=redundant-decls', '-Werror=missing-declarations', '-Werror=pointer-arith', '-Werror=undef', '-funsigned-char', '-Werror=implicit-int', '-Werror=implicit-function-declaration', '-Werror=format-security', '-pthread'])
|
|
self.env.Append(CFLAGS = ['-std=gnu99', '-Wwrite-strings'])
|
|
self.env.Append(CPPPATH = ['common/include', 'common/main', '.', self.user_settings.builddir])
|
|
self.env.Append(CPPFLAGS = ['-Wno-sign-compare'])
|
|
if (self.user_settings.editor == 1):
|
|
self.env.Append(CPPPATH = ['common/include/editor'])
|
|
# Get traditional compiler environment variables
|
|
for cc in ['CC', 'CXX', 'RC']:
|
|
value = getattr(self.user_settings, cc)
|
|
if value is not None:
|
|
self.env[cc] = value
|
|
for flags in ['CFLAGS', 'CPPFLAGS', 'CXXFLAGS', 'LIBS']:
|
|
value = getattr(self.user_settings, flags)
|
|
if value is not None:
|
|
self.env.Append(**{flags : SCons.Util.CLVar(value)})
|
|
if self.user_settings.LDFLAGS:
|
|
self.env.Append(LINKFLAGS = SCons.Util.CLVar(self.user_settings.LDFLAGS))
|
|
|
|
def check_endian(self):
|
|
# set endianess
|
|
if (self.__endian == "big"):
|
|
message(self, "BigEndian machine detected")
|
|
self.asm = 0
|
|
self.env.Append(CPPDEFINES = ['WORDS_BIGENDIAN'])
|
|
elif (self.__endian == "little"):
|
|
message(self, "LittleEndian machine detected")
|
|
|
|
def check_platform(self):
|
|
# windows or *nix?
|
|
platform_name = self.user_settings.host_platform or sys.platform
|
|
if self._argument_prefix_list:
|
|
prefix = ' with prefix list %s' % list(self._argument_prefix_list)
|
|
else:
|
|
prefix = ''
|
|
message(self, "compiling on %s for %s into %s%s" % (sys.platform, platform_name, self.user_settings.builddir or '.', prefix))
|
|
if platform_name == 'win32':
|
|
platform = self.Win32PlatformSettings
|
|
elif platform_name == 'darwin':
|
|
platform = self.DarwinPlatformSettings
|
|
else:
|
|
platform = self.LinuxPlatformSettings
|
|
self.platform_settings = platform(self, self.user_settings)
|
|
# Acquire environment object...
|
|
self.env = Environment(ENV = os.environ, tools = platform.tools)
|
|
# On Linux hosts, always run this. It should work even when
|
|
# cross-compiling a Rebirth to run elsewhere.
|
|
if sys.platform == 'linux2':
|
|
self.platform_settings.find_sdl_config(self, self.env)
|
|
self.platform_settings.adjust_environment(self, self.env)
|
|
|
|
def process_user_settings(self):
|
|
env = self.env
|
|
# opengl or software renderer?
|
|
if (self.user_settings.opengl == 1) or (self.user_settings.opengles == 1):
|
|
if (self.user_settings.opengles == 1):
|
|
message(self, "building with OpenGL ES")
|
|
env.Append(CPPDEFINES = ['OGLES'])
|
|
else:
|
|
message(self, "building with OpenGL")
|
|
env.Append(CPPDEFINES = ['OGL'])
|
|
|
|
# assembler code?
|
|
if (self.user_settings.asm == 1) and (self.user_settings.opengl == 0):
|
|
message(self, "including: ASSEMBLER")
|
|
env.Replace(AS = 'nasm')
|
|
env.Append(ASCOM = ' -f ' + str(self.platform_settings.osasmdef) + ' -d' + str(self.platform_settings.osdef) + ' -Itexmap/ ')
|
|
self.sources += asm_sources
|
|
else:
|
|
env.Append(CPPDEFINES = ['NO_ASM'])
|
|
|
|
# SDL_mixer support?
|
|
if (self.user_settings.sdlmixer == 1):
|
|
message(self, "including SDL_mixer")
|
|
env.Append(CPPDEFINES = ['USE_SDLMIXER'])
|
|
|
|
# debug?
|
|
if (self.user_settings.debug == 1):
|
|
message(self, "including: DEBUG")
|
|
env.Prepend(CFLAGS = ['-g'])
|
|
env.Prepend(CXXFLAGS = ['-g'])
|
|
else:
|
|
env.Append(CPPDEFINES = ['NDEBUG', 'RELEASE'])
|
|
env.Prepend(CFLAGS = ['-O2'])
|
|
env.Prepend(CXXFLAGS = ['-O2'])
|
|
if self.user_settings.memdebug:
|
|
message(self, "including: MEMDEBUG")
|
|
env.Append(CPPDEFINES = ['DEBUG_MEMORY_ALLOCATIONS'])
|
|
|
|
# profiler?
|
|
if (self.user_settings.profiler == 1):
|
|
env.Append(CPPFLAGS = ['-pg'])
|
|
|
|
#editor build?
|
|
if (self.user_settings.editor == 1):
|
|
env.Append(CPPDEFINES = ['EDITOR'])
|
|
|
|
# IPv6 compability?
|
|
if (self.user_settings.ipv6 == 1):
|
|
env.Append(CPPDEFINES = ['IPv6'])
|
|
|
|
# UDP support?
|
|
if (self.user_settings.use_udp == 1):
|
|
env.Append(CPPDEFINES = ['USE_UDP'])
|
|
# Tracker support? (Relies on UDP)
|
|
if( self.user_settings.use_tracker == 1 ):
|
|
env.Append( CPPDEFINES = [ 'USE_TRACKER' ] )
|
|
|
|
# Raspberry Pi?
|
|
if (self.user_settings.raspberrypi == 1):
|
|
print "using Raspberry Pi vendor libs in %s" % self.user_settings.rpi_vc_path
|
|
env.Append(CPPDEFINES = ['RPI', 'WORDS_NEED_ALIGNMENT'])
|
|
env.Append(CPPPATH = [
|
|
self.user_settings.rpi_vc_path+'/include',
|
|
self.user_settings.rpi_vc_path+'/include/interface/vcos/pthreads',
|
|
self.user_settings.rpi_vc_path+'/include/interface/vmcs_host/linux'])
|
|
env.Append(LIBPATH = self.user_settings.rpi_vc_path + '/lib')
|
|
env.Append(LIBS = ['bcm_host'])
|
|
if self.user_settings.pch:
|
|
self.create_pch_node(self.srcdir)
|
|
|
|
class DXXArchive(DXXCommon):
|
|
srcdir = 'common'
|
|
target = 'dxx-common'
|
|
__objects_common = DXXCommon.create_lazy_object_property([os.path.join(srcdir, f) for f in [
|
|
'2d/2dsline.cpp',
|
|
'2d/bitblt.cpp',
|
|
'2d/bitmap.cpp',
|
|
'2d/box.cpp',
|
|
'2d/canvas.cpp',
|
|
'2d/circle.cpp',
|
|
'2d/disc.cpp',
|
|
'2d/gpixel.cpp',
|
|
'2d/line.cpp',
|
|
'2d/pixel.cpp',
|
|
'2d/rect.cpp',
|
|
'2d/rle.cpp',
|
|
'2d/scalec.cpp',
|
|
'3d/clipper.cpp',
|
|
'3d/draw.cpp',
|
|
'3d/globvars.cpp',
|
|
'3d/instance.cpp',
|
|
'3d/matrix.cpp',
|
|
'3d/points.cpp',
|
|
'3d/rod.cpp',
|
|
'3d/setup.cpp',
|
|
'arch/sdl/joy.cpp',
|
|
'arch/sdl/rbaudio.cpp',
|
|
'arch/sdl/window.cpp',
|
|
'maths/fixc.cpp',
|
|
'maths/rand.cpp',
|
|
'maths/tables.cpp',
|
|
'maths/vecmat.cpp',
|
|
'misc/error.cpp',
|
|
'misc/hmp.cpp',
|
|
'misc/ignorecase.cpp',
|
|
'misc/strio.cpp',
|
|
'misc/strutil.cpp',
|
|
'texmap/ntmap.cpp',
|
|
'texmap/scanline.cpp'
|
|
]
|
|
])
|
|
objects_editor = DXXCommon.create_lazy_object_property([os.path.join(srcdir, f) for f in [
|
|
'editor/func.cpp',
|
|
'ui/button.cpp',
|
|
'ui/checkbox.cpp',
|
|
'ui/dialog.cpp',
|
|
'ui/file.cpp',
|
|
'ui/gadget.cpp',
|
|
'ui/icon.cpp',
|
|
'ui/inputbox.cpp',
|
|
'ui/keypad.cpp',
|
|
'ui/keypress.cpp',
|
|
'ui/keytrap.cpp',
|
|
'ui/listbox.cpp',
|
|
'ui/menu.cpp',
|
|
'ui/menubar.cpp',
|
|
'ui/message.cpp',
|
|
'ui/radio.cpp',
|
|
'ui/scroll.cpp',
|
|
'ui/ui.cpp',
|
|
'ui/uidraw.cpp',
|
|
'ui/userbox.cpp'
|
|
]
|
|
])
|
|
# for non-ogl
|
|
objects_arch_sdl = DXXCommon.create_lazy_object_property([os.path.join(srcdir, f) for f in [
|
|
'texmap/tmapflat.cpp'
|
|
]
|
|
])
|
|
objects_arch_sdlmixer = DXXCommon.create_lazy_object_property([os.path.join(srcdir, f) for f in [
|
|
'arch/sdl/digi_mixer_music.cpp',
|
|
]
|
|
])
|
|
class Win32PlatformSettings(LazyObjectConstructor, DXXCommon.Win32PlatformSettings):
|
|
platform_objects = LazyObjectConstructor.create_lazy_object_property([
|
|
'common/arch/win32/messagebox.cpp'
|
|
])
|
|
def __init__(self,program,user_settings):
|
|
LazyObjectConstructor.__init__(self)
|
|
DXXCommon.Win32PlatformSettings.__init__(self, program, user_settings)
|
|
self.user_settings = user_settings
|
|
@property
|
|
def objects_common(self):
|
|
objects_common = self.__objects_common
|
|
return objects_common + self.platform_settings.platform_objects
|
|
def __init__(self,user_settings):
|
|
self.PROGRAM_NAME = 'DXX-Archive'
|
|
self._argument_prefix_list = None
|
|
DXXCommon.__init__(self)
|
|
self.user_settings = user_settings.clone()
|
|
self.check_platform()
|
|
self.prepare_environment()
|
|
self.check_endian()
|
|
self.process_user_settings()
|
|
self.configure_environment()
|
|
|
|
def configure_environment(self):
|
|
fs = SCons.Node.FS.get_default_fs()
|
|
builddir = fs.Dir(self.user_settings.builddir or '.')
|
|
tests = ConfigureTests(self.program_message_prefix, self.user_settings)
|
|
log_file=fs.File('sconf.log', builddir)
|
|
conf = self.env.Configure(custom_tests = {
|
|
k:getattr(tests, k) for k in tests.custom_tests
|
|
},
|
|
conf_dir=fs.Dir('.sconf_temp', builddir),
|
|
log_file=log_file,
|
|
config_h=fs.File('dxxsconf.h', builddir),
|
|
clean=False,
|
|
help=False
|
|
)
|
|
self.added_environment_flags = tests.successful_flags
|
|
if not conf.env:
|
|
return
|
|
try:
|
|
for k in tests.custom_tests:
|
|
getattr(conf, k)()
|
|
except SCons.Errors.StopError as e:
|
|
raise SCons.Errors.StopError(e.args[0] + ' See {log_file} for details.'.format(log_file=log_file), *e.args[1:])
|
|
self.env = conf.Finish()
|
|
|
|
class DXXProgram(DXXCommon):
|
|
# version number
|
|
VERSION_MAJOR = 0
|
|
VERSION_MINOR = 58
|
|
VERSION_MICRO = 1
|
|
static_archive_construction = {}
|
|
def _apply_target_name(self,name):
|
|
return os.path.join(os.path.dirname(name), '.%s.%s' % (self.target, os.path.splitext(os.path.basename(name))[0]))
|
|
objects_similar_arch_ogl = DXXCommon.create_lazy_object_property([{
|
|
'source':[os.path.join('similar', f) for f in [
|
|
'arch/ogl/gr.cpp',
|
|
'arch/ogl/ogl.cpp',
|
|
]
|
|
],
|
|
'transform_target':_apply_target_name,
|
|
}])
|
|
objects_similar_arch_sdl = DXXCommon.create_lazy_object_property([{
|
|
'source':[os.path.join('similar', f) for f in [
|
|
'arch/sdl/gr.cpp',
|
|
]
|
|
],
|
|
'transform_target':_apply_target_name,
|
|
}])
|
|
objects_similar_arch_sdlmixer = DXXCommon.create_lazy_object_property([{
|
|
'source':[os.path.join('similar', f) for f in [
|
|
'arch/sdl/digi_mixer.cpp',
|
|
'arch/sdl/jukebox.cpp'
|
|
]
|
|
],
|
|
'transform_target':_apply_target_name,
|
|
}])
|
|
__objects_common = DXXCommon.create_lazy_object_property([{
|
|
'source':[os.path.join('similar', f) for f in [
|
|
'2d/font.cpp',
|
|
'2d/palette.cpp',
|
|
'2d/pcx.cpp',
|
|
'3d/interp.cpp',
|
|
'arch/sdl/digi.cpp',
|
|
'arch/sdl/digi_audio.cpp',
|
|
'arch/sdl/event.cpp',
|
|
'arch/sdl/init.cpp',
|
|
'arch/sdl/key.cpp',
|
|
'arch/sdl/mouse.cpp',
|
|
'arch/sdl/timer.cpp',
|
|
'main/ai.cpp',
|
|
'main/aipath.cpp',
|
|
'main/automap.cpp',
|
|
'main/cntrlcen.cpp',
|
|
'main/config.cpp',
|
|
'main/console.cpp',
|
|
'main/controls.cpp',
|
|
'main/credits.cpp',
|
|
'main/digiobj.cpp',
|
|
'main/effects.cpp',
|
|
'main/endlevel.cpp',
|
|
'main/fuelcen.cpp',
|
|
'main/fvi.cpp',
|
|
'main/game.cpp',
|
|
'main/gamecntl.cpp',
|
|
'main/gamefont.cpp',
|
|
'main/gamerend.cpp',
|
|
'main/gamesave.cpp',
|
|
'main/gameseg.cpp',
|
|
'main/gameseq.cpp',
|
|
'main/gauges.cpp',
|
|
'main/hostage.cpp',
|
|
'main/hud.cpp',
|
|
'main/inferno.cpp',
|
|
'main/kconfig.cpp',
|
|
'main/kmatrix.cpp',
|
|
'main/laser.cpp',
|
|
'main/lighting.cpp',
|
|
'main/menu.cpp',
|
|
'main/mglobal.cpp',
|
|
'main/mission.cpp',
|
|
'main/morph.cpp',
|
|
'main/multi.cpp',
|
|
'main/multibot.cpp',
|
|
'main/newdemo.cpp',
|
|
'main/newmenu.cpp',
|
|
'main/object.cpp',
|
|
'main/paging.cpp',
|
|
'main/physics.cpp',
|
|
'main/piggy.cpp',
|
|
'main/player.cpp',
|
|
'main/playsave.cpp',
|
|
'main/polyobj.cpp',
|
|
'main/powerup.cpp',
|
|
'main/render.cpp',
|
|
'main/robot.cpp',
|
|
'main/scores.cpp',
|
|
'main/slew.cpp',
|
|
'main/songs.cpp',
|
|
'main/state.cpp',
|
|
'main/switch.cpp',
|
|
'main/terrain.cpp',
|
|
'main/texmerge.cpp',
|
|
'main/text.cpp',
|
|
'main/titles.cpp',
|
|
'main/vclip.cpp',
|
|
'main/wall.cpp',
|
|
'main/weapon.cpp',
|
|
'mem/mem.cpp',
|
|
'misc/args.cpp',
|
|
'misc/hash.cpp',
|
|
'misc/physfsx.cpp',
|
|
]
|
|
],
|
|
'transform_target':_apply_target_name,
|
|
}])
|
|
objects_editor = DXXCommon.create_lazy_object_property([{
|
|
'source':[os.path.join('similar', f) for f in [
|
|
'editor/autosave.cpp',
|
|
'editor/centers.cpp',
|
|
'editor/curves.cpp',
|
|
'main/dumpmine.cpp',
|
|
'editor/eglobal.cpp',
|
|
'editor/elight.cpp',
|
|
'editor/eobject.cpp',
|
|
'editor/eswitch.cpp',
|
|
'editor/group.cpp',
|
|
'editor/info.cpp',
|
|
'editor/kbuild.cpp',
|
|
'editor/kcurve.cpp',
|
|
'editor/kfuncs.cpp',
|
|
'editor/kgame.cpp',
|
|
'editor/khelp.cpp',
|
|
'editor/kmine.cpp',
|
|
'editor/ksegmove.cpp',
|
|
'editor/ksegsel.cpp',
|
|
'editor/ksegsize.cpp',
|
|
'editor/ktmap.cpp',
|
|
'editor/kview.cpp',
|
|
'editor/med.cpp',
|
|
'editor/meddraw.cpp',
|
|
'editor/medmisc.cpp',
|
|
'editor/medrobot.cpp',
|
|
'editor/medsel.cpp',
|
|
'editor/medwall.cpp',
|
|
'editor/mine.cpp',
|
|
'editor/objpage.cpp',
|
|
'editor/segment.cpp',
|
|
'editor/seguvs.cpp',
|
|
'editor/texpage.cpp',
|
|
'editor/texture.cpp',
|
|
]
|
|
],
|
|
'transform_target':_apply_target_name,
|
|
}])
|
|
|
|
objects_use_udp = DXXCommon.create_lazy_object_property([{
|
|
'source':[os.path.join('similar', f) for f in [
|
|
'main/net_udp.cpp',
|
|
]
|
|
],
|
|
'transform_target':_apply_target_name,
|
|
}])
|
|
class UserSettings(DXXCommon.UserSettings):
|
|
@property
|
|
def BIN_DIR(self):
|
|
# installation path
|
|
return self.prefix + '/bin'
|
|
# Settings to apply to mingw32 builds
|
|
class Win32PlatformSettings(DXXCommon.Win32PlatformSettings):
|
|
def __init__(self,program,user_settings):
|
|
DXXCommon.Win32PlatformSettings.__init__(self,program,user_settings)
|
|
user_settings.sharepath = ''
|
|
self.platform_objects = self.platform_objects[:]
|
|
def adjust_environment(self,program,env):
|
|
DXXCommon.Win32PlatformSettings.adjust_environment(self, program, env)
|
|
rcbasename = os.path.join(program.srcdir, 'arch/win32/%s' % program.target)
|
|
self.platform_objects.append(env.RES(target='%s%s%s' % (program.user_settings.builddir, rcbasename, env["OBJSUFFIX"]), source='%s.rc' % rcbasename))
|
|
env.Append(CPPPATH = [os.path.join(program.srcdir, 'arch/win32/include')])
|
|
env.Append(LINKFLAGS = '-mwindows')
|
|
env.Append(LIBS = ['glu32', 'wsock32', 'ws2_32', 'winmm', 'mingw32', 'SDLmain', 'SDL'])
|
|
# Settings to apply to Apple builds
|
|
class DarwinPlatformSettings(DXXCommon.DarwinPlatformSettings):
|
|
def __init__(self,program,user_settings):
|
|
DXXCommon.DarwinPlatformSettings.__init__(self,program,user_settings)
|
|
user_settings.sharepath = ''
|
|
def adjust_environment(self,program,env):
|
|
DXXCommon.DarwinPlatformSettings.adjust_environment(self, program, env)
|
|
VERSION = str(program.VERSION_MAJOR) + '.' + str(program.VERSION_MINOR)
|
|
if (program.VERSION_MICRO):
|
|
VERSION += '.' + str(program.VERSION_MICRO)
|
|
env['VERSION_NUM'] = VERSION
|
|
env['VERSION_NAME'] = program.PROGRAM_NAME + ' v' + VERSION
|
|
self.platform_sources = [os.path.join(program.srcdir, f) for f in ['arch/cocoa/SDLMain.m', 'arch/carbon/messagebox.c']]
|
|
env.Append(FRAMEWORKS = ['ApplicationServices', 'Carbon', 'Cocoa', 'SDL'])
|
|
if (self.user_settings.sdlmixer == 1):
|
|
env.Append(FRAMEWORKS = ['SDL_mixer'])
|
|
env.Append(LIBS = ['../physfs/build/Debug/libphysfs.dylib'])
|
|
# Settings to apply to Linux builds
|
|
class LinuxPlatformSettings(DXXCommon.LinuxPlatformSettings):
|
|
def __init__(self,program,user_settings):
|
|
DXXCommon.LinuxPlatformSettings.__init__(self,program,user_settings)
|
|
user_settings.sharepath += '/'
|
|
|
|
@property
|
|
def objects_common(self):
|
|
objects_common = self.__objects_common
|
|
if (self.user_settings.use_udp == 1):
|
|
objects_common = objects_common + self.objects_use_udp
|
|
return objects_common + self.platform_settings.platform_objects
|
|
def __init__(self,prefix,variables):
|
|
self.variables = variables
|
|
self._argument_prefix_list = prefix
|
|
DXXCommon.__init__(self)
|
|
self.banner()
|
|
self.user_settings = self.UserSettings(program=self)
|
|
self.user_settings.register_variables(prefix=prefix, variables=self.variables)
|
|
|
|
def init(self,substenv):
|
|
self.user_settings.read_variables(self.variables, substenv)
|
|
if not DXXProgram.static_archive_construction.has_key(self.user_settings.builddir):
|
|
DXXProgram.static_archive_construction[self.user_settings.builddir] = DXXArchive(self.user_settings)
|
|
self.check_platform()
|
|
self.prepare_environment()
|
|
self.check_endian()
|
|
self.process_user_settings()
|
|
self.register_program()
|
|
|
|
def prepare_environment(self):
|
|
DXXCommon.prepare_environment(self)
|
|
self.env.Append(**DXXProgram.static_archive_construction[self.user_settings.builddir].added_environment_flags)
|
|
self.env.Append(CPPDEFINES = [('DXX_VERSION_MAJORi', str(self.VERSION_MAJOR)), ('DXX_VERSION_MINORi', str(self.VERSION_MINOR)), ('DXX_VERSION_MICROi', str(self.VERSION_MICRO))])
|
|
# For PRIi64
|
|
self.env.Append(CPPDEFINES = [('__STDC_FORMAT_MACROS',)])
|
|
self.env.Append(CPPPATH = [os.path.join(self.srcdir, f) for f in ['include', 'main', 'arch/include']])
|
|
|
|
def banner(self):
|
|
VERSION_STRING = ' v' + str(self.VERSION_MAJOR) + '.' + str(self.VERSION_MINOR) + '.' + str(self.VERSION_MICRO)
|
|
print '\n===== ' + self.PROGRAM_NAME + VERSION_STRING + ' =====\n'
|
|
|
|
def check_platform(self):
|
|
DXXCommon.check_platform(self)
|
|
env = self.env
|
|
# windows or *nix?
|
|
if sys.platform == 'darwin':
|
|
VERSION = str(self.VERSION_MAJOR) + '.' + str(self.VERSION_MINOR)
|
|
if (self.VERSION_MICRO):
|
|
VERSION += '.' + str(self.VERSION_MICRO)
|
|
env['VERSION_NUM'] = VERSION
|
|
env['VERSION_NAME'] = self.PROGRAM_NAME + ' v' + VERSION
|
|
env.Append(LIBS = ['physfs', 'm'])
|
|
|
|
def process_user_settings(self):
|
|
DXXCommon.process_user_settings(self)
|
|
env = self.env
|
|
# opengl or software renderer?
|
|
|
|
# SDL_mixer support?
|
|
if (self.user_settings.sdlmixer == 1):
|
|
if (sys.platform != 'darwin'):
|
|
env.Append(LIBS = ['SDL_mixer'])
|
|
|
|
# profiler?
|
|
if (self.user_settings.profiler == 1):
|
|
env.Append(LINKFLAGS = '-pg')
|
|
|
|
#editor build?
|
|
if (self.user_settings.editor == 1):
|
|
env.Append(CPPPATH = [os.path.join(self.srcdir, 'include/editor')])
|
|
|
|
env.Append(CPPDEFINES = [('SHAREPATH', '\\"' + str(self.user_settings.sharepath) + '\\"')])
|
|
|
|
def _register_program(self,dxxstr,program_specific_objects=[]):
|
|
env = self.env
|
|
exe_target = os.path.join(self.srcdir, self.target)
|
|
static_archive_construction = self.static_archive_construction[self.user_settings.builddir]
|
|
objects = static_archive_construction.objects_common[:]
|
|
objects.extend(self.objects_common)
|
|
objects.extend(program_specific_objects)
|
|
if (self.user_settings.sdlmixer == 1):
|
|
objects.extend(static_archive_construction.objects_arch_sdlmixer)
|
|
objects.extend(self.objects_similar_arch_sdlmixer)
|
|
if (self.user_settings.opengl == 1) or (self.user_settings.opengles == 1):
|
|
env.Append(LIBS = self.platform_settings.ogllibs)
|
|
objects.extend(self.objects_similar_arch_ogl)
|
|
else:
|
|
message(self, "building with Software Renderer")
|
|
objects.extend(static_archive_construction.objects_arch_sdl)
|
|
objects.extend(self.objects_similar_arch_sdl)
|
|
if (self.user_settings.editor == 1):
|
|
objects.extend(self.objects_editor)
|
|
objects.extend(static_archive_construction.objects_editor)
|
|
exe_target += '-editor'
|
|
if self.user_settings.program_name:
|
|
exe_target = self.user_settings.program_name
|
|
versid_cppdefines=self.env['CPPDEFINES'][:]
|
|
if self.user_settings.extra_version:
|
|
versid_cppdefines.append(('DESCENT_VERSION_EXTRA', '\\"%s\\"' % self.user_settings.extra_version))
|
|
objects.extend([self.env.StaticObject(target='%s%s%s' % (self.user_settings.builddir, self._apply_target_name(s), self.env["OBJSUFFIX"]), source=s, CPPDEFINES=versid_cppdefines) for s in ['similar/main/vers_id.cpp']])
|
|
# finally building program...
|
|
env.Program(target='%s%s' % (self.user_settings.builddir, str(exe_target)), source = self.sources + objects)
|
|
if (sys.platform != 'darwin'):
|
|
if self.user_settings.register_install_target:
|
|
install_dir = os.path.join(self.user_settings.DESTDIR or '', self.user_settings.BIN_DIR)
|
|
env.Install(install_dir, str(exe_target))
|
|
env.Alias('install', install_dir)
|
|
else:
|
|
syspath = sys.path[:]
|
|
cocoa = os.path.join(self.srcdir, 'arch/cocoa')
|
|
sys.path += [cocoa]
|
|
import tool_bundle
|
|
sys.path = syspath
|
|
tool_bundle.TOOL_BUNDLE(env)
|
|
env.MakeBundle(self.PROGRAM_NAME + '.app', exe_target,
|
|
'free.%s-rebirth' % dxxstr, os.path.join(self.srcdir, '%sgl-Info.plist' % dxxstr),
|
|
typecode='APPL', creator='DCNT',
|
|
icon_file=os.path.join(cocoa, '%s-rebirth.icns' % dxxstr),
|
|
subst_dict={'%sgl' % dxxstr : exe_target}, # This is required; manually update version for Xcode compatibility
|
|
resources=[[s, s] for s in [os.path.join(self.srcdir, 'English.lproj/InfoPlist.strings')]])
|
|
|
|
def GenerateHelpText(self):
|
|
return self.variables.GenerateHelpText(self.env)
|
|
|
|
class D1XProgram(DXXProgram):
|
|
PROGRAM_NAME = 'D1X-Rebirth'
|
|
target = 'd1x-rebirth'
|
|
srcdir = 'd1x-rebirth'
|
|
def prepare_environment(self):
|
|
DXXProgram.prepare_environment(self)
|
|
# Flags and stuff for all platforms...
|
|
self.env.Append(CPPDEFINES = [('DXX_BUILD_DESCENT_I', 1)])
|
|
|
|
# general source files
|
|
__objects_common = DXXCommon.create_lazy_object_property([{
|
|
'source':[os.path.join(srcdir, f) for f in [
|
|
'iff/iff.c',
|
|
'main/bm.c',
|
|
'main/bmread.c',
|
|
'main/collide.c',
|
|
'main/custom.cpp',
|
|
'main/fireball.c',
|
|
'main/gamemine.c',
|
|
'main/snddecom.cpp',
|
|
#'tracker/client/tracker_client.c'
|
|
]
|
|
],
|
|
}])
|
|
@property
|
|
def objects_common(self):
|
|
return self.__objects_common + DXXProgram.objects_common.fget(self)
|
|
|
|
# for editor
|
|
__objects_editor = DXXCommon.create_lazy_object_property([{
|
|
'source':[os.path.join(srcdir, f) for f in [
|
|
'main/hostage.cpp',
|
|
'editor/ehostage.cpp',
|
|
]
|
|
],
|
|
}])
|
|
@property
|
|
def objects_editor(self):
|
|
return self.__objects_editor + DXXProgram.objects_editor.fget(self)
|
|
|
|
# assembler related
|
|
objects_asm = DXXCommon.create_lazy_object_property([os.path.join(srcdir, f) for f in [
|
|
'texmap/tmap_ll.asm',
|
|
'texmap/tmap_flt.asm',
|
|
'texmap/tmapfade.asm',
|
|
'texmap/tmap_lin.asm',
|
|
'texmap/tmap_per.asm'
|
|
]
|
|
])
|
|
def register_program(self):
|
|
self._register_program('d1x')
|
|
|
|
class D2XProgram(DXXProgram):
|
|
PROGRAM_NAME = 'D2X-Rebirth'
|
|
target = 'd2x-rebirth'
|
|
srcdir = 'd2x-rebirth'
|
|
def prepare_environment(self):
|
|
DXXProgram.prepare_environment(self)
|
|
# Flags and stuff for all platforms...
|
|
self.env.Append(CPPDEFINES = [('DXX_BUILD_DESCENT_II', 1)])
|
|
|
|
# general source files
|
|
__objects_common = DXXCommon.create_lazy_object_property([{
|
|
'source':[os.path.join(srcdir, f) for f in [
|
|
'iff/iff.c',
|
|
'libmve/decoder8.c',
|
|
'libmve/decoder16.c',
|
|
'libmve/mve_audio.c',
|
|
'libmve/mvelib.c',
|
|
'libmve/mveplay.c',
|
|
'main/bm.c',
|
|
'main/collide.c',
|
|
'main/escort.cpp',
|
|
'main/fireball.c',
|
|
'main/gamemine.c',
|
|
'main/gamepal.cpp',
|
|
'main/movie.cpp',
|
|
'main/segment.cpp',
|
|
'misc/physfsrwops.c',
|
|
]
|
|
],
|
|
}])
|
|
@property
|
|
def objects_common(self):
|
|
return self.__objects_common + DXXProgram.objects_common.fget(self)
|
|
|
|
# for editor
|
|
__objects_editor = DXXCommon.create_lazy_object_property([{
|
|
'source':[os.path.join(srcdir, f) for f in [
|
|
'main/bmread.c',
|
|
]
|
|
],
|
|
}])
|
|
@property
|
|
def objects_editor(self):
|
|
return self.__objects_editor + DXXProgram.objects_editor.fget(self)
|
|
|
|
# assembler related
|
|
objects_asm = DXXCommon.create_lazy_object_property([os.path.join(srcdir, f) for f in [
|
|
'texmap/tmap_ll.asm',
|
|
'texmap/tmap_flt.asm',
|
|
'texmap/tmapfade.asm',
|
|
'texmap/tmap_lin.asm',
|
|
'texmap/tmap_per.asm'
|
|
]
|
|
])
|
|
|
|
def register_program(self):
|
|
self._register_program('d2x')
|
|
|
|
variables = Variables(['site-local.py'], ARGUMENTS)
|
|
filtered_help = FilterHelpText()
|
|
variables.FormatVariableHelpText = filtered_help.FormatVariableHelpText
|
|
def register_program(s,program):
|
|
import itertools
|
|
l = [v for (k,v) in ARGLIST if k == s] or [1]
|
|
# Fallback case: build the regular configuration.
|
|
if len(l) == 1:
|
|
try:
|
|
if int(l[0]):
|
|
return [program((s,), variables)]
|
|
return []
|
|
except ValueError:
|
|
# If not an integer, treat this as a configuration profile.
|
|
pass
|
|
r = []
|
|
for e in l:
|
|
for prefix in itertools.product(*[v.split('+') for v in e.split(',')]):
|
|
r.append(program(prefix, variables))
|
|
return r
|
|
d1x = register_program('d1x', D1XProgram)
|
|
d2x = register_program('d2x', D2XProgram)
|
|
|
|
# show some help when running scons -h
|
|
h = 'DXX-Rebirth, SConstruct file help:' + """
|
|
|
|
Type 'scons' to build the binary.
|
|
Type 'scons install' to build (if it hasn't been done) and install.
|
|
Type 'scons -c' to clean up.
|
|
|
|
Extra options (add them to command line, like 'scons extraoption=value'):
|
|
d1x=[0/1] Disable/enable D1X-Rebirth
|
|
d1x=prefix-list Enable D1X-Rebirth with prefix-list modifiers
|
|
d2x=[0/1] Disable/enable D2X-Rebirth
|
|
d2x=prefix-list Enable D2X-Rebirth with prefix-list modifiers
|
|
"""
|
|
substenv = SCons.Environment.SubstitutionEnvironment()
|
|
variables.Update(substenv)
|
|
for d in d1x + d2x:
|
|
d.init(substenv)
|
|
h += d.PROGRAM_NAME + ('.%d:\n' % d.program_instance) + d.GenerateHelpText()
|
|
Help(h)
|
|
|
|
#EOF
|