• Keine Ergebnisse gefunden

Library Declaratlon Files

Im Dokument ROS programmer's (Seite 35-38)

Lint

accepts certain library directives, such as -1m

and tests the source files for compatibility with these libraries. This is done by accessing library description files whose names are constructed from the library directives. These files all begin with the directive

/*

LINTLIBRARY

*/

which is followed by a series of dummy function definitions. The critical parts of these definitions are the declaration of the function return type, whether the dummy function returns a value, and the number and types of arguments to the function. The VARARGS and ARGSUSED directives can be used to specify features of the library functions.

La'nt

library files are processed almost exactly like ordinary source files. The only difference is that functions which are defined on a library file, but are not used on a source file, draw no complaints.

Lint

does not simulate a full library search algorithm, and complains if the source files contain a redefinition of a library routine (this is a feature!).

By default,

lint

checks the programs it is given against a standard library file, which con-tains descriptions of the programs which are normally loaded when a C program is run. When the -p fiag is in effect, another file is checked containing descriptions of the standard I/O library routines which are expected to be portable across various machines. The -n flag can be used to suppress all library checking.

Bu~,

etc.

Lint

was a difficult program to write, partially because it is closely connected with matters of programming style, and partially because users usually don't notice bugs which cause

lint

to miss errors which it should have caught. (By contrast, if

Unt

incorrectly complains about some-thing that is correct, the programmer reports that immediately!)

A number of areas remain to be further developed. The checking of structures and arrays is rather inadequate; size incompatibilities go unchecked, and no attempt is made to match up structure and union declarations across files. Some stricter checking of the use of the typed.ef is clearly desirable, but what checking is appropriate, and how to carry it out, is still to be deter-mined.

L,,'nt

shares the preprocessor with the C compiler. At some point it may be appropriate for a special version of the preprocessor to be constructed which checks for things such as unused macro definitions, macro arguments which have side effects which are not expanded at all, or are expanded more than once, etc.

The central problem with

lint

is the packaging of the information which it collects. There are many options which serve only to turn off, or slightly modify, certain features. There are pressures to add even more of these options.

In conclusion, the use of two programs is efficient: the compiler turns the program source into executable form, and

lint

concentrates on issues of portability, style, and efficiency.

Incorrectness and over-conservatism are only annoying, not fatal, so

Lint

can afford to be wrong. The compiler can be fast since it knows that

Unt

will correct its deficiencies. Finally, the programmer can concentrate at one stage of the programming process solely on the algo-rithms, data structures, and correctness of the program, and then later retrofit, with the aid of

Ia'nt,

the desirable properties of universality and portability.

See the lint( 1) page of the

ROS Reference Manual (9010)

for a summary of the lint options.

This document is based on a paper by S.1. Feldman of Bell Laboratories, August, 1978.

Intzoduct.lon

Make

mechanizes many activities of program development and maintenance. It is a mechanism for maintaining an up-to-date version of all the component files of a small to medium-size program.

Many files may exist as parts of a larger program. Some may require a macro procesor, others may need compiling with special options by different language compilers, and others may require processing by yace or lex. The output code from some steps may have to be loaded with special libraries and tested by certain test scripts.

Make

records the interdependence of files, mechanizes the procedure of figuring out which object modules need recompilation, and memorizes the exact sequence of operations needed to make or exercise a new version of the program.

Once the appropriate information has been established in a file, the simple command make

is frequently sumcient to update the involved program files, regardless of the number that have been edited since the last "make". The description file is easy to write and it changes infre-quently, making use of the make command easier than issuing one of the component com-mands by hand. The typical cycle of program development is:

think - edit - make - test ...

Make does not solve the problems of maintaining multiple source versions or of describ-ing huge programs.

Inttoduetory Examples

mak e updates a target file by ensuring that all of the flIes on which it depends exist and are up to date, then creates the target if it has not been modified since its dependents were.

Make does a depth-first search of the graph of dependences. The date and time of file modification is the key for make to determine if it needs updating.

To illustrate, let us consider a simple example: A program named prog is made by compil-ing" and loading three C-Ianguage files x.c, y. c, and z. c with the 1m library. By convention, the output of the C compilations will be found in files named X.O, y.o, and z.o. Assume that the files x.c and y.c share some declarations in a file named de/s, but that z.c does not. That is, X.C

and y. c have the line

#include "defs"

The following text describes the relationships and operations:

prog: x.o y.O z.O

cc x.o y.o z.o - 1m - 0 prog x.o y.o: defs

If this information were stored in a file named makefile, the command

make

would perform the operations needed to recreate prog after any changes had been made to any of the four source files x.c, y.c, z.c, or de!s.

Make operates using three sources of information: a user-supplied description file (as above), file names and "last-modified" times from the file system, and built-in rules to bridge some of the gaps. In our example, the first line says that prog depends on three. ".0" files.

Once these object files are current, the second line describes how to load them to create prog.

The third line says that x.o and y.o depend on the file de!s. From the file system, make discov-ers that there are three ". c" files corresponding to the needed ".0" files, and uses built-in information on how to generate an object from a source file (i.e., issue a "cc - c" command).

The following long-winded description file is equivalent to the one above, but takes no advantage of make's innate knowledge:

prog: x.o y.o z.o

cc x.o y.o z.o - IS - 0 prog x.o : x.c defs

cc - c x.c y.o : y.c defs

cc - c y.c z.o: z.c

cc - c z.c

If none of the source or object files had changed since the last time prog was made, all of the files would be current, and the command

make

would just announce this f~t and stop. If, however, the de!s file had been edited, x.c and y.c (but not z.c) would be recompiled, and then prog would be created from the new" .0" files. If only the file y.c had changed, only it would be recompiled, but it would still be necessary to reload prog.

If no target name is given on the make command line, the first target mentioned in the description is created; otherwise the specified targets are made. The command

make x.o

would recompile x.o if x.c or de!s had changed.

If the file exists after the commands are executed, its time of last modification is used in further decisions; otherwise the current time is used. It is often quite useful to include rules with mnemonic names and commands that do not ~tually produce a file with that name.

These entries can take advantage of make's ability to generate flIes and substitute macros.

Thus, an entry "save" might be included to copy a certain set of flIes, or an entry "cleanup"

might be used to throwaway unneeded intermediate files. In other cases one may maintain a zero-length file purely to keep tr~k of the time at which certain ~tions were performed. This technique is useful for maintaining remote archives and listings.

Make has a simple macro mechanism for substituting in dependency lines and command strings. Macros are defined by command arguments or description file lines with embedded equal signs. A m~ro is invoked by preceding the name by a dollar sign; m~ro names longer than one char~ter must be parenthesized. The name of the m~ro is either the single character after the dollar sign or a name inside parentheses. The following are valid m~ro invocations:

$(CFLAGS)

$2

$(XY)

$Z

$(Z)

The last two invocations are identical. $$ is a dollar sign. All of these macros are assigned values during input, as shown below. Four special macros change values during the execution of the command: $*, $@, $?, and $

<.

They will be discussed later. The following fragment shows the use:

OBJECTS = x.o y.O Z.O LIBES =

prog: $( OBJECTS)

cc $( OBJECTS) $(LIBES) - 0 prog The command

make

loads the three object files with the Ie library, which is automatically included by the cc( 1) com-mand. The command

make "LIBES= - 11- 1m"

loads them with both the Lex ("- 11") and the Standard ("- lc") libraries, since macro definitions on the command line override definitions in the description.

The following sections detail the form of description files and the command line, and dis-cuss options and builtrin rules in more detail.

Im Dokument ROS programmer's (Seite 35-38)