Compiling C++ programs

The basics

Class projects must be developed using the GNU C++ compiler, "g++". The GNU compiler is in use throughout industry and is the compiler that is used to build the Linux operating system and its utility programs. Programs submitted for grading will be built using g++. Submitted programs must build correctly.

The g++ compiler is easy to use. To compile source code into an executable program, enter a command like:

    g++ -o program program.cpp
This example command compiles the source code in the file "program.cpp" and puts the resulting executable image into the file "program." The "-o" option specifies the name of the executable image file. By convention, C++ source is stored in files with the ".cpp" extension and any necessary include files are stored in files with the ".h" extension. (Include files contain any declarations that a source module needs for compilation.) You may also specify more than one source module on the command line and all modules will be compiled and linked into the final executable program.

The command above is sufficient to build a self-contained program. However, we will be building programs that consist of multiple modules where each module is a separate source file. Software engineers often refer to this approach as "separately compiled modules," because each module is complete enough to be compiled on its own. Here is a sample command to compile a single source module:

    g++ -c program.cpp
The -c option tells the compiler to compile program.cpp without attempting to build a final executable program. In this case, the compiler will produce an "object module" named "program.o". You may specify more than one source module on the command line and the individual source modules will be compiled.

Once all of the source modules have been compiled, they must be linked into a full executable program. The fastest way to link separately compiled modules into an executable is by using a "g++" command again:

    g++ -o program program.o
This example command links the object module "program.o" with any precompiled, C/C++ library functions into the executable program named "program". You can, and must, put the names of any and all object modules that are part of the full program on the command line. If the list of object modules is incomplete, the link process will not find the definitions of (global) functions and variables, and "undefined symbol" errors will result.

The previous command is a convenient way to link the full program together. Behind the scenes, the g++ command invokes a utility program called the "linker" to stitch together the program parts along with any C or C++ library functions that are needed. The linker on Linux or UNIX is usually named "ld" and if you would like more information about it, use the command "man ld" to display the linker's manual page.

Building large programs

When a program grows beyond a few modules, the simple build procedure above becomes too cumbersome. Linux and UNIX provide a utility program, make, to build large programs with many dependencies between source modules. The make utility is the subject of another tech note.

Other compile options

The manual page for g++ shows many other compiler options. Some of these options control:

For this class, you should not have to specify any other options. Here are three options that you might want to try, however.

You may choose to use the GNU debugger, called "gdb," to control and monitor your program's execution. When the -g option is specified on the command line, the g++ compiler will put more symbolic information related to debugging into the final executable program file. The GNU debugger will read, use and display that information, hopefully making your work a little easier.

The -S compile option is fun to use if you are interested in seeing the code generated by the compiler for your program. This option tells the compiler to put the assembler language code for your program into a file with the ".s" extension. The command:

    g++ -S program.cpp
compiles the source in the file "program.cpp" and leaves the assembler code for the compiled program module in "program.s". You can look at the assembler code by editing the file or by displaying the file with the more command. This is a great way to learn assembler language programming or code generation, by the way.

The -pg option instructs the compiler to instrument your program in order to generate a profile of your program's execution. A profile shows the amount of time spent in the program's functions. This information is useful for performance tuning. The -pg option must be used for both compilation and linking as a special library must be linked into the final executable program. The profile data is produced when the program executes and is written into a file that can be displayed using the gprof program. Enter the command "man gprof" to get more information. Really ambitious people should also read about and try "gcov," which can be used in a similar way to produce line and function test coverage information.

Compilation errors

The g++ compiler is fairly picky, which is good, because it's error checking will help pick up problems before execution. However, it's pickiness means more error messages and warnings. If the compiler has just spewed a bunch of incomprehensible error messages, here are some suggestions:

Remember that the function signature in the class declaration must exactly match the function definition. The number and type of the arguments must be exactly the same and the return type of the function must be the same.

Some other common errors are:

Unfortunately, it's all too easy to fool the eye.

Earlier versions of the GNU compiler used different versions of the standard C and C++ libraries. Later versions of the compiler and its libraries use namespaces to separate old versions of the library functions from the new ones. If your program includes iostream (istream, ostream, etc.) and the compiler indicates that cin (cout, cerr, etc.) are undefined, add the line:

    using namespace std ;
after your includes to access the correct C++ namespace.

In complicated, multi-part C++ programs, it is possible for an include file to be included more than once. This is not unusual in large object-oriented programs as multiple parts of the same program may need access to declarations of the same abstract datatype. If an include file is read (included) more than once, the compiler may complain about "multiply defined" symbols. You should always surround the declarations in an include file with a #ifndef that prevents reprocessing. Here is an example of what to put in your include file:

    #ifndef INCFILE_H
    #define INCFILE_H
       ...
    #endif
By convention, the symbol to be tested (INCFILE_H in this case) is written all in capital letters and is the same as the name of the include file itself with any period characters replaced by underscore.

On-line documentation

Their are two Linux (UNIX) commands that provide on-line documentation:

The command:
    man apropos
displays the manual page for the apropos command. Try the commands below to learn more about the GNU g++ compiler, the debugger and the Ghostscript previewer:
    man g++
    man gdb
    man gs
The following table shows some basic commands that everyone should know. Use man to get more information about them.

Basic Linux/UNIX commands
ls Display directory contents
pwd Display current working directory
cd Change current working directory
mkdir Make a new directory
rmdir Remove an existing directory
rm Remove a file or files
more Display contents of a file (page by page)
lpr Print a file
chmod Change directory and file permissions to protect your files
Copyright © 2004-2013 Paul J. Drongowski