How Do You Rebuild A Program?
Easy enough to create a.class from a.java by running
javac a.java
But what if you have many source files?
javac *.java doesn't work with sub-directories
And will be very (very) slow for large programs
And what if some rely on others?
Suppose overlap.java uses
rect.java
Change rect.java
Forget to compile it
Compile and run overlap.java
Whoops
Automate, Automate, Automate
Anything worth repeating is worth automating
Most widely used tool for this is called Make
Invented in 1975 by Stuart Feldman when he was a summer student at Bell Labs
Make's role:
Figure out what has changed
Work out what is affected by those changes
Execute commands to bring things up to date (e.g. by recompiling)
Hello, Make
Put program in hello.java
Put the following into a file called hello.mk:
hello.class : hello.java
javac hello.java
Note: that indentation must be a tab
Yeah, it's lousy design...
...but he was only a summer student
Run make -f hello.mk
Make sees that hello.class depends on hello.java
But hello.class doesn't exist
So hello.java is compiled
Run make -f hello.mk again
Nothing happens
hello.class is already up to date
Terminology
hello.class is the target of the rule
hello.java is its prerequisite
May be many prerequisites
The compilation command is the rule's action
Rule may have many actions
How It Works
Make looks at when the target and its prerequisites were last modified
If the target exists, and is more recent than all its prerequisites, Make does nothing
If the target doesn't exist, or any prerequisite is more recent than the target, Make executes the action
Multiple Targets
Left.class : Left.java
javac Left.java
Right.class : Right.java
javac Right.java
Run make -f double.mk
Only Left.java is compiled
Becase the first target in the file is the default
Run make -f double.mk Right.class to build Right.class
Phony Targets
all : Left.class Right.class
Left.class : Left.java
javac Left.java
Right.class : Right.java
javac Right.java
all is a phony target
Doesn't correspond to a file
Never up to date
make -f all.mk compiles both Java files
Multiple Dependencies
Having targets depend on other targets forces Make to do things in a certain order
Test.class : Test.java Overlap.class
javac Test.java
Overlap.class : Overlap.java Rect.class
javac Overlap.java
Rect.class : Rect.java
javac Rect.java
Visualizing Dependencies
![[Visualizing Dependencies]](../img/make/visualizingDependencies.png)
Avoiding Redundancy
Often want to set options when compiling
-classpath to include libraries
-d to specify output directory
-source 1.4 to specify Java language version
Anything repeated in two or more places will eventually be wrong in at least one
Define variables (usually called "macros" in Make)
Warning: syntax is a bit tricky
Macro Example
JC = javac -source 1.4
Test.class : Test.java Overlap.class
${JC} Test.java
Overlap.class : Overlap.java Rect.class
${JC} Overlap.java
Rect.class : Rect.java
${JC} Rect.java
Automatic Variables
Make defines variables to represent parts of rules
$@ |
The target |
$< |
The first prerequisite |
$? |
All out-of-date prerequisites |
$^ |
All prerequisites |
Can also put @ at the start of an action line to stop Make printing it out before executing it
Automatic Variable Example
JC = javac -source 1.4
Test.class : Test.java Overlap.class
@echo "Building" $@
${JC} $<
Overlap.class : Overlap.java Rect.class
@echo "Building" $@
${JC} $<
Rect.class : Rect.java
@echo "Building" $@
${JC} $<
Pattern Rules
Most files are compiled the same way
So write a pattern rule for the general case
Use % to mark the stem of the file's name
Like using * in commands in DOS or UNIX
Accumulate extra prerequisites by giving rules without actions
Pattern Rule Example
JC = javac -source 1.4
Test.class : Overlap.class
Overlap.class : Rect.class
%.class : %.java
${JC} $<
Analysis
Pro
Simple things are simple to do...
...and to read
Con
The syntax is unpleasant
Complex things are difficult to read...
...and even more difficult to debug
Not really very portable
Uses native shell to execute commands
Do you use del or rm to delete files?
$Id: make.html,v 1.1.1.1 2004/01/04 05:02:31 reid Exp $