The Makefile

 

·       The Unix make utility reads instructions from text files. The makefile has instructions for a specific project.

o     The Makefile tells the make utility how to build a project with multiple files and in what order. 

·       The filename must be either “makefile” or “Makefile” and must reside in the directory where the project exists.

o     There are exceptions to this but for the purposes of the class we will assume the makefile will reside in each project directory.

·       Makefiles are composed of the following components:

o     Comments

o     Dependency Lines

o     Directives

o     Macros

o     Response files

o     Rules

o     Shell lines


·       Comments

o     A comment is indicated by the character “#”.  All text that appears after it will be ignored by the make utility until the end of line is detected.

o     Comments can start anywhere.  There are more complex comment styles but please start each new comment line with an # and avoid the continuation feature for now.

o     Example

#

# This is a comment

projecte.exe : main.obj io.obj # this is also a comment.

·       Rules

o     Rules tell make when and how to make a file.  The format is as follows:

A rule must have a dependency line and may have an action line after it.  The action line is executed if the dependency line is out of date.

Example:

Project.exe:  main.obj io.obj

This shows Project.exe as the main program that requires main.obj and io.obj as external sources of object code.  If the date of either one is new than Project.exe, then Project.exe is rebuilt.

·       Dependency Lines:  When to build a target

o     The lines with a “:” are called dependency lines.  To the left are the dependencies and to the right are the sources needed to make the dependency.

o     At the running of the make utility, the time and date when Project.exe was last built was compared to the dates when main.obj and io.obj were built.  If either main.obj or io.obj have new dates, then the shell line after the dependency line is executed.

o     The make process is recursive in that it will check all dependencies to make sure they are not out of date before completing the build process.

o     It is important that all dependencies be placed in a decending order in the file.

o     Some files may have the same dependencies.  For instance, suppose that two files needed a file called bitvect.h.  What would the dependency look like:

main.obj this.obj:  bitvect.h


 

·       Shell Lines

o     The indented lines (must have tab) that follow each dependency line are called shell lines.  Shell lines tell make how to build the target.

o     A target can have more than one shell line.  Each line must be preceeded by a tab.

o     After each shell is executed, make checks to see if it was completed without error.

o     You can ignore this but I would not at this point.


 

·       Macros are pretty cool

o     Comes from the Greek word makros meaning large.

o     Basically it is a shorthand or alias used in the makefile

o     A string is associated with another usually larger string

o     Inside the file, to expand a macro, you have to place the string inside of   $(    ) .

o     Examples of your macros:

HOME = /home/courses/cop4530/spring02

CPP = $(HOME)/cpp

TCPP = $(HOME)/tcpp

PROJ = .

INCL = -I $(PROJ) –I$(CPP) –I$(TCPP)

You can also define macros at the command line such as

          Make CPP = /home/courses/cop4530/spring02

And this would take precedence over the one in the file.


 

·       Inference Rules

o     Inference rules are a method of generalizing the build process.  In essence, it is a sort of wild card notation.

o     The “%” is used to indicate a wild card.

o     Examples:

%.obj : %.c

          $(CC) $(FLAGS) –c $(.SOURCE)

All .obj files have dependencies of all %.c files of the same name. 

·       Respond Files will not be covered.

·       Makefile Directives will not be covered at this time.


 

 

Example of a complex makefile:

 

CC = gcc

DIR = /home/faculty/whalley/public_html/cop5622proj/lib

CFLAGS = -g -I$(DIR) -I. -c

LFLAGS = -g

 

opt: analysis.o flow.o io.o misc.o opt.o opts.o peephole.o regs.o vect.o

      $(CC) $(LFLAGS) -o opt analysis.o flow.o io.o misc.o opt.o opts.o peephole.o regs.o vect.o

 

analysis.o: analysis.c analysis.h $(DIR)/misc.h $(DIR)/opt.h $(DIR)/vect.h

      $(CC) $(CFLAGS) analysis.c

 

flow.o: $(DIR)/flow.c $(DIR)/flow.h $(DIR)/opt.h

      $(CC) $(CFLAGS) $(DIR)/flow.c

 

io.o: $(DIR)/io.c $(DIR)/io.h analysis.h $(DIR)/misc.h $(DIR)/opt.h peephole.h $(DIR)/regs.h

      $(CC) $(CFLAGS) $(DIR)/io.c

 

misc.o: $(DIR)/misc.c $(DIR)/misc.h $(DIR)/opt.h

      $(CC) $(CFLAGS) $(DIR)/misc.c

 

opt.o: $(DIR)/opt.c $(DIR)/opt.h

      $(CC) $(CFLAGS) $(DIR)/opt.c

 

opts.o: opts.c $(DIR)/misc.h $(DIR)/regs.h $(DIR)/opt.h opts.h

      $(CC) $(CFLAGS) opts.c

 

peephole.o: peephole.c $(DIR)/misc.h $(DIR)/regs.h $(DIR)/opt.h peephole.h

      $(CC) $(CFLAGS) peephole.c

 

regs.o: $(DIR)/regs.c $(DIR)/regs.h $(DIR)/opt.h

      $(CC) $(CFLAGS) $(DIR)/regs.c

 

vect.o: $(DIR)/vect.c $(DIR)/vect.h $(DIR)/opt.h

      $(CC) $(CFLAGS) $(DIR)/vect.c