Add build-rehlds-from-source/en.md
Browse Source
1 changed file
with 95 additions and 0 deletions
build-rehlds-from-source/en.md
A
| @@ -0,0 +1,95 @@ | ||
| 1 | +--- | |
| 2 | +title: "How to Build ReHLDS from Source with Docker" | |
| 3 | +excerpt: "Compile ReHLDS yourself in a reproducible Docker container instead of trusting a random binary, and verify the engine you built is the one your server loads." | |
| 4 | +category: "installation" | |
| 5 | +tags: "rehlds, compile" | |
| 6 | +image: "" | |
| 7 | +read_time: "9 min read" | |
| 8 | +--- | |
| 9 | +<p>There are two honest reasons to build ReHLDS yourself. The first is trust: you are about to run a network-facing binary as a long-lived process, and "some .so from a forum post" is not a supply chain. The second is that you want a specific commit — a fix that is merged but not yet in a tagged release. Docker makes both reproducible, because the whole 32-bit toolchain lives in a throwaway container instead of on your host.</p> | |
| 10 | + | |
| 11 | +<h2>1. What ReHLDS actually needs to build</h2> | |
| 12 | +<p>ReHLDS is a 32-bit C++ project. On Linux it builds with a 32-bit GCC/Clang toolchain, and it uses a Python-based build script. So the container needs:</p> | |
| 13 | +<ul> | |
| 14 | +<li><code>gcc-multilib</code> / <code>g++-multilib</code> (or a Clang with 32-bit support)</li> | |
| 15 | +<li><code>python3</code></li> | |
| 16 | +<li><code>git</code></li> | |
| 17 | +<li>the 32-bit development libraries (<code>libc6-dev-i386</code>)</li> | |
| 18 | +</ul> | |
| 19 | +<p>Nothing else. The project vendors what it needs.</p> | |
| 20 | + | |
| 21 | +<h2>2. A build container</h2> | |
| 22 | +<p>Write <code>Dockerfile.rehlds</code>:</p> | |
| 23 | +<pre>FROM debian:12 | |
| 24 | + | |
| 25 | +RUN dpkg --add-architecture i386 \ | |
| 26 | + && apt-get update \ | |
| 27 | + && apt-get install -y --no-install-recommends \ | |
| 28 | + build-essential gcc-multilib g++-multilib libc6-dev-i386 \ | |
| 29 | + python3 python3-pip git ca-certificates \ | |
| 30 | + && rm -rf /var/lib/apt/lists/* | |
| 31 | + | |
| 32 | +WORKDIR /src | |
| 33 | +CMD ["/bin/bash"]</pre> | |
| 34 | +<p>Build it:</p> | |
| 35 | +<pre>docker build -t rehlds-build -f Dockerfile.rehlds .</pre> | |
| 36 | + | |
| 37 | +<h2>3. Clone and check out a known commit</h2> | |
| 38 | +<p>Do this on the host so the source survives the container:</p> | |
| 39 | +<pre>mkdir -p ~/build && cd ~/build | |
| 40 | +git clone --recursive https://github.com/rehlds/rehlds.git | |
| 41 | +cd rehlds | |
| 42 | +git log --oneline -5</pre> | |
| 43 | +<p><strong>Use <code>--recursive</code>.</strong> ReHLDS pulls in submodules; a clone without them fails partway through the build with missing-header errors that look like a broken toolchain but are not. If you already cloned without it:</p> | |
| 44 | +<pre>git submodule update --init --recursive</pre> | |
| 45 | +<p>Pin what you build. Either check out the tag matching the latest release, or note the commit hash — an unpinned <code>main</code> is not reproducible and you will not be able to tell, six months later, what is actually on your server.</p> | |
| 46 | +<pre>git checkout <tag-or-commit> | |
| 47 | +git rev-parse HEAD > ../rehlds-commit.txt</pre> | |
| 48 | + | |
| 49 | +<h2>4. Build inside the container</h2> | |
| 50 | +<pre>docker run --rm -it \ | |
| 51 | + -v ~/build/rehlds:/src \ | |
| 52 | + -w /src \ | |
| 53 | + rehlds-build bash</pre> | |
| 54 | +<p>Inside the container, invoke the project's build script. ReHLDS uses a Python build wrapper at the repository root; run it with the release configuration:</p> | |
| 55 | +<pre>python3 build.py --clean</pre> | |
| 56 | +<p>If the script name or flags differ in the revision you checked out, read the repository's own build documentation rather than guessing — the project has changed build systems more than once over its life, and inventing flags will only waste your afternoon.</p> | |
| 57 | +<p>On success the artefacts land in a <code>build/</code> or <code>publish/</code> directory. The one file you care about on Linux is:</p> | |
| 58 | +<pre>engine_i486.so</pre> | |
| 59 | + | |
| 60 | +<h2>5. Sanity-check the artefact before you ship it</h2> | |
| 61 | +<p>A 64-bit build is the single most common outcome of a misconfigured multilib toolchain, and it fails at load time with a confusing error. Check the architecture explicitly:</p> | |
| 62 | +<pre>file engine_i486.so</pre> | |
| 63 | +<p>It must report:</p> | |
| 64 | +<pre>ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked</pre> | |
| 65 | +<p>If it says <code>ELF 64-bit ... x86-64</code>, the multilib packages were not actually used. Rebuild with the 32-bit flags forced, and do not deploy the 64-bit object — it will produce <code>wrong ELF class: ELFCLASS64</code> at startup (see <a href="/tutorials/fix-wrong-elf-class-elfclass64">that error</a>).</p> | |
| 66 | +<p>Check the dynamic dependencies too:</p> | |
| 67 | +<pre>ldd engine_i486.so</pre> | |
| 68 | +<p>Every entry must resolve. A <code>not found</code> line here means the target server will need that 32-bit library installed — see <a href="/tutorials/install-32bit-libraries-cs16-linux">the 32-bit library guide</a>.</p> | |
| 69 | + | |
| 70 | +<h2>6. Deploy</h2> | |
| 71 | +<pre>cd /home/steam/hlds | |
| 72 | +cp engine_i486.so engine_i486.so.bak | |
| 73 | +scp user@buildhost:~/build/rehlds/build/engine_i486.so ./engine_i486.so | |
| 74 | +chmod 644 engine_i486.so | |
| 75 | +./hlds_run -game cstrike +map de_dust2 +maxplayers 20 +sv_lan 0</pre> | |
| 76 | +<p>Then, in the console:</p> | |
| 77 | +<pre>rehlds_version</pre> | |
| 78 | +<p>It should print the version corresponding to what you built. Record the commit hash from <code>rehlds-commit.txt</code> next to the deployed binary — a year from now, "which ReHLDS is this?" is a question you will actually need to answer.</p> | |
| 79 | + | |
| 80 | +<h2>Common errors</h2> | |
| 81 | +<ul> | |
| 82 | +<li><strong><code>fatal error: sys/cdefs.h: No such file or directory</code></strong> — <code>libc6-dev-i386</code> is missing from the container.</li> | |
| 83 | +<li><strong><code>skipping incompatible /usr/lib/x86_64-linux-gnu/... when searching for -lstdc++</code></strong> — the linker is finding 64-bit libraries for a 32-bit link. <code>g++-multilib</code> is not installed, or <code>-m32</code> is not being passed.</li> | |
| 84 | +<li><strong>Missing headers from a submodule path</strong> — you cloned without <code>--recursive</code>. Run <code>git submodule update --init --recursive</code>.</li> | |
| 85 | +<li><strong>Builds fine, server segfaults on start</strong> — you built for a different ABI than the rest of your stack, or mixed a self-built engine with a much older Metamod. Test on a staging server, never straight onto the public one.</li> | |
| 86 | +</ul> | |
| 87 | + | |
| 88 | +<h2>Verification</h2> | |
| 89 | +<ol> | |
| 90 | +<li><code>file engine_i486.so</code> reports <em>ELF 32-bit, Intel 80386</em>.</li> | |
| 91 | +<li><code>ldd</code> resolves every dependency.</li> | |
| 92 | +<li>The server boots and <code>rehlds_version</code> answers.</li> | |
| 93 | +<li>A client connects and plays for a full map without a crash.</li> | |
| 94 | +</ol> | |
| 95 | +<p>Once that holds, wire it into your normal deploy. The same container pattern works for <a href="/tutorials/build-regamedll-from-source">compiling ReGameDLL_CS</a>, which is the natural next step — the two are versioned together and you want them from the same era.</p> | |
| 0 | 96 |









