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 |