Skip to content

Linux: get the build and a running server/client working on modern Arch - #938

Open
KonTy wants to merge 6 commits into
tswow:masterfrom
KonTy:linux-modern-toolchain
Open

KonTy wants to merge 6 commits into
tswow:masterfrom
KonTy:linux-modern-toolchain

Conversation

@KonTy

@KonTy KonTy commented Jun 14, 2026

Copy link
Copy Markdown

Bit of an update on this one. I kept going after the build stuff and ended up getting a full server + client actually running on a clean Arch install, so I fixed the runtime problems I hit along the way too. It's bigger than it started. If that's annoying to review I can split it back out, just let me know.

Point of it is that on Linux you can now clone, run the build once, and come back to a running server and the wine client without hand-following the TrinityCore wiki. Windows already does that, Linux didn't really.

Build stuff (what this PR originally was):

  • Builds under gcc 16 / cmake 4 / boost 1.9x now. Compiler comes from TSWOW_CC/TSWOW_CXX with gcc as the default, parallel make, cmake policy minimum bumped for the old vendored deps, and the little boost_system fallback for distros that dropped the per-component config.
  • Added a dependency check at the top of build.js. It looks for the toolchain/cmake/boost/openssl/mariadb/7zip etc before doing anything and if something's missing it just prints the exact pacman/apt/dnf line for you instead of blowing up with some node-gyp mess 20 minutes in. Doesn't install anything itself unless you pass --install-deps (needs root). Had to put it in build.js because it runs before the first npm install, and that already needs a compiler for the native modules.
  • If the TrinityCore submodule isn't there it tells you to run git submodule update --init --recursive instead of a cryptic cmake error.
  • Uses the system 7-Zip to unpack the world DB. The bundled 7za is windows only and the old linux path called "p7zip" which isn't actually a command on arch.
  • Doesn't choke when there's no .git (zip downloads).
  • Swapped fs.rmdir({recursive}) for fs.rm. Node 26 removed the old one and it was silently hanging the build during the header copy, took me a while to find that.

Runtime stuff (new):

  • Manages a local MariaDB itself, same as windows does with its bundled mysql - inits the datadir, starts it on a private socket, makes the tswow user. Before this linux just assumed you already had a mysql server set up and running.
  • DB host defaults to 127.0.0.1 instead of localhost. With localhost the trinitycore mysql client goes looking for a unix socket at the default path and never finds ours, so auth/worldserver couldn't open their pools. This one confused me for a while.
  • Case sensitivity for the client - finds Wow.exe whatever the case, and symlinks the uppercase .MPQ names the extractors want temporarily then removes them so the game client doesn't trip over duplicate archives.
  • Skips a missing optional patch mpq during luaxml extraction instead of aborting.
  • Client problems don't kill the server anymore. A bad client start or an extraction error used to become an unhandled rejection that killed the managed mariadb and hung the whole thing.
  • Wine client shutdown. Runs the client in its own WINEPREFIX so stopping/restarting it can kill just that wine session cleanly instead of leaving a frozen Wow.exe and its wine helpers lying around. Won't touch other wine apps you've got open.

Windows paths are untouched, it's all behind isWindows() or in the linux-only branches.

On testing - I didn't want to just eyeball it so I ran it in throwaway qemu Arch VMs from a plain cloud image with nothing installed. Bare box with only node/npm/git, ran the build with --install-deps and it pulled the missing packages, compiled trinitycore all the way under gcc, downloaded and extracted the world db, built the helper tools and finished with "Installation successful". Then the runtime brought itself up - mariadb self-initialised, dbs created and migrated, authserver up on 3724 over 127.0.0.1, worldserver built and connected. On the VM with no client it stopped at "no maps" which is correct, and on one where I copied a real 3.3.5a client in the worldserver loaded 135 maps and hit "worldserver-daemon ready". Also ran the whole thing on my own machine and logged into the world, which is how I found the client-side runtime bugs above.

The matching TrinityCore submodule changes (boost::process moving to a v1 namespace in 1.91, the asio deadline_timer stuff, a couple filesystem renames) are over in tswow/TrinityCore#52 so they can be looked at separately instead of buried in here.

Couple notes - the one behaviour change for existing linux users is the default compiler going clang -> gcc, which was already in the first version of this. TSWOW_CC/TSWOW_CXX still override. And I've only actually tested on Arch; I tried to keep the preflight distro-agnostic (it covers apt/dnf/zypper too) but I can't personally vouch for ubuntu/fedora being clean.

Fine with splitting it up or dropping bits you don't want, whatever's easiest to get in.

KonTy added 4 commits June 14, 2026 11:12
…ains

Configure changes for the Linux branch of TrinityCore.compile:

- Pick the C/C++ compiler from TSWOW_CC / TSWOW_CXX and default to gcc.
  Recent clang releases reject TrinityCore when WITH_WARNINGS is on, so gcc
  is the safer default for Linux. Users who want clang can still set the
  env vars.
- Parallelise the build with make -j $(nproc). Single-threaded make is
  brutal on a project this size; nothing else here was relying on serial
  ordering.
- Pass CMAKE_POLICY_VERSION_MINIMUM=3.5 so cmake 4 stops erroring on the
  legacy minimums that several of TrinityCore's vendored deps still use.
- Add cmake/linux/boost_system_fallback/ to CMAKE_PREFIX_PATH so distros
  that omit boost_system-<ver>/boost_system-config.cmake (the per-component
  config went missing on some distros once boost_system became header-only
  in Boost 1.87) can still satisfy find_package(Boost ... system). The
  fallback only kicks in when no real boost_system config is found.
…r/blpconverter

Same treatment the Linux TrinityCore branch just got, applied to the two
small helper builds:

- Honour TSWOW_CC / TSWOW_CXX with a gcc default.
- Run make -j $(nproc) instead of plain make.
- Pass CMAKE_POLICY_VERSION_MINIMUM=3.5 to cmake; both helpers vendor
  StormLib and a couple of other small subprojects whose top-level
  cmake_minimum_required is too old for cmake 4 to accept.
Two small fixes to the bundled helper builds, both Linux-only in practice.

CMAKE_POLICY_VERSION_MINIMUM passed on the cmake command line does not
propagate into subprojects pulled in via FetchContent_Populate +
add_subdirectory, so add a CACHE-FORCE set() right after the top-level
cmake_minimum_required() in each. That covers StormLib (mpqbuilder) and
StormLib + a few other vendored pieces (blpconverter), all of which
declare cmake_minimum_required(2.8.x) and trip cmake 4.

blpconverter also vendors zlib, libpng and libimagequant. Their bundled C
sources predate C99: they use K&R parameter lists and call lseek/read/
write/close without including unistd.h. gcc 16's default C23 treats both
as errors. Pin C compilation to gnu11, downgrade the relevant warnings
back to non-errors, and define Z_HAVE_UNISTD_H so zlib pulls the header
in itself.
TSPlayer.h declares methods with TSArray<TSItemEntry>() as a default
argument. gcc 16 has tightened the rules around when a class template's
destructor is instantiated, and now instantiates std::vector<TSItemEntry>'s
destructor when parsing this header rather than only at the call site.

The forward declaration of TSItemEntry that the header already relied on
isn't enough for that, so include the real definition. No behavioural
change; older compilers happily accept the include too.
KonTy and others added 2 commits June 26, 2026 00:10
…data)

Builds on the modern-toolchain work in this branch to close the gap between
"it compiles on Linux" and the tswow promise of "clone, run the build, walk
away, come back to a running server".

Build entry (build.js):
- Check the system packages we need before running npm i (which compiles
  native modules and needs a C toolchain + python). If something's missing we
  print the exact install line for the user's distro - pacman/apt/dnf/zypper -
  instead of dying with a node-gyp error nobody can read. An opt-in
  --install-deps runs it. Nothing is installed without the user asking.
- If the TrinityCore submodule is missing, say "git submodule update --init
  --recursive" instead of a confusing cmake failure later.
- The bootstrap failure path used to exit 0 (looked like success); it now
  exits non-zero and lists the usual causes.

Database (MySQL.ts, NodeConfig.ts):
- Manage a local MariaDB on Linux the same way Windows manages its bundled
  MySQL: init the data dir, start it on a private socket/pid, create the tswow
  user (on both localhost and 127.0.0.1). Before this, Linux just assumed an
  external server was already up and configured, which isn't the walk-away
  experience.
- Default the DB host to 127.0.0.1 so the emulator connects over TCP. With
  localhost the C++ client goes looking for a unix socket at the default path
  and can't find ours.

Client data + runtime (Dataset.ts, Client.ts, Realm.ts, luaxmlreader.cpp):
- Handle case-sensitive filesystems: find Wow.exe regardless of case, and
  temporarily symlink the uppercase .MPQ names the extraction tools want, then
  remove them so the game client doesn't choke on duplicate archives.
- Keep the more thorough hasContent() checks for what's already extracted, but
  wrap the extraction so a client problem logs and continues instead of taking
  down the database and hanging the whole process.
- luaxmlreader skips a missing optional patch archive instead of aborting.

Misc:
- Use the system 7-Zip to unpack the world database (the bundled 7za is
  Windows-only; the old Linux path called p7zip which isn't a package on Arch).
- Replace fs.rmdir({recursive}) with fs.rm - Node 26 removed the old form and
  it was silently hanging the build.
- Don't crash the build when there's no .git (zip/tarball downloads).
- Small dedup: wsys.hasCommand/resolveExe helpers shared by the MySQL and
  7-Zip code.

Tested from a clean Arch VM (nothing but node/npm/git): npm run build
--install-deps installs the rest, compiles TrinityCore, pulls and unpacks the
TDB, and finishes with "Installation successful". Then the runtime brings up
MariaDB on its own, extracts dbc/maps/vmaps from a real client (135 maps
loaded), and both authserver and worldserver come up. Also verified on the
host that a client connects and a character logs into the world.
@KonTy KonTy changed the title Linux: build on modern toolchains (gcc 16, cmake 4, Boost 1.87+) Linux: hands-off build + runtime (deps preflight, self-managed MariaDB, client data, wine client) Jul 4, 2026
@KonTy KonTy changed the title Linux: hands-off build + runtime (deps preflight, self-managed MariaDB, client data, wine client) Linux: get the build and a running server/client working on modern Arch Jul 4, 2026
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.

2 participants