Anatomy of a Rule

114 Chapter 4 • Using GNU make all: TARGETS Rule to build object files OBJS: SRCS CC CFLAGS -c :.o=.c Rules to build individual targets ftp: FTPOBJS FTPHDRS CC LDFLAGS FTPOBJS -o ftp tftp: TFTPOBJS TFTPHDRS CC LDFLAGS TFTPOBJS -o tftp dnsresolver: DNSRESOLVEROBJS DNSRESOLVERHDRS CC LDFLAGS DNSRESOLVEROBJS -o dnsresolver clean: rm -f TARGETS OBJS install: cp TARGETS INSTALLDIR Additional Dependencies ftp.o: FTPHDRS tftp.o: TFTPHDRS dnsresolver.o: DNSRESOLVERHDRS After comments in the start of the makefile, the first part of the file defines variables used in this file. As you shall see, defining variables is very helpful if you need any modification in the Makefile or want to add or remove more files later on. After defining variables, the default target is defined with the name all as follows: all: TARGETS This in turn has dependencies on the three targets that we want to make. Please note that we dont have any command to build this default target. When make reaches the default target, it tries to meet dependencies to make sure that these are up-to-date. If any of these dependencies is not up-to-date, make will try to recreate it. The three dependencies to the default target ftp, tftp and dnsresolver have their own rules to build. For example, the following ftp rule shows that it depends upon two variables FTPOBJS and FTPHDRS. ftp: FTPOBJS FTPHDRS CC LDFLAGS FTPOBJS -o ftp This means that if any of the files listed in these two variables has changed, the ftp tar- get will be rebuilt. These files defined in the two variables are as follows: The make Rules 115 • ftp.o • common.o • ftp.h • common.h We have another rule to build object files from source files. This rule is as follows: OBJS: SRCS CC CFLAGS -c :.o=.c It will build any of the .o object file, which is not up-to-date from its corresponding .c source code file. The sign is used to substitute the name of the target by replacing .o with .c so that if we want to build the target common.o, the symbol will replace .o with .c in the target, making it common.c. This way the compiler gets the correct argument after the -c switch in the command line. This technique is especially useful if you are dealing with files with different extensions. For example, if the source code files are C++ files ending with .cpp, the above rule may be written as follows: OBJS: SRCS CC CFLAGS -c :.o=.cpp Now the will replace .o with .cpp for each file in the target. The clean rule will delete all of the object and executable files. The install rule will copy files into the root directory. Both of these rules have no dependency. This means that the com- mands in these rules dont depend on anything and will always be executed whenever this rule is invoked. The last part of the makefile lists some additional dependencies not covered by earlier rules. Note that these three rules in the end have no command to execute. You can have as many rules to build a target as you like, but only one of these rules should contain commands to build it. Now you can see how the use of variables is useful in this Makefile. If you add or remove some files or dependencies, you need to modify only the upper part of the makefile where vari- ables are defined, without worrying about the rest of the makefile. For example, if you add a new header file to the dependency list of ftp, you just need to modify the variable FTPHDRS. Similarly to add a new source code file common.c that is being used by ftp, you need to add it to the following two variables:

1. FTPOBJS

2. OBJS

By modifying these two variables, this will automatically be used by ftp, OBJS and clean rules. Now is the time to use this makefile and see how the make program executes different commands. The output of the make command is shown below that needs some attention to understand how the make program checks dependencies and builds different targets.