Compiling C++ programs
For more information about g++ and make see the
GNU manuals or run
info (the man pages for g++ and make are not very complete).
A common link-time error is forgetting to link library code into your
program that uses it. If the compiler fails at link time with a
list of undefined symbols in your program, it is due to your not
linking in one or more .o files or library .a or .so files into
your program (if you get an undefined reference error when a file
is being compiled from .C to .o, then this means you forgot to include
a header file).
For example, if you are calling the
Because C++ compilers mangle names, often times one cannot easily
decipher linker errors. For example, by looking at the following
output from the linker:
To list symbols in .so .a .o or an executable files, you can
use
Executable files that are built using static linking contain
all the library code needed to run. Executable files that are built
using dynamic linking do not contain library code from .so files.
Instead, library code from .so files is dynamically loaded into the
address space of the process at runtime. To list the shared object
dependencies of an executable file (or of a .so file) use
GDB Guide:
Some sample programs that you can copy and try out with gdb are available here:
/home/newhall/public/gdb_examples/
Setting breakpoints in C++ code:
One complication with gdb and C++ programs, is that you need to specify
methods and data members using the "classname::" prefix. In addition, you
often need to use a leading ' before the name for gdb to find the symbol,
and if methods are overloaded, you need to specify which method it is by
listing its full prototype (actually, if you hit TAB gdb will list all
possible matches for you and you can pick one of those).
For example, to set a break point in funciton pinPage of the BufMgr class,
I'd do the following:
Some sample programs that you can copy and try out with
valgrind are available here:
/home/newhall/public/purify_valgrind_examples/
valgrind Guide: "using valgrind"
information with a sample valgrind session and links to valgrind references.
g++, make
Interpreting linker errors c++filt, nm, dump, objdump, ldd
Debugging C++ programs gdb and valgrind
COMPILING
On the Linux machines use GNU's C++ compiler, g++,
to compile your C++ code.
Compile your code with warnings turned on (-Wall turns on
all warnings). And don't ignore warnings as you compile your code; warnings
usually indicate a lurking problem that can lead to real problems later.
Also, always create a Makefile and use make to build your project code.
Here is some more information about
make.
LINKING
sqrt function from the math
library, you need to include the math.h header file in your .C file
and you need to explicitly link the math library into your executable:
g++ -g -Wall -o myprog myprog.o -lm
^^^
For C and C++ library functions, look at the man page for information
on how to link in the library code as part of the g++ command line.
For other library code, including libraries you have written, you need to
tell the linker where the library code is located. To do this use the
-L command line option followed by the path(s) to library
code. For example, if I have two libraries in
/home/newhall/mylibs/, one of which is a shared object file named
libmymath.so and the other an archive file
named libsimple.a,
then I'd add the following to my makefile to link in these two libraries
plus the standard math library (this is only part of the makefile):
# add the path to my library code; -L tells the linker where to find it
LFLAGS += -L /home/newhall/mylibs
# list of libraries to link into executable; -l tells the linker which
# library to link into the executable
LIBS = -lmymath -lsimple -lm
OBJS = myprog.o
# path to any header files not in /usr/include or the current directory
INCLUDES += -I/home/newhall/include -I../include
default: myprog
myprog:
$(CC) $(CFLAGS) $(LFLAGS) -o myprog $(OBJS) $(LIBS)
${OBJS}: %.o : %.c
${CC} -c ${CFLAGS} ${LFLAGS} ${INCLUDES} ${@:.o=.c}
Deciphering linker errors containing mangled names
Undefined first referenced
symbol in file
foo__FifP12BufHashTable buf.o
ld: fatal: Symbol referencing errors. No output written to buftest
make: *** [buftest] Error 1
it may not be obvious what the symbol foo__FifP12BufHashTable is
because it is mangled. To get a mangled name's demangled form
you can use c++filt:
% c++filt foo__FifP12BufHashTable
foo(int, float, BufHashTable *) # the symbol's demangled form
Symbol Tables and Library Dependencies
nm or objdump -t to list the contents
of the symbol table. The output will include all symbols (e.g. functions,
global variables), and will list information about them including if they
are defined or not (defined in a .o means the code for this function or
the declaration of this global variable is in this file, undefined means
it is in some other .o, .a, or .so file).
ldd.
ldd will list the name of each shared object file and the full path to
its location. If a program fails at runtime with a linking error, it is
due to the runtime linker not being able to find one or more of
the .so files needed to run the executable.
% ldd a.out
linux-gate.so.1 => (0xffffe000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7e53000)
libm.so.6 => /lib/tls/libm.so.6 (0xb7e1c000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb7e11000)
libc.so.6 => /lib/tls/libc.so.6 (0xb7cdf000)
/lib/ld-linux.so.2 (0xb7f3b000)
DEBUGGING: gdb, ddd, valgrind
gdb and ddd
Debugging tools allow you to see what is going on inside your program
as it runs and/or let you see what your program was doing when it
crashed. gdb and ddd allow you to examine a program's
state (variables, stack frame contents, etc.), allow you to set breakpoints
to stop the program at a certain points to examine its state, and allow
you to alter the value of your program's state (change a variable's
value, call a function) as it runs. Learning to use a debugger can save you
hours/days of time over trying to debug via printf statements.
"how to use gdb" information, including information on compiling C++ programs for use with gdb, running gdb, commonly used commands, example sessions,
gdb and make, ddd, and keyboard shortcuts.
(gdb) break 'BufMgr::pinPage(int, Page *&, int)'
Actually, I'd just type break 'BufMgr::p then hit TAB for automatic completion.
(gdb) break 'BufMgr:: <tab> will list all methods of the BufMgr class
valgrind
valgrind is a tool for finding memory access errors in your code
(memory leaks, reading uninitialized memory, accessing unallocated memory,
array out-of-bounds errors, ...). In C and C++ programs, memory
access errors are the most difficult bugs to find and to fix. valgrind can
save you days worth of debugging effort by quickly pointing you to the
source and type of these memory access bugs in your program code.
valgrind is pretty easy to learn to use, and the effort you put in to learn
how to use it will be more than made up for by the debugging time you save
by using it.