ARTICLE 5 - Compiling without Microsoft Visual C++ (part II)
by HypoThermia
If you've followed the steps in the first part of the article
you should already have the Quake3 Source compiled to run on the Virtual Machine.
This final part of the article covers how to get the code compiling to produce binaries
on your platform.
It is assumed that all of the modifications you've needed to make so far have been placed in
a separate directory under \Quake3\source.
1. Compiling the binaries
Being able to compile the bytecode for the QVM is the minimum amount
of work that needs to be done with your header files. To make further development
work easier using your compiler you need to develop the means to compile
binaries from the Q3Source.
This is dictated by your compiler and platform. For command line tools
you should provide a makefile that defines the relationship between
the Q3Source and the compiled binaries. If your platform has a graphical
development environment then a project file would be desirable.
1.1. Project files
The project file is the only thing that should be placed outside your compiler
directory. As the Microsoft Visual C++ project went in the \Quake3\source
directory, so should yours. If it is a makefile then try and give
it a meaningful name like makefile.gcc.linux.
The work you've put in to understand the header files should now be
of benefit to you. If you needed to do any modifications to the Q3Source
then you shouldn't get error messages from these. Again, try to use existing
defined constants (related to your platform) within the Q3Source
to get the code compiling.
There is no substitute for familiarity with your compiler tools.
Take note that there are several files in source\game that
are also used to build the client (cgame) and user interface (ui).
It would also be beneficial to have any intermediate files created by
your compiler placed in your custom compiler directory.
Example:
Borland tools use an Integrated Development
Environment (IDE). Each of the three modules needs to be compiled to a
DLL for Win32.
Microsoft uses WIN32 to indicate compilation for Win32. The
Q3Source header files respond to this, so it needs to be defined.
The Borland IDE allows these values to be defined as part of the project
without modifying the Q3Source code. This is equivalent to the -Dxxxxxx
used with lcc.exe earlier.
Borland compilers prepend an underscore to the name of exported
functions. This conflicts with the Microsoft way of things, so each
of the exported definitions in the *.def files needs to be modified
to:
[EXPORTS]
vmMain=_vmMain
dllEntry=_dllEntry
Again, these files (one for each binary) are in the compiler specific
directory I'd created.
1.2. Using C_ONLY in the project
It is almost certainly necessary to include the following definition within
the project for each binary:
#define C_ONLY
Id wrote some Intel optimized assembler routines for some of
the performance critical math. If you can't compile that then define this
constant.
1.3. Defining constants
If the Q3Source can already be compiled for your platform using
another compiler, then you might find it beneficial to define some or all
of the constants used by that compiler. Any modifications you need to make
might be built upon this.
1.4. Handling system calls to Quake3
IMPORTANT: One other compiler option required for the Wintel
release is "data structures aligned on 4-byte boundaries". If you don't
use this option then you will see erratic and unexpected behaviour.
Each of the three binary files you need to build are equivalent to the
three bytecode files for the QVM. For the Wintel platform they are called
qagamex86.dll, cgamex86.dll, and uix86.dll.
Each requires that a file with a name like xx_syscalls.c is
included. It allows the binary to access optimized code within the Quake3
executable. You must ensure that QDECL is defined so that the
binary and executable can interface. The definition of QDECL is
in game\q_shared.h.
Get it wrong and the game will crash.
The function dllEntry() accepts the callback function in the
Quake3
executable. Despite the similar name to DllEntryPoint() used in
Win32 DLLs, it shouldn't be confused.
1.5. Making sure Quake3 can use your binaries
Only two functions need to be visible to the Quake3 executable:
vmMain()
and dllEntry(). Make sure these are exported from your binaries
in a way that Quake3 can see.
1.6. Development only
Building the server, client, and user interface code using binaries is
for debugging and testing purposes only. It is not for redistribution.
2. Making modifications
You will find that the Q3Source will generate quite a few warnings
when compiled. You should look at them to determine whether they are inconsequential.
For the most part they should be.
As you've already got Q3Source compiling to the bytecode you
shouldn't find that there are major issues.
If you should need to make modifications then keep the code portable.
If you need to introduce platform specific code that fixes problems
or issues that you discover, then try and keep the source code in a separate
file in your custom compiler directory.
3. Some possible errors
Some compilers have a slightly stricter interpretation of the C language
than others. If possible you should determine whether your compiler behaves
in the expected fashion.
3.1. Some warnings in Q3Source
Id Software have used several coding styles that can trigger warning messages.
Some can be ignored, others should at least be checked.
Errors like 'variable assigned a value but not used in function
xxxx' can be safely ignored. Whereas an error like 'Conversion
may lose significant digits' should be checked.
One error that you might see is 'Possibly incorrect assignment'. This
is caused by the following type of code:
for( j = 0; control = controls[j]; j++ )
At some point in the array controls[] an element is zero, this is guaranteed
by the usage of the array elsewhere. It also acts as a terminating condition,
the for-loop will terminate at the first zero value. It is equivalent to:
for( j = 0; (control = controls[j])==0; j++ )
and can be ignored.
3.2. Check your math library implementation
Depending on how your math library is implemented, you may find you are
getting sqrt:DOMAIN errors when using your build of cgame.
This arises from what appears to be a bug in the Quake3 executable
(build 1.15c) that results in the Q3Source trying to find a vector
perpendicular to {0,0,0}.
Fixing this is compiler dependent. You need to find a way to intercept
and ignore this error: check the help files for your compiler and its math
library. Your solution should be placed among your compiler dependent files,
The bug manifests itself when viewing demo001.dm3 with "timedemo
1".
Example:
This error is generated by the Borland math library implementation.
The solution is to include this file in the build of the client game code
(cgame):
// borland_hack.c
#include <math.h>
int _RTLENTRY _EXPFUNC _matherr(struct exception* e)
{
e->retval=1.0;
return 1;
}
4. Testing the binaries
Move the binaries into the same directory as your Quake3 executable,
and fire up Quake3.
To make sure that the binaries are tested use sv_pure=0.
Particularly important is the testing of demo001.dm3 using
"timedemo 1". If you get a sqrt:DOMAIN error then you will need to handle
this error generated by your math library.
5. Setting up and distributing your project
In setting up your work for distribution I would encourage the minimum
amount of modification to the Q3Source. You shouldn't need to go
in with a butcher's knife and make huge amounts of changes all over the
place.
5.1 Use a separate directory for your work
To help organize the changes you make I strongly recommend that you make
a directory under quake3\source to hold the files you create to
build the Q3Source successfully.
This allows more than one compiler to work from the same source distribution,
and the source\cgame, source\game and source\ui
directories don't get cluttered up.
The one exception to this is the project file you create to build binaries
for your platform. This should go in quake3\source and have a
unique and relevant name.
5.2 Document your changes
It is better for you to document your changes for someone else to apply
than redistribute modified source files. They can be integrated with an
existing project much more cleanly.
Example:
Open the header file game\q_shared.h and move to line 424, it should be:
float Q_crandom(int* seed);
Insert after it the following:
#ifdef __BORLANDC__
#ifdef random
#undef random
#endif
#endif
You might also consider distributing DIFF files.
5.3 Make your work available on the Internet
Others can then benefit from your hard work. Notify me so I can update
this site. Notify portals so others in the community can get the benefit
too.
6. Congratulations!
You've now got the Quake3 Source up and running.
You can dig in and start on that mod you've got planned. You know, the one that's
going to blow the net away!
|