11/02/05 CISC181 Lecture Notes Makefiles! Read Appendix G in your Andersen book about Makefiles (they will be on the next Exam! and you need this knowledge for lab05, as well as for project 1). In a makefile, there are targets, dependencies and actions Here is the make file from the Anderson book: Note that this Makefile is organized for C programming, rather than C++, but it illustrates the ideas. **************** BELOW THIS LINE IS THE MAKEFILE ******* # Makefile for the Trip program trip: main.o chicago.o indiana.o indy.o cc -o trip main.o chicago.o indiana.o indy.o main.o: main.c cc -c main.c chicago.o: chicago.c cc -c chicago.c indiana.o: indiana.c cc -c indiana.c indy.o: indy.c cc -c indy.c clean: rm *.o **************** ABOVE THIS LINE IS THE MAKEFILE ******* Everthing in this example Makefile from your book follows this pattern: target: dependency1 dependency2 dependency3 ... dependencyN action1 action2 action3 ... actionN Taken together, all of the lines like this form one "rule". In the file above, there are six rules. The targets for these rules are: trip: main.o: chicago.o: indiana.o: indy.o: clean: If we take the first rule, and break it down, we see that in this rule: trip: main.o chicago.o indiana.o indy.o cc -o trip main.o chicago.o indiana.o indy.o * the target is trip: * the rule lists four dependencies: main.o chicago.o indiana.o indy.o * the rule has one action line: cc -o trip main.o chicago.o indiana.o indy.o Although it is not seen in THIS makefile, it is possible to have multiple action lines on a single rule. For example, in the Makefile for proj1a, we have this rule: And in the Makefile for proj1b we have this rule: As your book explains: (1) comments start with #, as in: # Makefile for the Trip program Your make file should always start with a comment such as: # Makefile for lab05, CISC181, Fall 2005 # Chris Jones, CISC181 section 011 (2) Dependency lines start with a target, followed by a colon, followed by a list of files, e.g. trip: main.o chicago.o indiana.o indy.o This lines says that a binary (executable) called trip needs to be updated any time any of the following files change: main.o chicago.o indiana.o indy.o If trip were a "standalone" program, e.g. if there were a file trip.c (or in C++, trip.cc), then it wouldn't depend on anything else. By standalone, we mean that (a) all of the functions that the file calls and all of the definitions of structs, etc. are in the trip.c file itself, and (b) the only things the file links with are standard libraries But, that is not true of the trip executable. Rather, it is an executable composed of the functions in main.c, chicago.c, indy.c and indiana.c. The idea is that all four of those are separately compiled first into .o files, and then trip is linked from those. Dependency lines always start in the first column, and consist of a "target" followed by a colon, followed by a list of the things the target depends on. (3) A target is something that you can put on the command line of the make utility. For instance, if you type: make trip then the Makefile tries to make a "target" called "trip". Here's what happens when you type "make trip". There are two possibilties: (1) If there is a file called "Makefile" or "makefile" in the current directory, and that file contains a target called "trip". In that case, the make utility looks at all the things that follow the word "trip:" (i.e the dependencies of trip, or the "things trip depends on"), and it sees first whether those things are completely up-to-date. If not, those things are "recursively" treated as targets themselves. (We'll come back to that part in a moment.. for now, assume that all of them are up-to-date). Once all the things on the line are up-to-date, the make file then checks the "last modification times" of the files that "trip" depends on, vs. the "trip" file itself, to see whether to "fire" the rule or not. If the rule files, than all the actions lines are executed. Typically, though not always, this results in "making" a file that is of the same name as the target, e.g. trip: cc -o trip main.o chicago.o indiana.o indy.o (2) If there is NO file called "Makefile" in the current directory, OR if there is such a file, but no target in that file called "trip", then here's what happens: the make utility uses "default" rules to try to make a standalone program from files such as "trip.c", "trip.cc", "trip.sh", etc. If none of those are found, it will give up and print an error message. (3) Action lines follow the dependency line. Action lines must begin with a tab, NOT a sequence of spaces! (4) The "clean:" rule The rule starting with "clean" is an example of an empty dependency. In this case, the target "clean" is not the name of a file, but rather a command, which you would run by typing "make clean" at the Unix command line. Since the dependency is empty and does NOT create a file called "clean", this rules ALWAYS fires any time you invoke it by typing "make clean". The purpose of the action line will remove any files ending in .o. A make clean rule typically also removes files such as a.out, core, and any binaries in the file, e.g. clean: /bin/rm -f *.o core a.out /bin/rm -f trip (5) Variables in Makefiles Since there can be multiple binaries in a file (executables), it is more common to list them, and assign their names to a variables, as in: BINARIES= trip1 trip2 trip3 Then you can write a rule like this: clean: /bin/rm -f *.o core a.out ${BINARIES} Using a $ followed by the name of a variable in either {} or () substitutes the name of that variable. You also see this in action lines that invoke the C++ compiler; by setting the variable CCC, you can change which C++ compiler gets invoked, e.g. CCC=g++ ... myprog: myprog.o functions.o ${CCC} myprog.o functions.o -o myprog (6) Using the symbol $@ You can use the symbol $@ to stand for "the filename that is the target", and so, write that rule like this: myprog: myprog.o functions.o ${CCC} myprog.o functions.o -o $@ The purpose of this is it make "cutting and pasting" rules easier; there are fewer things to change if we want to change the name of the target (change it in one place, and the rule still works!) (7) Other kinds of special rules, e.g. "make all" and "make install" Not all rules have to be involved with compiling. The "clean" rule is an example of a rule that is used do run arbitrary Unix commands to clean things up. Another such rule is the "install" rule, which often appears in Makefiles to do two things: first, compile everything, then copy it to somewhere and change the permissions properly. Finally, the "all" rule is typically the first rule in a Makefile, it is there to list all the binaries that should be made. When you just type "make" by itself, by default, the target that is checked (and possibly fired if needed) is the very first target that appears in the Makefile. A rule such as: all: ${BINARIES} with an empty action means: if I type "make all", make sure that all the files listed in the variable binaries, e.g. BINARIES=prog1 prog2 prog3 are all up-to-date. [In lecture, show examples of various rules from the Makefiles for proj1a and proj1b, and review how to create a Makefile from scratch]