怎么介绍?
分类:
2010-06-19 03:42:56
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 cleanto 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 allto compile every library and link every executable within a complex project. More formal projects might use
make installto 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 pizzawill 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
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.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.
# (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
Suppose our directory contained only the following files
After typing make all, the make program would perform the following recursive tasks:makefile pizza.c pizza.h
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.Returning to Line 10, make will now attempt to execute line 11. However, this line is blank, so make will exit.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.
CC = gccWe could then write our pizza as
# Robert's pizza project.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.
# (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
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,
(The -e option gives environment definitions precedence over macro definitions in the description file.)setenv CC /usr/bin/cc
make -e all
The default rule for generating anyfile.o from anyfile.c is written as.SUFFIXES: .o .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..c.o:
$(CC) $(CFLAGS) -c $<
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
If instead we wanted to optimize the program, we would entertouch *.c
make all CLFAGS=-g
(The touch command sets the modification time of each listed filename to the current instant. Why is it necessary here?)touch *.c
make all CLFAGS=-O
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
Then the statementSOURCE = pizza.c pepperoni.c cheese.c mushrooms.c anchovies.c olives.c
would be equivalent toOBJECTS = $(SOURCE:.c=.0)
Thus, every occurence of the string ".c" in SOURCE, is replaced by the string ".o".OBJECTS = pizza.o pepperoni.o cheese.o mushrooms.o anchovies.o olives.o
# 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
$? | 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. |