1 ########################################################################
2 # Copyright (C) 2021 Alejandro Colomar <alx.manpages@gmail.com>
3 # SPDX-License-Identifier: GPL-2.0 OR LGPL-2.0
4 ########################################################################
7 # - Follow "Makefile Conventions" from the "GNU Coding Standards" closely.
8 # However, when something could be improved, don't follow those.
9 # - Uppercase variables, when referring files, refer to files in this repo.
10 # - Lowercase variables, when referring files, refer to system files.
11 # - Lowercase variables starting with '_' refer to absolute paths,
12 # including $(DESTDIR).
13 # - Uppercase variables starting with '_' refer to temporary files produced
15 # - Variables ending with '_' refer to a subdir of their parent dir, which
16 # is in a variable of the same name but without the '_'. The subdir is
17 # named after this project: <*/man>.
18 # - Variables ending in '_rm' refer to files that can be removed (exist).
19 # - Variables ending in '_rmdir' refer to dirs that can be removed (exist).
20 # - Targets of the form '%-rm' remove their corresponding file '%'.
21 # - Targets of the form '%/.-rmdir' remove their corresponding dir '%/'.
22 # - Targets of the form '%/.' create their corresponding directory '%/'.
23 # - Every file or directory to be created depends on its parent directory.
24 # This avoids race conditions caused by `mkdir -p`. Only the root
25 # directories are created with parents.
26 # - The 'FORCE' target is used to make phony some variables that can't be
27 # .PHONY to avoid some optimizations.
29 ########################################################################
31 SHELL
:= /bin
/bash
-Eeuo pipefail
34 MAKEFLAGS
+= --no-print-directory
35 MAKEFLAGS
+= --warn-undefined-variables
43 SYSCONFDIR
:= $(srcdir)/etc
44 TMACDIR
:= $(SYSCONFDIR
)/groff
/tmac
46 MAN0DIR
:= $(MANDIR
)/man0
47 MAN1DIR
:= $(MANDIR
)/man1
48 MAN2DIR
:= $(MANDIR
)/man2
49 MAN3DIR
:= $(MANDIR
)/man3
50 MAN4DIR
:= $(MANDIR
)/man4
51 MAN5DIR
:= $(MANDIR
)/man5
52 MAN6DIR
:= $(MANDIR
)/man6
53 MAN7DIR
:= $(MANDIR
)/man7
54 MAN8DIR
:= $(MANDIR
)/man8
56 datarootdir
:= $(prefix)/share
57 docdir
:= $(datarootdir
)/doc
58 mandir := $(datarootdir
)/man
59 man0dir := $(mandir)/man0
60 man1dir := $(mandir)/man1
61 man2dir := $(mandir)/man2
62 man3dir := $(mandir)/man3
63 man4dir := $(mandir)/man4
64 man5dir := $(mandir)/man5
65 man6dir := $(mandir)/man6
66 man7dir := $(mandir)/man7
67 man8dir := $(mandir)/man8
83 htmldir_
:= $(htmldir
)/man
85 _LINTDIR
:= $(builddir
)/lint
86 _HTMLDIR
:= $(builddir
)/html
87 _SRCDIR
:= $(builddir
)/src
89 _mandir
:= $(DESTDIR
)$(mandir)
90 _htmldir
:= $(DESTDIR
)$(htmldir_
)
93 DEFAULT_CHECKPATCHFLAGS
:=
94 EXTRA_CHECKPATCHFLAGS
:=
95 CHECKPATCHFLAGS
:= $(DEFAULT_CHECKPATCHFLAGS
) $(EXTRA_CHECKPATCHFLAGS
)
97 clang-tidy_config
:= $(SYSCONFDIR
)/clang-tidy
/config.yaml
98 DEFAULT_CLANG-TIDYFLAGS
:= --config-file
=$(clang-tidy_config
)
99 DEFAULT_CLANG-TIDYFLAGS
+= --quiet
100 DEFAULT_CLANG-TIDYFLAGS
+= --use-color
101 EXTRA_CLANG-TIDYFLAGS
:=
102 CLANG-TIDYFLAGS
:= $(DEFAULT_CLANG-TIDYFLAGS
) $(EXTRA_CLANG-TIDYFLAGS
)
104 DEFAULT_CPPLINTFLAGS
:=
105 EXTRA_CPPLINTFLAGS
:=
106 CPPLINTFLAGS
:= $(DEFAULT_CPPLINTFLAGS
) $(EXTRA_CPPLINTFLAGS
)
108 DEFAULT_IWYUFLAGS
:= -Xiwyu
--no_fwd_decls
109 DEFAULT_IWYUFLAGS
+= -Xiwyu
--error
111 IWYUFLAGS
:= $(DEFAULT_IWYUFLAGS
) $(EXTRA_IWYUFLAGS
)
115 CPPFLAGS
:= $(DEFAULT_CPPFLAGS
) $(EXTRA_CPPFLAGS
)
117 DEFAULT_CFLAGS
:= -std
=gnu17
118 DEFAULT_CFLAGS
+= -Wall
119 DEFAULT_CFLAGS
+= -Wextra
120 DEAFULT_CFLAGS
+= -Wstrict-prototypes
121 DEFAULT_CFLAGS
+= -Werror
122 DEFAULT_CFLAGS
+= -Wno-error
=unused-parameter
123 DEFAULT_CFLAGS
+= -Wno-error
=sign-compare
124 DEFAULT_CFLAGS
+= -Wno-error
=format
125 DEFAULT_CFLAGS
+= -Wno-error
=uninitialized
127 CFLAGS
:= $(DEFAULT_CFLAGS
) $(EXTRA_CFLAGS
)
129 DEFAULT_LDFLAGS
:= -Wl
,--as-needed
130 DEFAULT_LDFLAGS
+= -Wl
,--no-allow-shlib-undefined
131 DEFAULT_LDFLAGS
+= -Wl
,--no-copy-dt-needed-entries
132 DEFAULT_LDFLAGS
+= -Wl
,--no-undefined
134 LDFLAGS
:= $(DEFAULT_LDFLAGS
) $(EXTRA_LDFLAGS
)
136 DEFAULT_LDLIBS
:= -lc
138 LDLIBS
:= $(DEFAULT_LDLIBS
) $(EXTRA_LDLIBS
)
140 TMACFILES
:= $(sort $(shell find
$(TMACDIR
) -not
-type d
))
141 TMACNAMES
:= $(basename $(notdir $(TMACFILES
)))
142 GROFF_CHECKSTYLE_LVL
:= 3
143 DEFAULT_GROFFFLAGS
:= -man
144 DEFAULT_GROFFFLAGS
+= -t
145 DEFAULT_GROFFFLAGS
+= -M
$(TMACDIR
)
146 DEFAULT_GROFFFLAGS
+= $(foreach x
,$(TMACNAMES
),-m
$(x
))
147 DEFAULT_GROFFFLAGS
+= -rCHECKSTYLE
=$(GROFF_CHECKSTYLE_LVL
)
148 DEFAULT_GROFFFLAGS
+= -ww
150 GROFFFLAGS
:= $(DEFAULT_GROFFFLAGS
) $(EXTRA_GROFFFLAGS
)
152 DEFAULT_MANDOCFLAGS
:= -man
153 DEFAULT_MANDOCFLAGS
+= -Tlint
155 MANDOCFLAGS
:= $(DEFAULT_MANDOCFLAGS
) $(EXTRA_MANDOCFLAGS
)
157 DEFAULT_MAN2HTMLFLAGS
:=
158 EXTRA_MAN2HTMLFLAGS
:=
159 MAN2HTMLFLAGS
:= $(DEFAULT_MAN2HTMLFLAGS
) $(EXTRA_MAN2HTMLFLAGS
)
163 INSTALL_DATA
:= $(INSTALL
) -m
644
164 INSTALL_DIR
:= $(INSTALL
) -m
755 -d
167 RMDIR
:= rmdir
--ignore-fail-on-non-empty
168 CHECKPATCH
:= checkpatch
169 CLANG-TIDY
:= clang-tidy
173 LD
:= $(CC
) $(CFLAGS
)
180 MAN_SECTIONS
:= 0 1 2 3 4 5 6 7 8
189 $(info INSTALL
$(@D
)/)
202 install: install-man |
installdirs
206 installdirs: | installdirs-man
209 .PHONY
: uninstall remove
210 uninstall remove
: uninstall-man
215 $(RM
) -rf
$(builddir
)
218 ########################################################################
221 MANPAGES
:= $(sort $(shell find
$(MANDIR
)/man?
/ -type f | grep
'$(manext)'))
222 LINTMAN
:= $(sort $(shell find
$(MANDIR
)/man?
/ -type f | grep
'$(manext)' \
223 | xargs grep
-l
'^\.TH '))
224 _HTMLPAGES
:= $(patsubst $(MANDIR
)/%,$(_HTMLDIR
)/%.html
,$(MANPAGES
))
225 _htmlpages
:= $(patsubst $(_HTMLDIR
)/%,$(_htmldir
)/%,$(_HTMLPAGES
))
226 _manpages
:= $(patsubst $(MANDIR
)/%,$(_mandir
)/%,$(MANPAGES
))
227 _man0pages
:= $(filter %$(man0ext),$(_manpages
))
228 _man1pages
:= $(filter %$(man1ext),$(_manpages
))
229 _man2pages
:= $(filter %$(man2ext),$(_manpages
))
230 _man2pages
+= $(filter %$(man2type_ext
),$(_manpages
))
231 _man3pages
:= $(filter %$(man3ext),$(_manpages
))
232 _man3pages
+= $(filter %$(man3type_ext
),$(_manpages
))
233 _man4pages
:= $(filter %$(man4ext),$(_manpages
))
234 _man5pages
:= $(filter %$(man5ext),$(_manpages
))
235 _man6pages
:= $(filter %$(man6ext),$(_manpages
))
236 _man7pages
:= $(filter %$(man7ext),$(_manpages
))
237 _man8pages
:= $(filter %$(man8ext),$(_manpages
))
238 _LINT_groff
:=$(patsubst $(MANDIR
)/%,$(_LINTDIR
)/%.lint.groff.touch
,$(LINTMAN
))
239 _LINT_mandoc
:=$(patsubst $(MANDIR
)/%,$(_LINTDIR
)/%.lint.mandoc.touch
,$(LINTMAN
))
240 _SRCPAGEDIRS
:=$(patsubst $(MANDIR
)/%,$(_SRCDIR
)/%.d
,$(LINTMAN
))
241 _UNITS_src
:=$(sort $(patsubst $(MANDIR
)/%,$(_SRCDIR
)/%,$(shell \
242 find
$(MANDIR
)/man?
/ -type f \
243 | grep
'$(manext)$$' \
244 | xargs grep
-l
'^\.TH ' \
247 sed
-n
"s,^\... SRC BEGIN (\(.*.[ch]\))$$,$$m.d/\1,p"; \
249 _UNITS_h
:= $(filter %.h
,$(_UNITS_src
))
250 _UNITS_c
:= $(filter %.c
,$(_UNITS_src
))
251 _UNITS_o
:= $(patsubst %.c
,%.o
,$(_UNITS_c
))
252 _UNITS_bin
:= $(patsubst %.c
,%,$(_UNITS_c
))
253 _LINT_checkpatch
:= $(patsubst %.c
,%.lint.checkpatch.touch
,$(_UNITS_c
))
254 _LINT_clang-tidy
:= $(patsubst %.c
,%.lint.clang-tidy.touch
,$(_UNITS_c
))
255 _LINT_cpplint
:= $(patsubst %.c
,%.lint.cpplint.touch
,$(_UNITS_c
))
256 _LINT_iwyu
:= $(patsubst %.c
,%.lint.iwyu.touch
,$(_UNITS_c
))
258 MANDIRS
:= $(sort $(shell find
$(MANDIR
)/man?
-type d
))
259 _HTMLDIRS
:= $(patsubst $(MANDIR
)/%,$(_HTMLDIR
)/%/.
,$(MANDIRS
))
260 _LINTDIRS
:= $(patsubst $(MANDIR
)/%,$(_LINTDIR
)/%/.
,$(MANDIRS
))
261 _SRCDIRS
:= $(patsubst $(MANDIR
)/%,$(_SRCDIR
)/%/.
,$(MANDIRS
))
262 _htmldirs
:= $(patsubst $(_HTMLDIR
)/%,$(_htmldir
)/%,$(_HTMLDIRS
))
263 _mandirs
:= $(patsubst $(MANDIR
)/%,$(_mandir
)/%/.
,$(MANDIRS
))
264 _man0dir
:= $(filter %man0
/.
,$(_mandirs
))
265 _man1dir
:= $(filter %man1
/.
,$(_mandirs
))
266 _man2dir
:= $(filter %man2
/.
,$(_mandirs
))
267 _man3dir
:= $(filter %man3
/.
,$(_mandirs
))
268 _man4dir
:= $(filter %man4
/.
,$(_mandirs
))
269 _man5dir
:= $(filter %man5
/.
,$(_mandirs
))
270 _man6dir
:= $(filter %man6
/.
,$(_mandirs
))
271 _man7dir
:= $(filter %man7
/.
,$(_mandirs
))
272 _man8dir
:= $(filter %man8
/.
,$(_mandirs
))
274 _htmlpages_rm
:= $(addsuffix -rm,$(wildcard $(_htmlpages
)))
275 _man0pages_rm
:= $(addsuffix -rm,$(wildcard $(_man0pages
)))
276 _man1pages_rm
:= $(addsuffix -rm,$(wildcard $(_man1pages
)))
277 _man2pages_rm
:= $(addsuffix -rm,$(wildcard $(_man2pages
)))
278 _man3pages_rm
:= $(addsuffix -rm,$(wildcard $(_man3pages
)))
279 _man4pages_rm
:= $(addsuffix -rm,$(wildcard $(_man4pages
)))
280 _man5pages_rm
:= $(addsuffix -rm,$(wildcard $(_man5pages
)))
281 _man6pages_rm
:= $(addsuffix -rm,$(wildcard $(_man6pages
)))
282 _man7pages_rm
:= $(addsuffix -rm,$(wildcard $(_man7pages
)))
283 _man8pages_rm
:= $(addsuffix -rm,$(wildcard $(_man8pages
)))
285 _htmldirs_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_htmldirs
)))
286 _mandirs_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_mandirs
)))
287 _man0dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man0dir
)))
288 _man1dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man1dir
)))
289 _man2dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man2dir
)))
290 _man3dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man3dir
)))
291 _man4dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man4dir
)))
292 _man5dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man5dir
)))
293 _man6dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man6dir
)))
294 _man7dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man7dir
)))
295 _man8dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man8dir
)))
296 _mandir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_mandir
)/.
))
297 _htmldir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_htmldir
)/.
))
299 install_manX
:= $(foreach x
,$(MAN_SECTIONS
),install-man
$(x
))
300 installdirs_manX
:= $(foreach x
,$(MAN_SECTIONS
),installdirs-man
$(x
))
301 uninstall_manX
:= $(foreach x
,$(MAN_SECTIONS
),uninstall-man
$(x
))
305 $(_manpages
): $(_mandir
)/man
%: $(MANDIR
)/man
% |
$$(@D
)/.
307 $(INSTALL_DATA
) -T
$< $@
309 $(_mandirs
): %/.
: |
$$(dir %).
$(_mandir
)/.
311 $(_mandirs_rmdir
): $(_mandir
)/man
%/.
-rmdir
: $$(_man
%pages_rm
) FORCE
312 $(_mandir_rmdir
): $(uninstall_manX
) FORCE
315 .PHONY
: $(install_manX
)
316 $(install_manX
): install-man
%: $$(_man
%pages
) | installdirs-man
%
320 install-man
: $(install_manX
)
323 .PHONY
: $(installdirs_manX
)
324 $(installdirs_manX
): installdirs-man
%: $$(_man
%dir)
327 .PHONY
: installdirs-man
328 installdirs-man
: $(installdirs_manX
)
331 .PHONY
: $(uninstall_manX
)
332 $(uninstall_manX
): uninstall-man
%: $$(_man
%pages_rm
) $$(_man
%dir_rmdir
)
335 .PHONY
: uninstall-man
336 uninstall-man
: $(_mandir_rmdir
) $(uninstall_manX
)
340 ########################################################################
343 DISTNAME
:= $(shell git describe
2>/dev
/null
)
344 DISTFILE
:= $(builddir
)/$(DISTNAME
).
tar
346 dist := $(foreach x
,$(compression
),dist-
$(x
))
349 $(DISTFILE
): $(shell git ls-files
2>/dev
/null
) |
$$(@D
)/.
351 tar cf
$@
-T
/dev
/null
355 $(DISTFILE
).gz
: %.gz
: % |
$$(@D
)/.
359 $(DISTFILE
).xz
: %.xz
: % |
$$(@D
)/.
365 dist-tar
: $(DISTFILE
) | builddirs-dist
369 $(dist): dist-
%: $(DISTFILE
).
% | builddirs-dist
372 .PHONY
: builddirs-dist
373 builddirs-dist
: $(builddir
)/.
381 ########################################################################
384 $(_SRCPAGEDIRS
): $(_SRCDIR
)/%.d
: $(MANDIR
)/% |
$$(@D
)/.
389 $(_UNITS_src
): $$(patsubst $(_SRCDIR
)/%.d
,$(MANDIR
)/%,$$(@D
)) |
$$(@D
)
390 $(_UNITS_c
): $$(filter $$(@D
)/%.h
,$(_UNITS_h
))
395 -e
'/^\.TH/,/^\.SH/{/^\.SH/!p}' \
396 -e
'/^\.SH EXAMPLES/p' \
397 -e
"/^\... SRC BEGIN ($(@F))$$/,/^\... SRC END$$/p" \
398 |
$(MAN
) -P cat
-l
- \
403 $(_UNITS_o
): $(_SRCDIR
)/%.o
: $(_SRCDIR
)/%.c
405 $(CC
) -c
$(CPPFLAGS
) $(CFLAGS
) -o
$@
$<
407 $(_UNITS_bin
): $(_SRCDIR
)/%: $(_SRCDIR
)/%.o
409 $(LD
) $(LDFLAGS
) -o
$@
$< $(LDLIBS
)
411 $(_SRCDIRS
): %/.
: |
$$(dir %).
$(_SRCDIR
)/.
414 .PHONY
: build-src src
415 build-src src
: $(_UNITS_c
) | builddirs-src
419 build-cc
: $(_UNITS_o
)
423 build-ld
: $(_UNITS_bin
)
426 .PHONY
: builddirs-src
427 builddirs-src
: $(_SRCDIRS
)
431 ########################################################################
434 linters
:= checkpatch clang-tidy cpplint iwyu groff mandoc
435 lint
:= $(foreach x
,$(linters
),lint-
$(x
))
437 $(_LINT_checkpatch
): %.lint.checkpatch.touch
: %.c
438 $(info LINT
(checkpatch
) $@
)
439 $(CHECKPATCH
) $(CHECKPATCHFLAGS
) -f
$<
442 $(_LINT_clang-tidy
): %.lint.clang-tidy.touch
: %.c
443 $(info LINT
(clang-tidy
) $@
)
444 $(CLANG-TIDY
) $(CLANG-TIDYFLAGS
) $< -- $(CPPFLAGS
) $(CFLAGS
) 2>&1 \
445 | sed
'/generated\.$$/d'
448 $(_LINT_cpplint
): %.lint.cpplint.touch
: %.c
449 $(info LINT
(cpplint
) $@
)
450 $(CPPLINT
) $(CPPLINTFLAGS
) $< >/dev
/null
453 $(_LINT_iwyu
): %.lint.iwyu.touch
: %.c
454 $(info LINT
(iwyu
) $@
)
455 $(IWYU
) $(IWYUFLAGS
) $(CPPFLAGS
) $(CFLAGS
) $< 2>&1 \
457 | sed
'/correct/{N;d}' \
461 $(_LINT_groff
): $(_LINTDIR
)/%.lint.groff.touch
: $(MANDIR
)/% |
$$(@D
)/.
462 $(info LINT
(groff
) $@
)
463 $(GROFF
) $(GROFFFLAGS
) -z
$<
466 $(_LINT_mandoc
): $(_LINTDIR
)/%.lint.mandoc.touch
: $(MANDIR
)/% |
$$(@D
)/.
467 $(info LINT
(mandoc
) $@
)
468 $(MANDOC
) $(MANDOCFLAGS
) $<
471 $(_LINTDIRS
): %/.
: |
$$(dir %).
$(_LINTDIR
)/.
475 $(lint
): lint-
%: $$(_LINT_
%) | lintdirs
479 lintdirs
: $(_LINTDIRS
) $(_SRCDIRS
)
487 ########################################################################
491 # make MAN2HTMLFLAGS=whatever html
492 # The sed removes the lines "Content-type: text/html\n\n"
493 $(_HTMLPAGES
): $(_HTMLDIR
)/%.html
: $(MANDIR
)/% |
$$(@D
)/.
495 $(MAN2HTML
) $(MAN2HTMLFLAGS
) $< | sed
-e
1,2d
>$@
497 $(_HTMLDIRS
): %/.
: |
$$(dir %).
$(_HTMLDIR
)/.
499 $(_htmlpages
): $(_htmldir
)/%: $(_HTMLDIR
)/% |
$$(@D
)/.
501 $(INSTALL_DATA
) -T
$< $@
503 $(_htmldirs
): %/.
: |
$$(dir %).
$(_htmldir
)/.
506 .PHONY
: build-html html
507 build-html html
: $(_HTMLPAGES
) | builddirs-html
510 .PHONY
: builddirs-html
511 builddirs-html
: $(_HTMLDIRS
)
515 install-html
: $(_htmlpages
) | installdirs-html
518 .PHONY
: installdirs-html
519 installdirs-html
: $(_htmldirs
)
522 .PHONY
: uninstall-html
523 uninstall-html
: $(_htmldir_rmdir
) $(_htmldirs_rmdir
) $(_htmlpages_rm
)
527 ########################################################################