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