C Compilers

What is out there?

Currently, the RISC OS market has four C compilers; Acorn C (otherwise known as Norcroft), GCC, EasyC and LCC. Of these, GCC and LCC are both free. Acorn C is available from your friendly RISC OS suppliers for around £199 and EasyC from APDL for £30. The URLs for GCC and LCC are at the end of this. If you do not have an internet connection, you could make use of Archive's web retrieval system whereby you pay a small amount, and the software is sent to you.

All four compilers handle system calls differently and as such, the listings supplied in the C the WIMP series may require some slight alterations to enable them to work without any pain.

As I covered a fair while back the subject of conditional compilation (this is when the compiler comes across something like

#ifdef __arm__
 do something
#endif

#ifdef __dell__
 do something like for arm, but for dell
#endif

the compiler will compile the code for whichever machine is defined (here, it is either arm or dell) and completely ignore the other code. The same methodology can be employed for the use of other compilers as each compiler defines something which is specific to the compiler.

The internal codes

GCC defines riscos, Easy C defines __EASY_C, Norcroft defines __CC_NORCROFT and LCC defines __LCC__. These are not a complete set of definitions, but they are useful for determining which compiler is in use.

Implementing the code changes.

By using the different definitions, we can generate the code for the different compilers. It should be noted both GCC and LCC use !UnixLib as their library source, they can therefore be treated the same.

At the start of the program, it is important to the correct header files for the different compilers. These will be

/* Acorn C includes */ /* Easy C includes */
#ifdef __CC_NORCROFT #ifdef __EASY_C
#include "swis.h" #include "kernel.h"
#endif #endif
/* GCC includes */ /* LCC includes*/
#ifdef riscos #ifdef __LCC__
#include "sys/swis.h" #include "sys/swis.h"
#include "sys/os.h" #include "sys/os.h"
#endif #endif

As you can see, all four are using different header files. Each compiler (from here, GCC will also refer to LCC) requires these to perform the same tasks.

A small short cut which can also be employed is to not rely on one of the four compiler name #defines, rather to use a program specific one. This could be implemented thus

#ifndef __CC_NORCROFT
 #define COMPILER
#endif

The reason for needing these will become apparent with the following example. If you remember back to the very first of the C the WIMP series, you will see that there are two ways to call a swi.

Both are fine, just the one used by Acorn C is smaller and easier to handle, however, it is the long hand method which is employed by the non Acorn C compilers. This can be shown in the register_task function.

void register_task(void)
{
 #ifdef COMPILER
  _kernel_swi_regs r;
  r.r[0]=310;
  r.r[1]=0x4b534154;
  r.r[2]=(int)task_name;
  r.r[3]=NULL;
  _kernel_swi(Wimp_Initialise,&r,&r);
  task_handle=r.r[1];
 #else
  _swix(Wimp_Initialise,_INR(0,3)|_OUT(1),
              310,0x4b534154,task_name,NULL,&task_handle);
 #endif
}

When the compiler comes across this function when compiling the code, it will pre-process the correct code by seeing if COMPILER has been defined or not. It does not matter in this example which of the non Acorn C compilers you are using, if COMPILER has been defined, the first version of the call will be processed, otherwise, the second version is processed.

The second place where this pre-processing is required is in window creation function. Currently, EasyC defines a short as being 4 bytes. Acorn, GCC and LCC all define a short as 2 bytes. As the Wimp_CreateWindow swi requires that window minimum width and height be both 2 bytes, it is necessary to create a way to circumvent this problem.

This can be performed in the header file win.h in the following way

#ifdef __EASY_C
 #define shortint int :16
#else
 #define shortint short
#endif

then in the main window structure instead of having short win_min_width, it is replaced with shortint win_min_width. The compiler will pre-process this with the correct size for shortint. shortint is used as short has been previously defined by the compiler.

While it could be argued that to save time, all of the swi calls should be written using the _kernel_swi method (this way, the programmer only needs to write the code in one way and not have to use the #ifdef conditions), I feel it should be up to the software author to decide whichever he or she is happier with. There is nothing wrong with this. As I mainly use Acorn C for compiling my C sources, I'm more at home with the _swix/_IN|_OUT macro rather than the _kernel_swi.

As long as these changes are kept in mind, conversion from one compiler to another should not be that much of a problem. As Archive is restricted for space (the more pages Paul prints, the more it costs), I will stick with using the Acorn macros. The versions on the Acorn Education website and the next Archive CD will contain the full sources for the current crop of compilers. Should we be lucky enough to gain another C compiler, this will also be supported as and when I can obtain information on it.

GCC : http://hard-mofo.dvsr.net/gcc/
LCC : http://www.chocky.org/