# This file is a makefile again. You can run it using ‹make -f # autodep.mk›. CFLAGS += -std=c99 # Building programs in C poses some special challenges when header # files are involved. Recall that the right hand side of a ‹make› # rule lists the ingredients that enter the build process. For C # programs, this list should contain any header files that are # included: if the header file changes, we should rebuild all object # files that could possibly be affected by the change. But # maintaining such lists is tedious and error-prone. Nobody wants to # do it. # Fortunately, compilers and ‹make› offer some features to automate # this tedious task. When compiler builds an object file, it can # also produce a makefile fragment that describes what header files # were used in the process. The flags to do that are ‹-MD -MP›. # This makefile fragment will be stored in a file called ‹file.d› # (assuming we build ‹file.o›). You can read more in ‹man gcc›. CFLAGS += -MD -MP # Being able to refer to all sources (and object files) that entail # a single program is often very useful. We will call the list of # sources SRC and the list of object files OBJ. But we are lazy # programmers and we do not want to repeat ourselves. We just list # the source files and tell ‹make› that the object files are the # same files, but with ‹.c› replaced with ‹.o›. Notice the syntax: # we use curly braces here. The syntax is ‹${VAR:old=new}› where # ‹old› and ‹new› are suffixes: each whitespace-separated part of # the variable is checked and if it ends with the string ‹old›, that # part is replaced with ‹new› in the output. SRC = getenv.c foo.c OBJ = ${SRC:.c=.o} # getenv.o foo.o DEP = ${SRC:.c=.d} # getenv.d foo.d, see below for an explanation getenv: $(OBJ) # we need all the object files cc -o getenv $(OBJ) # Recall that ‹make› already knows how to build ‹.o› files from ‹.c› # files. It also knows to use ‹$(CFLAGS)›, so it will use our # special flags that we specified at the start and ‹cc› will # generate a ‹.d› file for each ‹.c› file. This ‹.d› file will # contain dependency information (in makefile format). # We add another (phony) rule, so we can do ‹make clean› to remove # all the files we built and start over if we wish. clean: rm -f $(DEP) $(OBJ) getenv # The final ingredient is the ‹-include› directive, which causes # ‹make› to include rules from other files. In this sense, it is # quite similar to the ‹#include› directive from C. The ‹-› at the # start means that it is not an error if some of the files do not # exist. After you run this makefile, you may want to inspect the # file ‹getenv.d› using a text editor. -include $(DEP) # That's it. You should be ready to work out the homework now, # described in ‹hw.txt›.