# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python: import os, sys def ResolveEnvPath(env, folder): if env in os.environ: path = os.environ[env] if os.path.isdir(path): return path else: 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 SdkHelpers = builder.Eval('hl2sdk-manifests/SdkHelpers.ambuild', { 'Project': 'metamod' }) class MMSConfig(object): def __init__(self): self.sdk_manifests = [] self.sdks = {} self.sdk_targets = [] self.binaries = [] self.generated_headers = None self.versionlib = None self.all_targets = [] self.target_archs = set() if builder.options.targets: target_archs = builder.options.targets.split(',') else: target_archs = ['x86'] if builder.backend == 'amb2': target_archs.append('x86_64') for arch in target_archs: try: cxx = builder.DetectCxx(target_arch = arch) self.target_archs.add(cxx.target.arch) except Exception as e: # Error if archs were manually overridden. if builder.options.targets: raise print('Skipping target {}: {}'.format(arch, e)) continue self.all_targets.append(cxx) if not self.all_targets: raise Exception('No suitable C/C++ compiler was found.') def use_auto_versioning(self): if builder.backend != 'amb2': return False return not getattr(builder.options, 'disable_auto_versioning', False) 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(r'(\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 findSdkPath(self, sdk_name): dir_name = 'hl2sdk-{}'.format(sdk_name) if builder.options.hl2sdk_root: sdk_path = os.path.abspath(os.path.normpath(os.path.join(builder.options.hl2sdk_root, dir_name))) if os.path.exists(sdk_path): return sdk_path return ResolveEnvPath('HL2SDK{}'.format(sdk_name.upper()), dir_name) def shouldIncludeSdk(self, sdk): if sdk.get('source2', False) and self.productVersion.startswith('1.'): return False return True def detectSDKs(self): sdk_list = [s for s in builder.options.sdks.split(',') if s] SdkHelpers.sdk_filter = self.shouldIncludeSdk SdkHelpers.find_sdk_path = self.findSdkPath SdkHelpers.findSdks(builder, self.all_targets, sdk_list) self.sdks = SdkHelpers.sdks self.sdk_manifests = SdkHelpers.sdk_manifests self.sdk_targets = SdkHelpers.sdk_targets def configure(self): builder.AddConfigureFile('pushbuild.txt') for cxx in self.all_targets: if cxx.target.arch not in ['x86', 'x86_64']: raise Exception('Unknown target architecture: {0}'.format(arch)) self.configure_cxx(cxx) def configure_cxx(self, cxx): if cxx.behavior == 'gcc': cxx.defines += [ 'stricmp=strcasecmp', '_stricmp=strcasecmp', '_snprintf=snprintf', '_vsnprintf=vsnprintf', 'HAVE_STDINT_H', 'GNUC', ] cxx.cflags += [ '-pipe', '-fno-strict-aliasing', '-Wall', '-Werror', '-Wno-uninitialized', '-Wno-unused', '-Wno-switch', '-msse', '-fPIC', ] cxx.cxxflags += ['-std=c++17'] if (cxx.version >= 'gcc-4.0') or cxx.family == 'clang': cxx.cflags += ['-fvisibility=hidden'] cxx.cxxflags += ['-fvisibility-inlines-hidden'] cxx.cxxflags += [ '-fno-exceptions', '-fno-rtti', '-fno-threadsafe-statics', '-Wno-non-virtual-dtor', '-Wno-overloaded-virtual', '-Wno-register', ] if (cxx.version >= 'gcc-4.7' or cxx.family == 'clang'): cxx.cxxflags += ['-Wno-delete-non-virtual-dtor'] if cxx.family == 'gcc': cxx.cflags += ['-mfpmath=sse'] if cxx.family == 'clang': cxx.cxxflags += ['-Wno-implicit-exception-spec-mismatch'] if cxx.version >= 'clang-3.9' or cxx.version >= 'apple-clang-10.0': cxx.cxxflags += ['-Wno-expansion-to-defined'] if cxx.version >= 'clang-3.6' or cxx.version >= 'apple-clang-7.0': cxx.cxxflags += ['-Wno-inconsistent-missing-override'] if cxx.version >= 'apple-clang-5.1' or cxx.version >= 'clang-3.4': cxx.cxxflags += ['-Wno-deprecated-register'] else: cxx.cxxflags += ['-Wno-deprecated'] # Work around SDK warnings. if cxx.version >= 'clang-10.0' or cxx.version >= 'apple-clang-12.0': cxx.cflags += [ '-Wno-implicit-int-float-conversion', '-Wno-tautological-overlap-compare', ] if cxx.version >= 'clang-13.0': cxx.cflags += [ '-Wno-ordered-compare-function-pointers', ] elif cxx.like('msvc'): 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', ] cxx.cflags += [ '/W3', '/Zi', '/EHsc', '/std:c++17', ] cxx.cxxflags += ['/TP'] cxx.linkflags += [ '/SUBSYSTEM:WINDOWS', 'kernel32.lib', 'user32.lib', 'gdi32.lib', 'winspool.lib', 'comdlg32.lib', 'advapi32.lib', 'shell32.lib', 'ole32.lib', 'oleaut32.lib', 'uuid.lib', 'odbc32.lib', 'odbccp32.lib', ] # Optimization if builder.options.opt == '1': cxx.defines += ['NDEBUG'] if cxx.behavior == 'gcc': cxx.cflags += ['-O3'] elif cxx.behavior == 'msvc': cxx.cflags += ['/Ox', '/Zo'] cxx.linkflags += ['/OPT:ICF', '/OPT:REF'] # Debugging if builder.options.debug == '1': cxx.defines += ['DEBUG', '_DEBUG'] if cxx.behavior == 'gcc': cxx.cflags += ['-g3'] elif cxx.behavior == 'msvc': cxx.cflags += ['/Od', '/RTC1'] # Don't omit the frame pointer. # This needs to be after our optimization flags which could otherwise disable it. if cxx.behavior == 'gcc': cxx.cflags += ['-fno-omit-frame-pointer'] elif cxx.behavior == 'msvc': cxx.cflags += ['/Oy-'] # Platform-specifics if cxx.target.platform == 'linux': cxx.defines += ['LINUX', '_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64'] if cxx.family == 'gcc': cxx.linkflags += ['-static-libgcc'] elif cxx.family == 'clang': cxx.linkflags += ['-lgcc_eh'] cxx.linkflags += ['-static-libstdc++'] elif cxx.target.platform == 'mac': cxx.defines += ['OSX', '_OSX', 'POSIX'] if cxx.version >= 'apple-clang-10.0': cxx.cflags += ['-mmacosx-version-min=10.9', '-stdlib=libc++'] cxx.linkflags += [ '-mmacosx-version-min=10.9', ] else: cxx.cflags += ['-mmacosx-version-min=10.5'] cxx.linkflags += [ '-mmacosx-version-min=10.5', ] cxx.linkflags += [ '-stdlib=libc++', '-lc++', ] cxx.cxxflags += ['-stdlib=libc++'] elif cxx.target.platform == 'windows': cxx.defines += ['WIN32', '_WINDOWS'] # Finish up. cxx.defines += [ 'MMS_USE_VERSIONLIB' ] cxx.includes += [ os.path.join(builder.sourcePath, 'public'), os.path.join(builder.sourcePath, 'third_party', 'amtl'), ] if self.use_auto_versioning(): cxx.defines += ['MMS_GENERATED_BUILD'] cxx.includes += [ os.path.join(builder.buildPath, 'includes'), os.path.join(builder.sourcePath, 'versionlib'), ] def AddVersioning(self, binary): if binary.compiler.target.platform == 'windows': binary.sources += ['version.rc'] binary.compiler.rcdefines += [ 'BINARY_NAME="{0}"'.format(binary.outputFile), 'RC_COMPILE' ] elif binary.compiler.target.platform == 'mac' and 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[binary.compiler.target.arch]] binary.compiler.sourcedeps += MMS.generated_headers if builder.options.breakpad_dump: binary.compiler.symbol_files = 'separate' return binary def Library(self, cxx, name): binary = cxx.Library(name) self.AddVersioning(binary) if binary.compiler.like('gcc'): binary.sources += [ os.path.join(builder.sourcePath, 'third_party', 'amtl', 'compat', 'stdcxx.cpp') ] return binary def Program(self, compiler, name): binary = compiler.Program(name) compiler = binary.compiler self.AddVersioning(binary) 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++'] return binary def StaticLibrary(self, cxx, name): return cxx.StaticLibrary(name) def HL2Library(self, context, compiler, name, sdk): binary = self.Library(compiler, name) cxx = binary.compiler cxx.cxxincludes += [ os.path.join(context.currentSourcePath), os.path.join(context.currentSourcePath, 'sourcehook'), os.path.join(context.sourcePath, 'loader'), ] for other_sdk in self.sdk_manifests: cxx.defines += ['SE_{}={}'.format(other_sdk['define'], other_sdk['code'])] if sdk['source2']: cxx.defines += ['META_IS_SOURCE2'] binary.sources += [ os.path.join(sdk['path'], 'public', 'tier0', 'memoverride.cpp'), os.path.join(sdk['path'], 'tier1', 'convar.cpp'), ] SdkHelpers.configureCxx(context, binary, sdk) return binary if getattr(builder, 'target', None) is not None: sys.stderr.write("Your output folder was configured for AMBuild 2.1, and Metamod:Source\n") sys.stderr.write("is now configured to use AMBuild 2.2. Please remove your output folder\n") sys.stderr.write("and reconfigure to continue.\n") os._exit(1) MMS = MMSConfig() MMS.detectProductVersion() MMS.detectSDKs() MMS.configure() if MMS.use_auto_versioning(): MMS.generated_headers = builder.Build( 'support/buildbot/Versioning', { 'MMS': MMS } ) MMS.versionlib = builder.Build( 'versionlib/AMBuildScript', { 'MMS': MMS } ) BuildScripts = [ 'loader/AMBuilder', 'core/AMBuilder', ] if getattr(builder.options, 'enable_tests', False): BuildScripts += [ 'core/sourcehook/test/AMBuilder', ] if builder.backend == 'amb2': BuildScripts += [ 'support/buildbot/PackageScript', ] builder.Build(BuildScripts, { 'MMS': MMS }) if builder.options.breakpad_dump: builder.Build('support/buildbot/BreakpadSymbols', { 'MMS': MMS })