How To Compile Without Microsoft Visual C++ (Part 2)

From ioquake3 wiki
Jump to: navigation, search

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.

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.

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.

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.

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.

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.

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.

Development only

Building the server, client, and user interface code using binaries is for debugging and testing purposes only. It is not for redistribution.

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.

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.

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.

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;
}

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.

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.

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.

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.

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.

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!