Back to main

Tools for Compiling C Programs

As suggested in the background section, it is necessary to translate ("compile") a program in to a form suitable for execution. The C compiler, gcc is the program which can do this. You can enter the source code using the editor xemacs which has special features to help you with programming. There is a debugger, gdb to assist in finding mistakes, and a project manager called make for building larger projects.

Building a program

Until one gains a considerable amount of experience, it is very unlikely that the programs one writes will work first time. Partly this is because the syntax of all programming languages is very strict -- omitting a semicolon will cause the program not to compile. The program logic may also be wrong: the code may compile perfectly and run without error, but simply produce incorrect results because the programmer has not properly designed the algorithm before implementing it as a C program.

Inevitably, the procedure laid out in the diagram inset on the right will be adopted. Each action has an appropriate tool associated with it:

xemacs, the editor
xemacs is an editor designed for programmers. It is highly configurable, and "understands" the syntax of the C language. As well as a mature GUI with familiar pull-down menus and dialogues, the program can be entirely controlled from the keyboard when the user has mastered the control- and escape-key sequences required. In experienced hands, this makes it one of the most powerful and fastest source code editors available
gcc, the C compiler
gcc is an extraordinaly flexible C compiler which performs the translation from C language to machine code. It supports more target architectures, and runs on more platforms than any other compiler, and can produce very efficient and optimised code.
gdb, the debugger
gdb is a symbollic debugger which allows you to step through the program a line at a time keeping a watch on all the variables you are using. It permits you to run the program up to a certain point or until a certain variable reaches a particular value. It is very useful to debug the logic of a program which is not behaving as you would like, even though it compiles without errors.

Using xemacs

You can start xemacs by typing xemacs & at the command prompt.

When starting xemacs from the command line you can tell it the name of the first file to edit, as in xemacs hello.c. Even better is xemacs hello.cpp & which will start xemacs, but also leave the shell open for business.

Xemacs is very clever. It will try to work out what type of file you are editing, and then use the appropriate mode for that file type. One way it does this is by testing the filename. It only does this when you first open the file, so if you are creating a new C program it is an advantage to start xemacs from the command line in this way.

Once xemacs opens its window on the screen you can begin editing. You can use the mouse for many operations, but it is strongly recomended that you learn a few keystroke shortcuts to speed up your work.

In the table below keystroke combinations are indicated as follows:

C-k
Means hold down the control (CTRL) key and at the same time press the 'k' key.
M-k
Means press the ESC key,  release it, then press the 'k' key.
(The M stands for META, a key that is present on most professional workstations, but not on PC keyboards. On PCs, the meta key can sometimes be accessed by using the ALT key, sometimes by using the Esc key sequence.)

ACTION KEYSTROKE DESCRIPTION
EXIT XEMACS C-x C-c Quits xemacs and prompt you to save any unsaved buffers
SAVE C-x C-s Saves the current buffer to its associated file without exiting xemacs
OPEN C-x C-f

Opens a file in a new buffer. You will be asked for a new filename at the bottom of the scneen. You can try pressing the TAB key to complete a partially typed filename.

Opening a new file will not close any existing buffers. You can have many files open for editing at the same time.

SPLIT THE SCREEN C-x 2 Split the current screen (or part of screen) into two, one above the other. Initially, the same buffer will be active in both parts.
C-x 3 As for C-x 2, but the two parts will be side by side.
UNSPLIT THE SCREEN C-x 0 That is CTRL X and zero. Unsplit the current part or the screen
CHANGE THE CURRENT BUFFER C-b buffername Change which buffer displayed in the current window.
START MARK C-space

Move the cursor to one end of the text to mark. Hold down the CTRL key and press the space bar.

Now move the cursor to the other end of the text to mark. You mark text prior to copying, or cutting it.

CUT C-w Having marked the text (see above), pressing CTRL w causes the marked text to disappear. It will be stored for later use in the paste buffer.
COPY M-w This will store the marked text in the paste buffer, but not delete it.
PASTE or YANK C-y This will insert the most recently CUT or COPIED text at the current cursor position. See also PREVIOUS YANK below.
PREVIOUS YANK M-y Having YANKed, replace the text just inserted with the next text from the paste buffer. (Just try it - Cut a few things, and you can restore any of them.) There is a limit to the size of the paste buffer, but it is very large.
SEARCH C-s target text

After you have pressed the CTRL s you type in the target for the search. Xemacs will search as you type, highlighting what it finds. If you mistype you can delete your errors and retype.

Exit search mode is done by pressing return on moving the cursor with one of the cursor keys.

SEARCH BACKWARDS C-r target text Same as SEARCH, except in Reverse. It searches back towards the top of the file.
SEARCH AGAIN C-s or C-r After a successful search, typing another C-s or C-r will find the next occurrence of the target text.
REPLACE M-% You will be prompted for a target text, and then for replacement text. Then for each "target" found you can choose an action:
  • 'space' or 'y' to replace.
  • ',' to replace once and stop.
  • 'Delete' to ignore and go to next.
  • '!' To replace all remaining matches.
  • 'ESC' to quit replace.
  • '^' to return to previous match.
OOPS C-] Sometimes you will start doing something, and Xemacs will prompt you for input on the bottom line, but you change your mind and want to return to normal editing. You can escape by typing  C-]

Using gcc

To compile a single file hello.c to produce a program called hello.exe you should use the command:
gcc -Wall -ggdb -o hello.exe hello.c

How is this command line constructed?

"C" programs should always have a filename ending with .c.

gcc stands for Gnu Compiler Collection, and can also compile other languages including Fortran, Pascal, Ada and others.

GCC was originally written as a freely available substitute for a proprietory compiler for the Unix operating system called cc. The project to create these freely available tools has the name GNU; hence the name GCC. By default, cc used to produce an output file called a.out (for assembler output, which was a runable binary file. In the Microsoft world a file is only runable if it has the filename extension .exe (or .com or .bat, but these do not concern us here). Therefore, the default output file from GCC on a Microsoft operating system is a.exe.

A very simple case

Suppose you want to compile a C program called "hello.c", and are happy that the output file will be called a.exe, just use the command:

gcc hello.cpp
We can use the -o option to rename the output file, as in :
gcc -o hello.exe hello.cpp
which will produce an output file called hello.exe.

If the source code for our program is split between several files (say, hello.c, code1.c, code2.c) we can use:

gcc -o hello.exe hello.c code1.c code2.c
to compile all three files to produce hello.exe.

Mistakes

We all make mistakes. Sometimes we ask GCC  to compile a programme containing errors. If GCC finds code that it cannot parse - a syntax error - it will print an error message on the screen. This message will indicate where, by line number, where the error was discovered.

NB: Where the error was discovered may not be where the error was made, it may be discovered  further down the program!
It can take a bit of practice to identify the true source of the error. Also, if you get more than one error, it can be a good idea to fix the first and then run the compiler again. Some of the other errors might simply be the result of the compiler being "confused" by the first error.

Warnings

The compiler can also protect you against some common programming errors. These are situations where you write code that, while it is not syntactically incorrect, does someting that is usually wrong or stupid. (You MAY stir hot coffee with your finger, but it is not advisable.) The messages that the compiler produces in these situations are called WARNINGS. Warnings are helpful. Use them to help you write (better) working code.

You can ask the compiler to provide different levels of warning using the following options:

-w
Inhibit all warnings - Not a good idea!
-pedantic
Warn about the slightest little thing that does not match the ANSI C or ISO C++ standards. - This might be going a bit too far at this stage.
-Wall
Warn about a lot of the commonest errors - You should probably use this towards the end of program development.
-W
Warn about some more common mistakes - You should probably always use this until moving on to the -Wall option.

Debugging

Sometimes a programme will compile correctly, without warnings, but still not work. The programme is not doing what the programmer thought s/he was telling it to do. S/he needs to observe the programme while it runs to see where its behaviour diverges from that intended. The debugger enables one to do this. The debugger installed on this system id gdb.

GDB will use the executable output from the compiler. It needs to know which parts of the executable results from which parts of the original source code. By default GCC produces the smallest possible executable. Adding the information needed for the debugger increases the executable program size, and might slow the code a little. To add this information we use the -g or the -ggdb option. The option -ggdb is preferable here.

While learning the language we are not very concerned about the size and speed of our code. Differences will usually be slight. Warnings should always be generated, and you should also include the debugging code.

Hence, To compile a single file hello.c to produce a program called hello.exe you should use the command:

gcc -Wall -ggdb -o hello.exe hello.c

Using make

Compiling files using the sort of command lines described above is all very well for very simple programs, but it is too tedious and error-prone a process to be used on programs made up of many source files. For example, the Linux kernel, which is written almost entirely in C, consists of 4048 files of source code, a total of 2884963 lines, as of version 2.4.16. Clearly, a more sophisticated tool is required to build packages of such size.

make is a program which calls the compiler for you automatically, in accordance with the requirements of your particular project as laid out in a file called (by default) Makefile. It is enormously complex and sophisticated, and can build suites of programs written in a mixture of langauges under a single project. Writing a makefile is a tricky process, and since we are concentrating on learning C, is outside the scope of this course. This does not mean it is forbidden knowledge, and you are welcome to look at the makefiles you are given and read the manual for make, but be warned that these are advanced tools for advanced programmes, and take no prisoners as far as novices are concerned!

You will be provided with makefiles which set up make to understand the following commands:

make depend
The first time you build a project, or when you add a file to or remove a file from the project, you can tell make to update the list of dependencies. This way, make can tell which files it has to compile in order to build the project.
make
make by itself does the business of compiling all of the files necessary to build the program. This happens in two phases:
  1. The compiler is invoked with -c flag to translate each source file into an object file with the extension .o;
  2. The compiler is invoked once again to link all of the objects generated in the previous phase into a single executable program.
make ensures only the minimum work is done to build the whole project; quite a benefit if your project contains thousands of C files, and you have only changed one source file! make will only recompile the files you have changed, and then relink the project.
make clean
Delete all of the files you can rebuild from source. Useful for making distributions containing just the bare essentials which other programmers can build on their own systems.
This is actually a very easy and painless process once the makefile has been set up. At each stage, make prints out a summary of the commands it executes on your behalf so you can see what is going on.

Below is a transcript of the process of building our Minefield application after it has been unpacked. The programmer issues the commands to build the dependencies file and then to make the project; everything else is produced by the make program. Note that this output may differ slightly from yours, because you don't have the original source code (you have to write that!). Ignore any errors you see along the lines of cc: No input files until you have written some. The application should still build from the supplied object files.

sh-2.05b$ make depend
cc -E -M -I . ../Minefield-src/main.c ../Minefield-src/username.c ../Minefield-src/timer.c ../Minefield-src/drawscreen.c ../Minefield-src/board.c ../Minefield-src/play.c ../Minefield-src/result.c ../Minefield-src/stamp.c ../Minefield-src/adjacent.c > .depend
sh-2.05b$ make
cc -c -g -I . ../Minefield-src/main.c -o main.o
cc -c -g -I . ../Minefield-src/username.c -o username.o
cc -c -g -I . ../Minefield-src/timer.c -o timer.o
cc -c -g -I . ../Minefield-src/drawscreen.c -o drawscreen.o
cc -c -g -I . ../Minefield-src/board.c -o board.o
cc -c -g -I . ../Minefield-src/play.c -o play.o
cc -c -g -I . ../Minefield-src/result.c -o result.o
cc -g -I . main.o username.o timer.o drawscreen.o board.o play.o result.o stamp.o adjacent.o /usr/lib/libcurses.so -o minefield

Summary:

System Requirements

To view this web resource, you will need:

Copyright and Acknowledgements

The tools upon which this course relies are Copyright the Free Software Foundataion where they are made available under the GPL (GNU Public Licence).

The content of this course was derived from that generated by many ex-colleagues at the University of Leeds, Department of Electronics and Electrical Engineering. Much of the content has been reworked, and substantially augmented, but Dr N J Bailey, Centre for Music Technology, The University of Glagsow. This manifestation is Copyright N J Bailey; some of the content is Copyright The University of Leeds.

Diagrams on this resource are drawn in XFig and are rendered by the browser using The University of Hamburg's Simple FIG viewer applet which is Copyright (C) 1996-2002 F.N.Hendrich, hendrich@informatik.uni-hamburg.de.

The source code, programming examples and exercises are all specific to this course, and are Copyright, Dr N J Bailey.

The applet for viewing and demonstrating C programs is Copyright Dr N J Bailey, and is to be found documented and with its source code on the Centre for Music Technology website under Software