HowTo: XCompile Xash3D-NG for ReactOS on Linux

January 17, 2024 @ 00:35

For about a year I haven’t updated my ReactOS server, so it was time to update everything and the new year was a good moment for that.

Installing and stuff was pretty easy, I don’t want to go into much detail about that, as it is mostly unzipping stuff and copy them somewhere. Maybe I go in a future post into detail, how this setup is built up.

Today I want to focus on the way to get an working win32 binary of Xash3D-NG, an fork of Xash3D maintained by a user called tyabus which represents the version 0.19.4 of Xash3D. This particular version is quite popular, even when a much more active developed fork, named Xash3D-FWGS (version 0.20), exists.

Reason for its popularity is, that still many of the Xash3D android apps are based on the old version, so there is a quite large user base. Unfortunately tyabus do not offer (any more?) binaries for his fork.

Update: There is a build pipeline for the Windows client binaries but no for the server ones, Github comment
I will upload my builds to http://hl.la10cy.net/downloads/ when there is a new one

So I have to compile them myself which is not such a big deal for me when it comes to compiling stuff for linux, but cross-compiling windows binaries on linux is something i am really not used to.

A year ago I already had this challange and I only remembered that it was not pretty easy for me. Compiling this time the latest master branch was a much dirtier game in comparison what I remembered from the last time and I forgot most of the things. So I want to write them down for the case I need these steps again or someone other can find some useful information from there, so I also will write about the way to the solution with all errors I came across.

 

Build environment

At first I went with my default choice, Debian stable which is bookworm 12.4 at the moment. Compiling and so on worked so far when I figured out how, but then it crashed on ReactOS:

reactos-xash3d-debian12-crash.png

The procedure entry point K32EnumProcessModules could not be located in the dynamic link library KERNEL32.dll

Mep. So let’s try compiling it on the Debian version where it worked last year, so I went with Debian 10 buster. Maybe it’s some weird library whatever new compiler stuff I don’t know and understand.

First we need some compiler, libraries and development files:

$ sudo apt install lib32gcc1-x32-cross lib32gcc1-amd64-cross g++-multilib git build-essential cmake gcc-multilib python ccache mingw-w64 mingw-w64-tools binutils-mingw-w64 binutils-mingw-w64-i686

 

Getting sauce and compile

When everything being installed, we can clone the repository

$ git clone --recursive https://github.com/tyabus/xash3d
$ cd xash3d

Do not forget the --recursive argument!

Now we can try to configure and compile the program. Luckily the Travis build scripts are in the scripts folder, so we can have a look there. I came up with this script:

#!/bin/bash

mkdir -p mingw-build
cd mingw-build
export CC="ccache i686-w64-mingw32-gcc"
export CXX="ccache i686-w64-mingw32-g++"
export CFLAGS="-static-libgcc -no-pthread"
export CXXFLAGS="-static-libgcc -static-libstdc++"

cmake -DXASH_DEDICATED=ON -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_CXX_FLAGS="-m32" -DCMAKE_C_FLAGS="-m32" ../

make -j2 VERBOSE=1
make install 

Saving this into a file build-win32.sh and make it executable chmod +x build-win32.sh and run it.

Now you should see some compile magic happen, but it will fail. In my case it failed with:

[  1%] Building RC object engine/CMakeFiles/xash.dir/__/game_launch/game.rc.obj
/bin/sh: 1: windres: not found
make[2]: *** [engine/CMakeFiles/xash.dir/build.make:1001: engine/CMakeFiles/xash.dir/__/game_launch/game.rc.obj] Error 127
make[1]: *** [CMakeFiles/Makefile2:91: engine/CMakeFiles/xash.dir/all] Error 2
make: *** [Makefile:152: all] Error 2

So I checked where i can get this windres command and found out, that there is a binary already contained in the package binutils-mingw-w64-i686 we have installed: https://packages.debian.org/search?suite … ;searchon=contents&keywords=windres

So I just tried to link it with the name CMake looked for it

$ ln -s /usr/bin/i686-w64-mingw32-windres /usr/local/bin/windres

Running build-win32.sh again it looks that we are a step forward

[  2%] Building RC object engine/CMakeFiles/xash.dir/__/game_launch/game.rc.obj
cd /home/la10cy/xash3d/mingw-build/engine && windres -O coff -DDBGHELP -DNO_LIBDL -DSINGLE_BINARY -DVECTORIZE_SINCOS -DXASH_BUILD_COMMIT="3589a50e" -DXASH_DEDICATED -DXASH_FASTSTR -DXASH_FORCEINLINE -DXASH_NONSTANDARD_LOAD -DXASH_USE_STB_SPRINTF -DXASH_W32CON -I/home/la10cy/xash3d/mingw-build/engine -I/home/la10cy/xash3d/engine/. -I/home/la10cy/xash3d/engine/common -I/home/la10cy/xash3d/engine/common/imagelib -I/home/la10cy/xash3d/engine/common/soundlib -I/home/la10cy/xash3d/engine/client -I/home/la10cy/xash3d/engine/client/vgui -I/home/la10cy/xash3d/engine/server -I/home/la10cy/xash3d/engine/../common -I/home/la10cy/xash3d/engine/../pm_shared   /home/la10cy/xash3d/game_launch/game.rc CMakeFiles/xash.dir/__/game_launch/game.rc.obj
cd /home/la10cy/xash3d/mingw-build/engine && /usr/bin/ccache  i686-w64-mingw32-gcc -DDBGHELP -DNO_LIBDL -DSINGLE_BINARY -DVECTORIZE_SINCOS -DXASH_BUILD_COMMIT="3589a50e" -DXASH_DEDICATED -DXASH_FASTSTR -DXASH_FORCEINLINE -DXASH_NONSTANDARD_LOAD -DXASH_USE_STB_SPRINTF -DXASH_W32CON @CMakeFiles/xash.dir/includes_C.rsp -m32 -O2 -g -DNDEBUG   -o CMakeFiles/xash.dir/platform/win32/con_win.c.obj   -c /home/la10cy/xash3d/engine/platform/win32/con_win.c
/home/la10cy/xash3d/game_launch/game.rc:1:10: fatal error: winver.h: No such file or directory
 #include <winver.h>
          ^~~~~~~~~~
compilation terminated.
windres: preprocessing failed.
make[2]: *** [engine/CMakeFiles/xash.dir/build.make:1001: engine/CMakeFiles/xash.dir/__/game_launch/game.rc.obj] Error 1
make[2]: *** Waiting for unfinished jobs....
make[2]: Leaving directory '/home/la10cy/xash3d/mingw-build'
make[1]: *** [CMakeFiles/Makefile2:91: engine/CMakeFiles/xash.dir/all] Error 2
make[1]: Leaving directory '/home/la10cy/xash3d/mingw-build'
make: *** [Makefile:152: all] Error 2
[  1%] Building RC object engine/CMakeFiles/xash.dir/__/game_launch/game.rc.obj
/home/la10cy/xash3d/game_launch/game.rc:1:10: fatal error: winver.h: No such file or directory
 #include <winver.h>
          ^~~~~~~~~~
compilation terminated.
windres: preprocessing failed.
make[2]: *** [engine/CMakeFiles/xash.dir/build.make:1001: engine/CMakeFiles/xash.dir/__/game_launch/game.rc.obj] Error 1
make[1]: *** [CMakeFiles/Makefile2:91: engine/CMakeFiles/xash.dir/all] Error 2
make: *** [Makefile:152: all] Error 2

Now it’s sad because it cannot find winver.h. Heading up again to https://packages.debian.org and let’s see where this file might be… It’s in the packge mingw-w64-i686-dev.

This is strange, because it should have been already installed as dependency with the other mingw packages. To check if it is there, just do a quick dpkg -l "mingw-w64-i686-dev". And yes, it is already installed

$ dpkg -l "mingw-w64-i686-dev"
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name               Version      Architecture Description
+++-==================-============-============-===============================================
ii  mingw-w64-i686-dev 6.0.0-3      all          Development files for MinGW-w64 targeting Win32

and yes, it is already installed. So that’s not the problem.

For some reason windres does not find the header files. After searching around with some search engines I learned, that you can set include paths with the compiler flags, like CFLAGS="-I/usr/i686-w64-mingw32/include/". So I added them in the script to CFLAGS and CXXFLAGS but without success.

On the verbose make output I noticed, that windres also uses this syntax to set include paths

windres -O coff -DDBGHELP -DNO_LIBDL ... -I/home/la10cy/xash3d/mingw-build/engine

So I removed the symlink in /usr/local/bin/ and replaced it with a small wrapper script

#!/bin/sh
/usr/bin/i686-w64-mingw32-windres -I/usr/i686-w64-mingw32/include $@

Making this executable and running the build script again now brings us again a small step forward, but the build still fails:

/usr/bin/ccache  i686-w64-mingw32-gcc -m32 -O2 -g -DNDEBUG   -Wl,--whole-archive CMakeFiles/xash.dir/objects.a -Wl,--no-whole-archive  -o xash_dedicated.exe -Wl,--out-implib,libxash_dedicated.dll.a -Wl,--major-image-version,0,--minor-image-version,0 @CMakeFiles/xash.dir/linklibs.rsp
/usr/bin/i686-w64-mingw32-ld: cannot find -lWs2_32
collect2: error: ld returned 1 exit status
make[2]: *** [engine/CMakeFiles/xash.dir/build.make:1182: engine/xash_dedicated.exe] Error 1
make[2]: Leaving directory '/home/la10cy/xash3d/mingw-build'
make[1]: *** [CMakeFiles/Makefile2:91: engine/CMakeFiles/xash.dir/all] Error 2
make[1]: Leaving directory '/home/la10cy/xash3d/mingw-build'
make: *** [Makefile:152: all] Error 2
[  1%] Linking C executable xash_dedicated.exe
/usr/bin/i686-w64-mingw32-ld: cannot find -lWs2_32
collect2: error: ld returned 1 exit status
make[2]: *** [engine/CMakeFiles/xash.dir/build.make:1182: engine/xash_dedicated.exe] Error 1
make[1]: *** [CMakeFiles/Makefile2:91: engine/CMakeFiles/xash.dir/all] Error 2
make: *** [Makefile:152: all] Error 2

This error said not much to me, I dont know what Ws2_32 is and why the linker (?) cannot find it, so I had to search and poke around again. After some greping for Ws2_32, which make couldn’t find, I found it in the file CMakeLists.txt and noticed that all other arguments on the same line where Ws2_32 is are lower case.

So I changed it to ws2_32 in the two mingw if branches I found in the file

diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt
index 7196ab7d..8bd6aafa 100644
--- a/engine/CMakeLists.txt
+++ b/engine/CMakeLists.txt
@@ -125,7 +125,7 @@ endif()
 if(WIN32 AND NOT XASH_64BIT)
        add_definitions( -DDBGHELP -DXASH_W32CON) # dbghelp crashhandler
        if(MINGW)
-               target_link_libraries(${XASH_ENGINE} -luser32 -lkernel32 -lgdi32 -lWs2_32 -ldbghelp -lpsapi)
+               target_link_libraries(${XASH_ENGINE} -luser32 -lkernel32 -lgdi32 -lws2_32 -ldbghelp -lpsapi)
        elseif(MSVC)
                target_link_libraries(${XASH_ENGINE} user32.lib kernel32.lib gdi32.lib Ws2_32.lib dbghelp.lib psapi.lib)
        endif()
@@ -134,7 +134,7 @@ else()
                add_definitions(-DUSE_SELECT)
        endif()
         if(MINGW)
-                target_link_libraries(${XASH_ENGINE} -luser32 -lkernel32 -lgdi32 -lWs2_32)
+                target_link_libraries(${XASH_ENGINE} -luser32 -lkernel32 -lgdi32 -lws2_32)
         elseif(MSVC)
                 target_link_libraries(${XASH_ENGINE} user32.lib kernel32.lib gdi32.lib Ws2_32.lib)
         endif()

And this did the trick!:D

Update: master branch got fixed:)7972f6d
$ ./build-win32.sh 
-- Target architecture: i386
-- Building for 32 Bit
-- git hash: 3589a50e
-- Disabled PIE for xash
-- Configuring done
-- Generating done
-- Build files have been written to: /home/la10cy/xash3d/mingw-build
/usr/bin/cmake -S/home/la10cy/xash3d -B/home/la10cy/xash3d/mingw-build --check-build-system CMakeFiles/Makefile.cmake 0
/usr/bin/cmake -E cmake_progress_start /home/la10cy/xash3d/mingw-build/CMakeFiles /home/la10cy/xash3d/mingw-build/CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/home/la10cy/xash3d/mingw-build'
make -f engine/CMakeFiles/xash.dir/build.make engine/CMakeFiles/xash.dir/depend
make[2]: Entering directory '/home/la10cy/xash3d/mingw-build'
cd /home/la10cy/xash3d/mingw-build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/la10cy/xash3d /home/la10cy/xash3d/engine /home/la10cy/xash3d/mingw-build /home/la10cy/xash3d/mingw-build/engine /home/la10cy/xash3d/mingw-build/engine/CMakeFiles/xash.dir/DependInfo.cmake --color=
make[2]: Leaving directory '/home/la10cy/xash3d/mingw-build'
make -f engine/CMakeFiles/xash.dir/build.make engine/CMakeFiles/xash.dir/build
make[2]: Entering directory '/home/la10cy/xash3d/mingw-build'
[  1%] Linking C executable xash_dedicated.exe
cd /home/la10cy/xash3d/mingw-build/engine && /usr/bin/cmake -E cmake_link_script CMakeFiles/xash.dir/link.txt --verbose=1
/usr/bin/cmake -E remove -f CMakeFiles/xash.dir/objects.a
/usr/bin/ar cr CMakeFiles/xash.dir/objects.a @CMakeFiles/xash.dir/objects1.rsp
/usr/bin/ccache  i686-w64-mingw32-gcc -m32 -O2 -g -DNDEBUG   -Wl,--whole-archive CMakeFiles/xash.dir/objects.a -Wl,--no-whole-archive  -o xash_dedicated.exe -Wl,--out-implib,libxash_dedicated.dll.a -Wl,--major-image-version,0,--minor-image-version,0 @CMakeFiles/xash.dir/linklibs.rsp
make[2]: Leaving directory '/home/la10cy/xash3d/mingw-build'
[100%] Built target xash
make[1]: Leaving directory '/home/la10cy/xash3d/mingw-build'
/usr/bin/cmake -E cmake_progress_start /home/la10cy/xash3d/mingw-build/CMakeFiles 0
[100%] Built target xash
Install the project...
-- Install configuration: "RelWithDebInfo"
-- Installing: /home/la10cy/xash3d/mingw-build/xash_dedicated.exe

Now we have our windows executable xash_dedicated.exe in mingw-build/ which can be ran on ReactOS:)

reactos-xash3d-ng-running.png

I was super happy when I had finally success. That I had to make my own small wrapper script for windres feels pretty wrong. I am super curious how a developer would solve this issue, what would be the right way to get this thing compiled.

 

What i haven’t successfully done yet is compiling the win32 client. There I have some other issues with SDL and I think what I am missing is giving the compiler the right version of SDL. But that would only a thing for the fun, the xash3d-fwgs windows client also runs well on ReactOS and is able to game on the 0.19 servers as well.

I hoped this helped someone - at least me in the future:p

 

In case someone needs the binary I compiled to run an own ReactOS Xash3D-NG 0.19 Half-Life Gamingserver, find it here:

https://hl.la10cy.net/downloads/xash3d-ng-tyabus-dedicated-mingw_3589a50.7z