idiomatic_makefiles.md (10404B)
1 # A Template for Portable Idiomatic Makefiles 2 3 2022-04-07 [Original at seninha.org][original] 4 5 In this post, I present the template I use to write portable, idiomatic 6 Makefiles for building C programs. 7 8 I use `${MYVAR}`, with curly braces, rather than `$(MYVAR)`, with parentheses, 9 but both notations are supported. In this document I identify two different 10 people: the developer or Makefile author, who writes the Makefile; and the user 11 or package maintainer, who defines the proper variables and run `make(1)`. 12 13 ## The Project Files 14 15 There are several files involved in the building process: the target files to be 16 built, the source files, and the intermediate files. They may be referenced 17 several times by different rules, so it is a good practice to name them with 18 variables. Suppose we're building a program called `myprog` composed of three 19 modules. These are the variables to be defined: 20 21 ```Makefile 22 PROG = myprog 23 SRCS = main.c parse.c util.c 24 OBJS = main.o parse.o util.o 25 ``` 26 27 The variable `PROG` is the final file; `SRCS` lists the source files; and `OBJS` 28 lists the intermediate, object files. Note that both the list of source files 29 and of object files are almost equal, differing only by the extension of the 30 files. POSIX `make(1)` has a notation for changing the ending of each word in a 31 variable. In order to avoid repeating ourselves, we can use this notation to 32 define `${OBJS}`. 33 34 ```Makefile 35 PROG = myprog 36 SRCS = main.c parse.c util.c 37 OBJS = ${SRCS:.c=.o} 38 ``` 39 40 We want to build our program when we call make without any arguments. To do 41 this, the first target should be `${PROG}` itself. However, it is a common 42 practice to use the target `all` to build the final files. So the first target 43 is `all`, which just has `${PROG}` as prerequisite. 44 45 ```Makefile 46 all: ${PROG} 47 ``` 48 49 Next we need to declare the dependencies between the program modules. This is 50 done with rules without commands. 51 52 ```Makefile 53 main.o: parse.h util.h 54 parse.o: parse.h util.h 55 util.o: util.h 56 ``` 57 58 ## The Compilation Rules 59 60 The compilation process is split in two parts: generate the object files from 61 the source files, and generate the program from the object files. So we need two 62 rules. 63 64 The following rule builds object files (.o) from source files (.c). The `.c.o` 65 is an inference rule that declares each .c file to be the prerequisite of a 66 homonymous .o file. This notation is defined by POSIX and is, therefore, 67 portable (different from the `%.o`: `%.c` rule, which is a GNU extension). In 68 the command of an inference rule (and only in the command of an inference rule), 69 the `$<` variable evaluates to the prerequisite file. 70 71 ```Makefile 72 .c.o: 73 ${CC} -I/usr/X11R6/include ${CFLAGS} ${CPPFLAGS} -c $< 74 ``` 75 76 We use the variable `${CC}` to expand to the proper C compiler command. This 77 variable is set by default to the proper command. We should use this variable 78 rather than hardcoding it to `gcc`, for example. 79 80 The variables `${CFLAGS}` and `${CPPFLAGS}` contains options that the user or 81 package maintainer wants to pass to the compiler or preprocessor. It is a bad 82 practice to define those variables in a Makefile; let the user (or package 83 maintainer) define them. Any option that must be passed to the compiler (such as 84 `-I/usr/X11R6/include` above) should be passed before those variables. If the 85 Makefile author, for example, define `${CFLAGS}` to `-I/usr/X11R6/include`, 86 either this value may override the values set by the user, or the values set by 87 the user may shadow the option set by the Makefile author. 88 89 The following rule links all object files into the program. We define `${OBJS}` 90 to be the prerequisites of `${PROG}`. The `$@` variable evaluates to the target 91 file (`${PROG}` in our case). Since this is not an inference rule, the `$<` 92 variable cannot be used; we must write `${OBJS}` both in the rule and in the 93 command. 94 95 ```Makefile 96 ${PROG}: ${OBJS} 97 ${CC} -o $@ ${OBJS} -L/usr/X11R6/lib -lX11 ${LDFLAGS} 98 ``` 99 100 The variable `${LDFLAGS}` contains options that the user or package maintainer 101 wants to pass to the linker. Again, it is a bad practice to define it in the 102 Makefile. The options `-L/usr/X11R6/lib` and `-lX11` are passed before this 103 variable (so the user can override or increment them if necessary). 104 105 ## The Installation rules 106 107 Your Makefile may include rules for installing the final files in the system. In 108 this example, two files are installed, `${PROG}` (the final, compiled program), 109 and `${PROG}.1` (the manpage, named as the program followed by `.1`). The 110 following rule performs the installation. 111 112 ```Makefile 113 PREFIX = /usr/local 114 MANPREFIX = ${PREFIX}/share/man 115 116 install: all 117 mkdir -p ${DESTDIR}${PREFIX}/bin 118 mkdir -p ${DESTDIR}${MANPREFIX}/man1 119 install -m 755 ${PROG} ${DESTDIR}${PREFIX}/bin/${PROG} 120 install -m 644 ${PROG}.1 ${DESTDIR}${MANPREFIX}/man1/${PROG}.1 121 ``` 122 123 Before installing, the program should have been built; therefore `all` must be a 124 prerequisite for `install`. 125 126 The user or package maintainer can set the variable `${DESTDIR}` to specify a 127 different installation destination. This variable must be prepended to each 128 installation path; and the Makefile author should not define it (it is left to 129 the user or package maintainer to define it). Note that there is no bar 130 separating ``${DESTDIR}`` from what follows, because the `${PREFIX}` and 131 `${MANPREFIX}` variables should already begin with a bar. 132 133 The Makefile author, however, is expected to define two variables pointing to 134 installation prefixes: `${PREFIX}`, pointing to the general installation prefix; 135 and `${MANPREFIX}`, pointing to the manual page installation prefix. There are 136 other commonly defined prefixes, such as `${bindir}`, set to `${PREFIX}/bin`. 137 The user or package maintainer can then invoke `make(1)` with those variables 138 assigned to different prefixes. On most GNU/Linux systems, for example, 139 `${PREFIX}` is assigned to `/usr`; and on OpenBSD, `${MANPREFIX}` is assigned to 140 `${PREFIX}/man` (without the `share/` part). 141 142 The variables `${PREFIX}` and `${MANPREFIX}` are not automatically assigned, but 143 they can be changed by the user or package maintainer. These variables are 144 commonly assigned in the Makefile by the Makefile author with the `?=` operator, 145 which assign them only if not already defined, rather than with the common `=` 146 operator. Thus, the values of these variables can be inherited from the 147 environment, and the user need not have to assign them on each invocation. This 148 operator is a non-POSIX extension, however, although supported by both GNU and 149 BSD make implementations. 150 151 Looking back at the installation commands, we first use `mkdir(1)` to create the 152 destination directories, and then use `install(1)` to install them. We could 153 simply call `install` with the `-D` flag, which automatically creates the 154 destination directories if necessary. However, this option is an extension and 155 is not supported by some implementations (such as FreeBSD's). Remember to 156 install each file with its proper permission modes with the `-m` option. 157 158 The Makefile author can also create a uninstallation rule, which simply removes 159 the files from their destination directories. 160 161 ```Makefile 162 uninstall: 163 rm ${DESTDIR}${PREFIX}/bin/${PROG} 164 rm ${DESTDIR}${MANPREFIX}/man1/${PROG}.1 165 ``` 166 167 ## The Cleaning Rule 168 169 The Makefile author can define a rule to clean the build directory and revert it 170 to its original state. Such rule is commonly called `clean`. It removes the 171 intermediate object files and the final files. As convenience, for the developer 172 to clean the build directory from core files that may be created by the system 173 during the development, the `clean` rule can also delete `.core` files. 174 175 ```Makefile 176 clean: 177 -rm -f ${OBJS} ${PROG} ${PROG:=.core} 178 ``` 179 180 Note that the command of this rule begins with an hyphen `-`. This causes make 181 to not return error (non-zero) exit status when the command fails. This is 182 handy, for cleaning an already cleaned build directory to not print errors. 183 184 ## The Phony Targets 185 186 In a Makefile, some rules specify "virtual" targets which do not correspond to 187 any file to be created. These are the "phony" targets. The `.PHONY` special 188 target is used to mark its prerequisites as phony targets. In our Makefile, we 189 have four phony targets: `all`, `install`, `uninstall`, and `clean`. 190 191 ```Makefile 192 .PHONY: all clean install uninstall 193 ``` 194 195 ## The Makefile 196 197 In the end, our Makefile should look like this: 198 199 ```Makefile 200 PROG = myprog 201 SRCS = main.c util.c 202 OBJS = ${SRCS:.c=.o} 203 204 PREFIX = /usr/local 205 MANPREFIX = ${PREFIX}/share/man 206 207 all: ${PROG} 208 209 main.o: parse.h util.h 210 parse.o: parse.h util.h 211 util.o: util.h 212 213 .c.o: 214 ${CC} -I/usr/X11R6/include ${CFLAGS} ${CPPFLAGS} -c $< 215 216 ${PROG}: ${OBJS} 217 ${CC} -o $@ ${OBJS} -L/usr/X11R6/lib -lX11 ${LDFLAGS} 218 219 install: all 220 mkdir -p ${DESTDIR}${PREFIX}/bin 221 mkdir -p ${DESTDIR}${MANPREFIX}/man1 222 install -m 755 ${PROG} ${DESTDIR}${PREFIX}/bin/${PROG} 223 install -m 644 ${PROG}.1 ${DESTDIR}${MANPREFIX}/man1/${PROG}.1 224 225 uninstall: 226 rm ${DESTDIR}${PREFIX}/bin/${PROG} 227 rm ${DESTDIR}${MANPREFIX}/man1/${PROG}.1 228 229 clean: 230 -rm -f ${OBJS} ${PROG} ${PROG:=.core} 231 232 .PHONY: all clean install uninstall 233 ``` 234 235 ## tl;dr 236 237 * Define variables for the final files to be built, the source files, and the 238 intermediate object files created by the building process. Those are 239 commonly named `${PROG}`, `${SRCS}` and `${OBJS}`, respectively. 240 * Include in the Makefile, but do not assign them, the variables `${CFLAGS}`, 241 `${CPPFLAGS}`, `${LDFLAGS}` and `${DESTDIR}`. They should be assigned by the 242 user or package maintainer. 243 * Evaluate the flag variables (`${CFLAGS}`, `${CPPFLAGS}`, and `${LDFLAGS}`) 244 after any hardcoded flag, so the user or package maintainer can override it. 245 * Include the `all` and `clean` phony targets. Optionally include `install` 246 and `uninstall` phony targets. Always mark them as `.PHONY`. 247 * Do not use `$<` on anything but on the command of inference rules. 248 * Do not use `-D` with `install(1)`. 249 * Do not call `c99` or `gcc` manually. Call the command set in `${CC}` 250 instead. 251 * Assign `${PREFIX}` and `${MANPREFIX}` to the proper installation prefixes. 252 You can assign them with the `?=` operator for the user convenience, but 253 this assignment operator is not portable, although commonly supported. 254 255 [original]: https://seninha.org/make/