make.md (5469B)
1 ### How to make and make clean 2 3 Do you write Makefiles? Do you want them to be fairly portable? Then 4 continue reading this. Here are some things that I keep in mind when 5 dealing with builds and `make`. First of all, there are cases where you 6 can use `make` without a Makefile. For example, if you have a simple 7 `test.c` just to quickly try something you can do: 8 9 $ make test 10 cc -O2 -pipe -o test test.c 11 12 And if you need some preprocessor flags: 13 14 $ CPPFLAGS=-DDEBUG make test 15 cc -O2 -pipe -DDEBUG -o test test.c 16 17 And if you also need to link with a library: 18 19 $ CPPFLAGS=-DDEBUG LDLIBS=-lpcap make test 20 cc -O2 -pipe -DDEBUG -o test test.c -lpcap 21 22 More flags or libs can be inserted like this: 23 24 $ CPPFLAGS=-DDEBUG LDLIBS="-lpcap -lm" make test 25 cc -O2 -pipe -DDEBUG -o test test.c -lpcap -lm 26 27 The reason these work is that most `make` implementations have inference 28 rules and default variable values, so they know how to build binaries 29 from certain files using the source file extension. To see the list of 30 inference rules (also known as implicit rules or suffix rules) do this 31 on a Makefile-less directory: 32 33 $ make -p 34 35 Now it should make more sense why and how the builds worked. For 36 development in C these are the important variables: 37 38 CC -- Compiler 39 CPPFLAGS -- Preprocessor flags 40 CFLAGS -- Compile flags 41 LDFLAGS -- Link flags 42 LDLIBS -- Libraries to link with 43 44 For C++ you also have: 45 46 CXX -- Compiler 47 CXXFLAGS -- Compile flags 48 49 Not all `make` implementations pre-define all of the above variables; 50 you should check with the systems you want to support first. 51 On the previous command line examples we define those as shell 52 environment variables and they are instantiated as make variables as 53 well (macros). We could also provide them as command line arguments to 54 the `make` command: 55 56 $ make CPPFLAGS=-DDEBUG LDLIBS=-lpcap test 57 cc -O2 -pipe -DDEBUG -o test test.c -lpcap 58 59 And double quotes also work there: 60 61 $ make CPPFLAGS=-DDEBUG LDLIBS="-lpcap -lm" test 62 cc -O2 -pipe -DDEBUG -o test test.c -lpcap -lm 63 64 Now instead of writing all these macros every time you may create a 65 simple Makefile to handle that part, but still rely on inference rules: 66 67 CPPFLAGS = -DDEBUG 68 LDLIBS = -lpcap -lm 69 70 Assuming the above Makefile, now type: 71 72 $ make test 73 cc -O2 -pipe -DDEBUG -o test test.c -lpcap -lm 74 75 Now let's add a default target so that we also avoid typing that. It is 76 customary that this default target is named `all`. Our Makefile now 77 becomes: 78 79 CPPFLAGS = -DDEBUG 80 LDLIBS = -lpcap -lm 81 82 all: test 83 84 Just do: 85 86 $ make 87 cc -O2 -pipe -DDEBUG -o test test.c -lpcap -lm 88 89 It is also common to have a `clean` target as well. Add the following: 90 91 clean: 92 rm -f test 93 94 Note that the shell command under the dependency line begins with a tab 95 character. The dependency here is empty and will always be unsatisfied, 96 so the `rm` command will always run: 97 98 $ make clean 99 rm -f test 100 101 That is true unless a file named `clean` appears in the filesystem. If 102 you want to ensure that such rules are not affected by this artifact you 103 can declare that they are special rules that are always evaluated. 104 Simply add: 105 106 .PHONY: all clean 107 108 Now that we have a Makefile let's run this command: 109 110 $ CPPFLAGS=-DPIC make 111 cc -O2 -pipe -DDEBUG -o test test.c -lpcap -lm 112 113 And the same with the macro as argument: 114 115 $ make CPPFLAGS=-DPIC 116 cc -O2 -pipe -DPIC -o test test.c -lpcap -lm 117 118 We see that the macro assignment in the Makefile overrides the shell 119 environment variable and the command line argument overrides the 120 Makefile! By now we have a simple Makefile with one target. How about 121 a Makefile with multiple targets? We would have to alter the `all:` 122 target and the `clean:` shell command because they deal with the same 123 stuff. Here we can use a macro assignment to hold the list of targets 124 like that: 125 126 BIN = bin1 bin2 127 128 all: $(BIN) 129 130 clean: 131 rm -f $(BIN) 132 133 And this way all we have to ever touch to add `bin3` is the `BIN` 134 variable. We get: 135 136 $ make && make clean 137 cc -O2 -pipe -DDEBUG -o bin1 bin1.c -lpcap -lm 138 cc -O2 -pipe -DDEBUG -o bin2 bin2.c -lpcap -lm 139 rm -f bin1 bin2 140 141 142 #### Notes on various make implementations 143 144 Some `make` implementations such as the IRIX one do not use the LDLIBS 145 variable in their default inference rules. We could do something like: 146 147 LDFLAGS = $(LDFLAGS) $(LDLIBS) 148 149 The problem with this is that the libraries will possibly appear before 150 the object files when linking and this may be a problem for some 151 compilers. The better solution is to rewrite the inference rules in a way 152 that includes LDLIBS at the end. For example: 153 154 .c: 155 $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LDLIBS) 156 157 158 #### More reading on portability 159 160 * [OpenBSD make(1)]( 161 http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man1/make.1) 162 * [NetBSD make(1)]( 163 http://netbsd.gw.com/cgi-bin/man-cgi?make+1) 164 * [Solaris make(1S)]( 165 https://docs.oracle.com/cd/E36784_01/html/E36870/make-1s.html) 166 * [System V make(1)]( 167 https://docs.oracle.com/cd/E36784_01/html/E36870/sysv-make-1.html) 168 * [IRIX 6.5 make(1)]( 169 http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?coll=0650&db=man&fname=/usr/share/catman/u_man/cat1/make.z) 170 * [Autoconf manual]( 171 https://www.gnu.org/software/autoconf/manual/autoconf.html#Portable-Make)