summaryrefslogblamecommitdiffstats
path: root/Makefile
blob: 60a8a3a0eb534225d62105502ba4b4e3b3f94720 (plain) (tree)
1
2
3
4
5
6
7
8
9







                                                                          
                                                                           
                                                                     



                                                                           















                                                                           
                                 


                                       
             
               

                      
 

                                       
                        








                             



                                 



















                             
                    
 









                                    






                                                                              




                                                            






















                                                         



                                                                     
                          


                                                            
                           


                                                                 




                                                                  



                                                                        
 
                       
                                 
                                    
                        

                                                
                          
                    

                               
                     
                   
                      
                        
 
 
                                 
 

           
    


                         
    
                               


                            
                           


                
                              
















                                  
                             
 
 



                                                                                
                                                                                
                                                       















                                                                                






                                                                             

                                              

                                                                       
 
                                                         




                                                                 








                                          

                                                           
                                                          
                                                         








                                                         










                                                               

                                                                






                                                                    
                                                        
                           

                                
                                           
 
                                                                   











                                                                
                                                   















                                                                        

     
                                                       



                           
                   
                           
                                                    









                                                                     
                                           


                                               
                                           


                                           

                                           

                     
                                          

          
                
                     


                
                       

          
                     
                          



                                                                        

      
                                       

                                            





                                                                           




                                                     
                                                                      



                                    
                                                                        



                                   

                                             
 
               
                                       


                
                                  







                                                                        
      
 
          
                                   
                                                         
                                                         
                           
                                                                     
 
                                             
 
                                                      


                                
                                             


                       
                                               
          

                      
                            
          

                    

                                              

                        

                              
 
                      

                                                                     
 

                                                                        
 
            
      
########################################################################
# Copyright (C) 2021        Alejandro Colomar <alx.manpages@gmail.com>
# SPDX-License-Identifier:  GPL-2.0  OR  LGPL-2.0
########################################################################
# Conventions:
#
# - Follow "Makefile Conventions" from the "GNU Coding Standards" closely.
#   However, when something could be improved, don't follow those.
# - Uppercase variables, when referring files, refer to files in this repo.
# - Lowercase variables, when referring files, refer to system files.
# - Lowercase variables starting with '_' refer to absolute paths,
#   including $(DESTDIR).
# - Uppercase variables starting with '_' refer to temporary files produced
#   in $builddir.
# - Variables ending with '_' refer to a subdir of their parent dir, which
#   is in a variable of the same name but without the '_'.  The subdir is
#   named after this project: <*/man>.
# - Variables ending in '_rm' refer to files that can be removed (exist).
# - Variables ending in '_rmdir' refer to dirs that can be removed (exist).
# - Targets of the form '%-rm' remove their corresponding file '%'.
# - Targets of the form '%/.-rmdir' remove their corresponding dir '%/'.
# - Targets of the form '%/.' create their corresponding directory '%/'.
# - Every file or directory to be created depends on its parent directory.
#   This avoids race conditions caused by `mkdir -p`.  Only the root
#   directories are created with parents.
# - The 'FORCE' target is used to make phony some variables that can't be
#   .PHONY to avoid some optimizations.
#
########################################################################

MAKEFLAGS += --no-print-directory
MAKEFLAGS += --warn-undefined-variables


srcdir   := .
builddir := tmp
DESTDIR  :=
prefix   := /usr/local

SYSCONFDIR  := $(srcdir)/etc
TMACDIR     := $(SYSCONFDIR)/groff/tmac
MANDIR      := $(srcdir)
MAN0DIR     := $(MANDIR)/man0
MAN1DIR     := $(MANDIR)/man1
MAN2DIR     := $(MANDIR)/man2
MAN3DIR     := $(MANDIR)/man3
MAN4DIR     := $(MANDIR)/man4
MAN5DIR     := $(MANDIR)/man5
MAN6DIR     := $(MANDIR)/man6
MAN7DIR     := $(MANDIR)/man7
MAN8DIR     := $(MANDIR)/man8

datarootdir := $(prefix)/share
docdir      := $(datarootdir)/doc
mandir      := $(datarootdir)/man
man0dir     := $(mandir)/man0
man1dir     := $(mandir)/man1
man2dir     := $(mandir)/man2
man3dir     := $(mandir)/man3
man4dir     := $(mandir)/man4
man5dir     := $(mandir)/man5
man6dir     := $(mandir)/man6
man7dir     := $(mandir)/man7
man8dir     := $(mandir)/man8
manext      := \.[0-9]
man0ext     := .0
man1ext     := .1
man2ext     := .2
man3ext     := .3
man4ext     := .4
man5ext     := .5
man6ext     := .6
man7ext     := .7
man8ext     := .8
htmldir     := $(docdir)
htmlext     := .html

htmldir_    := $(htmldir)/man

_LINTDIR    := $(builddir)/lint
_HTMLDIR    := $(builddir)/html
_SRCDIR     := $(builddir)/src

_mandir     := $(DESTDIR)$(mandir)
_htmldir    := $(DESTDIR)$(htmldir_)


clang-tidy_config       := $(SYSCONFDIR)/clang-tidy/config.yaml
DEFAULT_CLANG-TIDYFLAGS := --config-file=$(clang-tidy_config)
DEFAULT_CLANG-TIDYFLAGS += --quiet
DEFAULT_CLANG-TIDYFLAGS += --use-color
EXTRA_CLANG-TIDYFLAGS   :=
CLANG-TIDYFLAGS         := $(DEFAULT_CLANG-TIDYFLAGS) $(EXTRA_CLANG-TIDYFLAGS)

DEFAULT_IWYUFLAGS := -Xiwyu --no_fwd_decls
DEFAULT_IWYUFLAGS += -Xiwyu --error
EXTRA_IWYUFLAGS   :=
IWYUFLAGS         := $(DEFAULT_IWYUFLAGS) $(EXTRA_IWYUFLAGS)

DEFAULT_CPPFLAGS :=
EXTRA_CPPFLAGS   :=
CPPFLAGS         := $(DEFAULT_CPPFLAGS) $(EXTRA_CPPFLAGS)

DEFAULT_CFLAGS := -std=gnu17
DEFAULT_CFLAGS += -Wall
DEFAULT_CFLAGS += -Wextra
DEAFULT_CFLAGS += -Wstrict-prototypes
DEFAULT_CFLAGS += -Werror
EXTRA_CFLAGS   :=
CFLAGS         := $(DEFAULT_CFLAGS) $(EXTRA_CFLAGS)

DEFAULT_LDFLAGS := -Wl,--as-needed
DEFAULT_LDFLAGS += -Wl,--no-allow-shlib-undefined
DEFAULT_LDFLAGS += -Wl,--no-copy-dt-needed-entries
DEFAULT_LDFLAGS += -Wl,--no-undefined
EXTRA_LDFLAGS   :=
LDFLAGS         := $(DEFAULT_LDFLAGS) $(EXTRA_LDFLAGS)

DEFAULT_LDLIBS := -lc
EXTRA_LDLIBS   :=
LDLIBS         := $(DEFAULT_LDLIBS) $(EXTRA_LDLIBS)

TMACFILES            := $(sort $(shell find $(TMACDIR) -not -type d))
TMACNAMES            := $(basename $(notdir $(TMACFILES)))
GROFF_CHECKSTYLE_LVL := 3
DEFAULT_GROFFFLAGS   := -man
DEFAULT_GROFFFLAGS   += -t
DEFAULT_GROFFFLAGS   += -M $(TMACDIR)
DEFAULT_GROFFFLAGS   += $(foreach x,$(TMACNAMES),-m $(x))
DEFAULT_GROFFFLAGS   += -rCHECKSTYLE=$(GROFF_CHECKSTYLE_LVL)
DEFAULT_GROFFFLAGS   += -ww
EXTRA_GROFFFLAGS     :=
GROFFFLAGS           := $(DEFAULT_GROFFFLAGS) $(EXTRA_GROFFFLAGS)

DEFAULT_MANDOCFLAGS := -man
DEFAULT_MANDOCFLAGS += -Tlint
EXTRA_MANDOCFLAGS   :=
MANDOCFLAGS         := $(DEFAULT_MANDOCFLAGS) $(EXTRA_MANDOCFLAGS)

DEFAULT_MAN2HTMLFLAGS :=
EXTRA_MAN2HTMLFLAGS   :=
MAN2HTMLFLAGS         := $(DEFAULT_MAN2HTMLFLAGS) $(EXTRA_MAN2HTMLFLAGS)


INSTALL      := install
INSTALL_DATA := $(INSTALL) -m 644
INSTALL_DIR  := $(INSTALL) -m 755 -d
MKDIR        := mkdir -p
RM           := rm
RMDIR        := rmdir --ignore-fail-on-non-empty
CLANG-TIDY   := clang-tidy
IWYU         := iwyu
CC           := cc
LD           := $(CC) $(CFLAGS)
GROFF        := groff
MAN          := man
MANDOC       := mandoc
MAN2HTML     := man2html


MAN_SECTIONS := 0 1 2 3 4 5 6 7 8


.PHONY: all
all:
	$(MAKE) uninstall
	$(MAKE) install

%/.:
	$(info INSTALL	$(@D)/)
	$(INSTALL_DIR) $(@D)

%-rm:
	$(info RM	$*)
	$(RM) $*

%-rmdir:
	$(info RMDIR	$(@D))
	$(RMDIR) $(@D)


.PHONY: install
install: install-man | installdirs
	@:

.PHONY: installdirs
installdirs: | installdirs-man
	@:

.PHONY: uninstall remove
uninstall remove: uninstall-man
	@:

.PHONY: clean
clean:
	$(RM) -rf $(builddir)


########################################################################
# man

MANPAGES   := $(sort $(shell find $(MANDIR)/man?/ -type f | grep '$(manext)$$'))
LINTMAN    := $(sort $(shell find $(MANDIR)/man?/ -type f | grep '$(manext)$$' \
                             | xargs grep -l '^\.TH '))
_HTMLPAGES  := $(patsubst $(MANDIR)/%,$(_HTMLDIR)/%.html,$(MANPAGES))
_htmlpages  := $(patsubst $(_HTMLDIR)/%,$(_htmldir)/%,$(_HTMLPAGES))
_manpages   := $(patsubst $(MANDIR)/%,$(_mandir)/%,$(MANPAGES))
_man0pages  := $(filter %$(man0ext),$(_manpages))
_man1pages  := $(filter %$(man1ext),$(_manpages))
_man2pages  := $(filter %$(man2ext),$(_manpages))
_man3pages  := $(filter %$(man3ext),$(_manpages))
_man4pages  := $(filter %$(man4ext),$(_manpages))
_man5pages  := $(filter %$(man5ext),$(_manpages))
_man6pages  := $(filter %$(man6ext),$(_manpages))
_man7pages  := $(filter %$(man7ext),$(_manpages))
_man8pages  := $(filter %$(man8ext),$(_manpages))
_LINT_groff :=$(patsubst $(MANDIR)/%,$(_LINTDIR)/%.lint.groff.touch,$(LINTMAN))
_LINT_mandoc:=$(patsubst $(MANDIR)/%,$(_LINTDIR)/%.lint.mandoc.touch,$(LINTMAN))
_SRCPAGEDIRS:=$(patsubst $(MANDIR)/%,$(_SRCDIR)/%.d,$(LINTMAN))
_UNITS_c    :=$(sort $(patsubst $(MANDIR)/%,$(_SRCDIR)/%,$(shell \
		find $(MANDIR)/man?/ -type f \
		| grep '$(manext)$$' \
		| xargs grep -l '^\.TH ' \
		| while read m; do \
			<$$m \
			sed -n "s,^\... SRC BEGIN (\(.*.c\))$$,$$m.d/\1,p"; \
		done)))
_UNITS_o    := $(patsubst %.c,%.o,$(_UNITS_c))
_UNITS_bin  := $(patsubst %.c,%,$(_UNITS_c))
_LINT_clang-tidy := $(patsubst %.c,%.lint.clang-tidy.touch,$(_UNITS_c))
_LINT_iwyu       := $(patsubst %.c,%.lint.iwyu.touch,$(_UNITS_c))

MANDIRS   := $(sort $(shell find $(MANDIR)/man? -type d))
_HTMLDIRS  := $(patsubst $(MANDIR)/%,$(_HTMLDIR)/%/.,$(MANDIRS))
_LINTDIRS  := $(patsubst $(MANDIR)/%,$(_LINTDIR)/%/.,$(MANDIRS))
_SRCDIRS   := $(patsubst $(MANDIR)/%,$(_SRCDIR)/%/.,$(MANDIRS))
_htmldirs := $(patsubst $(_HTMLDIR)/%,$(_htmldir)/%,$(_HTMLDIRS))
_mandirs  := $(patsubst $(MANDIR)/%,$(_mandir)/%/.,$(MANDIRS))
_man0dir  := $(filter %man0/.,$(_mandirs))
_man1dir  := $(filter %man1/.,$(_mandirs))
_man2dir  := $(filter %man2/.,$(_mandirs))
_man3dir  := $(filter %man3/.,$(_mandirs))
_man4dir  := $(filter %man4/.,$(_mandirs))
_man5dir  := $(filter %man5/.,$(_mandirs))
_man6dir  := $(filter %man6/.,$(_mandirs))
_man7dir  := $(filter %man7/.,$(_mandirs))
_man8dir  := $(filter %man8/.,$(_mandirs))

_htmlpages_rm := $(addsuffix -rm,$(wildcard $(_htmlpages)))
_manpages_rm  := $(addsuffix -rm,$(wildcard $(_manpages)))
_man0pages_rm := $(filter %$(man0ext)-rm,$(_manpages_rm))
_man1pages_rm := $(filter %$(man1ext)-rm,$(_manpages_rm))
_man2pages_rm := $(filter %$(man2ext)-rm,$(_manpages_rm))
_man3pages_rm := $(filter %$(man3ext)-rm,$(_manpages_rm))
_man4pages_rm := $(filter %$(man4ext)-rm,$(_manpages_rm))
_man5pages_rm := $(filter %$(man5ext)-rm,$(_manpages_rm))
_man6pages_rm := $(filter %$(man6ext)-rm,$(_manpages_rm))
_man7pages_rm := $(filter %$(man7ext)-rm,$(_manpages_rm))
_man8pages_rm := $(filter %$(man8ext)-rm,$(_manpages_rm))

_htmldirs_rmdir := $(addsuffix -rmdir,$(wildcard $(_htmldirs)))
_mandirs_rmdir  := $(addsuffix -rmdir,$(wildcard $(_mandirs)))
_man0dir_rmdir  := $(addsuffix -rmdir,$(wildcard $(_man0dir)))
_man1dir_rmdir  := $(addsuffix -rmdir,$(wildcard $(_man1dir)))
_man2dir_rmdir  := $(addsuffix -rmdir,$(wildcard $(_man2dir)))
_man3dir_rmdir  := $(addsuffix -rmdir,$(wildcard $(_man3dir)))
_man4dir_rmdir  := $(addsuffix -rmdir,$(wildcard $(_man4dir)))
_man5dir_rmdir  := $(addsuffix -rmdir,$(wildcard $(_man5dir)))
_man6dir_rmdir  := $(addsuffix -rmdir,$(wildcard $(_man6dir)))
_man7dir_rmdir  := $(addsuffix -rmdir,$(wildcard $(_man7dir)))
_man8dir_rmdir  := $(addsuffix -rmdir,$(wildcard $(_man8dir)))
_mandir_rmdir   := $(addsuffix -rmdir,$(wildcard $(_mandir)/.))
_htmldir_rmdir  := $(addsuffix -rmdir,$(wildcard $(_htmldir)/.))

install_manX     := $(foreach x,$(MAN_SECTIONS),install-man$(x))
installdirs_manX := $(foreach x,$(MAN_SECTIONS),installdirs-man$(x))
uninstall_manX   := $(foreach x,$(MAN_SECTIONS),uninstall-man$(x))


.SECONDEXPANSION:
$(_manpages): $(_mandir)/man%: $(MANDIR)/man% | $$(@D)/.
	$(info INSTALL	$@)
	$(INSTALL_DATA) -T $< $@

$(_mandirs): %/.: | $$(dir %). $(_mandir)/.

$(_mandirs_rmdir): $(_mandir)/man%/.-rmdir: $$(_man%pages_rm) FORCE
$(_mandir_rmdir): $(uninstall_manX) FORCE


.PHONY: $(install_manX)
$(install_manX): install-man%: $$(_man%pages) | installdirs-man%
	@:

.PHONY: install-man
install-man: $(install_manX)
	@:

.PHONY: $(installdirs_manX)
$(installdirs_manX): installdirs-man%: $$(_man%dir)
	@:

.PHONY: installdirs-man
installdirs-man: $(installdirs_manX)
	@:

.PHONY: $(uninstall_manX)
$(uninstall_manX): uninstall-man%: $$(_man%pages_rm) $$(_man%dir_rmdir)
	@:

.PHONY: uninstall-man
uninstall-man: $(_mandir_rmdir) $(uninstall_manX)
	@:


########################################################################
# src

$(_SRCPAGEDIRS): $(_SRCDIR)/%.d: $(MANDIR)/% | $$(@D)/.
	$(info MKDIR	$@)
	$(MKDIR) $@
	touch $@

$(_UNITS_c): $$(@D)
	$(info SED	$@)
	<$(patsubst $(_SRCDIR)/%.d,$(MANDIR)/%,$<) \
	sed -n \
		-e '/^\.TH/,/^\.SH/{/^\.SH/!p}' \
		-e '/^\.SH EXAMPLES/p' \
		-e "/^\... SRC BEGIN ($(@F))$$/,/^\... SRC END$$/p" \
	| $(MAN) -P cat -l - \
	| sed '/^[^ ]/d' \
	| sed 's/^       //' \
	>$@ \
	|| exit $$?

$(_UNITS_o): $(_SRCDIR)/%.o: $(_SRCDIR)/%.c
	$(info CC	$@)
	$(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $<

$(_UNITS_bin): $(_SRCDIR)/%: $(_SRCDIR)/%.o
	$(info LD	$@)
	$(LD) $(LDFLAGS) -o $@ $< $(LDLIBS)

$(_SRCDIRS): %/.: | $$(dir %). $(_SRCDIR)/.


.PHONY: build-src src
build-src src: $(_UNITS_c) | builddirs-src
	@:

.PHONY: build-cc
build-cc: $(_UNITS_o)
	@:

.PHONY: build-ld
build-ld: $(_UNITS_bin)
	@:

.PHONY: builddirs-src
builddirs-src: $(_SRCDIRS)
	@:


########################################################################
# lint

linters := clang-tidy iwyu groff mandoc
lint    := $(foreach x,$(linters),lint-$(x))

$(_LINT_clang-tidy): %.lint.clang-tidy.touch: %.c
	$(info LINT (clang-tidy)	$@)
	$(CLANG-TIDY) $(CLANG-TIDYFLAGS) $< -- $(CPPFLAGS) $(CFLAGS) 2>&1 \
	| sed '/generated\.$$/d' || exit $$?
	touch $@

$(_LINT_iwyu): %.lint.iwyu.touch: %.c
	$(info LINT (iwyu)	$@)
	$(IWYU) $(IWYUFLAGS) $(CPPFLAGS) $(CFLAGS) $<
	touch $@

$(_LINT_groff): $(_LINTDIR)/%.lint.groff.touch: $(MANDIR)/% | $$(@D)/.
	$(info LINT (groff)	$@)
	$(GROFF) $(GROFFFLAGS) -z $<
	touch $@

$(_LINT_mandoc): $(_LINTDIR)/%.lint.mandoc.touch: $(MANDIR)/% | $$(@D)/.
	$(info LINT (mandoc)	$@)
	$(MANDOC) $(MANDOCFLAGS) $<
	touch $@

$(_LINTDIRS): %/.: | $$(dir %). $(_LINTDIR)/.


.PHONY: $(lint)
$(lint): lint-%: $$(_LINT_%) | lintdirs
	@:

.PHONY: lintdirs
lintdirs: $(_LINTDIRS) $(_SRCDIRS)
	@:

.PHONY: lint
lint: $(lint)
	@:


########################################################################
# html

# Use with
#  make MAN2HTMLFLAGS=whatever html
# The sed removes the lines "Content-type: text/html\n\n"
$(_HTMLPAGES): $(_HTMLDIR)/%.html: $(MANDIR)/% | $$(@D)/.
	$(info MAN2HTML	$@)
	$(MAN2HTML) $(MAN2HTMLFLAGS) $< | sed -e 1,2d >$@ || exit $$?

$(_HTMLDIRS): %/.: | $$(dir %). $(_HTMLDIR)/.

$(_htmlpages): $(_htmldir)/%: $(_HTMLDIR)/% | $$(@D)/.
	$(info INSTALL	$@)
	$(INSTALL_DATA) -T $< $@

$(_htmldirs): %/.: | $$(dir %). $(_htmldir)/.


.PHONY: build-html html
build-html html: $(_HTMLPAGES) | builddirs-html
	@:

.PHONY: builddirs-html
builddirs-html: $(_HTMLDIRS)
	@:

.PHONY: install-html
install-html: $(_htmlpages) | installdirs-html
	@:

.PHONY: installdirs-html
installdirs-html: $(_htmldirs)
	@:

.PHONY: uninstall-html
uninstall-html: $(_htmldir_rmdir) $(_htmldirs_rmdir) $(_htmlpages_rm)
	@:


########################################################################

$(V).SILENT:
FORCE: