Wavelength Logo
tl.jpg (2351 bytes) blank.gif (837 bytes) tr.jpg (2446 bytes)
blank.gif (837 bytes)
How to Compile the Half-Life Standard SDK on the Linux Platform by Leon Hartwig
blank.gif (837 bytes)
Contributed by: Leon Hartwig (jehannum@planethalflife.com)
Originally posted at the Phineas Bot site:
http://web.archive.org/web/20030406181629/http://www.planethalflife.com/phineas/

A very high percentage of the internet Half-Life servers are run using the Linux operating system and the Linux version of the Half-Life server. Surprisingly, aside from my own Phineas Bot, there have been no Linux versions of any mods released (to my knowledge). Hopefully, this article will change that. I will provide a step-by-step walkthrough, explaining exactly what must be edited in the Standard SDK in order to successfully compile it under Linux. Editing the Half-Life Standard SDK source code and compiling it for Linux is so easy that every mod-maker who is familiar with compiling programs under Linux, or knows someone who is, should consider it.

This article will not teach you the basics. It is written for people who know what their compilers are, and how to use them. If you don't know what a makefile is and how to use one, I would recommend that you find someone who does know and is willing to help you out with your mod.

This article does not address the Professional SDK, only the Standard SDK. I do not have the Pro SDK, nor am I interested in it. You may or may not be able to use this text as a guideline in porting the Pro SDK, but I am not supporting such use of this article.

Before I begin the walkthrough, I would like to address one of the problems that people often run into when using Windows text files in Linux. Windows text files have a ^M (carriage return) character at the end of every line that is very unfriendly to many Linux preprocessors and compilers. You will get otherwise unexplainable errors when you try to compile files with these characters in them. When you transfer source files over to a Linux OS, you must find some way of stripping those characters out of the files. There are programs that do this (many text editors will), but one good way is to use FTP. Chances are, you will already be using FTP to transfer the files to a Linux computer. The trick is to transfer .h and .cpp files in ASCII mode, rather than BINARY mode. This will strip out the ^M characters with no extra effort.

Now, on to the porting. If you are using a browser capable of color display, you will notice that tan text is used to indicate something that needs to be changed, and green text is used to indicate what the change should be:

Step #1
In the "engine/" directory, rename the file "PROGS.H" to "progs.h"
The only change is to make all of the letters in the filename lowercase.

 

Step #2
In the "engine/" directory, edit the file "eiface.h":

Near line 37, change this code block:

#define DLLEXPORT __stdcall

To this code block:

/* LINUX COMPILE */
#ifdef _WIN32
#define DLLEXPORT __stdcall
#else
#define DLLEXPORT __attribute__((stdcall))
#endif
/* END LINUX COMPILE */

 

Step #3
In the "dlls/" directory, edit the file "cbase.h":

Near line 54, change this code block:

#define EXPORT    _declspec( dllexport )

To this code block:

/* LINUX COMPILE */
#ifdef _WIN32
#define EXPORT  _declspec( dllexport )
#else
#define EXPORT
#endif
/* END LINUX COMPILE */

 

Step #4
In the "dlls/" directory, edit the file "extdll.h":

Near line 35, change this code block:

// Prevent tons of unused windows definitions
#define WIN32_LEAN_AND_MEAN
#define NOWINRES
#define NOSERVICE
#define NOMCX
#define NOIME
#include "WINDOWS.H"

// Misc C-runtime library headers
#include "STDIO.H"
#include "STDLIB.H"
#include "MATH.H"

To this code block:

/* LINUX COMPILE */
#ifdef _WIN32

// Prevent tons of unused windows definitions
#define WIN32_LEAN_AND_MEAN
#define NOWINRES
#define NOSERVICE
#define NOMCX
#define NOIME
#include "WINDOWS.H"

// Misc C-runtime library headers
#include "STDIO.H"
#include "STDLIB.H"
#include "MATH.H"

#else
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>

#define ULONG ulong
#define FALSE 0
#define TRUE  1

#ifndef max
#define max(a,b)    (((a) > (b)) ? (a) : (b))
#endif

#ifndef min
#define min(a,b)    (((a) <(b)) ? (a) : (b))
#endif

#define itoa(a,b,c) sprintf(b, "%d", a)

typedef unsigned char BYTE;
#endif
/* END LINUX COMPILE */

 

Step #5
In the "dlls/" directory, edit the file "h_export.cpp":

Near line 48, change this code block:

void DLLEXPORT GiveFnptrsToDll(   enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals )

To this code block:

/* LINUX COMPILE */
#ifdef _WIN32
void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals )
#else
extern "C" void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals )
#endif
/* END LINUX COMPILE */

Also in h_export.cpp, near line 29, change this code block:

// Required DLL entry point
BOOL WINAPI DllMain(
   HINSTANCE hinstDLL,
   DWORD fdwReason,
   LPVOID lpvReserved)
{
        if      (fdwReason == DLL_PROCESS_ATTACH)
    {
    }
        else if (fdwReason == DLL_PROCESS_DETACH)
    {
    }
        return TRUE;
}

To this code block:

/* LINUX COMPILE */
#ifdef _WIN32
// Required DLL entry point
BOOL WINAPI DllMain(
   HINSTANCE hinstDLL,
   DWORD fdwReason,
   LPVOID lpvReserved)
{
        if      (fdwReason == DLL_PROCESS_ATTACH)
    {
    }
        else if (fdwReason == DLL_PROCESS_DETACH)
    {
    }
        return TRUE;
}
#endif
/* END LINUX COMPILE */

 

Step #6
In the "dlls/" directory, edit the file "plane.cpp":

Near line 15, change this code block:

#include "extdll.h"
#include "plane.h"

To this code block:

#include "extdll.h"
/* LINUX COMPILE */
#include "util.h"
/* END LINUX COMPILE */
#include "plane.h"

 

Step #7
In the "dlls/" directory, edit the file "util.h":

Near line 89, change this code block:

#define LINK_ENTITY_TO_CLASS(mapClassName,DLLClassName) \
        extern "C" _declspec( dllexport ) void mapClassName( entvars_t *pev ); \
        void mapClassName( entvars_t *pev ) { GetClassPtr( (DLLClassName *)pev ); }

To this code block:

/* LINUX COMPILE */
#define LINK_ENTITY_TO_CLASS(mapClassName,DLLClassName) \
        extern "C" EXPORT void mapClassName( entvars_t *pev ); \
        void mapClassName( entvars_t *pev ) { GetClassPtr( (DLLClassName *)pev ); }
/* END LINUX COMPILE */

 

Step #8
In the "dlls/" directory, edit the file "util.cpp":

Near line 1597, change this code block:

unsigned int CSaveRestoreBuffer :: HashString( const char *pszToken )
{
        unsigned int    hash = 0;

        while ( *pszToken )
                hash = _rotr( hash, 4 ) ^ *pszToken++;

        return hash;
}

To this code block:

/* LINUX COMPILE */
#ifndef _WIN32
/* Thanks to Mike Harrington for this. */
extern "C" {
    unsigned _rotr ( unsigned val, int shift) {
        register unsigned lobit;         /* non-zero means lo bit set */
        register unsigned num = val;     /* number to rotate */

        shift &= 0x1f;                   /* modulo 32 -- this will also make
                                           negative shifts work */

        while (shift--) {
                lobit = num & 1;        /* get high bit */
                num >>= 1;               /* shift right one bit */
                if (lobit)
                        num |= 0x80000000;  /* set hi bit if lo bit was set */
        }

        return num;
    }
}
#endif
/* END LINUX COMPILE */

unsigned int CSaveRestoreBuffer :: HashString( const char *pszToken )
{
        unsigned int    hash = 0;

        while ( *pszToken )
                hash = _rotr( hash, 4 ) ^ *pszToken++;

        return hash;
}

That's all there is to editing the SDK. Now, you just need a good makefile and you should be all set. Luckily, I have one for you (I use gmake, by the way): Makefile.gz

If you have followed the walkthrough correctly and your Linux system isn't too much out of line with the one I use (Red Hat 5.1 with many updated packages), the SDK should compile for you. I haven't surpressed any warnings, so you will get A LOT of them. Don't let that scare you; they are nothing to be worried about in the least (if you disagree, contact me and share your concerns).

If you have done extensive modifications to the SDK, what you see in this article might not be enough to completely port your additional work to Linux. If this happens and you need some help, feel free to contact me. I have my hands full with projects of my own, so I can't guarantee that I will spend much time on your problem (if any), but it can't hurt to ask.

I am completely open to suggestions on how to improve anything you've read in this article, including the makefile.

-Jehannum
August 22, 1999

 

blank.gif (837 bytes)
bl.jpg (2471 bytes) blank.gif (837 bytes) br.jpg (2132 bytes)