|
|
makefile-guideline.txt - bitreich-style - Style guide for programmers. |
|
|
 |
git clone git://bitreich.org/bitreich-style (git://bitreich.org) |
|
|
 |
Log |
|
|
 |
Files |
|
|
 |
Refs |
|
|
 |
Tags |
|
|
 |
README |
|
|
 |
LICENSE |
|
|
|
--- |
|
|
|
makefile-guideline.txt (8924B) |
|
|
|
--- |
|
|
|
1 Title: Guidelines for writing simple portable Makefiles |
|
|
|
2 |
|
|
|
3 |
|
|
|
4 This page describes some guidelines and good practices for writing simple, |
|
|
|
5 portable POSIX Makefiles. It assumes a basic level of understanding in |
|
|
|
6 writing Makefiles and focuses on projects that use the C programming |
|
|
|
7 language. |
|
|
|
8 |
|
|
|
9 make is used because it has been around for a long time, is available |
|
|
|
10 on many systems, is a POSIX standard and has been proven to work well |
|
|
|
11 for most projects. |
|
|
|
12 |
|
|
|
13 |
|
|
|
14 Targets |
|
|
|
15 ------- |
|
|
|
16 |
|
|
|
17 The following targets should be defined in the Makefile: |
|
|
|
18 |
|
|
|
19 * all or the "default": build the project. |
|
|
|
20 * clean: clean files used by compilation, such as: object files, compiled |
|
|
|
21 binaries. |
|
|
|
22 * install: install the built project. |
|
|
|
23 * uninstall (optional): uninstall the project. |
|
|
|
24 * dist (optional): create a source tarball of the project intended as |
|
|
|
25 redistribution for source packages. |
|
|
|
26 * tests (optional): run unit tests. |
|
|
|
27 |
|
|
|
28 |
|
|
|
29 Portability |
|
|
|
30 ----------- |
|
|
|
31 |
|
|
|
32 Do not use GNUisms in Makefiles. Testing with different make |
|
|
|
33 implementations, such as BSD make, which mostly respects POSIX, is very |
|
|
|
34 useful. Use POSIX Makefile rules: |
|
|
|
35 https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html |
|
|
|
36 |
|
|
|
37 Try to place yourself in the shoes of a package maintainer / porter. This |
|
|
|
38 helps make sure that the package is easy to maintain: |
|
|
|
39 |
|
|
|
40 * https://www.openbsd.org/faq/ports/ |
|
|
|
41 * https://www.netbsd.org/docs/pkgsrc/ |
|
|
|
42 * https://www.freebsd.org/doc/en_US.ISO8859-1/books/porters-handbook/book.html |
|
|
|
43 * https://wiki.voidlinux.org/A_General_Introduction_To_Package_Creation |
|
|
|
44 |
|
|
|
45 |
|
|
|
46 Variables |
|
|
|
47 --------- |
|
|
|
48 |
|
|
|
49 It is recommended to respect the following commonly-used variables. |
|
|
|
50 |
|
|
|
51 * $DESTDIR: make use of the $DESTDIR variable for the install targets. This |
|
|
|
52 makes it simpler to install the package to another location and make binary |
|
|
|
53 packages. It is the prefix destination directory to install to (before $PREFIX). |
|
|
|
54 It should be unset by default. |
|
|
|
55 |
|
|
|
56 * $PREFIX: this variable specifies the prefix location to install to, it should be |
|
|
|
57 "/usr/local" by default since this is most commonly used for ports. |
|
|
|
58 |
|
|
|
59 * $MANPREFIX or $MANDIR: |
|
|
|
60 * Distributions can use different locations for man pages for ports or in general. |
|
|
|
61 * Some distributions package documentation in a separate package (project-doc). |
|
|
|
62 |
|
|
|
63 Specifying compiler and linker flags: |
|
|
|
64 |
|
|
|
65 * $CC, $CFLAGS, $LDFLAGS, $CPPFLAGS: make sure to respect the default set flags |
|
|
|
66 as specified in POSIX: |
|
|
|
67 https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html under the |
|
|
|
68 section "Default rules". This make it easier for the ports build system to use |
|
|
|
69 the set variables and not having to patch the Makefile in some way. |
|
|
|
70 |
|
|
|
71 * $CFLAGS: do not hard-code optimization flags like (-O2) or diagnostic flags |
|
|
|
72 such as -Wall, -Wextra, -pedantic. Even more importantly, do not |
|
|
|
73 specify unportable compiler flags. |
|
|
|
74 |
|
|
|
75 * $LDFLAGS: do not hard-code linker flags like -s (symbol stripping) or -g, |
|
|
|
76 -static or such flags. |
|
|
|
77 |
|
|
|
78 * Libraries: using separate variables for compile and link per library (for |
|
|
|
79 example libpng, libjpeg) can be useful for building in ports. |
|
|
|
80 For example a variable LIBPNG_CFLAGS, LIBPNG_LDFLAGS for the header files or |
|
|
|
81 library location. |
|
|
|
82 |
|
|
|
83 |
|
|
|
84 Considerations |
|
|
|
85 -------------- |
|
|
|
86 |
|
|
|
87 * It is not recommended to suppress compilation output with the @ prefix (for |
|
|
|
88 example to make output look nicer aligned). The verbose output is very useful |
|
|
|
89 for debugging and suppressing it only adds debugging abstractions. |
|
|
|
90 |
|
|
|
91 * Try to use a single-file Makefile, at least for small projects. If needed some |
|
|
|
92 configuration could be included from the Makefile: config.mk. Keep in mind |
|
|
|
93 that reducing abstractions will increase readability and debugability. Package |
|
|
|
94 maintainers/porters do not want to have to relearn a new system for each |
|
|
|
95 software package. |
|
|
|
96 |
|
|
|
97 * As specified above, different systems can use different locations for certain |
|
|
|
98 things like man pages, X11 header files and libraries and ports installation. |
|
|
|
99 |
|
|
|
100 Examples: |
|
|
|
101 * X11: commonly uses /usr/X11R6 on BSD-like platforms. |
|
|
|
102 * Man page directories: on OpenBSD: /usr/local/man. |
|
|
|
103 |
|
|
|
104 Testing on many different systems is useful! For example: Linux, OpenBSD, NetBSD. |
|
|
|
105 |
|
|
|
106 |
|
|
|
107 Examples |
|
|
|
108 -------- |
|
|
|
109 |
|
|
|
110 Below is an example of a Makefile from the json2tsv project. It is |
|
|
|
111 line-numbered and annotated with remarks on why things are done the way |
|
|
|
112 they are. |
|
|
|
113 |
|
|
|
114 1 .POSIX: |
|
|
|
115 |
|
|
|
116 Specify POSIX compatibility: "To receive exactly the behavior described in this |
|
|
|
117 section, the user shall ensure that a portable makefile shall: Include the |
|
|
|
118 special target .POSIX" |
|
|
|
119 |
|
|
|
120 2 |
|
|
|
121 3 NAME = json2tsv |
|
|
|
122 4 VERSION = 0.5 |
|
|
|
123 5 |
|
|
|
124 |
|
|
|
125 Define a name and version variable of the project which can be reused, for |
|
|
|
126 example for the dist tarball. |
|
|
|
127 |
|
|
|
128 6 # paths |
|
|
|
129 7 PREFIX = /usr/local |
|
|
|
130 8 MANPREFIX = ${PREFIX}/man |
|
|
|
131 9 DOCPREFIX = ${PREFIX}/share/doc/${NAME} |
|
|
|
132 10 |
|
|
|
133 |
|
|
|
134 Specify default sane paths. |
|
|
|
135 |
|
|
|
136 11 RANLIB = ranlib |
|
|
|
137 12 |
|
|
|
138 |
|
|
|
139 This variable is not specified by default in POSIX. It is commonly "ranlib", |
|
|
|
140 but can be overwritten. |
|
|
|
141 |
|
|
|
142 13 BIN = ${NAME} |
|
|
|
143 |
|
|
|
144 In this case it's simple: the binary is the program name. |
|
|
|
145 |
|
|
|
146 14 SRC = ${BIN:=.c} |
|
|
|
147 |
|
|
|
148 C source files, so just json2tsv.c here. |
|
|
|
149 |
|
|
|
150 15 HDR = json.h |
|
|
|
151 |
|
|
|
152 Header files. |
|
|
|
153 |
|
|
|
154 16 MAN1 = ${BIN:=.1} |
|
|
|
155 |
|
|
|
156 Man section 1 pages. |
|
|
|
157 |
|
|
|
158 17 DOC = \ |
|
|
|
159 18 LICENSE\ |
|
|
|
160 19 README |
|
|
|
161 20 |
|
|
|
162 |
|
|
|
163 Other documentation and license files. |
|
|
|
164 |
|
|
|
165 21 LIBJSON = libjson.a |
|
|
|
166 22 LIBJSONSRC = json.c |
|
|
|
167 23 LIBJSONOBJ = ${LIBJSONSRC:.c=.o} |
|
|
|
168 24 |
|
|
|
169 25 LIB = ${LIBJSON} |
|
|
|
170 26 |
|
|
|
171 |
|
|
|
172 Build the json.c file as a local reusable linkable library (libjson.a). |
|
|
|
173 |
|
|
|
174 27 all: ${BIN} |
|
|
|
175 28 |
|
|
|
176 |
|
|
|
177 The default build rule: build the binary. |
|
|
|
178 |
|
|
|
179 29 ${BIN}: ${LIB} ${BIN:=.o} |
|
|
|
180 30 |
|
|
|
181 |
|
|
|
182 The binary depends on the libjson library and its own object file. |
|
|
|
183 |
|
|
|
184 31 OBJ = ${SRC:.c=.o} ${LIBJSONOBJ} |
|
|
|
185 32 |
|
|
|
186 |
|
|
|
187 The object files are all C source-code substituted to from .c to .o and the |
|
|
|
188 local libjson library files, so: json2tsv.o json.o |
|
|
|
189 |
|
|
|
190 33 ${OBJ}: ${HDR} |
|
|
|
191 34 |
|
|
|
192 |
|
|
|
193 Ensure the object files are recompiled if the header file contents change. |
|
|
|
194 |
|
|
|
195 35 .o: |
|
|
|
196 36 ${CC} ${LDFLAGS} -o $@ $< ${LIB} |
|
|
|
197 |
|
|
|
198 Linking, use the system specified LDFLAGS. |
|
|
|
199 |
|
|
|
200 37 |
|
|
|
201 38 .c.o: |
|
|
|
202 39 ${CC} ${CFLAGS} ${CPPFLAGS} -c $< |
|
|
|
203 |
|
|
|
204 Compiling, use the system specified CFLAGS and CPPFLAGS. |
|
|
|
205 |
|
|
|
206 40 |
|
|
|
207 41 ${LIBJSON}: ${LIBJSONOBJ} |
|
|
|
208 42 ${AR} -rc $@ $? |
|
|
|
209 43 ${RANLIB} $@ |
|
|
|
210 44 |
|
|
|
211 |
|
|
|
212 Create an archive of the libjson object files. Note that ar -s is an extension |
|
|
|
213 so ranlib is called as a separate command. It is also useful to be specified |
|
|
|
214 separately for cross-compiling. |
|
|
|
215 |
|
|
|
216 45 dist: |
|
|
|
217 46 rm -rf "${NAME}-${VERSION}" |
|
|
|
218 47 mkdir -p "${NAME}-${VERSION}" |
|
|
|
219 48 cp -f ${MAN1} ${DOC} ${HDR} \ |
|
|
|
220 49 ${SRC} ${LIBJSONSRC} Makefile "${NAME}-${VERSION}" |
|
|
|
221 |
|
|
|
222 Use the -f (force) options for rm ensures make does not return an error |
|
|
|
223 on failure. For cp it ensures to overwrite the file even if it is busy. For |
|
|
|
224 mkdir the -p flag is used to create all intermediary directories and to not |
|
|
|
225 return an error if the directory already exists. |
|
|
|
226 |
|
|
|
227 50 # make tarball |
|
|
|
228 51 tar cf - "${NAME}-${VERSION}" | gzip -c > "${NAME}-${VERSION}.tar.gz" |
|
|
|
229 |
|
|
|
230 Make a tarball. gzip from stdin is used for portability (tar z is non-POSIX). |
|
|
|
231 https://pubs.opengroup.org/onlinepubs/007908799/xcu/tar.html |
|
|
|
232 |
|
|
|
233 52 rm -rf "${NAME}-${VERSION}" |
|
|
|
234 53 |
|
|
|
235 |
|
|
|
236 54 clean: |
|
|
|
237 55 rm -f ${BIN} ${OBJ} ${LIB} |
|
|
|
238 |
|
|
|
239 Remove the binary, object files and the local archive library (.a) file. |
|
|
|
240 |
|
|
|
241 56 |
|
|
|
242 57 install: all |
|
|
|
243 58 # installing executable files. |
|
|
|
244 59 mkdir -p "${DESTDIR}${PREFIX}/bin" |
|
|
|
245 60 cp -f ${BIN} "${DESTDIR}${PREFIX}/bin" |
|
|
|
246 |
|
|
|
247 cp's -f flag ensures overwriting the file even if it is busy. |
|
|
|
248 |
|
|
|
249 61 for f in ${BIN}; do chmod 755 "${DESTDIR}${PREFIX}/bin/$$f"; done |
|
|
|
250 62 # installing example files. |
|
|
|
251 63 mkdir -p "${DESTDIR}${DOCPREFIX}" |
|
|
|
252 64 cp -f ${DOC} "${DESTDIR}${DOCPREFIX}" |
|
|
|
253 65 for d in ${DOC}; do chmod 644 "${DESTDIR}${DOCPREFIX}/$$d"; done |
|
|
|
254 66 # installing manual pages for general commands: section 1. |
|
|
|
255 67 mkdir -p "${DESTDIR}${MANPREFIX}/man1" |
|
|
|
256 68 cp -f ${MAN1} "${DESTDIR}${MANPREFIX}/man1" |
|
|
|
257 69 for m in ${MAN1}; do chmod 644 "${DESTDIR}${MANPREFIX}/man1/$$m"; done |
|
|
|
258 70 |
|
|
|
259 |
|
|
|
260 Explicitly set permissions for executable files and for documentation. |
|
|
|
261 |
|
|
|
262 71 uninstall: |
|
|
|
263 72 # removing executable files. |
|
|
|
264 73 for f in ${BIN}; do rm -f "${DESTDIR}${PREFIX}/bin/$$f"; done |
|
|
|
265 74 # removing example files. |
|
|
|
266 75 for d in ${DOC}; do rm -f "${DESTDIR}${DOCPREFIX}/$$d"; done |
|
|
|
267 |
|
|
|
268 76 -rmdir "${DESTDIR}${DOCPREFIX}" |
|
|
|
269 |
|
|
|
270 Try to remove the doc directory, but if it is shared by other packages and |
|
|
|
271 rmdir returns an error code then that is ok and make still proceeds. |
|
|
|
272 |
|
|
|
273 77 # removing manual pages. |
|
|
|
274 78 for m in ${MAN1}; do rm -f "${DESTDIR}${MANPREFIX}/man1/$$m"; done |
|
|
|
275 79 |
|
|
|
276 80 .PHONY: all clean dist install uninstall |
|
|
|
277 |
|
|
|
278 |
|
|
|
279 References |
|
|
|
280 ---------- |
|
|
|
281 |
|
|
|
282 - https://www.gnu.org/prep/standards/standards.html#DESTDIR |
|
|
|
283 - https://nullprogram.com/blog/2017/08/20/ |
|
|
|
284 - https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html |
|
|
|
285 - https://pubs.opengroup.org/onlinepubs/9699919799/ |
|