PS2 Linux Programming

 

The Development Process

 

The following programs are used in the development process:

 

emacs          This is a common text editor which is available for just about any platform, Linux included.

 

gcc              This is the GNU C compiler. The PS2 Linux kit comes with a special version of gcc that knows about the PS2 hardware.

 

g++             This is the C++ version of gcc.

 

make           This program automates the build process.

 

 

Writing Code

 

The starting point will be the standard “hello world” Program. Create a file called “main.c”. At the Linux command prompt, type:

 

$ emacs main.c

 

This will open emacs and start editing “main.c

 

Enter the basic “hello world” program.

 

#include <stdio.h>

int main (void)

{

printf (“hello world\n”);

return 0;

}

 

 

Save the file using Ctrl-X,Ctrl-S, then quit using Ctrl-X,Ctrl-C.

 

 

Compiling the program

 

The compiler is called with a few arguments telling it what to build, and how to built it. Type the following at the command prompt:

 

$ gcc –o main main.c

 

The “-o main” part tells gcc what to call the output file. Assuming the program was correct, gcc will make a file called “main”.

 

 

Running the program

 

To run the program, type the following command  at the prompt:

 

$ ./ main

 

The “./” at the start tells Linux to look for the program in the current folder.

If everything went to plan, the program should output “hello world”.

 

 

Multiple source files

 

All the above is just fine if there is only a single source file, but for multiple source file things need to be treated differently. In the above examples, gcc performed the compile and link steps in a single shot. With more than one file, things need to be done separately. Intermediate object files are explicitly created (which have the extension “.o”) for all the source files, and then linked together to form the final executable binary file. For instance, to compile a program that resides in “file1.c”, “file2.c” and “file3.c”, the following commands could be used:

 

$ gcc –c file1.c

$ gcc –c file2.c

$ gcc –c file3.c

$ gcc –o big_program file1.o file2.o file3.o

 

The “-c” option tells gcc to compile the file but to go no further. By default, this will generate an output file called “<filename>.o”.

 

 

Makefiles

 

As can be imagined, running gcc with a string of arguments for each source file will get tedious and prone to error. The make utility can be used to improve the process. Make works out what needs to be built and in what order to perform the build. Make then builds the executable program.

 

Before make can proceed, it needs to be told how to build the executable. Make reads its input commands from a file called “Makefile” (note the capital 'M') in the current directory. This file contains rules on how to build files. See 'info make' (at the command prompt) for more information.

 

 

Creating the Makefile

 

Creating makefiles will not be covered in detail in this tutorial. The makefile given at the end of these notes can be used to build executables from most of the C files that will be used in this tutorial series. Note that lines beginning with # are comment lines in a makefile.

 

Save this makefile into the working directory directory along with the source files. Type:

 

$ make

 

Messages should appear as make runs various programs to build the executable. Run the program using:

 

$ make run

 

or it can still be run with:

 

$ ./main

 

The comment lines in the make file outlines what is going on.

 

Make files are well documented and it is possible to find out exactly what is going on by reading the documentation. All that needs to be know for now is that to add new files to the project, simply add the file name to the OBJS list. For example if the file goodbye.c is to be added to the project the file name goodbye.o needs to be appended to the OBJS line within the makefile.

 

Any header files that are used are included as dependencies in this makefile. If new header files are added to any of the source files, or the arrangement of header files is changed, the dependency file (.depend) must be recreated by executing:

 

$ make depend

 

To start from fresh build, all the intermediate files that have been created are deleted with:

 

$ make clean

 

Rebuild the executable file with:

 

$ make depend

 

followed by:

 

$ make

 

The CFLAGS (Compiler flags) variable in the make file is set to the equivalent of a debug build as it tells gcc to put debug information into the program which can be used by a debugger. Once the development of a program has been completed, it can be made to run faster by replacing the debug flag (-g) with something like “-O3” (a letter O then three not zero-three). This causes gcc to optimise the code at optimisation level 3 (3 is the fastest but will take longest to compile). Levels 1 and 2 can be used for faster compile times at the expense of a little execution speed.

 

It is recommended that all compilations are performed with the –Wall compiler flag. This is a very strict mode that treats warnings as errors. This is a good practice as it can stop unforeseen problems from arising ( this is especially important for PS2 development as locking up the PS2 is a hassle and generally requires a reboot). Other compiler options can be found by reading the gcc/g++ manual – see the links below.

 

 

Debugging

 

Debugging on PS2 Linux can be accomplished using GDB. This debugger is far from great and is rather buggy. It is possible to debug without this tool with the use of printf statements to the console at any point in a program. Experiment with the development environment to come up with a method of debugging that is most convenient.

 

Assert are a very useful debugging tool. In order to use assert in a program, conditions that must be true if the program is running correctly are found and tested with an assert. For example, if x must be equal to zero at a certain point in a program then the statement -  assert(x == 0) – is entered into the code at that point. If this condition is not true. the code will exit with an error message and the program can be investigated to find out what is causing the assertion to fail.

 

When writing Playstation 2 Linux programs try not to crash the machine. With PS2 Linux there is the risk of damaging the file system if there is a crash. Also PS2 Linux takes a long time to reboot after a crash so it is best that the code is protected as much as possible with asserts. Always double check the code before it is executed.

 

 

Manuals

 

The GNU manuals are very useful and can be found online here:

 

GNU Make:

http://www.gnu.org/software/make/manual/make.html

 

GCC and G++:

http://gcc.gnu.org/onlinedocs/

(The version included with PS2 Linux is 2.95.2)

 

GDB:

http://www.gnu.org/manual/gdb-4.17/gdb.html

 

Manuals for certain tools can be browsed on the kit by typing:

 

“$ man <program>”

 

e.g. “man g++” will provide the g++ manual.

 

A similar command is “info <program>”.

 

 

Dr Henry S Fortuna

University of Abertay Dundee

h.s.fortuna@abertay.ac.uk

 

 

A standard Makefile

 

#################################################

# This makefile will build an executable made from C files.

# Henry S Fortuna

#

# To create the dependency file:

# make depend

#

# To build the executable:

# make

#

# To execute:

# make run

#

# To clean out all objects, targets and dependencies

# make clean

#################################################

 

# The target name

TARGET = main

 

# The compiler being used

CC = gcc

 

# The known file extensions

.SUFFIXES: .c .o

 

# The object files to build

OBJS = main.o

 

# The libraries to link

LIBS = -lm

 

# The compiler flags to use

# -g - produce debugging information

# -Wall - turn most of the important warnings on

# -Werror - treat warnings as errors and abort compilation

# -ffast-math - allow less checking for faster maths routines

# - fsingle-precision-constant - use single precision constants

CFLAGS = -g -Wall -Werror -ffast-math -fsingle-precision-constant

 

# build the target file from the objects

$(TARGET): $(OBJS)

              $(CC) -o $@ $(OBJS) $(CFLAGS) $(LIBS)

 

# build the object files from the c source files

.c.o:

              $(CC) -c $< $(CFLAGS) -o $@

 

# create the dependancy file      

depend:

              $(CC) $(CFLAGS) -MM *.c > .depend

             

run:

              ./main

 

# remove all the built files

clean:

              rm -f $(TARGET)

              rm -f $(OBJS)

              rm -f .depend

 

#include the dependencies into the build

-include .depend

 

#################################################