7a3e4054c7
It turns out this was already enabled on MSVC (due to /EHsc), but let's enable it on other platforms as well. Exception handling comes with a huge caveat: SourceMod and SourcePawn are not exception safe. Not only do they predate usable STL (C++11), they often predate C++03, and sometimes even C++ itself. There are many places we do not use RAII, or where we accumulate state in a way that cannot be interrupted. By enabling exceptions, we are NOT inviting general try/catch. We are still assuming that a `throw` anywhere within SourceMod will ultimately result in a crash. However, as we enable more and more STL, we are losing the ability to gracefully handle constructor failures and malloc failures. So try-catch is now enabled. It should only be used in the narrowest of circumstances: - When an exception can be thrown by a library call, and - There is no way "a priori" to tell if an exception will be thrown (for example, std::bad_alloc or std::system_error), and - Handling the exception is meaningful. Generally malloc failures should not be considered meaningful. Once memory is exhausted, the program will crash or be OOM-killed, so there's no point in handling the failure. However, cases where the allocation amount is variable may be meaningful to handle. A simple example would be CDataPack, where if a plugin leaks entries, it's better to handle this gracefully given that vector growth is geometric. Another example might be reads of a massive file or network request into a buffer. These cases should be rare, given that memory pressure is usually fatal to srcds anyway. But if you've decided to handle an exception, the try-catch block should be as narrow as possible. For example, the following is erroneous: ke::Maybe<SomeGiganticThing> object; try { object.init(); } catch (const std::bad_alloc&) { } `ke::Maybe` is not threadsafe, and this can leak. Basically, do as little as possible in try blocks, and use them sparingly, because they're very difficult to audit. We are also not inviting use of `throw`, as auditing it is even more complex than try/catch. It is better to abort(), or use boolean returns and two-stage object initialization.
709 lines
24 KiB
Python
709 lines
24 KiB
Python
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
|
import os, sys
|
|
|
|
class SDK(object):
|
|
def __init__(self, sdk, ext, aDef, name, platform, dir):
|
|
self.folder = 'hl2sdk-' + dir
|
|
self.envvar = sdk
|
|
self.ext = ext
|
|
self.code = aDef
|
|
self.define = name
|
|
self.platform = platform
|
|
self.name = dir
|
|
self.path = None # Actual path
|
|
self.platformSpec = platform
|
|
|
|
# By default, nothing supports x64.
|
|
if type(platform) is list:
|
|
self.platformSpec = {p: ['x86'] for p in platform}
|
|
else:
|
|
self.platformSpec = platform
|
|
|
|
def shouldBuild(self, target, archs):
|
|
if target.platform not in self.platformSpec:
|
|
return False
|
|
if not len([i for i in self.platformSpec[target.platform] if i in archs]):
|
|
return False
|
|
return True
|
|
|
|
WinOnly = ['windows']
|
|
WinLinux = ['windows', 'linux']
|
|
WinLinuxMac = ['windows', 'linux', 'mac']
|
|
CSGO = {
|
|
'windows': ['x86'],
|
|
'linux': ['x86', 'x64'],
|
|
'mac': ['x64']
|
|
}
|
|
|
|
PossibleSDKs = {
|
|
'episode1': SDK('HL2SDK', '2.ep1', '1', 'EPISODEONE', WinLinux, 'episode1'),
|
|
'ep2': SDK('HL2SDKOB', '2.ep2', '3', 'ORANGEBOX', WinLinux, 'orangebox'),
|
|
'css': SDK('HL2SDKCSS', '2.css', '6', 'CSS', WinLinuxMac, 'css'),
|
|
'hl2dm': SDK('HL2SDKHL2DM', '2.hl2dm', '7', 'HL2DM', WinLinuxMac, 'hl2dm'),
|
|
'dods': SDK('HL2SDKDODS', '2.dods', '8', 'DODS', WinLinuxMac, 'dods'),
|
|
'sdk2013': SDK('HL2SDK2013', '2.sdk2013', '9', 'SDK2013', WinLinuxMac, 'sdk2013'),
|
|
'tf2': SDK('HL2SDKTF2', '2.tf2', '11', 'TF2', WinLinuxMac, 'tf2'),
|
|
'l4d': SDK('HL2SDKL4D', '2.l4d', '12', 'LEFT4DEAD', WinLinuxMac, 'l4d'),
|
|
'nucleardawn': SDK('HL2SDKND', '2.nd', '13', 'NUCLEARDAWN', WinLinuxMac, 'nucleardawn'),
|
|
'l4d2': SDK('HL2SDKL4D2', '2.l4d2', '15', 'LEFT4DEAD2', WinLinuxMac, 'l4d2'),
|
|
'darkm': SDK('HL2SDK-DARKM', '2.darkm', '2', 'DARKMESSIAH', WinOnly, 'darkm'),
|
|
'swarm': SDK('HL2SDK-SWARM', '2.swarm', '16', 'ALIENSWARM', WinOnly, 'swarm'),
|
|
'bgt': SDK('HL2SDK-BGT', '2.bgt', '4', 'BLOODYGOODTIME', WinOnly, 'bgt'),
|
|
'eye': SDK('HL2SDK-EYE', '2.eye', '5', 'EYE', WinOnly, 'eye'),
|
|
'csgo': SDK('HL2SDKCSGO', '2.csgo', '21', 'CSGO', CSGO, 'csgo'),
|
|
'portal2': SDK('HL2SDKPORTAL2', '2.portal2', '17', 'PORTAL2', [], 'portal2'),
|
|
'blade': SDK('HL2SDKBLADE', '2.blade', '18', 'BLADE', WinOnly, 'blade'),
|
|
'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '19', 'INSURGENCY', WinLinuxMac, 'insurgency'),
|
|
'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '14', 'CONTAGION', WinOnly, 'contagion'),
|
|
'bms': SDK('HL2SDKBMS', '2.bms', '10', 'BMS', WinLinux, 'bms'),
|
|
'doi': SDK('HL2SDKDOI', '2.doi', '20', 'DOI', WinLinuxMac, 'doi'),
|
|
}
|
|
|
|
def ResolveEnvPath(env, folder):
|
|
if env in os.environ:
|
|
path = os.environ[env]
|
|
if os.path.isdir(path):
|
|
return path
|
|
return None
|
|
|
|
head = os.getcwd()
|
|
oldhead = None
|
|
while head != None and head != oldhead:
|
|
path = os.path.join(head, folder)
|
|
if os.path.isdir(path):
|
|
return path
|
|
oldhead = head
|
|
head, tail = os.path.split(head)
|
|
|
|
return None
|
|
|
|
def Normalize(path):
|
|
return os.path.abspath(os.path.normpath(path))
|
|
|
|
def SetArchFlags(compiler, arch, platform):
|
|
if compiler.behavior == 'gcc':
|
|
if arch == 'x86':
|
|
compiler.cflags += ['-m32']
|
|
compiler.linkflags += ['-m32']
|
|
if platform == 'mac':
|
|
compiler.linkflags += ['-arch', 'i386']
|
|
elif arch == 'x64':
|
|
compiler.cflags += ['-m64', '-fPIC']
|
|
compiler.linkflags += ['-m64']
|
|
if platform == 'mac':
|
|
compiler.linkflags += ['-arch', 'x86_64']
|
|
elif compiler.like('msvc'):
|
|
if builder.target.arch == 'x86':
|
|
compiler.linkflags += ['/MACHINE:X86']
|
|
elif builder.target.arch == 'x64':
|
|
compiler.linkflags += ['/MACHINE:X64']
|
|
|
|
def AppendArchSuffix(binary, name, arch):
|
|
if arch == 'x64':
|
|
binary.localFolder = name + '.x64'
|
|
|
|
class SMConfig(object):
|
|
def __init__(self):
|
|
self.sdks = {}
|
|
self.binaries = []
|
|
self.extensions = []
|
|
self.generated_headers = None
|
|
self.mms_root = None
|
|
self.mysql_root = {}
|
|
self.spcomp = None
|
|
self.spcomp_bins = None
|
|
self.smx_files = {}
|
|
self.versionlib = None
|
|
self.archs = builder.target.arch.replace('x86_64', 'x64').split(',')
|
|
|
|
def use_auto_versioning(self):
|
|
if builder.backend != 'amb2':
|
|
return False
|
|
return not getattr(builder.options, 'disable_auto_versioning', False)
|
|
|
|
@property
|
|
def tag(self):
|
|
if builder.options.debug == '1':
|
|
return 'Debug'
|
|
return 'Release'
|
|
|
|
def detectProductVersion(self):
|
|
builder.AddConfigureFile('product.version')
|
|
|
|
# For OS X dylib versioning
|
|
import re
|
|
with open(os.path.join(builder.sourcePath, 'product.version'), 'r') as fp:
|
|
productContents = fp.read()
|
|
m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
|
|
if m == None:
|
|
self.productVersion = '1.0.0'
|
|
else:
|
|
major, minor, release = m.groups()
|
|
self.productVersion = '{0}.{1}.{2}'.format(major, minor, release)
|
|
|
|
def detectSDKs(self):
|
|
sdk_list = builder.options.sdks.split(',')
|
|
use_none = sdk_list[0] == 'none'
|
|
use_all = sdk_list[0] == 'all'
|
|
use_present = sdk_list[0] == 'present'
|
|
|
|
for sdk_name in PossibleSDKs:
|
|
sdk = PossibleSDKs[sdk_name]
|
|
if sdk.shouldBuild(builder.target, self.archs):
|
|
if builder.options.hl2sdk_root:
|
|
sdk_path = os.path.join(builder.options.hl2sdk_root, sdk.folder)
|
|
else:
|
|
sdk_path = ResolveEnvPath(sdk.envvar, sdk.folder)
|
|
if sdk_path is None or not os.path.isdir(sdk_path):
|
|
if use_all or sdk_name in sdk_list:
|
|
raise Exception('Could not find a valid path for {0}'.format(sdk.envvar))
|
|
continue
|
|
if use_all or use_present or sdk_name in sdk_list:
|
|
sdk.path = Normalize(sdk_path)
|
|
self.sdks[sdk_name] = sdk
|
|
|
|
if len(self.sdks) < 1 and len(sdk_list) and not use_none:
|
|
raise Exception('No SDKs were found that build on {0}-{1}, nothing to do.'.format(
|
|
builder.target.platform, builder.target.arch))
|
|
|
|
if builder.options.mms_path:
|
|
self.mms_root = builder.options.mms_path
|
|
else:
|
|
self.mms_root = ResolveEnvPath('MMSOURCE110', 'mmsource-1.10')
|
|
if not self.mms_root:
|
|
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source')
|
|
if not self.mms_root:
|
|
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'mmsource-central')
|
|
|
|
if not self.mms_root or not os.path.isdir(self.mms_root):
|
|
raise Exception('Could not find a source copy of Metamod:Source')
|
|
self.mms_root = Normalize(self.mms_root)
|
|
|
|
if builder.options.hasMySql:
|
|
if builder.options.mysql_path:
|
|
self.mysql_root['x86'] = builder.options.mysql_path
|
|
else:
|
|
for i in range(10):
|
|
self.mysql_root['x86'] = ResolveEnvPath('MYSQL55', 'mysql-5.' + str(i))
|
|
if self.mysql_root['x86']:
|
|
break
|
|
if not self.mysql_root['x86'] or not os.path.isdir(self.mysql_root['x86']):
|
|
raise Exception('Could not find a path to MySQL!')
|
|
self.mysql_root['x86'] = Normalize(self.mysql_root['x86'])
|
|
|
|
# For now, ignore 64-bit MySQL on Windows
|
|
if 'x64' in self.archs and builder.target.platform != 'windows':
|
|
if builder.options.mysql64_path:
|
|
self.mysql_root['x64'] = builder.options.mysql64_path
|
|
else:
|
|
for i in range(10):
|
|
self.mysql_root['x64'] = ResolveEnvPath('MYSQL55_64', 'mysql-5.' + str(i) + '-x86_64')
|
|
if self.mysql_root['x64']:
|
|
break
|
|
if not self.mysql_root['x64'] or not os.path.isdir(self.mysql_root['x64']):
|
|
raise Exception('Could not find a path to 64-bit MySQL!')
|
|
self.mysql_root['x64'] = Normalize(self.mysql_root['x64'])
|
|
|
|
def configure(self):
|
|
builder.AddConfigureFile('pushbuild.txt')
|
|
|
|
if not set(self.archs).issubset(['x86', 'x64']):
|
|
raise Exception('Unknown target architecture: {0}'.format(builder.target.arch))
|
|
|
|
cxx = builder.DetectCxx()
|
|
|
|
if cxx.like('msvc') and len(self.archs) > 1:
|
|
raise Exception('Building multiple archs with MSVC is not currently supported')
|
|
|
|
if cxx.family == 'msvc':
|
|
if cxx.version < 1900:
|
|
raise Exception('Only MSVC 2015 and later are supported, c++14 support is required.')
|
|
if cxx.family == 'gcc':
|
|
if cxx.version < 'gcc-4.9':
|
|
raise Exception('Only GCC versions 4.9 or greater are supported, c++14 support is required.')
|
|
if cxx.family == 'clang':
|
|
if cxx.version < 'clang-3.4':
|
|
raise Exception('Only clang versions 3.4 or greater are supported, c++14 support is required.')
|
|
|
|
if cxx.like('gcc'):
|
|
self.configure_gcc(cxx)
|
|
elif cxx.family == 'msvc':
|
|
self.configure_msvc(cxx)
|
|
|
|
# Optimizaiton
|
|
if builder.options.opt == '1':
|
|
cxx.defines += ['NDEBUG']
|
|
|
|
# Debugging
|
|
if builder.options.debug == '1':
|
|
cxx.defines += ['DEBUG', '_DEBUG']
|
|
|
|
# Platform-specifics
|
|
if builder.target.platform == 'linux':
|
|
self.configure_linux(cxx)
|
|
elif builder.target.platform == 'mac':
|
|
self.configure_mac(cxx)
|
|
elif builder.target.platform == 'windows':
|
|
self.configure_windows(cxx)
|
|
|
|
# Finish up.
|
|
cxx.defines += [
|
|
'SOURCEMOD_BUILD',
|
|
'SM_USE_VERSIONLIB',
|
|
]
|
|
cxx.includes += [
|
|
os.path.join(builder.sourcePath, 'public'),
|
|
]
|
|
if self.use_auto_versioning():
|
|
cxx.defines += ['SM_GENERATED_BUILD']
|
|
cxx.includes += [
|
|
os.path.join(builder.buildPath, 'includes'),
|
|
os.path.join(builder.sourcePath, 'versionlib'),
|
|
]
|
|
|
|
def configure_gcc(self, cxx):
|
|
cxx.defines += [
|
|
'stricmp=strcasecmp',
|
|
'_stricmp=strcasecmp',
|
|
'_snprintf=snprintf',
|
|
'_vsnprintf=vsnprintf',
|
|
'HAVE_STDINT_H',
|
|
'GNUC',
|
|
]
|
|
cxx.cflags += [
|
|
'-pipe',
|
|
'-fno-strict-aliasing',
|
|
'-Wall',
|
|
'-Werror',
|
|
'-Wno-unused',
|
|
'-Wno-switch',
|
|
'-Wno-array-bounds',
|
|
'-msse',
|
|
'-fvisibility=hidden',
|
|
]
|
|
|
|
if cxx.version == 'apple-clang-6.0' or cxx.version == 'clang-3.4':
|
|
cxx.cxxflags += ['-std=c++1y']
|
|
else:
|
|
cxx.cxxflags += ['-std=c++14']
|
|
|
|
cxx.cxxflags += [
|
|
'-fno-threadsafe-statics',
|
|
'-Wno-non-virtual-dtor',
|
|
'-Wno-overloaded-virtual',
|
|
'-fvisibility-inlines-hidden',
|
|
]
|
|
|
|
have_gcc = cxx.family == 'gcc'
|
|
have_clang = cxx.family == 'clang'
|
|
if cxx.version >= 'clang-3.9' or cxx.version == 'clang-3.4' or cxx.version > 'apple-clang-6.0':
|
|
cxx.cxxflags += ['-Wno-expansion-to-defined']
|
|
if cxx.version == 'clang-3.9' or cxx.version == 'apple-clang-8.0':
|
|
cxx.cflags += ['-Wno-varargs']
|
|
if cxx.version >= 'clang-3.4' or cxx.version >= 'apple-clang-7.0':
|
|
cxx.cxxflags += ['-Wno-inconsistent-missing-override']
|
|
if cxx.version >= 'clang-2.9' or cxx.version >= 'apple-clang-3.0':
|
|
cxx.cxxflags += ['-Wno-null-dereference']
|
|
if have_clang or (cxx.version >= 'gcc-4.6'):
|
|
cxx.cflags += ['-Wno-narrowing']
|
|
if have_clang or (cxx.version >= 'gcc-4.7'):
|
|
cxx.cxxflags += ['-Wno-delete-non-virtual-dtor']
|
|
if cxx.version >= 'gcc-4.8':
|
|
cxx.cflags += ['-Wno-unused-result']
|
|
if cxx.version >= 'gcc-9.0':
|
|
cxx.cxxflags += ['-Wno-class-memaccess', '-Wno-packed-not-aligned']
|
|
if have_clang:
|
|
cxx.cxxflags += ['-Wno-implicit-exception-spec-mismatch']
|
|
if cxx.version >= 'apple-clang-5.1' or cxx.version >= 'clang-3.4':
|
|
cxx.cxxflags += ['-Wno-deprecated-register']
|
|
else:
|
|
cxx.cxxflags += ['-Wno-deprecated']
|
|
cxx.cflags += ['-Wno-sometimes-uninitialized']
|
|
|
|
# Work around SDK warnings.
|
|
if cxx.version >= 'clang-10.0':
|
|
cxx.cflags += [
|
|
'-Wno-implicit-int-float-conversion',
|
|
'-Wno-tautological-overlap-compare',
|
|
]
|
|
|
|
if have_gcc:
|
|
cxx.cflags += ['-mfpmath=sse']
|
|
cxx.cflags += ['-Wno-maybe-uninitialized']
|
|
|
|
if builder.options.opt == '1':
|
|
cxx.cflags += ['-O3']
|
|
|
|
# Don't omit the frame pointer.
|
|
cxx.cflags += ['-fno-omit-frame-pointer']
|
|
|
|
def configure_msvc(self, cxx):
|
|
if builder.options.debug == '1':
|
|
cxx.cflags += ['/MTd']
|
|
cxx.linkflags += ['/NODEFAULTLIB:libcmt']
|
|
else:
|
|
cxx.cflags += ['/MT']
|
|
cxx.defines += [
|
|
'_CRT_SECURE_NO_DEPRECATE',
|
|
'_CRT_SECURE_NO_WARNINGS',
|
|
'_CRT_NONSTDC_NO_DEPRECATE',
|
|
'_ITERATOR_DEBUG_LEVEL=0',
|
|
]
|
|
cxx.cflags += [
|
|
'/W3',
|
|
]
|
|
cxx.cxxflags += [
|
|
'/EHsc',
|
|
'/GR-',
|
|
'/TP',
|
|
]
|
|
cxx.linkflags += [
|
|
'kernel32.lib',
|
|
'user32.lib',
|
|
'gdi32.lib',
|
|
'winspool.lib',
|
|
'comdlg32.lib',
|
|
'advapi32.lib',
|
|
'shell32.lib',
|
|
'ole32.lib',
|
|
'oleaut32.lib',
|
|
'uuid.lib',
|
|
'odbc32.lib',
|
|
'odbccp32.lib',
|
|
]
|
|
|
|
if builder.options.opt == '1':
|
|
cxx.cflags += ['/Ox', '/Zo']
|
|
cxx.linkflags += ['/OPT:ICF', '/OPT:REF']
|
|
|
|
if builder.options.debug == '1':
|
|
cxx.cflags += ['/Od', '/RTC1']
|
|
|
|
# This needs to be after our optimization flags which could otherwise disable it.
|
|
# Don't omit the frame pointer.
|
|
cxx.cflags += ['/Oy-']
|
|
|
|
def configure_linux(self, cxx):
|
|
cxx.defines += ['_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
|
|
cxx.linkflags += ['-lm']
|
|
if cxx.family == 'gcc':
|
|
cxx.linkflags += ['-static-libgcc']
|
|
elif cxx.family == 'clang':
|
|
cxx.linkflags += ['-lgcc_eh']
|
|
cxx.linkflags += ['-static-libstdc++']
|
|
|
|
def configure_mac(self, cxx):
|
|
cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL']
|
|
cxx.cflags += ['-mmacosx-version-min=10.7']
|
|
cxx.linkflags += [
|
|
'-mmacosx-version-min=10.7',
|
|
'-stdlib=libc++',
|
|
]
|
|
cxx.cxxflags += ['-stdlib=libc++']
|
|
|
|
def configure_windows(self, cxx):
|
|
cxx.defines += ['WIN32', '_WINDOWS']
|
|
|
|
def add_libamtl(self):
|
|
# Add libamtl.
|
|
self.libamtl = {}
|
|
for arch in self.archs:
|
|
def get_configure_fn(arch):
|
|
return lambda builder, name: self.StaticLibrary(builder, name, arch)
|
|
extra_vars = {'Configure': get_configure_fn(arch)}
|
|
libamtl = builder.Build('public/amtl/amtl/AMBuilder', extra_vars)
|
|
self.libamtl[arch] = libamtl.binary
|
|
|
|
def AddVersioning(self, binary, arch):
|
|
if builder.target.platform == 'windows':
|
|
binary.sources += ['version.rc']
|
|
binary.compiler.rcdefines += [
|
|
'BINARY_NAME="{0}"'.format(binary.outputFile),
|
|
'RC_COMPILE',
|
|
]
|
|
if self.use_auto_versioning():
|
|
binary.compiler.rcdefines += ['SM_GENERATED_BUILD']
|
|
elif builder.target.platform == 'mac':
|
|
if binary.type == 'library':
|
|
binary.compiler.postlink += [
|
|
'-compatibility_version', '1.0.0',
|
|
'-current_version', self.productVersion
|
|
]
|
|
if self.use_auto_versioning():
|
|
binary.compiler.linkflags += [self.versionlib[arch]]
|
|
binary.compiler.sourcedeps += SM.generated_headers
|
|
return binary
|
|
|
|
def LibraryBuilder(self, compiler, name, arch):
|
|
binary = compiler.Library(name)
|
|
AppendArchSuffix(binary, name, arch)
|
|
self.AddVersioning(binary, arch)
|
|
if binary.compiler.like('msvc'):
|
|
binary.compiler.linkflags += ['/SUBSYSTEM:WINDOWS']
|
|
return binary
|
|
|
|
def ProgramBuilder(self, compiler, name, arch):
|
|
binary = compiler.Program(name)
|
|
AppendArchSuffix(binary, name, arch)
|
|
self.AddVersioning(binary, arch)
|
|
if '-static-libgcc' in binary.compiler.linkflags:
|
|
binary.compiler.linkflags.remove('-static-libgcc')
|
|
if '-lgcc_eh' in binary.compiler.linkflags:
|
|
binary.compiler.linkflags.remove('-lgcc_eh')
|
|
if binary.compiler.like('gcc'):
|
|
binary.compiler.linkflags += ['-lstdc++', '-lpthread']
|
|
if binary.compiler.like('msvc'):
|
|
binary.compiler.linkflags += ['/SUBSYSTEM:CONSOLE']
|
|
return binary
|
|
|
|
def StaticLibraryBuilder(self, compiler, name, arch):
|
|
binary = compiler.StaticLibrary(name)
|
|
AppendArchSuffix(binary, name, arch)
|
|
return binary;
|
|
|
|
def Library(self, context, name, arch):
|
|
compiler = context.cxx.clone()
|
|
SetArchFlags(compiler, arch, builder.target.platform)
|
|
return self.LibraryBuilder(compiler, name, arch)
|
|
|
|
def Program(self, context, name, arch):
|
|
compiler = context.cxx.clone()
|
|
SetArchFlags(compiler, arch, builder.target.platform)
|
|
return self.ProgramBuilder(compiler, name, arch)
|
|
|
|
def StaticLibrary(self, context, name, arch):
|
|
compiler = context.cxx.clone()
|
|
SetArchFlags(compiler, arch, builder.target.platform)
|
|
return self.StaticLibraryBuilder(compiler, name, arch)
|
|
|
|
def ConfigureForExtension(self, context, compiler):
|
|
compiler.cxxincludes += [
|
|
os.path.join(context.currentSourcePath),
|
|
os.path.join(context.currentSourcePath, 'sdk'),
|
|
os.path.join(builder.sourcePath, 'public', 'extensions'),
|
|
os.path.join(builder.sourcePath, 'sourcepawn', 'include'),
|
|
os.path.join(builder.sourcePath, 'public', 'amtl', 'amtl'),
|
|
os.path.join(builder.sourcePath, 'public', 'amtl'),
|
|
]
|
|
return compiler
|
|
|
|
def ExtLibrary(self, context, name, arch):
|
|
binary = self.Library(context, name, arch)
|
|
self.ConfigureForExtension(context, binary.compiler)
|
|
return binary
|
|
|
|
def ConfigureForHL2(self, binary, sdk, arch):
|
|
compiler = binary.compiler
|
|
|
|
SetArchFlags(compiler, arch, builder.target.platform)
|
|
|
|
compiler.cxxincludes += [
|
|
os.path.join(self.mms_root, 'core'),
|
|
os.path.join(self.mms_root, 'core', 'sourcehook'),
|
|
]
|
|
|
|
defines = ['SE_' + PossibleSDKs[i].define + '=' + PossibleSDKs[i].code for i in PossibleSDKs]
|
|
compiler.defines += defines
|
|
|
|
paths = [
|
|
['public'],
|
|
['public', 'engine'],
|
|
['public', 'mathlib'],
|
|
['public', 'vstdlib'],
|
|
['public', 'tier0'],
|
|
['public', 'tier1']
|
|
]
|
|
if sdk.name == 'episode1' or sdk.name == 'darkm':
|
|
paths.append(['public', 'dlls'])
|
|
paths.append(['game_shared'])
|
|
else:
|
|
paths.append(['public', 'game', 'server'])
|
|
paths.append(['public', 'toolframework'])
|
|
paths.append(['game', 'shared'])
|
|
paths.append(['common'])
|
|
|
|
compiler.defines += ['SOURCE_ENGINE=' + sdk.code]
|
|
|
|
if sdk.name in ['sdk2013', 'bms'] and compiler.like('gcc'):
|
|
# The 2013 SDK already has these in public/tier0/basetypes.h
|
|
compiler.defines.remove('stricmp=strcasecmp')
|
|
compiler.defines.remove('_stricmp=strcasecmp')
|
|
compiler.defines.remove('_snprintf=snprintf')
|
|
compiler.defines.remove('_vsnprintf=vsnprintf')
|
|
|
|
if compiler.like('msvc'):
|
|
compiler.defines += ['COMPILER_MSVC', 'COMPILER_MSVC32']
|
|
compiler.linkflags += ['legacy_stdio_definitions.lib']
|
|
else:
|
|
compiler.defines += ['COMPILER_GCC']
|
|
|
|
if arch == 'x64':
|
|
compiler.defines += ['X64BITS', 'PLATFORM_64BITS']
|
|
|
|
# For everything after Swarm, this needs to be defined for entity networking
|
|
# to work properly with sendprop value changes.
|
|
if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']:
|
|
compiler.defines += ['NETWORK_VARS_ENABLED']
|
|
|
|
if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2']:
|
|
if builder.target.platform in ['linux', 'mac']:
|
|
compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE']
|
|
|
|
if builder.target.platform == 'linux':
|
|
if sdk.name in ['csgo', 'blade']:
|
|
compiler.linkflags.remove('-static-libstdc++')
|
|
compiler.linkflags += ['-lstdc++']
|
|
compiler.defines += ['_GLIBCXX_USE_CXX11_ABI=0']
|
|
|
|
for path in paths:
|
|
compiler.cxxincludes += [os.path.join(sdk.path, *path)]
|
|
|
|
if builder.target.platform == 'linux':
|
|
if sdk.name == 'episode1':
|
|
lib_folder = os.path.join(sdk.path, 'linux_sdk')
|
|
elif sdk.name in ['sdk2013', 'bms']:
|
|
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'linux32')
|
|
elif arch == 'x64':
|
|
lib_folder = os.path.join(sdk.path, 'lib', 'linux64')
|
|
else:
|
|
lib_folder = os.path.join(sdk.path, 'lib', 'linux')
|
|
elif builder.target.platform == 'mac':
|
|
if sdk.name in ['sdk2013', 'bms']:
|
|
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'osx32')
|
|
elif arch == 'x64':
|
|
lib_folder = os.path.join(sdk.path, 'lib', 'osx64')
|
|
else:
|
|
lib_folder = os.path.join(sdk.path, 'lib', 'mac')
|
|
|
|
if builder.target.platform in ['linux', 'mac']:
|
|
if sdk.name in ['sdk2013', 'bms'] or arch == 'x64':
|
|
compiler.postlink += [
|
|
compiler.Dep(os.path.join(lib_folder, 'tier1.a')),
|
|
compiler.Dep(os.path.join(lib_folder, 'mathlib.a'))
|
|
]
|
|
else:
|
|
compiler.postlink += [
|
|
compiler.Dep(os.path.join(lib_folder, 'tier1_i486.a')),
|
|
compiler.Dep(os.path.join(lib_folder, 'mathlib_i486.a'))
|
|
]
|
|
|
|
if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']:
|
|
if arch == 'x64':
|
|
compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces.a'))]
|
|
else:
|
|
compiler.postlink += [compiler.Dep(os.path.join(lib_folder, 'interfaces_i486.a'))]
|
|
|
|
dynamic_libs = []
|
|
if builder.target.platform == 'linux':
|
|
if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'bms', 'nucleardawn', 'l4d2', 'insurgency', 'doi']:
|
|
dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so']
|
|
elif arch == 'x64' and sdk.name in ['csgo', 'blade']:
|
|
dynamic_libs = ['libtier0_client.so', 'libvstdlib_client.so']
|
|
elif sdk.name in ['l4d', 'blade', 'insurgency', 'doi', 'csgo']:
|
|
dynamic_libs = ['libtier0.so', 'libvstdlib.so']
|
|
else:
|
|
dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so']
|
|
elif builder.target.platform == 'mac':
|
|
compiler.linkflags.append('-liconv')
|
|
dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib']
|
|
elif builder.target.platform == 'windows':
|
|
libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
|
|
if sdk.name in ['swarm', 'blade', 'insurgency', 'doi', 'csgo']:
|
|
libs.append('interfaces')
|
|
for lib in libs:
|
|
lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib'
|
|
compiler.linkflags.append(compiler.Dep(lib_path))
|
|
|
|
for library in dynamic_libs:
|
|
source_path = os.path.join(lib_folder, library)
|
|
output_path = os.path.join(binary.localFolder, library)
|
|
|
|
def make_linker(source_path, output_path):
|
|
def link(context, binary):
|
|
cmd_node, (output,) = context.AddSymlink(source_path, output_path)
|
|
return output
|
|
return link
|
|
|
|
linker = make_linker(source_path, output_path)
|
|
compiler.linkflags[0:0] = [compiler.Dep(library, linker)]
|
|
|
|
return binary
|
|
|
|
def HL2Library(self, context, name, sdk, arch):
|
|
binary = self.Library(context, name, arch)
|
|
self.ConfigureForExtension(context, binary.compiler)
|
|
return self.ConfigureForHL2(binary, sdk, arch)
|
|
|
|
def HL2Project(self, context, name):
|
|
project = context.cxx.LibraryProject(name)
|
|
self.ConfigureForExtension(context, project.compiler)
|
|
return project
|
|
|
|
def HL2Config(self, project, name, sdk, arch):
|
|
binary = project.Configure(name, '{0} - {1}'.format(self.tag, sdk.name))
|
|
AppendArchSuffix(binary, name, arch)
|
|
self.AddVersioning(binary, arch)
|
|
return self.ConfigureForHL2(binary, sdk, arch)
|
|
|
|
SM = SMConfig()
|
|
SM.detectProductVersion()
|
|
SM.detectSDKs()
|
|
SM.configure()
|
|
SM.add_libamtl()
|
|
|
|
if SM.use_auto_versioning():
|
|
SM.generated_headers = builder.Build(
|
|
'tools/buildbot/Versioning',
|
|
{ 'SM': SM }
|
|
)
|
|
SM.versionlib = builder.Build(
|
|
'versionlib/AMBuilder',
|
|
{ 'SM': SM }
|
|
)
|
|
|
|
# Build SourcePawn externally.
|
|
SP = builder.Build('sourcepawn/AMBuildScript', {
|
|
'external_root': SM,
|
|
'external_amtl': os.path.join(builder.sourcePath, 'public', 'amtl'),
|
|
'external_build': ['core'],
|
|
})
|
|
if len(SP.spcomp) > 1:
|
|
SM.spcomp = SP.spcomp['x86']
|
|
else:
|
|
SM.spcomp = SP.spcomp[list(SP.spcomp.keys())[0]]
|
|
SM.spcomp_bins = list(SP.spcomp.values())
|
|
for arch in SM.archs:
|
|
SM.binaries += [
|
|
SP.libsourcepawn[arch]
|
|
]
|
|
|
|
BuildScripts = [
|
|
'loader/AMBuilder',
|
|
'core/AMBuilder',
|
|
'core/logic/AMBuilder',
|
|
'extensions/bintools/AMBuilder',
|
|
'extensions/clientprefs/AMBuilder',
|
|
'extensions/curl/AMBuilder',
|
|
'extensions/cstrike/AMBuilder',
|
|
'extensions/geoip/AMBuilder',
|
|
'extensions/mysql/AMBuilder',
|
|
'extensions/regex/AMBuilder',
|
|
'extensions/sdkhooks/AMBuilder',
|
|
'extensions/sdktools/AMBuilder',
|
|
'extensions/sqlite/AMBuilder',
|
|
'extensions/tf2/AMBuilder',
|
|
'extensions/topmenus/AMBuilder',
|
|
'extensions/updater/AMBuilder',
|
|
]
|
|
|
|
if builder.backend == 'amb2':
|
|
BuildScripts += [
|
|
'plugins/AMBuilder',
|
|
'tools/buildbot/PackageScript',
|
|
]
|
|
|
|
builder.Build(BuildScripts, { 'SM': SM })
|
|
|
|
if builder.options.breakpad_dump:
|
|
builder.Build('tools/buildbot/BreakpadSymbols', { 'SM': SM })
|