Skip to content

Add x86_64 (64-bit) build support#39

Open
moonexpr wants to merge 8 commits into
KyleSanderson:masterfrom
moonexpr:x86_64-support
Open

Add x86_64 (64-bit) build support#39
moonexpr wants to merge 8 commits into
KyleSanderson:masterfrom
moonexpr:x86_64-support

Conversation

@moonexpr

@moonexpr moonexpr commented Jun 16, 2026

Copy link
Copy Markdown

Summary

Team Fortress 2's dedicated server (and other Source games) now ship a 64-bit
srcds, and SourceMod 1.12 has matching 64-bit support — but SteamWorks only
builds for x86, so it can't be loaded on a 64-bit server. This generalizes the
build to multi-arch (x86 + x86_64), following the modern AlliedModders
pattern (as used by e.g. sourcetvmanager), so a 64-bit SteamWorks.ext.so can
be produced. x86 still builds exactly as before — no functional or API change
for existing users.

What changed

Build system

  • configure.py: --target--targets (comma-separated arch list).
  • AMBuildScript: dict-form platformSpec + SDK.shouldBuild(); per-arch
    all_targets loop; drop hardcoded -m32 / /MACHINE:X86; add -fPIC and
    COMPILER_MSVC64 for x86_64; bump to C++17; modernize the gcc version gates
    (cxx.family + vendor-prefixed versions) so -Wno-unused-result et al.
    actually apply on a current gcc.
  • Add the tf2 SDK (WinLinux64). sdk2013 stays x86-only because it ships no
    lib/public/linux64 tier libs; 64-bit builds against a 64-bit-capable SDK
    (e.g. -s tf2).
  • buildbot/PackageScript: route x86_64 binaries to
    addons/sourcemod/extensions/x64/ (SourceMod 1.12 convention).
  • Extension/AMBuilder: build one binary per (sdk, arch); pick the
    arch-appropriate Steam API (redistributable_bin/linux64/libsteam_api.so,
    win64/steam_api64.lib).

Detours (the only genuinely x86-specific code)

  • The bundled 32-bit CDetour + hand-rolled asm/asm.c trampolines cannot work
    on x86_64. Build against SourceMod's safetyhook-based public/CDetour/detours.cpp
    instead, compiling safetyhook from the copy SourceMod bundles
    (public/safetyhook). safetyhook provides x86/x86_64 inline hooks.
  • Re-provide the DETOUR_CREATE_STATIC_FIXED convenience macro SourceMod
    dropped (the underlying CreateDetour(void*) overload still exists).

Steamworks SDK currency

  • ISteamGameServer::ForceHeartbeat() was removed from the public Steamworks
    SDK (master-server heartbeats are automatic now). The ForceHeartbeat native
    is made a no-op so existing plugins keep loading.

Building

python configure.py -s tf2 --targets x86,x86_64 \
  --hl2sdk-root <hl2sdks> --sm-path <sourcemod> --mms-path <metamod> \
  --steamworks-path <SteamworksSDK> && ambuild

against the hl2sdk tf2 branch and SourceMod / Metamod 1.12-dev.

Validation

Built x86 + x86_64 with gcc 13.3 against hl2sdk-tf2 + SourceMod 1.12. The
64-bit SteamWorks.ext.so loads on a live 64-bit TF2 srcds (SourceMod
1.12.0.7239):

 File: SteamWorks.ext.so
 Loaded: Yes (version 1.2.3)
 Binary info: API version 8
 Method: Loaded by SourceMod, attached to Metamod:Source

The binary exports GetSMExtAPI + CreateInterface and links libsteam_api.so.

Exercised end-to-end with a test plugin calling SteamWorks natives — the Steam
game-server interfaces resolve and return correct live data on the 64-bit server:

[SW-E2E] connected=1 vac=1 gotip=1 ip=167.99.111.85

(connected/vac/IP match the server's real, Steam-registered state — proving
the interface resolution actually works, not just that the extension loads.)

A GitHub Actions workflow (also added here) builds the linux + windows
x86 + x86_64 matrix green; AMBuild selects the per-arch MSVC toolchain via
AMBUILD_VCVARS_{X86,X86_64}. The Windows artifacts contain
SteamWorks.ext.dll for both extensions/ (x86) and extensions/x64/ (x86_64).

Relationship to #38

This converges with @bottiger1's earlier 64-bit PR (#38), which had the right
shape — multi-arch AMBuildScript, dropping the bundled 32-bit CDetour/asm,
the ForceHeartbeat change, the DETOUR_CREATE_STATIC_FIXED macro, and runtime
discovery of libsteam_api.so — but was left rough ("probably broke buildbot …
do what you will with this") and never merged.

This PR is a clean, complete take on the same goal: it builds safetyhook from the
copy SourceMod bundles (so the detour layer actually links), produces both x86
and x86_64, packages 64-bit binaries under extensions/x64/, and is validated
loading on a live 64-bit server. It adopts #38's dl_iterate_phdr-based
libsteam_api.so discovery
(credited in the commit) so the Steam interface
creators resolve regardless of install layout. Credit to @bottiger1 for the
original 64-bit work.

Packaging cleanup

Folded in alongside the x64 work is a small, self-contained packaging cleanup
(no interdependency with the build change):

  • delete the stale .travis.yml and .github/workflows/c-cpp.yml, both
    superseded by the ci.yml added here.
  • default configure.py --sdks to present rather than all.
  • rewrite the README with build instructions and a link to the plugin API
    (Pawn/includes/SteamWorks.inc).
  • include the commit short SHA in the CI upload-artifact name.

Limitations / not yet verified

  • The Windows .dlls build in CI (x86 + x86_64, linking steam_api64.lib)
    but were not run on a live Windows server. Windows x64 gamedata byte-patterns,
    if any are needed at runtime, are a separate concern.
  • 32-bit still builds but was not run on the (64-bit) validation server.
  • The libsteam_api.so runtime discovery was verified on a server where
    bin/libsteam_api.so is also the loaded path; it was not tested on a layout
    where the library lives elsewhere (which is the case the change is for).
  • Built against SourceMod / Metamod 1.12-dev; validated on SM 1.12.0.7239.

moonexpr added 7 commits June 16, 2026 11:31
Generalize the build from x86-only to a multi-arch (x86 + x86_64) configure,
following the modern AlliedModders pattern, so the extension can be built for
64-bit srcds (e.g. 64-bit Team Fortress 2).

Build system:
- configure.py: --target -> --targets (comma-separated arch list).
- AMBuildScript: dict-form platformSpec + SDK.shouldBuild(); per-arch
  all_targets loop; drop hardcoded -m32 / /MACHINE:X86; add -fPIC and
  COMPILER_MSVC64 for x86_64; bump to C++17; modernize gcc version gates
  (cxx.family + vendor-prefixed versions) so -Wno-unused-result etc. apply.
- Add the tf2 SDK (WinLinux64); sdk2013 stays x86-only as it ships no
  lib/public/linux64 tier libs.
- PackageScript: route x86_64 binaries to extensions/x64/ (SM 1.12 convention).
- Extension/AMBuilder: build one binary per (sdk, arch); pick the
  arch-appropriate libsteam_api.so (linux64 / win64 steam_api64.lib).

Detours (the only x86-specific code):
- Drop the bundled 32-bit CDetour + asm trampolines and build against
  SourceMod's safetyhook-based public/CDetour, compiling safetyhook from the
  copy SourceMod bundles. safetyhook provides x86_64 inline hooks.
- Re-provide the DETOUR_CREATE_STATIC_FIXED macro SM dropped (the underlying
  CreateDetour(void*) overload still exists).

SDK currency:
- ISteamGameServer::ForceHeartbeat() was removed from the public Steamworks
  SDK (heartbeats are now automatic); make the sm_ForceHeartbeat native a
  no-op so existing plugins keep loading.

Builds clean for linux x86_64 against hl2sdk-tf2 + SourceMod 1.12.
The Steam API library path was hardcoded to the 32-bit "./bin/libsteam_api.so"
layout, which is not guaranteed to exist on a 64-bit srcds. Discover the
actually-loaded library via dl_iterate_phdr so the Steam interface creators
resolve regardless of architecture / install layout, falling back to the old
path and keeping the gamedata LibSteamAPI override.

Adopts the runtime-discovery approach from bottiger1's prior 64-bit PR
(KyleSanderson#38).
swtest.sp exercises the built extension by calling Steam natives that require
the game-server interfaces to have resolved, so a build can be confirmed
functional (not just loadable) on a live server. README documents the run.
The gcc arm already builds at -std=c++17 and the bundled safetyhook sub-build
sets /std:c++17 for itself, but the global MSVC arm omitted it, so the extension
translation units (which pull in the safetyhook-based CDetour headers, requiring
C++17) would compile under MSVC's default C++14 and fail. Parity fix, MSVC-only.
Builds the extension on a [ubuntu-latest, windows-latest] matrix for both arches
against hl2sdk-tf2 + SourceMod/Metamod 1.12, with the Steamworks SDK from the
rlabrecque mirror; verifies the win64 import lib before linking.
A single vsdevcmd only puts one arch's cl.exe on PATH, so AMBuild could not
build the x86_64 target (found x86 cl, errored on the arch mismatch). Set
AMBUILD_VCVARS_X86 / AMBUILD_VCVARS_X86_64 to the vcvars32/vcvars64 scripts so
AMBuild runs the matching one per target, building both arches in one job.
On modern AMBuild cxx.vendor does not equal 'msvc', so the entire MSVC flags
block (incl. /std:c++17) was skipped on Windows — MSVC then compiled the
safetyhook-based detour headers at its default C++14 and failed on std::optional.
Switch the vendor checks to cxx.like('msvc')/cxx.family (as the gcc arm and
webcon already do) so the MSVC flags actually apply.
@moonexpr moonexpr mentioned this pull request Jun 17, 2026
- remove stale CI (.travis.yml and c-cpp.yml; superseded by ci.yml)
- configure.py: default --sdks to "present" instead of "all"
- rewrite README with a link to the SteamWorks.inc plugin API + build steps
- ci: include the commit short SHA in the upload-artifact name
@moonexpr moonexpr marked this pull request as ready for review June 17, 2026 05:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant