Chinaunix首页 | 论坛 | 博客
  • 博客访问: 750252
  • 博文数量: 217
  • 博客积分: 2401
  • 博客等级: 大尉
  • 技术积分: 2030
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-16 06:58
个人简介

怎么介绍?

文章分类

全部博文(217)

文章存档

2023年(2)

2022年(3)

2021年(29)

2020年(12)

2019年(5)

2018年(5)

2017年(5)

2016年(3)

2015年(6)

2014年(12)

2013年(16)

2012年(9)

2011年(6)

2010年(15)

2009年(30)

2008年(59)

我的朋友

分类:

2010-06-19 03:42:56

Makefile Tutorial

Robert R. Snapp
Department of Computer Science
University of Vermont
Burlington, Vermont 05405
(snapp@cs.uvm.edu)

Introduction to the make program

make is a UNIX program that helps programmers efficiently build projects. The goal of each project is usually one or more executable programs. Each executable program is called a target. Thus, to create and executable program called pizza, a user would type

make pizza

in a UNIX shell. If all of the object code exists, and is up-to-date, the make program would invoke the appropriate linker, which would then produce the executable. However, if the object code is out-of-date, or does not even exist, the make program will invoke the appropriate compiler (making up-to-date object code from the project's source code), followed by a call to the linker.

Targets can also refer to other file operations. For example, it is common practice to invoke

make clean
to delete object files, executable programs, and core dumps from a project directory. (Usually you want to do this before you distribute (or submit) a project.) Similarly, one might use
make all
to compile every library and link every executable within a complex project. More formal projects might use
make install
to copy (or move) every executable, compiled library, and header file to an appropriate subdirectory in the file system. (The make program should also compile and link as needed.

Users can interact with the make program with a number of command line arguments. For example,

make -d pizza
will print lots of debugging information as it tries to make the pizza program. More information about these arguments can obtained from the make man page: Just type
man make

Introduction to makefiles

Unfortunately, the make program is not very intelligent, and thus needs instructions from the developer on how each target is created. By default, make will first look for a special file in the current directory called either makefile or Makefile. A makefile is a description file that details how each target should be processed. Let's look at a sample for my , which defines five targets:

# Robert's pizza project.
# (Characters from the first "#" to the end of the line are ignored.)

pizza.o: pizza.c pizza.h # Line 4
gcc -c pizza.c # Line 5

pizza: pizza.o # Line 7
gcc -o pizza pizza.o # Line 8

all: pizza # Line 10

clean: # Line 12
rm pizza pizza.o # Line 13

install: pizza # Line 15
mv pizza /usr/local/bin # Line 16
cp pizza.h /usr/local/include # Line 17
echo "Your pizza is ready!" # Line 18
Note how simple the syntax is. The name of each target begins a new line, and is followed by a colon. After the colon is a list of file names that the target depends on. (These are often called prerequisites. It is important to emphasize that each continuation line, that is lines 5, 8, 13, 16, 17, and 18, begin with a TAB character.

Suppose our directory contained only the following files

makefile    pizza.c     pizza.h
After typing make all, the make program would perform the following recursive tasks:

First make will try to create the file named pizza, because pizza is a prerequisite to the target all on line 10.

In order to create pizza, make will parse line 7. Since pizza.o is a prerequisite to pizza, make will needs to create pizza.o before it can create pizza.
The target pizza.o has two prerequisites: pizza.c and pizza.h. (If these did not exist, make would fail, as neither of these file names is specified as a target in the makefile.) Since both of these files exist in the current directory, line 5 is executed. Assuming the syntax of the source files is correct (and gcc exists), gcc will create the object file pizza.o.
Returning to Line 7, make can proceed with the task of creating file pizza. Line 8 is executed, and gcc will link pizza.o to create our pizza program.
Returning to Line 10, make will now attempt to execute line 11. However, this line is blank, so make will exit.

Makefile macros

The make program supports many other features that allow one to create more versitile description files. One of the most useful of these are macros. A macro is symbol that can be defined within a makefile to represent a list of other symbols. For example, we might wish to create a symbol CC that exapnds to "gcc." We can accomplish this with the single line
CC = gcc
We could then write our pizza as
# Robert's pizza project.
# (Characters from the first "#" to the end of the line are ignored.)

CC = gcc # Line 4

pizza.o: pizza.c pizza.h # Line 6
${CC} -c pizza.c # Line 7

pizza: pizza.o # Line 9
${CC} -o pizza pizza.o # Line 10

all: pizza # Line 12

clean: # Line 14
rm pizza pizza.o # Line 15

install: pizza # Line 17
mv pizza /usr/local/bin # Line 18
cp pizza.h /usr/local/include # Line 19
echo "Your pizza is ready!" # Line 20
The macro CC is expanded by typing ${CC}, as shown on lines 7 and 10. (One can use parentheses instead of brackets.) Note that $CC (without brackets) would be parsed as ${C}C. Thus, the new makefile would function as it did before. However, if you wanted to use a different compiler for your project, you would now only have to edit line 4.

Once a macro has been defined, you can overide its definition in the command line. For example, if we want to build our project with the compiler /usr/bin/cc, we could invoke the command

make all "CC = /usr/bin/cc"
It is also possible to initialize a macro variable using a UNIX shell environment variable. For csh (C-shell) or tcsh,
setenv CC /usr/bin/cc
make -e all
(The -e option gives environment definitions precedence over macro definitions in the description file.)

Suffix Rules

Large projects use many source files, hence they require many object (.o) files for the build. It is cumbersome to write a pair of lines like lines 6 and 7 above, for each individual object file. To alleviate this chore, the make program will assume a set of standard rules, called suffix rules, that describe how each object file should be generated from the corresponding source. First, it's important to specify which suffixes are important to your project. These are stored in the .SUFFIXES macro, which should be placed in the description file. For example,
.SUFFIXES: .o .c
The default rule for generating anyfile.o from anyfile.c is written as
.c.o:
$(CC) $(CFLAGS) -c $<
The first line specifies that a filename with a .c extension is a prerequisite to the corresponding filename with a .o extension. (This is syntactically different from before: here, no characters should appear after the colon.) In the second line, the macro $< evaluates to the prerequisite filename. Thus if we were to replace lines 6 and 7 by the above suffix rule, all would be well.

We also introduced the symbol CFLAGS which can be used to modify the manner in which the source is compiled. For example, if you wanted to use an interactive source debugger, such as gdb, you might invoke make by

touch *.c
make all CLFAGS=-g
If instead we wanted to optimize the program, we would enter
touch *.c
make all CLFAGS=-O
(The touch command sets the modification time of each listed filename to the current instant. Why is it necessary here?)

Most implementations of make have built-in, or default, suffix rules. If you want to know what they are, type

make -p -f/dev/null

Suffix Replacement Macros

Some implementations of make support the following string substition macro. Suppose the macro SOURCE was defined to expand to a list of file names, e.g.,
SOURCE = pizza.c pepperoni.c cheese.c mushrooms.c anchovies.c olives.c
Then the statement
OBJECTS = $(SOURCE:.c=.0)
would be equivalent to
OBJECTS = pizza.o pepperoni.o cheese.o mushrooms.o anchovies.o olives.o
Thus, every occurence of the string ".c" in SOURCE, is replaced by the string ".o".

Putting things all together

Here's a more sophisticated version of our original
# Robert's pizza project.                              # Line  1
SOURCE = pizza.c pepperoni.c cheese.c\
mushrooms.c anchovies.c olives.c # Line 2
HEADERS = pizza.h topping.h # Line 3
OBJECTS = ${SOURCE:.c=.o} # Line 4

.PREFIXES = .c .o # Line 6
CC = gcc
CFLAGS = -O -I${HOME}/include # Line 8
RM = /usr/bin/rm -f # Line 9
MV = /usr/bin/mv -f # Line 10
CP = /usr/bin/cp -f # Line 11

.c.o: # Line 13
${CC} -c ${CFLAGS} $< # Line 14

pizza: ${OBJECTS} # Line 16
${CC} -o $@ ${OBJECTS} -lm # Line 17

all: pizza # Line 19

clean: # Line 21
-${RM} pizza *.o core # Line 22

install: pizza # Line 24
${MV} pizza /usr/local/bin # Line 25
${CP} ${HEADERS} /usr/local/include # Line 26
@echo "Your pizza is ready!" # Line 27

Internal macro symbols

$? The list of prerequisites that are younger than than the target. (Cannot be used in a suffix rule.)
$@ Name of the current target. (If the target is a library, the this expands to the library name.)
$$@ Name of the current target. (Can only be used in a prerequisite list.)
$< The prerequisite file name in a suffix rule.
$* In a suffix rule, this expands to the root name of the file.
$% Expands to a .o file if the target is a library.

References

Andrew Oram and Steve Talbott, Managing Projects with Make, O'Reilly, Sebastapol, CA, 1991.
阅读(1077) | 评论(0) | 转发(0) |
0

上一篇:Makefile

下一篇:Endianness

给主人留下些什么吧!~~