diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4d5d306..aed6092 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-24.04] - sourcemod-version: [1.11-dev] + sourcemod-version: [master] libboost-version: [boost-1.82.0] python-version: ['3.10'] include: diff --git a/AMBuildScript b/AMBuildScript index d5c0188..9cbc459 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -51,7 +51,7 @@ def ResolveEnvPath(env, folder): def Normalize(path): return os.path.abspath(os.path.normpath(path)) - + def SetArchFlags(compiler): if compiler.behavior == 'gcc': if compiler.target.arch == 'x86_64': @@ -77,7 +77,7 @@ class ExtensionConfig(object): self.all_targets = [] self.target_archs = set() self.libboost_root = None - + self.libsafetyhook = {} if builder.options.targets: target_archs = builder.options.targets.split(',') @@ -125,13 +125,11 @@ class ExtensionConfig(object): if builder.options.sm_path: self.sm_root = builder.options.sm_path else: - self.sm_root = ResolveEnvPath('SOURCEMOD18', 'sourcemod-1.10') + self.sm_root = ResolveEnvPath('SOURCEMOD113', 'sourcemod-1.13') if not self.sm_root: - self.sm_root = ResolveEnvPath('SOURCEMOD', 'sourcemod-source') + self.sm_root = ResolveEnvPath('SOURCEMOD', 'sourcemod') if not self.sm_root: self.sm_root = ResolveEnvPath('SOURCEMOD_DEV', 'sourcemod-central') - if not self.sm_root: - self.sm_root = ResolveEnvPath('SOURCEMOD', 'sourcemod') if not self.sm_root or not os.path.isdir(self.sm_root): raise Exception('Could not find a source copy of Sourcemod') @@ -140,13 +138,11 @@ class ExtensionConfig(object): 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') + self.mms_root = ResolveEnvPath('MMSOURCE112', 'mmsource-1.12') if not self.mms_root: - self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'mmsource-central') + self.mms_root = ResolveEnvPath('MMSOURCE', 'metamod-source') if not self.mms_root: - self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod') + self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source') if not self.mms_root or not os.path.isdir(self.mms_root): raise Exception('Could not find a source copy of Metamod:Source') @@ -176,21 +172,21 @@ class ExtensionConfig(object): def configure_cxx(self, cxx): 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.version < 1914 and builder.options.generator != 'vs': + raise Exception(f'Only MSVC 2017 15.7 and later are supported, full C++17 support is required. ({str(cxx.version)} < 1914)') + elif cxx.family == 'gcc': + if cxx.version < 'gcc-9': + raise Exception('Only GCC versions 9 or later are supported, full C++17 support is required.') + elif cxx.family == 'clang': + if cxx.version < 'clang-5': + raise Exception('Only clang versions 5 or later are supported, full C++17 support is required.') if cxx.like('gcc'): self.configure_gcc(cxx) elif cxx.family == 'msvc': self.configure_msvc(cxx) - # Optimizaiton + # Optimization if builder.options.opt == '1': cxx.defines += ['NDEBUG'] @@ -228,20 +224,21 @@ class ExtensionConfig(object): '-Wno-unused', '-Wno-switch', '-Wno-array-bounds', - '-msse', + '-Wno-unknown-pragmas', + '-Wno-dangling-else', '-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'] + if cxx.target.arch in ['x86', 'x86_64']: + cxx.cflags += ['-msse'] cxx.cxxflags += [ '-fno-threadsafe-statics', '-Wno-non-virtual-dtor', '-Wno-overloaded-virtual', + '-Wno-register', '-fvisibility-inlines-hidden', + '-std=c++17', ] have_gcc = cxx.family == 'gcc' @@ -271,29 +268,21 @@ class ExtensionConfig(object): cxx.cflags += ['-Wno-sometimes-uninitialized'] # Work around SDK warnings. - if cxx.version >= 'clang-10.0': + 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-21.0': + cxx.cflags += ['-Wno-uninitialized-const-pointer'] + if have_gcc: cxx.cflags += ['-mfpmath=sse'] cxx.cflags += ['-Wno-maybe-uninitialized'] if builder.options.opt == '1': - cxx.cflags += [ - '-O3', - '-ftree-vectorize', - ] - if have_clang: - cxx.cflags += [ - '-fexperimental-new-pass-manager', - '-mllvm', - '-inline-threshold=1000', - '-mllvm', - '-vectorize-loops', - ] + cxx.cflags += ['-O3'] # Don't omit the frame pointer. cxx.cflags += ['-fno-omit-frame-pointer'] @@ -317,6 +306,7 @@ class ExtensionConfig(object): '/EHsc', '/GR-', '/TP', + '/std:c++17', ] cxx.linkflags += [ 'kernel32.lib', @@ -345,7 +335,7 @@ class ExtensionConfig(object): cxx.cflags += ['/Oy-'] def configure_linux(self, cxx): - cxx.defines += ['_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64'] + cxx.defines += ['LINUX', '_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64'] cxx.linkflags += ['-lm'] if cxx.family == 'gcc': cxx.linkflags += ['-static-libgcc'] @@ -358,9 +348,9 @@ class ExtensionConfig(object): def configure_mac(self, cxx): cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL'] - cxx.cflags += ['-mmacosx-version-min=10.7'] + cxx.cflags += ['-mmacosx-version-min=10.15'] cxx.linkflags += [ - '-mmacosx-version-min=10.7', + '-mmacosx-version-min=10.15', '-stdlib=libc++', '-lc++', ] @@ -393,7 +383,7 @@ class ExtensionConfig(object): '-current_version', self.productVersion ] return binary - + def LibraryBuilder(self, compiler, name): binary = compiler.Library(name) self.AddVersioning(binary) @@ -426,7 +416,7 @@ class ExtensionConfig(object): compiler = compiler.clone() SetArchFlags(compiler) return self.ProgramBuilder(compiler, name) - + def StaticLibrary(self, context, compiler, name): compiler = compiler.clone() SetArchFlags(compiler) @@ -451,6 +441,47 @@ class ExtensionConfig(object): self.ConfigureForExtension(context, binary.compiler) return binary + def AddCDetour(self, binary): + sm_public_path = os.path.join(self.sm_root, 'public') + gameconfigs_header = os.path.join(sm_public_path, 'IGameConfigs.h') + + if binary.compiler.like('msvc'): + binary.compiler.cflags += ['/FI' + gameconfigs_header] + else: + binary.compiler.cflags += ['-include', gameconfigs_header] + + if os.path.exists(os.path.join(sm_public_path, 'safetyhook')): + binary.sources += [ os.path.join(sm_public_path, 'CDetour', 'detours.cpp') ] + binary.compiler.cxxincludes += [ os.path.join(builder.sourcePath, 'safetyhook', 'include') ] + + for task in self.libsafetyhook: + if task.target.arch == binary.compiler.target.arch: + binary.compiler.linkflags += [task.binary] + return + raise Exception('No suitable build of safetyhook was found.') + else: + binary.sources += [ + os.path.join(sm_public_path, 'CDetour', 'detours.cpp'), + os.path.join(sm_public_path, 'asm', 'asm.c'), + ] + # sm1.10+ + libudis_folder = os.path.join(sm_public_path, 'libudis86') + if os.path.isdir(libudis_folder): + binary.compiler.defines += ['HAVE_STRING_H'] + binary.sources += [ + os.path.join(libudis_folder, 'decode.c'), + os.path.join(libudis_folder, 'itab.c'), + os.path.join(libudis_folder, 'syn-att.c'), + os.path.join(libudis_folder, 'syn-intel.c'), + os.path.join(libudis_folder, 'syn.c'), + os.path.join(libudis_folder, 'udis86.c'), + ] + +class SafetyHookShim(object): + def __init__(self): + self.all_targets = {} + self.libsafetyhook = {} + if getattr(builder, 'target', None) is not None: sys.stderr.write("Your output folder was configured for AMBuild 2.1, and SourceMod is now\n") sys.stderr.write("configured to use AMBuild 2.2. Please remove your output folder and\n") @@ -461,6 +492,17 @@ SM = ExtensionConfig() SM.detectSDKs() SM.configure() +if os.path.exists(os.path.join(SM.sm_root, 'public', 'safetyhook')): + # we need to pull safetyhook in locally because ambuild does not take kindly to outside relpaths + import shutil + safetyhook_dest = Normalize(builder.sourcePath + '/safetyhook/') + shutil.copytree(os.path.join(SM.sm_root, 'public', 'safetyhook'), safetyhook_dest, dirs_exist_ok=True) + + SafetyHook = SafetyHookShim() + SafetyHook.all_targets = SM.all_targets + builder.Build('safetyhook/AMBuilder', {'SafetyHook': SafetyHook }) + SM.libsafetyhook = SafetyHook.libsafetyhook + # This will clone the list and each cxx object as we recurse, preventing child # scripts from messing up global state. builder.targets = builder.CloneableList(SM.all_targets) diff --git a/AMBuilder b/AMBuilder index d570e80..3d832d4 100644 --- a/AMBuilder +++ b/AMBuilder @@ -33,13 +33,7 @@ for cxx in builder.targets: 'Callback.cpp', 'CallbackHandler.cpp', os.path.join(SM.sm_root, 'public', 'smsdk_ext.cpp'), - os.path.join(SM.sm_root, 'public', 'asm', 'asm.c'), - os.path.join(SM.sm_root, 'public', 'libudis86', 'decode.c'), - os.path.join(SM.sm_root, 'public', 'libudis86', 'itab.c'), - os.path.join(SM.sm_root, 'public', 'libudis86', 'syn-att.c'), - os.path.join(SM.sm_root, 'public', 'libudis86', 'syn-intel.c'), - os.path.join(SM.sm_root, 'public', 'libudis86', 'syn.c'), - os.path.join(SM.sm_root, 'public', 'libudis86', 'udis86.c'), ] + SM.AddCDetour(binary) SM.extensions += [builder.Add(binary)]