DikuMUD with open-source tools
This guide details the process of migrating a legacy DikuMUD codebase (specifically ROM 2.4 or Merc derivatives) from a legacy 32-bit environment to a modern 64-bit Linux distribution. It focuses on resolving common compilation errors, pointer-to-integer casting issues, and library deprecations.

Update the Makefile for Modern GCC
Legacy Diku codebases often use outdated compiler flags. Modern GCC (v10+) defaults to '-fno-common', which causes multiple definition errors for global variables defined in headers. You must explicitly add '-fcommon' to your C_FLAGS and ensure the math and crypt libraries are linked correctly.
CC = gcc
C_FLAGS = -Wall -O2 -g -fcommon
L_FLAGS = -lcrypt -lm⚠ Common Pitfalls
- •Failure to include -lcrypt will lead to 'undefined reference to crypt' errors during the linking phase.
- •Using -O3 optimization can sometimes trigger race conditions in legacy signal handling code.
Resolve Pointer-to-Integer Casting
In 32-bit systems, pointers and integers were both 4 bytes. In 64-bit systems, pointers are 8 bytes while integers remain 4 bytes. This causes crashes in functions like act() or spell handlers where pointers are cast to (int). You must identify these casts and use (long) or (intptr_t) to prevent data truncation.
/* Bad: result = (int)vo; */
/* Good: */
result = (int)(long)vo;⚠ Common Pitfalls
- •Do not simply change all ints to longs; focus specifically on variables that store memory addresses.
- •Check the 'vo' (void pointer) usage in do_cast and spell functions specifically.
Fix Crypt Library Headers
Modern Linux distributions moved 'crypt' from unistd.h to crypt.h. You must update your includes in comm.c and any file handling password encryption to include the correct header conditionally.
#if defined(linux)
#include <crypt.h>
#endif⚠ Common Pitfalls
- •If you use an external crypt library like libxcrypt, you may need to install the development headers (libcrypt-dev) on your host machine.
Audit Shared Global Variables
DikuMUDs often define variables like 'descriptor_list' or 'char_list' in merc.h and instantiate them in db.c. Use the 'extern' keyword in the header file and define the variable in only one .c file to satisfy modern linker requirements.
/* In merc.h */
extern DESCRIPTOR_DATA *descriptor_list;
/* In comm.c */
DESCRIPTOR_DATA *descriptor_list;⚠ Common Pitfalls
- •Duplicate definitions without 'extern' will cause 'multiple definition' linker errors if -fcommon is not used.
Update Signal Handling for Modern Posix
Legacy signal handling in Diku often uses signal() which can lead to unreliable behavior. While not strictly required for compilation, switching to sigaction() prevents the MUD from hanging during heavy I/O or when receiving SIGCHLD.
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(SIGPIPE, &sa, NULL);⚠ Common Pitfalls
- •Ignoring SIGPIPE is critical for MUDs to prevent the process from terminating when a player's telnet client closes the connection abruptly.
Validate Area and Player File Paths
Legacy code often uses hardcoded relative paths (e.g., "../area/castles.are"). Ensure the directory structure matches the code's expectations. Use 'mkdir -p' to recreate the var/lib/area and player directories.
⚠ Common Pitfalls
- •Case-sensitivity: Linux is case-sensitive, whereas some legacy Diku environments (like those run on early Windows ports) were not. Ensure all filenames in the code match the disk exactly.
What you built
After completing these steps, the codebase should compile without warnings on a 64-bit architecture. Immediate next steps include running the binary with 'gdb' to catch any remaining segmentation faults during the initial area loading phase, particularly in the 'fread_string' function.