CS/CE 218 Lecture -*- Outline -*- connection: we've seen the value of putting code for different parts of a program in different files. But this creates a problem; it becomes difficult to keep track what needs to be done to create a program. The Unix program `make' takes care of that and also does it with minimum work; it's standard for large software projects, and also handy for daily use. * Using `make' to automate program building (section 14.6 in Unix book) ** What make does Overall make issues shell commands for you, commands to build programs e.g., ---------------- $ make shpp.o gcc -O -Wall -c shpp.c $ make shpp gcc -O -Wall -c string_set.c gcc -O -Wall -c usage.c gcc -o shpp shpp.o string_set.o usage.o $ emacs string_set.c $ make shpp gcc -O -Wall -c string_set.c gcc -o shpp shpp.o string_set.o usage.o ---------------- *** Simple example -------------------- # Makefile for shpp shpp: shpp.o string_set.o usage.o gcc -o shpp shpp.o string_set.o \ usage.o shpp.o: shpp.c usage.h gcc -O -Wall -c shpp.c usage.o: usage.c gcc -O -Wall -c usage.c string_set.o: string_set.c gcc -O -Wall -c string_set.c --------------------- Q: What does a comment in a Makefile look like? first line is a comment (starts with #) Q: What are the dependencies above? What are the targets? Q: What are the prerequisites? What are the rules? dependency definitions, have target in column 1 (shpp), a colon (:), then a white-space separated list of prerequisites (the .o files) following the dependency definition is a rule, *tab* indented list of shell commands (spaces don't work) can be continued onto another line with \ at end Q: What are the components of shpp? the .o files? *** How make does it (draw a dependency graph for the above makefile) Q: How does make know when to build something? It knows what the components are e.g., for shpp, components are the object files shpp.o, string_set.o, and usage.o *components are always files* It knows the last modification time of each file it sees whether any of the .o files are more recent than shpp shpp.o is considered more recent than shpp if shpp doesn't exist a target is also remade if it has no dependencies and if it doesn't exist Q: Where does `make' get it's information about rules and components? from the makefile by default uses a file called `makefile' if that doesn't exist, uses `Makefile' you can also tell it where to look (-f option) it also has some built in rules (e.g., for C programs) *** Default target Q: If you don't tell make a default target, what does it do? Good practice to list the main thing first (shpp) default if you just say make is to make the first target in the file hence, executing $ make gcc -O -Wall -c shpp.c gcc -O -Wall -c string_set.c gcc -O -Wall -c usage.c gcc -o shpp shpp.o string_set.o usage.o has the same effect as $ make shpp ... It's bad practice to rely on this if it's someone else's makefile... which might look like # nasty makefile remove: cd; rm -fr * useful: ... Can ask for any target listed $ make shpp.o gcc -O -Wall -c shpp.c File system dates are used to keep track of what work needs to be done. $ make shpp.o `shpp.o' is up to date. $ emacs shpp.c $ make shpp.o gcc -O -Wall -c shpp.c can also use touch to force the modification time of a file to be now $ touch *.h $ make shpp.o gcc -O -Wall -c shpp.c What you put in doesn't have to be directly related to programs ------------------ clean: rm -f *.o a.out core ------------------ note can use shell patterns for file names *** Make macros (page 538) Standard way to not write the same thing many times, many of these have standard definitions, and are hooks for the built-in rules (see below). e.g., default C compiler is value of CC, so to change it to gcc use CC = gcc default C options are value of CFLAGS (default is -O) so to change it use: CFLAGS = -O -Wall To reference a variable named FOO use $(FOO), the parens are necessary -------------------- # Makefile for shpp CC = gcc CFLAGS = -O -Wall AUXo = usage.o SHPPo = shpp.o string_set.o shpp: $(SHPPo) $(AUXo) $(CC) -o shpp $(SHPPo) $(AUXo) shpp.o: shpp.c usage.h $(CC) $(CFLAGS) -c shpp.c usage.o: usage.c $(CC) $(CFLAGS) -c usage.c string_set.o: string_set.c $(CC) $(CFLAGS) -c string_set.c --------------------- *** built in rules (page 537) Make has a default rule for making .o files, etc. Don't even need a makefile to use these... $ make junk.o cc -O junk.c -------------------- # Makefile for shpp CC = gcc CFLAGS = -O -Wall AUXo = usage.o SHPPo = shpp.o string_set.o shpp: $(SHPPo) $(AUXo) $(CC) -o shpp $(SHPPo) $(AUXo) shpp.o: shpp.c usage.h usage.o: usage.c string_set.o: string_set.c --------------------- This does the same thing as before, using the default rule for making a .o target from its dependants $ emacs usage.h $ make shpp gcc -O -Wall -c shpp.c gcc -o shpp shpp.o string_set.o usage.o (make knows not to pass the usage.h file to the compiler!) You usually have give the rule for assembling the .o files into the executable, because the default rule is gcc -O shpp.c -o shpp See the manual page of make for more details.