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:
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 grep
ing 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!
Update: master branch got fixed7972f6d
$ ./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
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
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