Выбрать главу

Managing Software Projects with Subversion

Although make can be used to manage a software project, larger software projects require document management, source code controls, security, and revision tracking as the source code goes through a series of changes during its development. Subversion provides source code version control utilities for this kind of large software project management.

The Subversion system is used to track changes to multiple versions of files, and it can be used to backtrack or branch off versions of documents inside the scope of a project. It can also be used to prevent or resolve conflicting entries or changes made to source code files by multiple developers. Source code control with Subversion requires the use of at least the following five command options on the svn command line:

► checkout — Checks out revisions

► update — Updates your sources with changes made by other developers

► add — Adds new files to the repository

► delete — Eliminates files from the repository

► commit — Publishes changes to other repository developers

Note that some of these commands require you to use additional fields, such as the names of files. With the commit command, you should always try to pass the -m parameter (lets you provide a message describing the change) followed by some information about your changes. For example:

svn commit -m "This fixes bug 204982."

One of the most impressive features of Subversion is its ability to work offline — any local Subversion checkout automatically has a .svn directory hidden in there, which contains copies of all checked out files. Thanks to this, you can check your current files against the ones you checked out without having to contact the server — it all runs locally.

Debugging Tools

Debugging is both a science and an art. Sometimes, the simplest tool — the code listing — is the best debugging tool. At other times, however, you need to use other debugging tools. Three of these tools are splint, gprof, and gdb.

Using splint to Check Source Code

The splint command is similar to the traditional Unix lint command: It statically examines source code for possible problems, and it also has many additional features. Even if your C code meets the standards for C and compiles cleanly, it might still contain errors. splint performs many types of checks and can provide extensive error information. For example, this simple program might compile cleanly and even run:

$ gcc -o tux tux.c

$ ./tux

But the splint command might point out some serious problems with the source:

$ splint tux.c

Splint 3.1.1 --- 17 Feb 2004 tux.c: (in function main)

tux.c:2:19: Return value (type int) ignored: putchar(t[++j] -...

 Result returned by function call is not used. If this is intended, can cast

 result to (void) to eliminate message. (Use -retvalint to inhibit warning)

Finished checking --- 1 code warning

You can use the splint command's -strict option, like this, to get a more verbose report:

$ splint -strict tux.c

GCC also supports diagnostics through the use of extensive warnings (through the -Wall and -pedantic options):

$ gcc -Wall tux.c

tux.c:1: warning: return type defaults to `int'

tux.c: In function `main':

tux.c:2: warning: implicit declaration of function `putchar'

Using gprof to Track Function Time

You use the gprof (profile) command to study how a program is spending its time. If a program is compiled and linked with -p as a flag, a mon.out file is created when it executes, with data on how often each function is called and how much time is spent in each function. gprof parses and displays this data. An analysis of the output generated by gprof helps you determine where performance bottlenecks occur. Using an optimizing compiler can speed up a program, but taking the time to use gprof's analysis and revising bottleneck functions significantly improves program performance.

Doing Symbolic Debugging with gdb

The gdb tool is a symbolic debugger. When a program is compiled with the -g flag, the symbol tables are retained and a symbolic debugger can be used to track program bugs. The basic technique is to invoke gdb after a core dump (a file containing a snapshot of the memory used by a program that has crashed) and get a stack trace. The stack trace indicates the source line where the core dump occurred and the functions that were called to reach that line. Often, this is enough to identify a problem. It isn't the limit of gdb, though.

gdb also provides an environment for debugging programs interactively. Invoking gdb with a program enables you to set breakpoints, examine the values of variables, and monitor variables. If you suspect a problem near a line of code, you can set a breakpoint at that line and run gdb. When the line is reached, execution is interrupted. You can check variable values, examine the stack trace, and observe the program's environment. You can single-step through the program to check values. You can resume execution at any point. By using breakpoints, you can discover many bugs in code.

A graphical X Window System interface to gdb is called the Data Display Debugger, or ddd.

Using the GNU C Compiler

If you elected to install the development tools package when you installed Fedora 7 (or perhaps later on, using RPM or other package tools), you should have the GNU C compiler (gcc). Many different options are available for the GNU C compiler, and many of them are similar to those of the C and C++ compilers that are available on other Unix systems. Look at the man page or information file for gcc for a full list of options and descriptions.

When you use gcc to build a C program, the compilation process takes place in several steps:

1. First, the C preprocessor parses the file. To do so, it sequentially reads the lines, includes header files, and performs macro replacement.

2. The compiler parses the modified code to determine whether the correct syntax is used. In the process, it builds a symbol table and creates an intermediate object format. Most symbols have specific memory addresses assigned, although symbols defined in other modules, such as external variables, do not.

3. The last compilation stage, linking, ties together different files and libraries and then links the files by resolving the symbols that had not previously been resolved.

NOTE

Most C programs compile with a C++ compiler if you follow strict ANSI rules. For example, you can compile the standard hello.c program (everyone's first program) with the GNU C++ compiler. Typically, you name the file something like hello.cc, hello.c, hello.c++, or hello.cxx. The GNU C++ compiler accepts any of these names.