Topic : Compiling C++ Programs On Unix
Author : LUPG
Page : 1 Next >>
Go to page :


Compiling "C" And "C++" Programs On Unix Systems - gcc/g++


Table Of Contents:
1.Preface
2.Compiling A Single-Source "C" Program
3.Running The Resulting Program
4.Creating Debug-Ready Code
5.Creating Optimized Code
6.Getting Extra Compiler Warnings
7.Compiling A Single-Source "C++" Program
8.Compiling A Multi-Source "C" Program
9.Getting a Deeper Understanding - Compilation Steps




Preface - How To Read This Document

This document tries to give the reader basic knowledge in compiling C and C++ programs on a Unix system. If you've no knowledge as to how to compile C programs under Unix (for instance, you did that until now on other operating systems), you'd better read this tutorial first, and then write a few programs before you try to get to gdb, makefiles or C libraries.

If you're already familiar with that, it's recommended to learn about makefiles, and then go and learn other C programming topics and practice the usage of makefiles, before going on to read about C libraries. This last issue is only relevant to larger projects, while makefiles make sense even for a small program composed of but a few source files.

As a policy, we'll stick with the basic features of programming tools mentioned here, so that the information will apply to more then a single tool version. This way, you might find the information here useful, even if the system you're using does not have the GNU tools installed.

In this lovely tutorial, we'll deal with compilation of a C program, using the compiler directly from the command line. It might be that you'll eventually use a more sophisticated interface (an IDE - Integrated Development Environment) of some sort, but the common denominator you'll always find is the plain command line interface. Further more, even if you use an IDE, it could help you understand how things work "behind the scenes". We'll see how to compile a program, how to combine several source files into a single program, how to add debug information and how to optimize code.





Compiling A Single-Source "C" Program

The easiest case of compilation is when you have all your source code set in a single file. This removes any unnecessary steps of synchronizing several files or thinking too much. Lets assume there is a file named 'single_main.c' that we want to compile. We will do so using a command line similar to this:

cc single_main.c

Note that we assume the compiler is called "cc". If you're using a GNU compiler, you'll write 'gcc' instead. If you're using a Solaris system, you might use 'acc', and so on. Every compiler might show its messages (errors, warnings, etc.) differently, but in all cases, you'll get a file 'a.out' as a result, if the compilation completed successfully. Note that some older systems (e.g. SunOs) come with a C compiler that does not understand ANSI-C, but rather the older 'K&R' C style. In such a case, you'll need to use gcc (hopefully it is installed), or learn the differences between ANSI-C and K&R C (not recommended if you don't really have to), or move to a different system.

You might complain that 'a.out' is a too generic name (where does it come from anyway? - well, that's a historical name, due to the usage of something called "a.out format" for programs compiled on older Unix systems). Suppose that you want the resulting program to be called "single_main". In that case, you could use the following line to compile it:

cc single_main.c -o single_main

Every compiler I've met so far (including the glorious gcc) recognized the '-o' flag as "name the resulting executable file 'single_main'".





Running The Resulting Program

Once we created the program, we wish to run it. This is usually done by simply typing its name, as in:

single_main

However, this requires that the current directory be in our PATH (which is a variable telling our Unix shell where to look for programs we're trying to run). In many cases, this directory is not placed in our PATH. Aha! - we say. Then lets show this computer who is smarter, and thus we try:

./single_main

This time we explicitly told our Unix shell that we want to run the program from the current directory. If we're lucky enough, this will suffice. However, yet one more obstacle could block our path - file permission flags.

When a file is created in the system, it is immediately given some access permission flags. These flags tell the system who should be given access to the file, and what kind of access will be given to them. Traditional Unix systems use 3 kinds of entities to which they grant (or deny) access: The user which owns the file, the group which owns the file, and everybody else. Each of these entities may be given access to read the file ('r'), write to the file ('w') and execute the file ('x').

Now, when the compiler created the program file for us, we became owners of the file. Normally, the compiler would make sure that we get all permissions to the file - read, write and execute. It might be, thought that something went wrong, and the permissions are set differently. In that case, we can set the permissions of the file properly (the owner of a file can normally change the permission flags of the file), using a command like this:

chmod u+rwx single_main

This means "the user ('u') should be given ('+') permissions read ('r'), write ('x') and execute ('x') to the file 'single_main'. Now we'll surely be able to run our program. Again, normally you'll have no problem running the file, but if you copy it to a different directory, or transfer it to a different computer over the network, it might loose its original permissions, and thus you'll need to set them properly, as shown above. Note too that you cannot just move the file to a different computer an expect it to run - it has to be a computer with a matching operating system (to understand the executable file format), and matching CPU architecture (to understand the machine-language code that the executable file contains).

Finally, the run-time environment has to match. For example, if we compiled the program on an operating system with one version of the standard C library, and we try to run it on a version with an incompatible standard C library, the program might crush, or complain that it cannot find the relevant C library. This is especially true for systems that evolve quickly (e.g. Linux with libc5 vs. Linux with libc6), so beware.





Creating Debug-Ready Code

Normally, when we write a program, we want to be able to debug it - that is, test it using a debugger that allows running it step by step, setting a break point before a given command is executed, looking at contents of variables during program execution, and so on. In order for the debugger to be able to relate between the executable program and the original source code, we need to tell the compiler to insert information to the resulting executable program that'll help the debugger. This information is called "debug information". In order to add that to our program, lets compile it differently:

cc -g single_main.c -o single_main

The '-g' flag tells the compiler to use debug info, and is recognized by mostly any compiler out there. You will note that the resulting file is much larger then that created without usage of the '-g' flag. The difference in size is due to the debug information. We may still remove this debug information using the strip command, like this:

strip single_main

You'll note that the size of the file now is even smaller then if we didn't use the '-g' flag in the first place. This is because even a program compiled without the '-g' flag contains some symbol information (function names, for instance), that the strip command removes. You may want to read strip's manual page (man strip) to understand more about what this command does.





Creating Optimized Code

After we created a program and debugged it properly, we normally want it to compile into an efficient code, and the resulting file to be as small as possible. The compiler can help us by optimizing the code, either for speed (to run faster), or for space (to occupy a smaller space), or some combination of the two. The basic way to create an optimized program would be like this:

cc -O single_main.c -o single_main

The '-O' flag tells the compiler to optimize the code. This also means the compilation will take longer, as the compiler tries to apply various optimization algorithms to the code. This optimization is supposed to be conservative, in that it ensures us the code will still perform the same functionality as it did when compiled without optimization (well, unless there are bugs in our compiler). Usually can define an optimization level by adding a number to the '-O' flag. The higher the number - the better optimized the

Page : 1 Next >>