make: Keeps a Set of Programs Current


make: Keeps a Set of Programs Current

Tip: This section covers the GNU make program

This section describes the GNU make program. Other make tools (BSN make, GNUstep make, Borland make, and so on) are available as well as similar tools such as ant (the Apache build tool). Makefiles created for GNU make are often incompatible with other make tools, which can be problematic if you are trying to compile code targeted for another platform.


In a large program with many source and header files, the files typically depend on one another in complex ways. When you change a file that other files depend on, you must recompile all dependent files. For example, you might have several source files, all of which use a single header file. When you change the header file, you must recompile each of the source files. The header file might depend on other header files, and so forth. Figure 27-3 shows a simple example of these kinds of dependency relationships. Each arrow in this figure points from a file to another file that depends on it.

Figure 27-3. Dependency graph for the target form


When you are working on a large program, it can be difficult, time-consuming, and tedious to determine which modules need to be recompiled because of their dependency relationships. The make utility automates this process.

Dependency lines: target files and prerequisite files


At its simplest, make looks at dependency lines in a file named makefile or Makefile in the working directory. The dependency lines indicate relationships among files, specifying a target file that depends on one or more prerequisite files. If you have modified any of the prerequisite files more recently than their target file, make updates the target file based on construction commands that follow the dependency line. The make utility normally stops if it encounters an error during the construction process.

The file containing the updating information for the make utility is called a makefile. (See page 832 for a trivial example.) A simple makefile has the following syntax:


target: prerequisite-list
TAB construction-commands

The dependency line consists of the target and the prerequisite-list, separated by a colon. Each construction-commands line (you may have more than one) must start with a TAB and must follow the dependency line. Long lines can be continued by placing a BACKSLASH (\) as the last character on the line.

The target is the name of the file that depends on the files in the prerequisite-list. The construction-commands are regular shell commands that construct (usually compile and/or link) the target file. The make utility executes the construction-commands when the modification time of one or more files in the prerequisite-list is more recent than that of the target file.

The following example shows the dependency line and construction commands for the file named form in Figure 27-3. The form file depends on the prerequisites size.o and length.o. An appropriate gcc command constructs the target:

form: size.o length.o TAB    gcc -o form size.o length.o


Each of the prerequisites on one dependency line can be a target on another dependency line. For example, both size.o and length.o are targets on other dependency lines. Although the example in Figure 27-3 illustrates a simple case, in other situations the nesting of dependency specifications can create a complex hierarchy that dictates relationships among many files.

The following makefile (named Makefile) corresponds to the complete dependency structure shown in Figure 27-3. The executable file form depends on two object files, and each of these object files depends on its respective source file and a header file, form.h. In turn, form.h depends on two other header files.

$ cat Makefile form: size.o length.o         gcc -o form size.o length.o size.o: size.c form.h         gcc -c size.c length.o: length.c form.h         gcc -c length.c form.h: num.h table.h         cat num.h table.h > form.h


Although the last line would not normally be seen in a makefile, it illustrates the point that you can put any shell command on a construction line. Because the shell processes makefiles, the command line should be one that you could enter in response to a shell prompt.

The following command builds the default target form if any of its prerequisites are more recent than their corresponding targets or if any of the targets do not exist:

$ make


Thus, if the file form has been deleted, make will rebuild it, regardless of the modification dates of its prerequisite files. The first target in a makefile is the default and is built when you call make without any arguments.

If you want make to rebuild a target other than the first one in the makefile, you must provide that target as an argument to make. The following command rebuilds only form.h if it does not exist or if its prerequisites were more recently modified than the target:

$ make form.h


Implied Dependencies

You can rely on implied dependencies and construction commands to facilitate the job of writing a makefile. For instance, if you do not include a dependency line for an object file, make assumes that the object file depends on a compiler or assembler source code file. Thus, if a prerequisite for a target file is xxx.o and no dependency line identifies xxx.o as a target, make looks at the filename extension to determine how to build the .o file. If it finds an appropriate source file, make provides a default construction command line that calls the proper compiler or the assembler to create the object file. Table 27-1 lists some filename extensions that make recognizes and the type of file that corresponds to each filename extension.

Table 27-1. Filename extensions

Filename with extension

Type of file

filename.c

C programming language source code

filename.C, filename.cc, filename.cxx, filename.c++, filename.cpp

C++ programming language source code

filename.f

Fortran programming language source code

filename.h

Header file

filename.l

flex, lex lexical analyzer generator source code

filename.m

Objective-C programming language source code

filename.o

Object module

filename.s

Assembler code

filename.sh

Shell script

filename.y

bison, yacc parser generator source code


C and C++ are traditional programming languages that are available with Red Hat many other Linux distributions. The bison and flex tools create command languages.

In the next example, a makefile keeps the file named compute up-to-date. The make utility ignores any line that begins with a pound sign (#), so the first three lines of the following makefile are comment lines. The first dependency line shows that compute depends on two object files: compute.o and calc.o. The corresponding construction line gives the command that make needs to produce compute. The second dependency line shows that compute.o depends not only on its C source file but also on the compute.h header file. The construction line for compute.o uses the C compiler optimizer (O3 option). The third set of dependency and construction lines is not required. In their absence, make infers that calc.o depends on calc.c and produces the command line needed for the compilation:

$ cat Makefile # # Makefile for compute # compute: compute.o calc.o         gcc -o compute compute.o calc.o compute.o: compute.c compute.h         gcc -c -O3 compute.c calc.o: calc.c         gcc -c calc.c clean:         rm *.o *core* *~


There are no prerequisites for clean, the last target. This target is commonly used to get rid of extraneous files that may be out-of-date or no longer needed, such as .o files.

Below are some sample executions of make based on the previous makefile. As the ls command shows, compute.o, calc.o, and compute are not up-to-date. Consequently the make command runs the construction commands that re-create them.

$ ls -ltr total 22 rwrw  1 alex  pubs  311 Jun 21 15:56 makefile rwrw  1 alex  pubs  354 Jun 21 16:02 calc.o rwxrwx  1 alex  pubs 6337 Jun 21 16:04 compute rwrw  1 alex  pubs   49 Jun 21 16:04 compute.h rwrw  1 alex  pubs  880 Jun 21 16:04 compute.o rwrw  1 alex  pubs  780 Jun 21 18:20 compute.c rwrw  1 alex  pubs  179 Jun 21 18:20 calc.c $ make gcc -c -O3 compute.c gcc -c calc.c gcc -o compute compute.o calc.o


If you run make once and then run it again without making any changes to the prerequisite files, make indicates that the program is up-to-date and does not execute any commands:

$ make make: 'compute' is up to date.


touch


The next example uses the touch utility to change the modification time of a prerequisite file. This simulation shows what happens when you alter the file. The make utility executes only the commands necessary to bring the out-of-date targets up-to-date:

$ touch calc.c $ make gcc -c calc.c gcc -o compute compute.o calc.o


In the next example, touch changes the modification time of compute.h. The make utility re-creates compute.o because it depends on compute.h and re-creates the executable because it depends on compute.o:

$ touch compute.h $ make gcc -c -O3 compute.c gcc -o compute compute.o calc.o


n


If you want to see what make would do if you ran it, run it with the n (no execute) option. This option displays the commands that make would execute but it does not execute them.

t


As these examples illustrate, touch is useful when you want to fool make either into recompiling programs or into not recompiling them. You can use touch to update the modification times of all source files so that make considers nothing to be up-to-date; make will then recompile everything. Alternatively, you can use touch or the t option to make to touch all relevant files; make then considers everything to be up-to-date. Using touch in this manner is useful if the modification times of files have changed yet the files remain up-to-date (as can happen when you copy a set of files from one directory to another).

The following example uses make n several times to see what make would do if you gave a make command. The first command shows that the target, compute, is up-to-date. Next touch makes the modification dates on all *.c files more recent than their targets, and make n shows what make would do if you called it without the n option. The maket command then brings all targets up-to-date. The final make n command confirms that compute is up-to-date.

$ make n make: 'compute' is up to date. $ touch *.c $  make n gcc c O3 compute.c gcc c calc.c gcc o compute compute.o calc.o $  make t touch compute.o touch calc.o touch compute $  make n make: 'compute' is up to date.


j


The j (jobs) option performs a number of tasks in parallel; the numeric argument to j specifies the number of jobs or processes. Most make tasks hit the disk first and the CPU second, resulting in CPU usage dropping between compilations. On a multiprocessor system, you can reduce CPU usage by issuing the command make j n, where n is the number of CPUs plus 1. Running tasks in parallel can significantly reduce the build time for a large project.

It is a good idea to keep intermediate files around while you are writing and debugging a program so that you need to rebuild only the ones that change. Once you are satisfied with the program you have created, you can use the makefile to release the disk space occupied by the extra files. Using a clean target in a makefile means that you do not have to remember all the little pieces that can safely be deleted. The next example simply removes all object (.o) files and all files with filenames that end with a tilde (~):

$ make clean rm *.o *.~


Optional: Macros

The make utility's macro facility enables you to create and use macros within a makefile. The syntax of a macro definition is

ID = list

where ID is an identifying name and list is a list of filenames. After this macro definition, $(ID) represents list in the makefile.

With a macro you can compile a program with any of several C compilers by making only a minor change to the makefile. By using the CC macro and replacing all occurrences of gcc in the makefile on page 846 with $(CC), for example, you need to assign a value only to CC to use the compiler of your choice:

$ cat Makefile # # Makefile for compute # CC=gcc compute: compute.o calc.o         $(CC) o compute compute.o calc.o compute.o: compute.c compute.h         $(CC) c O3 compute.c calc.o: calc.c         $(CC) c calc.c clean:         rm *.o


This example assumes that the compiler/loader flags are the same across compilers/loaders. In a more complex situation, you may need to create macros for these flags or use the default values.

Several commercial, high-performance compilers are available for Linux. You could specify the compiler from the Portland Group, pgcc, by replacing the CC=gcc assignment with CC=pgcc. If you do not assign a value to the CC macro, it defaults to gcc under Linux. The CC macro invokes the C compiler with only the options that you specify.

Several other macro definitions are commonly used. The CFLAGS macro sends arguments to the C compiler, LDFLAGS sends arguments to the linker (ld, or gcc o), and CPPFLAGS sends arguments to the C preprocessor and programs that use it, including gcc. The COMPILE.c macro expands to $(CC) c $(CFLAGS) $(CPPFLAGS). The LINK.c macro expands to $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS).

By default, make invokes the C compiler without any options (except the c option when it is appropriate to compile but not link a file). You can use the CFLAGS macro definition to cause make to call the C compiler with specific options. In the following syntax, replace options with the options you want to use:

CFLAGS = options

The following makefile uses macros as well as implied dependencies and constructions:

# makefile: report, print, printf, printh # CC=gcc CFLAGS = -O3 # comment out the two lines above and uncomment the # two below when you are using the Portland Group's compiler #CC=pgcc #CFLAGS = -fast FILES = in.c out.c ratio.c process.c tally.c OBJECTS = in.o out.o ratio.o process.o tally.o HEADERS = names.h companies.h conventions.h report: $(OBJECTS)         $(LINK.c) -o report $(OBJECTS) ratio.o: $(HEADERS) process.o: $(HEADERS) tally.o: $(HEADERS) print:        pr $(FILES) $(HEADERS) | lpr printf:        pr $(FILES) | lpr printh:        pr $(HEADERS) | lpr


Following the comment lines in this example, the makefile uses the CFLAGS macro to cause make always to use the optimizer (O3 option) when it invokes the C compiler as the result of an implied construction. (The CC and CFLAGS definitions for the pgcc C compiler perform the same functions when they are uncommented and you are working with pgcc, except that you use fast with pgcc and O3 with gcc.) A construction line in a makefile overrides the corresponding implied construction line, if one exists. If you want to apply a macro to a construction command, you must include the macro in that command; see OBJECTS in the construction command for the report target. Following CFLAGS, the makefile defines the FILES, OBJECTS, and HEADERS macros. Each of these macros defines a list of files.

The first dependency line in the preceding example shows that report depends on the list of files defined by OBJECTS. The corresponding construction line uses the LINK.c macro to link the files defined by OBJECTS and create an executable file named report. If you specify any LDFLAGS, they are used in this step.

The next three dependency lines show that three object files depend on the list of files defined by HEADERS. Because there are no construction lines, make looks for a source code file corresponding to each object file and compiles it. These three dependency lines ensure that the object files are recompiled if any header files change.

You can combine several targets on one dependency line, so these three dependency lines could have been combined into one line:

ratio.o process.o tally.o: $(HEADERS)


The three final dependency lines in the preceding example send source and header files to the printer. These lines have nothing to do with compiling the report file; none of these targets (print, printf, and printh) depends on anything. When you call one of these targets from the command line, make executes the construction line following it. The following command prints all source files defined by FILES:

$ make printf


You can override macros in a makefile by specifying them on the command line. The following command adds debugging symbols to all object files:

$ make CFLAGS=-g ...






A Practical Guide to Red Hat Linux
A Practical Guide to Red HatВ® LinuxВ®: Fedoraв„ў Core and Red Hat Enterprise Linux (3rd Edition)
ISBN: 0132280272
EAN: 2147483647
Year: 2006
Pages: 383

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