|
|
english_knight - english_knight - A ninja replacement. |
|
|
 |
git clone git://bitreich.org/english_knight git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/english_knight (git://bitreich.org) |
|
|
 |
Log |
|
|
 |
Files |
|
|
 |
Refs |
|
|
 |
Tags |
|
|
 |
README |
|
|
 |
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 |
|