Section 4.2. Make

   


4.2. Make

A mainstay of Unix development is make, a tool that makes it easy for you to describe how to compile programs. Although small programs may need only one command to compile their one source code file into one executable file, it is still easier to type make than to type gcc -o2 -ggdb -DSOME_ DEFINE -o foo foo.c. Furthermore, when you have lots of files to compile, and you have changed only a few source files, make will create new object files only when the relevant source files have been modified.

For make to perform this magic, you need to describe all the files in a Makefile. Here is an example:

  1:  # Makefile  2:  3:  OBJS = foo. o bar. o baz. o  4:  LDLIBS = -L/usr/local/lib/ - lbar  5:  6:  foo: $(OBJS)  7:          gcc -o foo $(OBJS) $(LDLIBS)  8:  9:  install: foo 10:          install -m 644 foo /usr/bin 11: .PHONY: install 


  • Line 1 is a comment; make follows the common Unix tradition of delimiting comments with a # character.

  • Line 3 defines a variable called OBJS as foo.o bar.o baz.o.

  • Line 4 defines another variable, LDLIBS.

  • Line 6 starts the definition of a rule, which states that the file foo depends on (in this case, is built from) the files whose names are contained in the variable OBJS. foo is called the target, and $(OBJS) is called the dependency list. Note the syntax for variable expansion: You wrap the variable name in $(...).

  • Line 7 is a command line that tells you how to build the target from the dependency list. There may be multiple command lines, and the first character in the command line must be a tab.

  • Line 9 is an interesting target. It does not actually try to make a file called install; instead (as you can see in line 10), it installs foo in /usr/bin using the standard install program. But this line brings up an ambiguity in make: What if a file named install exists and it is newer than foo? In that case, when you run the command make install, make says, "install' is up to date" and quits.

  • Line 11 tells make that install is not a file, and that it should ignore any file named "install" when computing the install dependency. Thus, if the install dependency is invoked (we shall see how to do that later), the command in line 10 will always be invoked. .PHONY is a directive, which alters make's operation; it tells make, in this case, that the install target is not the name of a file. PHONY targets are often used to take actions such as installation or making a single target name that relies on several other targets all being built, like this:

     all: foo bar baz .PHONY: all 

    Unfortunately, .PHONY is not supported by some versions of make. A less obvious, less efficient, but more portable way of doing the same things is

     all: foo bar baz FORCE FORCE: 

    This works only if there is no file named "FORCE".

Items in dependency lists may be file names, but, as far as make is concerned, they are other targets. The foo item in the install dependency list is a target. When make attempts to resolve the install dependency, it sees that it first has to resolve the foo dependency. To resolve the foo dependency, it has to resolve the foo. o, bar. o, and baz.o dependencies.

Note that there are no lines that explicitly tell make how to build foo.o, bar.o, or baz.o. You certainly do not create these files directly in your editor of choice! make provides implied dependencies that you do not have to write. If you have a dependency on a file that ends in .o and you have a file that has the same name except that it ends in .c, make assumes that the object file depends on the source file. Built-in suffix rules provided with make allow you to greatly simplify many Makefiles, and you can write your own suffix rules (explained on page 34) when the built-in rules do not meet your needs.

By default, make exits as soon as any command it runs fails (returns an error). There are two ways to get around this, if you wish to.

The -k argument causes make to build as much as possible, without stopping as soon as a command invocation returns an error. It is useful, for example, when porting; you can build as many object files as possible, then port the files that failed to build without having to wait for intermediary files to build in the meantime.

If you know that one command will always return an error, but you wish to ignore the error condition, you can use some shell magic. The /bin/false command always returns an error, so the command

 /bin/false 


will always cause make to abort its current run unless the -k option is in use. However,

 any_ command || /bin/true 


will never cause make to abort its current run; if any_ command returns false, then the shell will run /bin/true and return its exit code, which is guaranteed to be success.

Make interprets unrecognized command-line arguments that do not start with a dash (-)[2] as targets to build. So make install will cause make to try to satisfy the install target. If the foo target is not up to date, make will first satisfy the foo dependency by building it, and then it will install it. If you need to build a target that starts with a dash, you will need to precede the target name with a separate double-dash (--) argument.

[2] The combined minus and hyphen character is often called a dash.

4.2.1. Complex Command Lines

Each command line is executed in its own subshell, so cd commands in a command line affect only the line on which they are written. You can extend any line in a Makefile over multiple lines by using backslash extension: If you put a \ as the final character on a line, the line after it will be considered to be part of it, joined to it by a space. Command lines often look like this:

  1:        cd some_directory ; \  2:          do this to file $(FOO); \  3:          do that  4:        cd another_directory ; \  5:          if [ -f some_file] ; then\  6:            do something else ; \  7:          done ; \  8:          for i in * ; do \  9:            echo $$i >> some_ file ; \ 10:         done 


There are only two lines in that fragment, as far as make is concerned. The first command line starts on line 1 and continues through line 3; the second command line starts on line 4 and continues through line 10. There are several points to note here.

  • another_ directory is relative not to some_directory, but rather to the directory in which make was run, because they are executed in different subshells.

  • The lines that constitute each command line are passed to the shell as a single line, so all the ; characters that the shell needs must be there, including the ones that are usually omitted in a shell script because the presence of newline characters implies them. For more information on shell programming, see Learning the bash Shell [Newham, 1995].

  • When you need to dereference a make variable, you can just dereference it normally (that is, $(VAR)), but when you need to dereference a shell variable, you need to escape the $ character by including it twice: $$i.

4.2.2. Variables

It often happens that you want to define a variable one component at a time. You might want to write something like this:

 OBJS = foo.o OBJS = $(OBJS) bar.o OBJS = $(OBJS) baz.o 


At this point, you expect OBJS to be defined as foo.o bar.o baz.o but it is actually defined as $(OBJS) baz.o, because make does not expand variables until they are used.[3] If you do this, as soon as you reference OBJS in a rule, make will enter an infinite loop.[4] For this reason, many Makefiles have sections that look like this:

[3] Although this behavior may seem inconvenient, it is an important feature and not a bug. Not expanding variables is critically important for writing the generic suffix rules that create implied dependencies.

[4] Most versions of make, including the GNU version, which is distributed with Linux, will detect that they are in an infinite loop and quit with an error message.

 OBJS1 = foo.o OBJS2 = bar.o OBJS3 = baz.o OBJS = $(OBJS1) $(OBJS2) $(OBJS3) 


You will most often see variable declarations like the preceding one when a variable declaration would otherwise be too long for the programmer's comfort.

Variable expansion brings up a typical issue that a Linux programmer is called on to decide. The GNU tools distributed with Linux are generally more capable than the versions of the tools included with other systems, and GNU make is no exception. The authors of GNU make created another way to do variable assignment that avoids this problem, but not every version of make understands GNU make's alternative forms of variable assignment. Fortunately, GNU make can be built for any system to which you could easily port source code written on Linux, but do you want to force the people porting your code to other systems to use GNU make? If you do, you can use simple variable assignment:

 OBJS : = foo.o OBJS : = $(OBJS) bar.o OBJS : = $(OBJS) baz.o 


The := operator causes GNU make to evaluate the variable expression at assignment time, rather than wait to evaluate the expression when it is used in a rule. With this code, OBJS does indeed contain foo.o bar.o baz.o.

Simple variable assignment is often useful, but GNU make also has another assignment syntax that deals specifically with this problem, one straight from the C language:

 OBJS := foo.o OBJS += bar.o OBJS += baz.o 


4.2.3. Suffix Rules

This is another context in which you have to decide whether to write standard Makefiles or to use useful GNU extensions. Standard suffix rules are more limited than are the GNU pattern rules, but most situations can be handled sufficiently well by the standard suffix rules, and pattern rules are not supported by many other versions of make.

Suffix rules look like this:

 .c.o:         $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $< .SUFFIXES: .c .o 


This rule says (we sweep the details under the carpet) that make should, unless it is otherwise explicitly instructed, turn a.c file into a.o file by running the attached command line. Each .c file will be treated as though it were explicitly listed as a dependency of the respective .o file in your Makefile.

That suffix rule introduces another of make's features: automatic variables. It is clear that you need a way to substitute the dependency and target into the command line. The automatic variable $@ stands for the target, $< stands for the first dependency, and $^ stands for all the dependencies.

Several other automatic variables are available and documented in the make manual. All automatic variables can be used in normal rules, as well as in suffix and pattern rules.

The final line of the example introduces another directive. .SUFFIXES tells make that .c and .o are suffixes that make should use to find a way to turn the existing source files into the desired targets.

Pattern rules are more powerful and, therefore, slightly more complex than suffix rules; it would take too long to cover them in detail here. The equivalent pattern rule to the preceding suffix rule is

 %.o : %.c         $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $< 


If you want to know more about make, see Managing Projects with make [Oram, 1993]. GNU make also includes an excellent and easy-to-read manual in Texinfo format, which you can read online, print out, or order as a book from the Free Software Foundation.

Most large Open Source projects use the Automake, Autoconf, and Libtool tools. These tools are essentially collections of knowledge about the peculiarities of different systems and of community standards for how to build projects, so that you have to write only the bits that are actually specific to your project. For example, Automake writes "install" and "uninstall" targets, Autoconf automatically determines the capabilities of the system and configures the software to match the system, and Libtool deals with differences in how shared libraries are managed between different systems. Documenting these three tools is an entire book of its own, GNU Autoconf, Automake, and Libtool [Vaughan, 2000]; Linux Application Development provides the background you need in order to read and use GNU Autoconf, Automake, and Libtool.


       
    top
     


    Linux Application Development
    Linux Application Development (paperback) (2nd Edition)
    ISBN: 0321563220
    EAN: 2147483647
    Year: 2003
    Pages: 168

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