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 MAKEFLAGS
+= --no-print-directory
32 MAKEFLAGS
+= --warn-undefined-variables
40 SYSCONFDIR
:= $(srcdir)/etc
41 TMACDIR
:= $(SYSCONFDIR
)/groff
/tmac
43 MAN0DIR
:= $(MANDIR
)/man0
44 MAN1DIR
:= $(MANDIR
)/man1
45 MAN2DIR
:= $(MANDIR
)/man2
46 MAN3DIR
:= $(MANDIR
)/man3
47 MAN4DIR
:= $(MANDIR
)/man4
48 MAN5DIR
:= $(MANDIR
)/man5
49 MAN6DIR
:= $(MANDIR
)/man6
50 MAN7DIR
:= $(MANDIR
)/man7
51 MAN8DIR
:= $(MANDIR
)/man8
53 datarootdir
:= $(prefix)/share
54 docdir
:= $(datarootdir
)/doc
55 mandir := $(datarootdir
)/man
56 man0dir := $(mandir)/man0
57 man1dir := $(mandir)/man1
58 man2dir := $(mandir)/man2
59 man3dir := $(mandir)/man3
60 man4dir := $(mandir)/man4
61 man5dir := $(mandir)/man5
62 man6dir := $(mandir)/man6
63 man7dir := $(mandir)/man7
64 man8dir := $(mandir)/man8
78 htmldir_
:= $(htmldir
)/man
80 _LINTDIR
:= $(builddir
)/lint
81 _HTMLDIR
:= $(builddir
)/html
82 _SRCDIR
:= $(builddir
)/src
84 _mandir
:= $(DESTDIR
)$(mandir)
85 _htmldir
:= $(DESTDIR
)$(htmldir_
)
88 clang-tidy_config
:= $(SYSCONFDIR
)/clang-tidy
/config.yaml
89 DEFAULT_CLANG-TIDYFLAGS
:= --config-file
=$(clang-tidy_config
)
90 DEFAULT_CLANG-TIDYFLAGS
+= --quiet
91 DEFAULT_CLANG-TIDYFLAGS
+= --use-color
92 EXTRA_CLANG-TIDYFLAGS
:=
93 CLANG-TIDYFLAGS
:= $(DEFAULT_CLANG-TIDYFLAGS
) $(EXTRA_CLANG-TIDYFLAGS
)
95 DEFAULT_IWYUFLAGS
:= -Xiwyu
--no_fwd_decls
96 DEFAULT_IWYUFLAGS
+= -Xiwyu
--error
98 IWYUFLAGS
:= $(DEFAULT_IWYUFLAGS
) $(EXTRA_IWYUFLAGS
)
102 CPPFLAGS
:= $(DEFAULT_CPPFLAGS
) $(EXTRA_CPPFLAGS
)
104 DEFAULT_CFLAGS
:= -std
=gnu17
105 DEFAULT_CFLAGS
+= -Wall
106 DEFAULT_CFLAGS
+= -Wextra
107 DEAFULT_CFLAGS
+= -Wstrict-prototypes
108 DEFAULT_CFLAGS
+= -Werror
110 CFLAGS
:= $(DEFAULT_CFLAGS
) $(EXTRA_CFLAGS
)
112 DEFAULT_LDFLAGS
:= -Wl
,--as-needed
113 DEFAULT_LDFLAGS
+= -Wl
,--no-allow-shlib-undefined
114 DEFAULT_LDFLAGS
+= -Wl
,--no-copy-dt-needed-entries
115 DEFAULT_LDFLAGS
+= -Wl
,--no-undefined
117 LDFLAGS
:= $(DEFAULT_LDFLAGS
) $(EXTRA_LDFLAGS
)
119 DEFAULT_LDLIBS
:= -lc
121 LDLIBS
:= $(DEFAULT_LDLIBS
) $(EXTRA_LDLIBS
)
123 TMACFILES
:= $(sort $(shell find
$(TMACDIR
) -not
-type d
))
124 TMACNAMES
:= $(basename $(notdir $(TMACFILES
)))
125 GROFF_CHECKSTYLE_LVL
:= 3
126 DEFAULT_GROFFFLAGS
:= -man
127 DEFAULT_GROFFFLAGS
+= -t
128 DEFAULT_GROFFFLAGS
+= -M
$(TMACDIR
)
129 DEFAULT_GROFFFLAGS
+= $(foreach x
,$(TMACNAMES
),-m
$(x
))
130 DEFAULT_GROFFFLAGS
+= -rCHECKSTYLE
=$(GROFF_CHECKSTYLE_LVL
)
131 DEFAULT_GROFFFLAGS
+= -ww
133 GROFFFLAGS
:= $(DEFAULT_GROFFFLAGS
) $(EXTRA_GROFFFLAGS
)
135 DEFAULT_MANDOCFLAGS
:= -man
136 DEFAULT_MANDOCFLAGS
+= -Tlint
138 MANDOCFLAGS
:= $(DEFAULT_MANDOCFLAGS
) $(EXTRA_MANDOCFLAGS
)
140 DEFAULT_MAN2HTMLFLAGS
:=
141 EXTRA_MAN2HTMLFLAGS
:=
142 MAN2HTMLFLAGS
:= $(DEFAULT_MAN2HTMLFLAGS
) $(EXTRA_MAN2HTMLFLAGS
)
146 INSTALL_DATA
:= $(INSTALL
) -m
644
147 INSTALL_DIR
:= $(INSTALL
) -m
755 -d
150 RMDIR
:= rmdir
--ignore-fail-on-non-empty
151 CLANG-TIDY
:= clang-tidy
154 LD
:= $(CC
) $(CFLAGS
)
161 MAN_SECTIONS
:= 0 1 2 3 4 5 6 7 8
170 $(info INSTALL
$(@D
)/)
183 install: install-man |
installdirs
187 installdirs: | installdirs-man
190 .PHONY
: uninstall remove
191 uninstall remove
: uninstall-man
196 $(RM
) -rf
$(builddir
)
199 ########################################################################
202 MANPAGES
:= $(sort $(shell find
$(MANDIR
)/man?
/ -type f | grep
'$(manext)$$'))
203 LINTMAN
:= $(sort $(shell find
$(MANDIR
)/man?
/ -type f | grep
'$(manext)$$' \
204 | xargs grep
-l
'^\.TH '))
205 _HTMLPAGES
:= $(patsubst $(MANDIR
)/%,$(_HTMLDIR
)/%.html
,$(MANPAGES
))
206 _htmlpages
:= $(patsubst $(_HTMLDIR
)/%,$(_htmldir
)/%,$(_HTMLPAGES
))
207 _manpages
:= $(patsubst $(MANDIR
)/%,$(_mandir
)/%,$(MANPAGES
))
208 _man0pages
:= $(filter %$(man0ext),$(_manpages
))
209 _man1pages
:= $(filter %$(man1ext),$(_manpages
))
210 _man2pages
:= $(filter %$(man2ext),$(_manpages
))
211 _man3pages
:= $(filter %$(man3ext),$(_manpages
))
212 _man4pages
:= $(filter %$(man4ext),$(_manpages
))
213 _man5pages
:= $(filter %$(man5ext),$(_manpages
))
214 _man6pages
:= $(filter %$(man6ext),$(_manpages
))
215 _man7pages
:= $(filter %$(man7ext),$(_manpages
))
216 _man8pages
:= $(filter %$(man8ext),$(_manpages
))
217 _LINT_groff
:=$(patsubst $(MANDIR
)/%,$(_LINTDIR
)/%.lint.groff.touch
,$(LINTMAN
))
218 _LINT_mandoc
:=$(patsubst $(MANDIR
)/%,$(_LINTDIR
)/%.lint.mandoc.touch
,$(LINTMAN
))
219 _SRCPAGEDIRS
:=$(patsubst $(MANDIR
)/%,$(_SRCDIR
)/%.d
,$(LINTMAN
))
220 _UNITS_c
:=$(sort $(patsubst $(MANDIR
)/%,$(_SRCDIR
)/%,$(shell \
221 find
$(MANDIR
)/man?
/ -type f \
222 | grep
'$(manext)$$' \
223 | xargs grep
-l
'^\.TH ' \
226 sed
-n
"s,^\... SRC BEGIN (\(.*.c\))$$,$$m.d/\1,p"; \
228 _UNITS_o
:= $(patsubst %.c
,%.o
,$(_UNITS_c
))
229 _UNITS_bin
:= $(patsubst %.c
,%,$(_UNITS_c
))
230 _LINT_clang-tidy
:= $(patsubst %.c
,%.lint.clang-tidy.touch
,$(_UNITS_c
))
231 _LINT_iwyu
:= $(patsubst %.c
,%.lint.iwyu.touch
,$(_UNITS_c
))
233 MANDIRS
:= $(sort $(shell find
$(MANDIR
)/man?
-type d
))
234 _HTMLDIRS
:= $(patsubst $(MANDIR
)/%,$(_HTMLDIR
)/%/.
,$(MANDIRS
))
235 _LINTDIRS
:= $(patsubst $(MANDIR
)/%,$(_LINTDIR
)/%/.
,$(MANDIRS
))
236 _SRCDIRS
:= $(patsubst $(MANDIR
)/%,$(_SRCDIR
)/%/.
,$(MANDIRS
))
237 _htmldirs
:= $(patsubst $(_HTMLDIR
)/%,$(_htmldir
)/%,$(_HTMLDIRS
))
238 _mandirs
:= $(patsubst $(MANDIR
)/%,$(_mandir
)/%/.
,$(MANDIRS
))
239 _man0dir
:= $(filter %man0
/.
,$(_mandirs
))
240 _man1dir
:= $(filter %man1
/.
,$(_mandirs
))
241 _man2dir
:= $(filter %man2
/.
,$(_mandirs
))
242 _man3dir
:= $(filter %man3
/.
,$(_mandirs
))
243 _man4dir
:= $(filter %man4
/.
,$(_mandirs
))
244 _man5dir
:= $(filter %man5
/.
,$(_mandirs
))
245 _man6dir
:= $(filter %man6
/.
,$(_mandirs
))
246 _man7dir
:= $(filter %man7
/.
,$(_mandirs
))
247 _man8dir
:= $(filter %man8
/.
,$(_mandirs
))
249 _htmlpages_rm
:= $(addsuffix -rm,$(wildcard $(_htmlpages
)))
250 _manpages_rm
:= $(addsuffix -rm,$(wildcard $(_manpages
)))
251 _man0pages_rm
:= $(filter %$(man0ext)-rm,$(_manpages_rm
))
252 _man1pages_rm
:= $(filter %$(man1ext)-rm,$(_manpages_rm
))
253 _man2pages_rm
:= $(filter %$(man2ext)-rm,$(_manpages_rm
))
254 _man3pages_rm
:= $(filter %$(man3ext)-rm,$(_manpages_rm
))
255 _man4pages_rm
:= $(filter %$(man4ext)-rm,$(_manpages_rm
))
256 _man5pages_rm
:= $(filter %$(man5ext)-rm,$(_manpages_rm
))
257 _man6pages_rm
:= $(filter %$(man6ext)-rm,$(_manpages_rm
))
258 _man7pages_rm
:= $(filter %$(man7ext)-rm,$(_manpages_rm
))
259 _man8pages_rm
:= $(filter %$(man8ext)-rm,$(_manpages_rm
))
261 _htmldirs_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_htmldirs
)))
262 _mandirs_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_mandirs
)))
263 _man0dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man0dir
)))
264 _man1dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man1dir
)))
265 _man2dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man2dir
)))
266 _man3dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man3dir
)))
267 _man4dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man4dir
)))
268 _man5dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man5dir
)))
269 _man6dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man6dir
)))
270 _man7dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man7dir
)))
271 _man8dir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_man8dir
)))
272 _mandir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_mandir
)/.
))
273 _htmldir_rmdir
:= $(addsuffix -rmdir
,$(wildcard $(_htmldir
)/.
))
275 install_manX
:= $(foreach x
,$(MAN_SECTIONS
),install-man
$(x
))
276 installdirs_manX
:= $(foreach x
,$(MAN_SECTIONS
),installdirs-man
$(x
))
277 uninstall_manX
:= $(foreach x
,$(MAN_SECTIONS
),uninstall-man
$(x
))
281 $(_manpages
): $(_mandir
)/man
%: $(MANDIR
)/man
% |
$$(@D
)/.
283 $(INSTALL_DATA
) -T
$< $@
285 $(_mandirs
): %/.
: |
$$(dir %).
$(_mandir
)/.
287 $(_mandirs_rmdir
): $(_mandir
)/man
%/.
-rmdir
: $$(_man
%pages_rm
) FORCE
288 $(_mandir_rmdir
): $(uninstall_manX
) FORCE
291 .PHONY
: $(install_manX
)
292 $(install_manX
): install-man
%: $$(_man
%pages
) | installdirs-man
%
296 install-man
: $(install_manX
)
299 .PHONY
: $(installdirs_manX
)
300 $(installdirs_manX
): installdirs-man
%: $$(_man
%dir)
303 .PHONY
: installdirs-man
304 installdirs-man
: $(installdirs_manX
)
307 .PHONY
: $(uninstall_manX
)
308 $(uninstall_manX
): uninstall-man
%: $$(_man
%pages_rm
) $$(_man
%dir_rmdir
)
311 .PHONY
: uninstall-man
312 uninstall-man
: $(_mandir_rmdir
) $(uninstall_manX
)
316 ########################################################################
319 $(_SRCPAGEDIRS
): $(_SRCDIR
)/%.d
: $(MANDIR
)/% |
$$(@D
)/.
326 <$(patsubst $(_SRCDIR
)/%.d
,$(MANDIR
)/%,$<) \
328 -e
'/^\.TH/,/^\.SH/{/^\.SH/!p}' \
329 -e
'/^\.SH EXAMPLES/p' \
330 -e
"/^\... SRC BEGIN ($(@F))$$/,/^\... SRC END$$/p" \
331 |
$(MAN
) -P cat
-l
- \
337 $(_UNITS_o
): $(_SRCDIR
)/%.o
: $(_SRCDIR
)/%.c
339 $(CC
) -c
$(CPPFLAGS
) $(CFLAGS
) -o
$@
$<
341 $(_UNITS_bin
): $(_SRCDIR
)/%: $(_SRCDIR
)/%.o
343 $(LD
) $(LDFLAGS
) -o
$@
$< $(LDLIBS
)
345 $(_SRCDIRS
): %/.
: |
$$(dir %).
$(_SRCDIR
)/.
348 .PHONY
: build-src src
349 build-src src
: $(_UNITS_c
) | builddirs-src
353 build-cc
: $(_UNITS_o
)
357 build-ld
: $(_UNITS_bin
)
360 .PHONY
: builddirs-src
361 builddirs-src
: $(_SRCDIRS
)
365 ########################################################################
368 linters
:= clang-tidy iwyu groff mandoc
369 lint
:= $(foreach x
,$(linters
),lint-
$(x
))
371 $(_LINT_clang-tidy
): %.lint.clang-tidy.touch
: %.c
372 $(info LINT
(clang-tidy
) $@
)
373 $(CLANG-TIDY
) $(CLANG-TIDYFLAGS
) $< -- $(CPPFLAGS
) $(CFLAGS
) 2>&1 \
374 | sed
'/generated\.$$/d' || exit
$$?
377 $(_LINT_iwyu
): %.lint.iwyu.touch
: %.c
378 $(info LINT
(iwyu
) $@
)
379 $(IWYU
) $(IWYUFLAGS
) $(CPPFLAGS
) $(CFLAGS
) $<
382 $(_LINT_groff
): $(_LINTDIR
)/%.lint.groff.touch
: $(MANDIR
)/% |
$$(@D
)/.
383 $(info LINT
(groff
) $@
)
384 $(GROFF
) $(GROFFFLAGS
) -z
$<
387 $(_LINT_mandoc
): $(_LINTDIR
)/%.lint.mandoc.touch
: $(MANDIR
)/% |
$$(@D
)/.
388 $(info LINT
(mandoc
) $@
)
389 $(MANDOC
) $(MANDOCFLAGS
) $<
392 $(_LINTDIRS
): %/.
: |
$$(dir %).
$(_LINTDIR
)/.
396 $(lint
): lint-
%: $$(_LINT_
%) | lintdirs
400 lintdirs
: $(_LINTDIRS
) $(_SRCDIRS
)
408 ########################################################################
412 # make MAN2HTMLFLAGS=whatever html
413 # The sed removes the lines "Content-type: text/html\n\n"
414 $(_HTMLPAGES
): $(_HTMLDIR
)/%.html
: $(MANDIR
)/% |
$$(@D
)/.
416 $(MAN2HTML
) $(MAN2HTMLFLAGS
) $< | sed
-e
1,2d
>$@ || exit
$$?
418 $(_HTMLDIRS
): %/.
: |
$$(dir %).
$(_HTMLDIR
)/.
420 $(_htmlpages
): $(_htmldir
)/%: $(_HTMLDIR
)/% |
$$(@D
)/.
422 $(INSTALL_DATA
) -T
$< $@
424 $(_htmldirs
): %/.
: |
$$(dir %).
$(_htmldir
)/.
427 .PHONY
: build-html html
428 build-html html
: $(_HTMLPAGES
) | builddirs-html
431 .PHONY
: builddirs-html
432 builddirs-html
: $(_HTMLDIRS
)
436 install-html
: $(_htmlpages
) | installdirs-html
439 .PHONY
: installdirs-html
440 installdirs-html
: $(_htmldirs
)
443 .PHONY
: uninstall-html
444 uninstall-html
: $(_htmldir_rmdir
) $(_htmldirs_rmdir
) $(_htmlpages_rm
)
448 ########################################################################