Introduction to Compilation


The GNU compiler takes a number of different stages in the process of building an object. These stages can be filtered down to four: preprocessing, compiling, assembling, and linking (see Figure 4.1).

click to expand
Figure 4.1: The stages of compilation.

The preprocessing, compiling, and assembling stages are commonly collected together into one phase, but they re shown as independent here to illustrate some of the capabilities of GCC. Table 4.1 identifies the input files and files that result.

In the preprocessing stage, the source file ( *.c ) is preprocessed with the include files ( .h headers). At this stage, directives such as #ifdef , #include , and #define are resolved. The result is an intermediate file. Usually, this file isn t externally generated at all, but we show it here for completeness. With the source file now preprocessed, it can be compiled into assembly in the compiling stage ( *.s ). The assembly file is then converted into machine instructions in the assembling stage, resulting in an object file ( *.o ). Finally, the machine code is linked together ( potentially with other machine code objects or object libraries) into an executable binary.

Table 4.1: Compilation Stages with Inputs and Outputs

Stage

Input

Output

GCC Example

Preprocessing

*.c

*.i

gcc -E  test.c -o test.i

Compiling

*.i

*.s

GCC -S test.i -o test.s

Assembling

*.s

*.o

GCC -c test.s -o test.o

Linking

*.o

*

GCC test.o -o test

That s enough preliminaries . Let s now dig into GCC and see the variety of ways it can be used. We ll first look at a number of patterns that illustrate GCC in use, and then we ll explore some of the most useful options of GCC. This includes options for debugging, enabling various warnings, and optimizations. We ll then investigate a number of GNU tools that are related to GCC.

Patterns for GCC (Compile, Compile and Link)

The simplest example from which to begin is the compilation of a C source file to an image. In this example, the entire source necessary is contained within the single file, so we use GCC as follows :

 $ GCC test.c -o test 

Here we compile the  test.c file and place the resulting executable image in a file called test (using the -o output option). If instead we wanted just the object file for the source, we d use the -c flag, as follows:

 $ GCC -c test.c 

By default, the resulting object is named test.o , but we could force the output of the object to newtest.o , as:

 $ GCC -c test.c -o newtest.o 

Most programs we ll develop will involve more than one file. GCC handles this easily on the command line as:

 $ GCC -o image first.c second.c third.c 

Here we compile three source files ( first.c , second.c , and third.c ) and link them together into the executable named image .

Note  

In all examples where an executable will result, all C programs require a function called main . This is the main entry point for the program and should appear once in all the files to be compiled and linked together. When simply compiling a source file to an object, the link phase is not yet performed, and therefore the main function is not necessary.

Useful Options

In many cases, we ll keep our header files in a directory that s separate from where we keep our source files. Consider an example where our source is kept in a subdirectory called ./src , and at the same level is a directory where our include files are kept, ./inc . We can tell GCC that the headers are provided here (while compiling within the ./src subdirectory as:

 $ gcc test.c -I../inc -o test 

We could specify numerous include subdirectories using multiple -I specs :

 $ gcc test.c -I../inc -I../../inc2 -o test 

Here we specify another include subdirectory called inc2 that is two directories up from our current directory.

For configuration of software, we can specify symbolic constants on the compile line. For example, defining a symbolic constant in source or header as

 #define TEST_CONFIGURATION 

could be just as easily defined on the command line using the -D option as:

 $ gcc -DTEST_CONFIGURATION test.c -o test 

The advantage to specifying this on the command line is that we need not modify any source to change its behavior (as specified by the symbolic constant).

One final useful option provides us with the means to emit a source and assembly interspersed listing. Consider the following command line:

 $ gcc -c -g -Wa,-ahl,-L test.c 

Most interesting in this command is the -Wa option, which passes the subsequent options to the assembler stage to intersperse the C source with assembly.

Compiler Warnings

While the GCC compiler will abort the compilation process if an error is detected, the discovery of warnings indicates potential problems that should be fixed, though it might still result in a working executable. GCC provides a very rich warning system, but it must be enabled to take advantage of the full spectrum of warnings that can be detected .

The most common use of GCC for finding common warnings is the -Wall option. This turns on all warnings of a given type, which consists of the most generally encountered issues in applications. Its use is this:

 $ gcc -Wall test.c -o test 
Table 4.2: Warning Options Enabled in -Wall

Option

Purpose

unused-function

Warn of undefined but declared static function.

unused-label

Warn of declared but unused label.

unused-parameter

Warn of unused function argument.

unused-variable

Warn of unused locally declared variable

unused-value

Warn of computed but unused value.

format

Verify that the format strings of printf and so on have valid arguments based upon the types specified in the format string.

implicit-int

Warn when a declaration doesn t specify a type.

implicit-function-

Warn of a function being used prior to its declaration. _declaration

char-subscripts

Warn if an array is subscripted by a char (common error considering that the type is signed).

missing-braces

Warn if an aggregate initializer is not fully bracketed.

parentheses

Warn of omissions of ()s if they could be ambiguous.

return-type

Warn of function declarations that default to int or functions that lack a return, which note a return type.

sequence-point

Warn of code elements that are suspicious (such as a[i] = c[i++]; ).

switch

In switch statements that lack a default, warn of missing cases that would be present in the switch argument.

strict-aliasing

Use strictest rules for aliasing of variables (such as trying to alias a void* to a double ).

unknown-pragmas

Warn of #pragma directives that are not recognized.

uninitialized

Warn of variables that are used but not initialized (enabled only with -O2 optimization level).

A synonym for -Wall is ”all-warnings . Table 4.2 lists the plethora of warning options that are enabled within -Wall .

Note that most options also have a negative form, so that they can be disabled (if on by default or covered by an aggregate option such as -Wall ). For example, if we wanted to enable -Wall but disable the unused warning set, we could specify this as follows:

 $ gcc -Wall -Wno-unused test.c -o test 
Table 4.3: Other Useful Warning Options Not Enabled in -Wall

Option

Purpose

cast-align

Warn whenever a pointer is cast and the required alignment is increased.

sign-compare

Warn if a signed vs. unsigned compare could yield an incorrect result.

missing- prototypes

Warn if a global function is used without a previous prototype definition.

packed

Warn if a structure is provided with the packed attribute and no packing occurs.

padded

Warn if a structure is padded to align it (resulting in a larger structure).

unreachable-code

Warn if code is found that can never be executed.

inline

Warn if a function marked as inline could not be inlined.

disabled-optimization

Warn that the optimizer was not able to perform a given optimization (required too much time or resources to perform).

Numerous other warnings can be enabled outside of -Wall . Table 4.3 provides a list of some of the more useful options and their descriptions.

One final warning option that can be very useful is -Werror . This option specifies that instead of simply issuing a warning if one is detected, the compiler will instead treat all warnings as errors and abort the compilation process. This can be very useful to ensure the highest quality code and is therefore recommended.




GNU/Linux Application Programming
GNU/Linux Application Programming (Programming Series)
ISBN: 1584505680
EAN: 2147483647
Year: 2006
Pages: 203
Authors: M. Tim Jones

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net