First, set up an environment like the client build environment. Reference the client autobuild Powershell script.
Before cloning the repos via git, turn off git's automatic CR/LF conversion: git config –global core.autocrlf false
The server will break pretty hard if some critical items have CRs in them. For example, you might get:
)EE] Got bonus line or otherwise unknown value before max stat! (
when trying to run the server, collect assets, etc.
When installing packages with Pacman, make sure you get ones from MinGW whenever possible. They are often prefixed by:
mingw64/mingw-w64-x86_64-
I used Windows' own junctions for linking the maps and arch repos, like:
C:\autobuild.server\cfsource\cfserver\lib>mklink /j maps C:\autobuild.server\cfsource\cfmaps Junction created for maps <<===>> C:\autobuild.server\cfsource\cfmaps C:\autobuild.server\cfsource\cfserver\lib>mklink /j arch C:\autobuild.server\cfsource\cfarch Junction created for arch <<===>> C:\autobuild.server\cfsource\cfarch
Run autoconf like the normal server build process:
sh autogen.sh
This should be mostly reliable.
At this point, you can call make
. However, it'll error out twice. You need to strip out some #ifdef bits, so that the MXE cross-compile stuff applies to us too:
diff --git a/common/object.cpp b/common/object.cpp index bd71d8ed7..cee1e7618 100644 --- a/common/object.cpp +++ b/common/object.cpp @@ -39,7 +39,6 @@ #include "sproto.h" #include "stringbuffer.h" -#ifdef CF_MXE_CROSS_COMPILE # define ffs(word) (__builtin_constant_p (word) \ ? __builtin_ffs (word) \ : ({ int __cnt, __tmp; \ @@ -49,7 +48,6 @@ : "=&r" (__cnt), "=r" (__tmp) \ : "rm" (word), "1" (-1)); \ __cnt + 1; })) -#endif static int compare_ob_value_lists_one(const object *, const object *); static int compare_ob_value_lists(const object *, const object *); diff --git a/socket/init.cpp b/socket/init.cpp index ed7e48940..5129d527b 100644 --- a/socket/init.cpp +++ b/socket/init.cpp @@ -97,11 +97,7 @@ void init_connection(socket_struct *ns, const char *from_ip) { SockList sl; #ifdef WIN32 /* ***WIN32 SOCKET: init win32 non blocking socket */ -#ifdef CF_MXE_CROSS_COMPILE u_long temp = 1; -#else - long temp = 1; -#endif if (ioctlsocket(ns->fd, FIONBIO , &temp) == -1) LOG(llevError, "init_connection: Error on ioctlsocket.\n");
These warnings seem mostly harmless:
CXX win32.o win32.cpp: In function 'void service_register()': win32.cpp:171:29: warning: ISO C++ forbids converting a string constant to 'wchar_t*' [-Wwrite-strin gs] 171 | #define SERVICE_DESCRIPTION L"Crossfire is a multiplayer online RPG game." | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ win32.cpp:183:31: note: in expansion of macro 'SERVICE_DESCRIPTION' 183 | wchar_t *strDescription = SERVICE_DESCRIPTION; | ^~~~~~~~~~~~~~~~~~~ win32.cpp: In function 'void service_handle()': win32.cpp:167:29: warning: ISO C++ forbids converting a string constant to 'LPWSTR' {aka 'wchar_t*'} [-Wwrite-strings] 167 | #define SERVICE_NAME L"Crossfire" | ^~~~~~~~~~~~ win32.cpp:345:11: note: in expansion of macro 'SERVICE_NAME' 345 | { SERVICE_NAME, ServiceMain }, | ^~~~~~~~~~~~
One of make
's steps is to do some kind of collect steps, so if it fails here, note that the .exe has actually been built, and might be working. See above for the notes on CRLFs.
Even if all the config/data files are missing, you should be able to call the exe with the -h
or -v
flags, and it should run cleanly.
Once this step has been passed, it will attempt to do some python stuff. I got warnings here, and Python did not appear to work:
make[3]: Entering directory '/c/autobuild.server/cfsource/cfserver/plugins/cfpython' CXX pyi_generate-pyi-generate.o CXX pyi_generate-cfpython.o CXX pyi_generate-cfpython_archetype.o CXX pyi_generate-cfpython_object.o CXX pyi_generate-cfpython_map.o CXX pyi_generate-cfpython_party.o CXX pyi_generate-cfpython_region.o CXX pyi_generate-cjson.o CXX ../common/pyi_generate-plugin_common.o CXXLD pyi-generate.exe CXX cfpython.lo CXX cfpython_archetype.lo CXX cfpython_object.lo CXX cfpython_map.lo CXX cfpython_party.lo CXX cfpython_region.lo CXX cjson.lo CXX ../common/plugin_common.lo CXXLD cfpython.la libtool: warning: undefined symbols not allowed in x86_64-w64-mingw32 shared libraries; building static only make[3]: Leaving directory '/c/autobuild.server/cfsource/cfserver/plugins/cfpython' make[2]: Leaving directory '/c/autobuild.server/cfsource/cfserver/plugins/cfpython' Making all in cfanim make[2]: Entering directory '/c/autobuild.server/cfsource/cfserver/plugins/cfanim' Making all in include make[3]: Entering directory '/c/autobuild.server/cfsource/cfserver/plugins/cfanim/include' make[3]: Nothing to be done for 'all'. make[3]: Leaving directory '/c/autobuild.server/cfsource/cfserver/plugins/cfanim/include' make[3]: Entering directory '/c/autobuild.server/cfsource/cfserver/plugins/cfanim' CXX cfanim.lo CXXLD cfanim.la libtool: warning: undefined symbols not allowed in x86_64-w64-mingw32 shared libraries; building static only make[3]: Leaving directory '/c/autobuild.server/cfsource/cfserver/plugins/cfanim'
I completely skipped any make install
steps.
Instead, I just pointed the server toward the correct config and lib folders:
Owner@DESKTOP-QH5PE0V MINGW64 /c/autobuild.server/cfsource/cfserver/server $ crossfire-server.exe -conf /c/autobuild.server/cfsource/cfserver/lib/config -data /c/autobuild.server/cfsource/cfserver/lib [II] Initializing modules
This resulted in a working server. It does throw errors about sockets, but this is not fatal. I never bothered to give it the ability to write anything to disk, so this fails as expected.
25/02/22 14:09:52 [EE] Cannot setsockopt(SO_REUSEADDR): Invalid argument 25/02/22 14:09:52 [EE] Cannot setsockopt(SO_REUSEADDR): Invalid argument 25/02/22 14:09:52 [II] Warning: Unable to open /usr/var/crossfire/accounts [No such file or directory]
Python simply doesn't work:
25/02/22 14:15:12 [EE] The requested handler doesn't exist: Python at 8/10 in map Port Gate of Scorn 25/02/22 14:15:15 [EE] The requested handler doesn't exist: Python at 6/10 in map Port Gate of Scorn
So, now trying make install
. It puts stuff in these dirs, I think:
/mingw64/etc/crossfire Contains only config files /mingw64/libexec/crossfire Contains only random_map.exe /mingw64/bin Contains lots of binaries, also crossfire-server.exe, cfdb_convert, crossloop, player_dl.pl /mingw64/var/crossfire Contains various "var-type" data dirs and files /mingw64/share/crossfire Contains various data, mostly packed /mingw64/share/man/man6 Contains crossfire and crossloop manfiles /mingw64/lib/crossfire/plugins Contains cfpython and cfanim, both .a and .la
Trying to run crossfire-server.exe
from the root dir fails, because it can't find maps:
[EE] Can't open C:/msys64/mingw64/share/crossfire/maps/HallOfSelection: No such file or directory [EE] Initial map /HallOfSelection can't be found! Please ensure maps are correctly installed. [EE] Unable to continue without initial map. Fatal error: See last error
So, we now junction maps into this location.
Now it appears to launch, but immediately dumps back to the console. The server does not appear to be running in the background, and the exit code appears to be “3”:
Owner@DESKTOP-QH5PE0V MINGW64 / $ crossfire-server [II] Initializing modules [II] citybell (Ring bells every hour for defined temples): activated [II] citylife (Add NPCs in towns): activated [II] rhg (Add random maps to exits in towns): disabled [II] Starting to collect assets from C:/msys64/mingw64/share/crossfire [II] Finished collecting assets from C:/msys64/mingw64/share/crossfire [EE] Couldn't parse todtick, using default value 0 [EE] C:/msys64/mingw64/var/crossfire/clockdata: cannot rename from C:/msys64/mingw64/var/cr ossfire/clockdata.tmp: File exists 25/02/22 20:19:53 [II] Crossfire unknown 25/02/22 20:19:53 [II] Unable to open C:/msys64/mingw64/var/crossfire/accounts [No such fil e or directory]. This may be because this is a new server and no accounts exist yet. 25/02/22 20:19:53 [II] Initialization complete (1217 ms). Waiting for connections. Owner@DESKTOP-QH5PE0V MINGW64 / $ echo $? 3
Maybe it's missing arch too? Let's try forcing a data dir:
Owner@DESKTOP-QH5PE0V MINGW64 / $ crossfire-server.exe -conf /c/autobuild.server/cfsource/cfserver/lib/config -data /c/autobuild.server/cfsource/cfserver/lib [II] Initializing modules [II] citybell (Ring bells every hour for defined temples): activated [II] citylife (Add NPCs in towns): activated [II] rhg (Add random maps to exits in towns): disabled [II] Starting to collect assets from /c/autobuild.server/cfsource/cfserver/lib [II] Finished collecting assets from /c/autobuild.server/cfsource/cfserver/lib 25/02/22 20:21:26 [II] Crossfire unknown 25/02/22 20:21:26 [EE] Cannot setsockopt(SO_REUSEADDR): Invalid argument 25/02/22 20:21:26 [EE] Cannot setsockopt(SO_REUSEADDR): Invalid argument 25/02/22 20:21:26 [II] Initialization complete (31585 ms). Waiting for connections.
Now it took much longer to init, and seems to keep running. The server again works, but python is broken.
Let's try linking arch, just in case.
No change.
Somehow, it's gotten worse. Now, when calling it from the root dir, it uses the wrong prefix to try to find stat_bonus:
Owner@DESKTOP-QH5PE0V MINGW64 / $ crossfire-server.exe [II] Initializing modules [II] citybell (Ring bells every hour for defined temples): activated [II] citylife (Add NPCs in towns): activated [II] rhg (Add random maps to exits in towns): disabled [EE] Fatal error: could not open experience table (/usr/etc/crossfire/stat_bonus) Owner@DESKTOP-QH5PE0V MINGW64 / $
It should be looking in /mingw64/etc/crossfire/stat_bonus
Forcing it to use specific paths still works: $ crossfire-server.exe -conf /c/autobuild.server/cfsource/cfserver/lib/config -data /c/autobuild.server/cfsource/cfserver/lib
If everything is loaded, but the server exits early with exit code 0 (to check: issue echo $?
), try purging var/crossfire/accounts, or all of var/crossfire.
If it exits with exit code 3, the cause is unknown, but a TCP socket stuck in TIME_WAIT is a possible culprit.
The libtool message about symbols is preventing an actual .dll file from being created. We can override libtool by editing libtool:7478 to read allow_undefined=no
.
Now, the cfpython.dll is built, but cfanim fails:
make[3]: Entering directory '/c/autobuild.server/cfsource/cfserver/plugins/cfanim' CXXLD cfanim.la C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/14.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe : .libs/cfanim.o: in function `find_by_name': C:/autobuild.server/cfsource/cfserver/plugins/cfanim/cfanim.cpp:847:(.text+0x208c): undefined refere nce to `map_space(mapstruct const*, int, int)' collect2.exe: error: ld returned 1 exit status make[3]: *** [Makefile:497: cfanim.la] Error 1 make[3]: Leaving directory '/c/autobuild.server/cfsource/cfserver/plugins/cfanim' make[2]: *** [Makefile:554: all-recursive] Error 1 make[2]: Leaving directory '/c/autobuild.server/cfsource/cfserver/plugins/cfanim' make[1]: *** [Makefile:395: all-recursive] Error 1 make[1]: Leaving directory '/c/autobuild.server/cfsource/cfserver/plugins' make: *** [Makefile:434: all-recursive] Error 1
The server looks for plugins in /usr/lib/crossfire/plugins
, so we need to manually put this into C:\msys64\usr\lib\crossfire\plugins
. Maybe make install would do it for us.
But, the server uses PLUGIN_SUFFIX
to know what files to load as plugins. According to include/win32.h, this should be .dll
, but I guess the server/Makefile.am
takes precedence. So, we rename the file to have an extension of .so
.
However, when the server tries to load it, we get 25/02/26 14:45:17 [EE] Plugin error while requesting /usr/lib/crossfire/plugins/cfpython.dll.so.initPlugin: No such process