Compiling C and C++ Programs
gcc is the "GNU" C Compiler, and
g++ is the "GNU C++ compiler. These are free compilers that are available on all of the department machines. Below are several examples that show how to use g++ to compile C++ programs. Note that most of the information applies to C programs as well
Example 1: Compiling a simple program
Consider the following example: Let "hello.C" be a file that contains the following C++ code.
#include "iostream.h" int main() { cout << "Hello...\n"; }
A standard way to compile this program is with the command
g++ hello.C -o hello
This command compiles hello.C into an executable program named "hello" that you run by typing './hello' (or possibly just 'hello') at the command line. It does nothing more than print "Hello..." on the screen.
Alternatively, the above program could be compiled using the following two commands.
g++ -c hello.C g++ hello.o -o hello
The end result is the same, but this two-step method first
compiles hello.C into a machine code file named "hello.o" and then
links hello.o with some system libraries to produce the final program "hello". In fact the first method also does this two-stage process of compiling and linking, but the stages are done transparently, and the intermediate file "hello.o" is deleted in the process.
Frequently used compilation options
C and C++ compilers allow for many options for how to compile a program, and the examples below demonstrate how to use many of the more commonly used options. In each example, "myprog.C" contains C++ source code for the executable "myprog". In most cases options can be combined, although it is generally not useful to use "debugging" and "optimization" options together.
- Compile myprog.C so that myprog contains symbolic information that enables it to be debugged with the gdb debugger (and produces more useful error messages with valgrind).
g++ -g myprog.C -o myprog
- Have the compiler generate warnings about syntactically correct but questionable looking code. It is good practice to always use the -Wall option.
g++ -Wall myprog.C -o myprog
- Generate symbolic information for gdb and many warning messages.
g++ -g -Wall myprog.C -o myprog
- Generate optimized code with warnings. The -O is a capital o and not the number 0!
g++ -Wall -O myprog.C -o myprog
- Generate especially optimized code that will only run on Pentium 4 machines.
g++ -Wall -O -march=pentium4 myprog.C -o myprog
- Compile myprog.C when it contains Xlib graphics routines.
g++ myprog.C -o myprog -lX11
If "myprog.c" is a C program, then the above commands will all work by replacing g++ with gcc and "myprog.C" with "myprog.c". Below are a few examples that apply only to C programs.
- Compile a C program that uses math functions such as "sqrt".
gcc myprog.C -o myprog -lm
Example 2: Compiling a program with multiple source files
If the source code is in several files, say "file1.C" and "file2.C", then they can be compiled into an executable program named "myprog" using the following command:
g++ file1.C file2.C -o myprog
The same result can be achieved using the following three commands:
g++ -c file1.C g++ -c file2.C g++ file1.o file2.o -o myprog
The advantage of the second method is that it compiles each of the source files separately. If, for instance, the above commands were used to create "myprog", and "file1.C" was subsequently modified, then the following commands would correctly update "myprog".
g++ -c file1.C g++ file1.o file2.o -o myprog
Note that file2.C does not need to be recompiled, so the time required to rebuild myprog is shorter than if the first method for compiling myprog were used. When there are numerous source file, and a change is only made to one of them, the time savings can be significant. This process, though somewhat complicated, is generally handled automatically by a makefile.
6. More Examples
The following are more examples of all three approaches (static, shared, and dynamically loaded libraries). File libhello.c is a trivial library, with libhello.h as its header. File demo_use.c is a trivial caller of the library. This is followed by commented scripts (script_static and script_dynamic) showing how to use the library as a static and shared library. This is followed by demo_dynamic.c and script_dynamic, which show how to use the shared library as a dynamically loaded library.
6.1. File libhello.c
/* libhello.c - demonstrate library use. */
#include <stdio.h>
void hello(void) {
printf("Hello, library world.\n");
}
|
6.2. File libhello.h
/* libhello.h - demonstrate library use. */
void hello(void);
|
6.3. File demo_use.c
/* demo_use.c -- demonstrate direct use of the "hello" routine */
#include "libhello.h"
int main(void) {
hello();
return 0;
} |
6.4. File script_static
#!/bin/sh
# Static library demo
# Create static library's object file, libhello-static.o.
# I'm using the name libhello-static to clearly
# differentiate the static library from the
# dynamic library examples, but you don't need to use
# "-static" in the names of your
# object files or static libraries.
gcc -Wall -g -c -o libhello-static.o libhello.c
# Create static library.
ar rcs libhello-static.a libhello-static.o
# At this point we could just copy libhello-static.a
# somewhere else to use it.
# For demo purposes, we'll just keep the library
# in the current directory.
# Compile demo_use program file.
gcc -Wall -g -c demo_use.c -o demo_use.o
# Create demo_use program; -L. causes "." to be searched during
# creation of the program. Note that this command causes
# the relevant object file in libhello-static.a to be
# incorporated into file demo_use_static.
gcc -g -o demo_use_static demo_use.o -L. -lhello-static
# Execute the program.
./demo_use_static |
6.5. File script_shared
#!/bin/sh
# Shared library demo
# Create shared library's object file, libhello.o.
gcc -fPIC -Wall -g -c libhello.c
# Create shared library.
# Use -lc to link it against C library, since libhello
# depends on the C library.
gcc -g -shared -Wl,-soname,libhello.so.0 \
-o libhello.so.0.0 libhello.o -lc
# At this point we could just copy libhello.so.0.0 into
# some directory, say /usr/local/lib.
# Now we need to call ldconfig to fix up the symbolic links.
# Set up the soname. We could just execute:
# ln -sf libhello.so.0.0 libhello.so.0
# but let's let ldconfig figure it out.
/sbin/ldconfig -n .
# Set up the linker name.
# In a more sophisticated setting, we'd need to make
# sure that if there was an existing linker name,
# and if so, check if it should stay or not.
ln -sf libhello.so.0 libhello.so
# Compile demo_use program file.
gcc -Wall -g -c demo_use.c -o demo_use.o
# Create program demo_use.
# The -L. causes "." to be searched during creation
# of the program; note that this does NOT mean that "."
# will be searched when the program is executed.
gcc -g -o demo_use demo_use.o -L. -lhello
# Execute the program. Note that we need to tell the program
# where the shared library is, using LD_LIBRARY_PATH.
LD_LIBRARY_PATH="." ./demo_use
|
6.6. File demo_dynamic.c
/* demo_dynamic.c -- demonstrate dynamic loading and
use of the "hello" routine */
/* Need dlfcn.h for the routines to
dynamically load libraries */
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
/* Note that we don't have to include "libhello.h".
However, we do need to specify something related;
we need to specify a type that will hold the value
we're going to get from dlsym(). */
/* The type "simple_demo_function" describes a function that
takes no arguments, and returns no value: */
typedef void (*simple_demo_function)(void);
int main(void) {
const char *error;
void *module;
simple_demo_function demo_function;
/* Load dynamically loaded library */
module = dlopen("libhello.so", RTLD_LAZY);
if (!module) {
fprintf(stderr, "Couldn't open libhello.so: %s\n",
dlerror());
exit(1);
}
/* Get symbol */
dlerror();
demo_function = dlsym(module, "hello");
if ((error = dlerror())) {
fprintf(stderr, "Couldn't find hello: %s\n", error);
exit(1);
}
/* Now call the function in the DL library */
(*demo_function)();
/* All done, close things cleanly */
dlclose(module);
return 0;
} |
6.7. File script_dynamic
#!/bin/sh
# Dynamically loaded library demo
# Presume that libhello.so and friends have
# been created (see dynamic example).
# Compile demo_dynamic program file into an object file.
gcc -Wall -g -c demo_dynamic.c
# Create program demo_use.
# Note that we don't have to tell it where to search for DL libraries,
# since the only special library this program uses won't be
# loaded until after the program starts up.
# However, we DO need the option -ldl to include the library
# that loads the DL libraries.
gcc -g -o demo_dynamic demo_dynamic.o -ldl
# Execute the program. Note that we need to tell the
# program where get the dynamically loaded library,
# using LD_LIBRARY_PATH.
LD_LIBRARY_PATH="." ./demo_dynamic |