As expected, as a UNIX look-alike, Linux includes these traditional UNIX software-development tools:
A text editor, such as
vi or
emacs , for editing the source code (described in Chapter 11)
A C compiler for compiling and linking programs written in C-the programming language of choice for writing UNIX applications (although nowadays, many programmers are turning to C++). Linux includes the GNU C and C++ compilers. Originally, the GNU C Compiler was known as GCC. The acronym GCC now stands for GNU Compiler Collection (see description in
http://gcc .gnu.org/ ).
The GNU make utility for automating the software build process-the process of combining object modules into an executable or a library
A debugger for debugging programs. Linux includes the GNU debugger
gdb .
A version-control system to keep track of various revisions of a source file. Linux comes with RCS (Revision Control System) and CVS (Concurrent Versions System). Nowadays, most open-source projects use CVS as the version-control system.
These tools are installed automatically if you select the Development Tools package group when you install Red Hat Linux from this book's companion CD-ROMs, following the steps outlined in Chapter 2. The next few sections briefly describe how to use these tools to write applications for Linux.
You may have noticed that most of the Linux software-development tools are from the Free Software Foundation's GNU project. The online documentation for all these tools comes as
info files. The
info program is GNU's hypertext help system.
To see
info in action, type info at the shell prompt, or type Esc-x followed by info in GNU Emacs. Typically, I access
info from GNU Emacs; doing so enables me to use online help while editing a program. However, you can always type info in a separate terminal window. info at the shell prompt.
Figure 23-1: The Terminal Window after Typing info at the Shell Prompt.
In
info , the online help text is organized in nodes; each node represents information on a specific topic. The first line shows the header for that node.
info screen, with a directory of topics. This directory is an info file:
/usr/share/info/dir , a text file that contains embedded special characters. The following are a few lines from the /usr/share/info/dir file that correspond to the screen shown in Figure 23-1:
$Id: dir,v 1.2 1996/09/24 18:43:01 karl Exp $ This is the file .../info/dir, which contains the topmost node of the Info hierarchy. The first time you invoke Info you start off looking at that node, which is (dir)Top. ^_ (This is the Ctrl+_ character) File: dir Node: Top This is the top of the INFO tree This (the Directory node) gives a menu of major topics. Typing "q" exits, "?" lists all Info commands, "d" returns here, "h" gives a primer for first-timers, "mEmacs<Return>" visits the Emacs topic, etc. In Emacs, you can click mouse button 2 on a menu item or cross reference to select it. * Menu: Texinfo documentation system * Standalone info program: (info-stnd). Standalone Info-reading program. * Texinfo: (texinfo). The GNU documentation format. * install-info: (texinfo)Invoking install-info. Update info/dir entries. * makeinfo: (texinfo)makeinfo Preferred. Translate Texinfo source. (...Lines deleted...)
A comparison of this listing with the screen shown in info displays only the lines that follow the Ctrl+_ character. In your system, the
/usr/share/info directory contains this
info file, as well as others, with the text for each topic. Usually, these
info files are stored in compressed format. You really don't have to know these details to use the
info files.
Insider Insight |
You have to use several single-letter commands to navigate info files. The best way to learn the commands is to type h from the initial info directory, shown in Figure 23-1. Type d after reading the help screens to return to the initial directory of topics. |
From the directory screen of info system, in turn, displays the top-level menu of items for GCC, as shown in Figure 23-2.
Figure 23-2: The Info Window, Showing the Top-Level Help on GCC.
You can explore further by typing m, followed by one of the menu items shown in Figure 23-2.
While you're at it, you may want to type m, then copy; then press Enter in the screen shown in Figure 23-2. That action displays the GNU General Public License (GPL), shown in Figure 23-3.
Figure 23-3: The Info Window, Showing the First Page of the GNU General Public License (GPL).
GPL covers Linux and the gcc compiler. GPL requires distribution of the source code (that's why all Linux distributions come with source code). In the 'Implications of GNU Licenses' section, you learn that you can still use GNU tools to develop commercial applications and to distribute applications in binary form (without source code), as long as they link with selected GNU libraries only.
At any time in
info , you can type d to return to the
info topic directory shown in info from the Emacs editor, press Ctrl+X, followed by Ctrl+C, to quit the Emacs editor.
The most important software-development tool in Linux is GCC, which is the GNU C and C++ compiler. In fact, GCC can compile three languages: C, C++, and Objective-C (a language that adds object-oriented extensions to C). You use the same
gcc command to compile and link both C and C++ source files. The GCC compiler supports ANSI standard C, making it easy to port any ANSI C program to Linux. In addition, if you've ever used a C compiler on other UNIX systems, you are right at home with GCC.
Use the
gcc command to run GCC. By default, when you use the
gcc command on a source file, GCC preprocesses, compiles, and links the executable. However, you can use GCC options to stop this process at an intermediate stage. For example, you might invoke
gcc by using the
-c option to compile a source file and to generate an object file, but not to perform the link step.
Using GCC to compile and link a few C source files is very simple. Suppose you want to compile and link a simple program made up of two source files. The following listing shows the file
area.c (the main program that computes the area of a circle whose radius is specified through the command line):
#include <stdio.h> #include <stdlib.h> /* Function prototype */ double area_of_circle(double r); int main(int argc, char **argv) { if(argc < 2) { printf("Usage: %s radius\n", argv[0]); exit(1); } else { double radius = atof(argv[1]); double area = area_of_circle(radius); printf("Area of circle with radius %f = %f\n", radius, area); } return 0; }
The following listing shows the file
circle.c , which provides a function that computes the area of a circle.
#include <math.h> #define SQUARE(x) ((x)*(x)) double area_of_circle(double r) { return 4.0 * M_PI * SQUARE(r); }
For such a simple program, of course, I can place everything in a single file, but this contrived example lets me show you how to handle multiple files.
To compile these two programs and to create an executable file named
area , you might use this command:
gcc -o area area.c circle.c
This invocation of GCC uses the
-o option to specify the name of the executable file. (If you do not specify the name of an output file, GCC creates a file named
a.out .)
If there are too many source files to compile and link, compile the files individually, and generate object files (that have the
.o extension). That way, when you change a source file, you need to compile only that file and to link all the object files. The following example shows how to separate the compile and link steps for the example program:
gcc -c area.c gcc -c circle.c gcc -o area area.o circle.o
The first two invocations of
gcc with the
-c option compile the source files. The third invocation links the object files into an executable named
area .
In case you are curious, here's how you run the sample program (to compute the area of a circle with a radius of 1):
./area 1 Area of circle with radius 1.000000 = 12.566371
Insider Insight |
Incidentally, you have to add the ./ prefix to the program's name ( area ) only if the current directory is not in the PATH environment variable. There is no harm in adding the prefix, even if your PATH contains the current directory. |
GNU CC is a combined C and C++ compiler, so the
gcc command also can compile C++ source files. GCC uses the file extension to determine whether a file is C or C++. C files have a lowercase
.c extension, whereas C++ files end with
.C or
.cpp .
Although the
gcc command can compile a C++ file, that command does not automatically link with various class libraries that C++ programs typically require. That's why it's easier to compile and link a C++ program by using the
g++ command, which invokes
gcc with appropriate options.
Suppose you want to compile the following simple C++ program stored in a file named
hello.C (it's customary to use an uppercase C extension for C++ source files):
#include <iostream> int main() { using namespace std; cout << "Hello from Red Hat Linux!" << endl; }
To compile and link this program into an executable program named
hello , use this command:
g++ -o hello hello.C
This command creates the
hello executable, which you can run as follows:
./hello Hello from Red Hat Linux!
As you see in the following section, a host of GCC options controls various aspects of compiling C++ programs.
Following is the basic syntax of the
gcc command:
gcc options filenames
Each option starts with a hyphen (
- ) and usually has a long name, such as
-funsigned-char or
-finline-functions . Many commonly used options are short, however, such as
-c , to compile only, and
-g , to generate debugging information, (needed to debug the program by using the GNU debugger).
You can view a summary of all GCC options by using
info . Type info at the shell prompt, and press
m , followed by
gcc . Then follow the menu items: Invoking GCC>Option Summary. Usually, you do not have to specify GCC options explicitly; the default settings are fine for most applications. Table 23-1 lists some of the GCC options you might use.
Option |
Meaning |
---|---|
-ansi |
Support ANSI standard C syntax only. (This option disables some GNU C-specific features, such as the asm and typeof keywords.) |
-c |
Compile and generate object file only |
-DMACRO |
Define the macro with the string '1' as its value |
-DMACRO= DEFN |
Define the macro as DEFN where DEFN is some text |
-E |
Run only the C preprocessor |
-fallow-single-precision |
Perform all math operations in single precision |
-fpack-struct |
Pack all structure members without any padding |
-fpcc-struct-return |
Return all struct and union values in memory, rather than in registers. (Returning values this way is less efficient, but is compatible with other compilers.) |
-fPIC |
Generate position-independent code (PIC) suitable for use in a shared library |
-freg-struct-return |
When possible, return struct and union values in registers |
-g |
Generate debugging information. (The GNU debugger can use this information.) |
-IDIRECTORY |
Search the specified directory for files you include by using the #include preprocessor directive |
-LDIRECTORY |
Search the specified directory for libraries |
-lLIBRARY |
Search the specified library when linking |
-mcpu= cputype |
Optimize code for a specific processor ( cputype can take many different values-some common ones are i386 , i486 , i586 , i686 , pentium2 , pentium3 , and pentium4 ). |
-o FILE |
Generate the specified output file (used to designate the name of an executable file) |
-O0 |
Do not optimize |
-O or -O1 |
Optimize the generated code |
-O2 |
Optimize even more |
-O3 |
Perform optimizations beyond those done for -O2 |
-pedantic |
Generate errors if any non-ANSI standard extensions are used |
-pg |
Add extra code to the program so that, when run, it generates information the gprof program can use to display timing details for various parts of the program |
-shared |
Generate a shared object file (typically used to create a shared library) |
-U MACRO |
Undefine the specified macro ( MACRO ) |
-v |
Display the version number of GCC |
-w |
Don't generate any warning messages |
-Wl, OPTION |
Pass the OPTION string (containing multiple comma-separated options) to the linker. To create a shared library named libXXX.so.1, for example, use the following flag: -Wl,-soname,libXXX.so.1 |
When an application is made up of more than a few source files, compiling and linking the files by manually typing the
gcc command is inconvenient. Also, you do not want to compile every file whenever you change something in a single source file. The GNU
make utility is helpful in this situation because
make can compile only those files that really must be compiled.
The
make utility works by reading and interpreting a makefile: a text file you have to prepare according to a specified syntax. The makefile describes which files constitute a program and explains how to compile and link the files to build the program. Whenever you change one or more files, make determines which files should be recompiled and issues the appropriate commands for compiling those files and rebuilding the program.
The
make utility is, in fact, specified in Section 6.2 of the POSIX.2 standard (IEEE Standard 1003.2-1992) for shells and tools. GNU make conforms to the POSIX.2 standard.
By default, GNU
make looks for a makefile that has one of the following names, in the order shown:
In UNIX systems, using
Makefile as the name of the makefile is customary because it appears near the beginning of directory listings where the uppercase names appear before the lowercase names.
When you download software from the Internet, you usually find a
Makefile , together with the source files. To build the software, you have only to type make at the shell prompt; make takes care of all the steps necessary to build the software.
If your makefile does not have a standard name, such as
Makefile , you have to use the
-f option to specify the makefile's name. If your makefile is called
webprog.mak , for example, you have to run
make using the following command line:
make -f webprog.mak
GNU
make also accepts several other command-line options, which are summarized in the 'How to Run make' section of this chapter.
For a program that consists of several source and header files, the makefile specifies the following:
The items
make will create-usually the object files and the executable. The term target is used for an item to be created.
The files or other actions required to create the target.
Which commands should be executed to create each target.
Suppose you have a C++ source file named
form.C that contains the following preprocessor directive:
#include "form.h" // Include header file
The object file
form.o clearly depends on the source file
form.C and the header file
form.h . In addition to these dependencies, you must specify how
make should convert the
form.C file to the object file
form.o . Suppose you want
make to run
g++ (because the source file is in C++) with these options:
-c (compile only)
-g (generate debugging information)
-O2 (optimize some)
In the makefile, you can express this with the following rule:
# This a comment in the makefile # The following lines indicate how form.o depends # form.C and form.h and how to create form.o. form.o: form.C form.h g++ -c -g -O2 form.C
In this example, the first noncomment line shows
form.o as the target and
form.C and
form.h as the dependent files.
Insider Insight |
The line following the dependency indicates how to build the target from its dependents. This line must start with a Tab; otherwise make will not work. |
The benefit of using
make is that it prevents unnecessary compilations. After all, you can invoke
g++ (or
gcc ) in a shell script to compile and link all the files that make up your application, but the shell script compiles everything, even if the compilations are unnecessary. GNU
make , on the other hand, builds a target, only if one or more of its dependents have changed since the last time the target was built.
make verifies this change by examining the time of the last modification of the target and the dependents.
make treats the target as the name of a goal to be achieved; the target does not have to be a file. You can have a rule such as this:
clean: rm -f *.o
This rule specifies an abstract target named clean that does not depend on anything. This dependency statement says that to make clean, GNU make should invoke the command
rm -f *.o , which deletes all files that have the .o extension (these are the object files). Thus, the net effect of creating the target named clean is to delete the object files.
In addition to the basic service of building targets from dependents, GNU
make includes many nice features that make it easy for you to express the dependencies and rules for building a target from its dependents. If you need to compile a large number of C++ files by using GCC with the same options, for example, typing the options for each file is tedious. You can avoid this task by defining a variable or macro in
make as follows:
# Define macros for name of compiler CXX= g++ # Define a macro for the GCC flags CXXFLAGS= -O2 -g -mcpu=i686 # A rule for building an object file form.o: form.C form.h $(CXX) -c $(CXXFLAGS) form.C
In this example,
CXX and
CXXFLAGS are
make variables. GNU
make prefers to call them variables, but most UNIX
make utilities call them macros.
To use a variable anywhere in the makefile, start with a dollar sign (
$ ) followed by the variable within parentheses. GNU
make replaces all occurrences of a variable with its definition; thus, it replaces all occurrences of
$(CXXFLAGS) with the string
-O2 -g -mcpu=i686 .
GNU
make has several predefined variables that have special meanings. Table 23-2 lists these variables. In addition to the variables listed in Table 23-2, GNU
make considers all environment variables predefined.
Variable |
Meaning |
---|---|
$% |
Member name for targets that are archives. If the target is libDisp.a(image.o) , for example, $% is image.o , and $@ is libDisp.a . |
$* |
Name of the target file without the extension |
$+ |
Names of all dependent files with duplicate dependencies, listed in their order of occurrence |
$ < |
The name of the first dependent file |
$? |
Names of all dependent files (with spaces between the names) that are newer than the target |
$@ |
Complete name of the target |
$^ |
Names of all dependent files, with spaces between the names. Duplicates are removed from the dependent filenames. |
AR |
Name of the archive-maintaining program (Default value: ar ) |
ARFLAGS |
Flags for the archive-maintaining program (Default value: rv ) |
AS |
Name of the assembler program that converts the assembly language to object code (Default value: as ) |
ASFLAGS |
Flags for the assembler |
CC |
Name of the C compiler. (Default value: cc ) |
CFLAGS |
Flags to be passed to the C compiler |
CO |
Name of the program that extracts a file from RCS (Default value: co ) |
COFLAGS |
Flags for the RCS co program |
CPP |
Name of the C preprocessor (Default value: $(CC) -E ) |
CPPFLAGS |
Flags for the C preprocessor. |
CXX |
Name of the C++ compiler (Default value: g++ ) |
CXXFLAGS |
Flags to be passed to the C++ compiler |
FC |
Name of the FORTRAN compiler (Default value: f77 ) |
FFLAGS |
Flags for the FORTRAN compiler |
GET |
Name of the program to extract a file from SCCS (Default value: get ) |
GFLAGS |
Flags for the SCCS get program |
LDFLAGS |
Flags for the compiler when it is supposed to invoke the linker ld |
LEX |
Name of the program to convert Lex grammar to C program (Default value: lex ) |
LFLAGS |
Flags for Lex |
MAKEINFO |
Name of the program that converts Texinfo source files to info files (Default value: makeinfo ) |
Name of the command to delete a file (Default value: rm -f ) |
|
TEX |
Name of the program to generate TeX DVI files from TeX source files (Default value: tex ) |
TEXI2DVI |
Name of the program to generate TeX DVI files from the Texinfo source (Default value: texi2dvi ) |
YACC |
Name of the program to convert YACC grammars to C programs (Default value: yacc -r ) |
YFLAGS |
Flags for yacc |
GNU
make also includes built-in, or implicit, rules that define how to create specific types of targets from various dependencies. An example of an implicit rule is the command that make should execute to generate an object file from a C source file.
GNU make supports two types of implicit rules:
Suffix rules -Suffix rules define implicit rules for
make . A suffix rule defines how to convert a file that has one extension to a file that has another extension. Each suffix rule is defined with the target showing a pair of suffixes (file extensions). The suffix rule for converting a
.c (C source) file to a
.o (object) file, for example, might be written as follows:
.c.o: $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
This rule uses the predefined variables
CC ,
CFLAGS and
CPPFLAGS . For filenames, the rule uses the variables
$@ (the complete name of the target) and
$ < (the name of the first dependent file).
Pattern rules-These rules are more versatile because you can specify more complex dependency rules by using pattern rules. A pattern rule looks just like a regular rule, except that a single percent sign (
% ) appears in the target's name. The dependencies also use
% to indicate how the dependency names relate to the target's name. The following pattern rule specifies how to convert any file
X.c to a file
X.o :
%.o: %.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
GNU
make has a large set of implicit rules, defined as both suffix and pattern rules. To see a list of all known variables and rules, run make by using the following command:
make -p -f/dev/null
The output includes the names of variables, as well as implicit rules.
You can write a makefile easily if you use GNU
make 's predefined variables and its built-in rules. Consider, for example, a makefile that creates the executable
xdraw from three C source files (
xdraw.c ,
xviewobj.c , and
shapes.c ) and two header files (
shapes.h ). Assume that each source file includes one of the header files. Given these facts, here is what a sample makefile might look like:
######################################################### # Sample makefile # Comments start with '#' # ######################################################### # Use standard variables to define compile and link flags CFLAGS= -g -O2 # Define the target "all" all: xdraw OBJS=xdraw.o xviewobj.o shapes.o xdraw: $(OBJS) # Object files xdraw.o: Makefile xdraw.c xdraw.h xviewobj.o: Makefile xviewobj.c xdraw.h shapes.o: Makefile shapes.c shapes.h
This makefile relies on GNU
make 's implicit rules. The conversion of
.c files to
.o files uses the built-in rule. Defining the variable
CFLAGS passes the flags to the C compiler.
The target named
all is defined as the first target in a makefile for a reason-if you run GNU
make without specifying any targets in the command line (see the
make syntax described in the following section), it builds the first target it finds in the makefile. By defining the first target
all as
xdraw , you can ensure that
make builds this executable file, even if you do not explicitly specify it as a target. UNIX programmers traditionally use
all as the name of the first target, but the target's name is immaterial; what matters is that it is the first target in the makefile.
If you have a directory that contains the appropriate source files and header files, you can try the makefile. Here's what happens when I try the sample makefile:
make cc -g -O2 -c xdraw.c -o xdraw.o cc -g -O2 -c xviewobj.c -o xviewobj.o cc -g -O2 -c shapes.c -o shapes.o cc xdraw.o xviewobj.o shapes.o -o xdraw
As the output of make shows,
make uses the
cc command (which happens to be a symbolic link to GCC in your Red Hat Linux system) with appropriate options to compile the source files and, finally, to link the objects to create the xdraw executable.
Typically, you run
make with a single command in the command line; that is, you run make by typing
make . When run this way, GNU
make looks for a file named
GNUmakefile ,
makefile , or
Makefile -in that order. If
make finds one of these makefiles, it builds the first target specified in that makefile. However, if
make does not find an appropriate makefile, it displays the following error message and exits:
make: *** No targets. Stop.
If your makefile happens to have a different name from the default names, you have to use the
-f option to specify the makefile. The syntax of this
make option is the following:
make -f filename
where
filename is the name of the makefile.
Even when you have a makefile with a default name such as Makefile, you may want to build a specific target out of several targets defined in the makefile. In that case, you have to run make by using this syntax:
make target
If the makefile contains the target named
clean , you can build that target with this command:
make clean
Another special syntax overrides the value of a
make variable. For example, GNU make uses the
CFLAGS variable to hold the flags used when compiling C files. You can override the value of this variable when you invoke
make . Here is an example of how you can define
CFLAGS to be the option
-g -O2 :
make CFLAGS="-g -O2"
In addition to these options, GNU make accepts several other command-line options. Table 23-3 lists the GNU
Option |
Meaning |
---|---|
-b |
Ignore but accept for compatibility with other versions of make |
-C DIR |
Change to the specified directory before reading the makefile |
-d |
Print debugging information |
-e |
Allow environment variables to override definitions of similarly named variables in the makefile |
-f |
Read FILE as the makefile |
-h |
Display the list of make options |
-i |
Ignore all errors in commands executed when building a target |
-I DIR |
Search specified directory for included makefiles (the capability to include a file in a makefile is unique to GNU make ) |
-j NUM |
Specify the number of commands that make can run simultaneously |
-k |
Continue to build unrelated targets, even if an error occurs when building one of the targets |
-l LOAD |
Don't start a new job if load average is at least LOAD (a floating-point number) |
-m |
Ignore but accept for compatibility with other versions of make |
-n |
Print the commands to be executed, but do not execute them |
-o |
Do not rebuild the file named FILE , even if it is older than its dependents |
-p |
Display the make database of variables and implicit rules |
-q |
Do not run anything, but return zero if all targets are up to date; return 1 if anything needs updating and 2 if an error occurs |
-r |
Get rid of all built-in rules |
-R |
Get rid of all built-in variables and rules |
-s |
Work silently (without displaying the commands as they are executed) |
-t |
Change the timestamp of the files |
-v |
Display the version number of make and a copyright notice |
-w |
Display the name of the working directory before and after processing the makefile |
-W FILE |
Assume that the specified file has been modified (used with -n to see what happens if you modify that file) |