aboutsummaryrefslogblamecommitdiffstats
path: root/mk/lang-c.mk
blob: 63015fb3153b955d184c8c35b5248c751889f768 (plain) (tree)


















































































































































































































































































































                                                                                                                                                                              
# Copyright (C) 2015, 2016  Mattias Andrée <maandree@member.fsf.org>
# 
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved.  This file is offered as-is,
# without any warranty.


#=== This file includes rules for C programs. ===#


# This file is ignored unless _C_STD is defined.
# _C_STD should be set the the version of C that
# is used.
# 
# If you want to compile with -pedantic, define
# the variable _PEDANTIC.
# 
# Define _CPPFLAGS with any additional CPP
# flags to use, _CFLAGS with any additional CC
# flags to use, and _LDFLAGS with any additional
# LD flags to use.
# 
# Defined in path.mk, you can change _ALL_DIRS
# if you do not want CPP definitions for all
# directories.
# 
# Define _HEADER_DIRLEVELS to specify the directory
# nesting level in src. It is assumed that all
# directories contain header files. Set to '0' if
# there are no header files.
# 
# _BIN shall list all commands to build. These
# should be the basenames. For each command
# you should be the variable _OBJ_$(COMMAND)
# that lists all objects files (without the
# suffix and without the aux/ prefix) that
# are required to build the command.
# 
# Binary you want installed to /sbin rather than
# /bin shall be listed in _SBIN rather than in
# _BIN. _SBIN and _BIN may not list binaries
# with identical names. Analogically, you may
# add _LIBEXEC for binary to be installed to
# /libexec.
# 
# If you only have one binary, you may select
# to define _BINDIR to name the variable with
# the pathname for the directory the binary
# shall be installed. For example, if you want
# the binary to be installed to /usr/sbin,
# define _BINDIR = SBINDIR.
# 
# List libraries to compile in in _LIB. For each
# library, you should also define
# _SO_VERSION_$(LIBRARY) and _SO_MAJOR_$(LIBRARY)
# with the full version number and the major
# version number, respectively. Additionally,
# list all header files that shall be installed
# in _H, these should not contain the 'src/' prefix
# or the '.h' suffix.


ifdef _C_STD



# HELP VARIABLES:

# Figure out whether the GCC is being used.
ifeq ($(shell $(PRINTF) '%s\n' ${CC} | $(HEAD) -n 1),gcc)
__USING_GCC = 1
endif

# Are there any commands?
ifdef _BIN
__HAVE_CMD_C = 1
endif
ifdef _SBIN
__HAVE_CMD_C = 1
endif
ifdef _LIBEXEC
__HAVE_CMD_C = 1
endif


# WHEN TO BUILD, INSTALL, AND UNINSTALL:

ifdef __HAVE_CMD_C
cmd: cmd-c
install-cmd: install-cmd-c
uninstall: uninstall-cmd-c
endif
ifdef _LIB
lib: lib-c
install-lib: install-lib-c
uninstall: uninstall-lib-c
endif


# BUILD VARIABLES:

# Optimisation settings for C code compilation.
ifndef OPTIMISE
ifndef DEBUG
OPTIMISE = -O2 -g
endif
ifdef DEBUG
ifdef __USING_GCC
OPTIMISE = -Og -g
endif
ifndef __USING_GCC
OPTIMISE = -g
endif
endif
endif

# Warning settings for C code compilation.
ifdef _PEDANTIC
_PEDANTIC = -pedantic
endif
ifndef WARN
ifndef DEBUG
WARN = -Wall
endif
ifdef DEBUG
ifdef __USING_GCC
WARN = -Wall -Wextra $(_PEDANTIC) -Wdouble-promotion -Wformat=2 -Winit-self -Wmissing-include-dirs   \
       -Wtrampolines -Wmissing-prototypes -Wmissing-declarations -Wnested-externs                    \
       -Wno-variadic-macros -Wsync-nand -Wunsafe-loop-optimizations -Wcast-align                     \
       -Wdeclaration-after-statement -Wundef -Wbad-function-cast -Wwrite-strings -Wlogical-op        \
       -Wstrict-prototypes -Wold-style-definition -Wpacked -Wvector-operation-performance            \
       -Wunsuffixed-float-constants -Wsuggest-attribute=const -Wsuggest-attribute=noreturn           \
       -Wsuggest-attribute=format -Wnormalized=nfkc -fstrict-aliasing -fipa-pure-const -ftree-vrp    \
       -fstack-usage -funsafe-loop-optimizations -Wshadow -Wredundant-decls -Winline -Wcast-qual     \
       -Wsign-conversion -Wstrict-overflow=5 -Wconversion -Wsuggest-attribute=pure -Wswitch-default  \
       -Wstrict-aliasing=1 -fstrict-overflow -Wfloat-equal -Wpadded -Waggregate-return               \
       -Wtraditional-conversion
endif
ifndef __USING_GCC
WARN = -Wall -Wextra $(_PEDANTIC)
endif
endif
endif

# Support for internationalisation?
ifndef WITHOUT_GETTEXT
_CPPFLAGS += -D'USE_GETTEXT=1'
endif

# Add CPP definitions for all directories.
_CPPFLAGS += $(foreach D,$(_ALL_DIRS),-D'$(D)="$($(D))"')

# Compilation and linking flags, and command.
ifndef CPPFLAGS
CPPFLAGS =
endif
ifndef CFLAGS
CFLAGS = $(OPTIMISE) $(WARN)
endif
ifndef LDFLAGS
LDFLAGS = $(OPTIMISE) $(WARN)
endif
__CC = $(CC) -std=$(_C_STD) -c $(_CPPFLAGS) $(_CFLAGS)
__LD = $(CC) -std=$(_C_STD) $(_LDFLAGS)
__CC_POST = $(CPPFLAGS) $(CFLAGS) $(EXTRA_CPPFLAGS) $(EXTRA_CFLAGS)
__LD_POST = $(LDFLAGS) $(EXTRA_LDFLAGS)

# Header files.
__H =
ifdef _HEADER_DIRLEVELS
ifeq ($(_HEADER_DIRLEVELS),1)
__H += src/*.h
endif
ifneq ($(_HEADER_DIRLEVELS),1)
ifeq ($(_HEADER_DIRLEVELS),2)
__H += src/*.h
__H += src/*/*.h
endif
ifneq ($(_HEADER_DIRLEVELS),2)
ifneq ($(_HEADER_DIRLEVELS),0)
__H += $(foreach W,$(shell $(SEQ) $(_HEADER_DIRLEVELS) | while read n; do $(ECHO) $$($(SEQ) $$n)" " | $(SED) 's/[^ ]* /\/\*/g'; done | $(XARGS) $(ECHO)),src$(W).h)
endif
endif
endif
endif

# Directory for the binary if there is only one binary.
ifndef _BINDIR
_BINDIR = BINDIR
endif


# BUILD RULES:

.PHONY: cmd-c
cmd-c: $(foreach B,$(_BIN) $(_SBIN) $(_LIBEXEC),bin/$(B))

.PHONY: lib-c
lib-c: $(foreach B,$(_LIB),bin/$(B).so)

# Compile a C file into an object file for a command.
aux/%.o: $(v)src/%.c $(foreach H,$(__H),$(v)$(H))
	@$(PRINTF_INFO) '\e[00;01;31mCC\e[34m %s\e[00m$A\n' "$@"
	@$(MKDIR) -p $(shell $(DIRNAME) $@)
	$(Q)$(__CC) -o $@ $< $(__CC_POST) #$Z
	@$(ECHO_EMPTY)

# Compile a C file into an object file for a library.
aux/%.pic.o: $(v)src/%.c $(foreach H,$(__H),$(v)$(H))
	@$(PRINTF_INFO) '\e[00;01;31mCC\e[34m %s\e[00m$A\n' "$@"
	@$(MKDIR) -p $(shell $(DIRNAME) $@)
	$(Q)$(__CC) -fPIC -o $@ $< $(__CC_POST) #$Z
	@$(ECHO_EMPTY)

# Link object files into a library.
# Dependencies are declared below.
bin/%.so:
	@$(PRINTF_INFO) '\e[00;01;31mLD\e[34m %s\e[00;32m$A\n' "$@"
	@$(MKDIR) -p bin
	$(Q)$(__LD) -shared -Wl,-soname,$*.so.$(_SO_MAJOR_$*) -o $@ $^ $(__LD_POST) #$Z
	@$(ECHO_EMPTY)

# Link object files into a command.
# Dependencies are declared below.
bin/%:
	@$(PRINTF_INFO) '\e[00;01;31mLD\e[34m %s\e[00;32m$A\n' "$@"
	@$(MKDIR) -p bin
	$(Q)$(__LD) -o $@ $^ $(__LD_POST) #$Z
	@$(ECHO_EMPTY)

# Dependencies for the rule above.
include aux/lang-c.mk
aux/lang-c.mk: Makefile
	@$(MKDIR) -p aux
	@$(ECHO) > aux/lang-c.mk
	@$(foreach B,$(_BIN) $(_SBIN) $(_LIBEXEC),$(ECHO) bin/$(B): $(foreach O,$(_OBJ_$(B)),aux/$(O).o) >> aux/lang-c.mk &&) $(TRUE)
	@$(foreach B,$(_LIB),$(ECHO) bin/$(B).so: $(foreach O,$(_OBJ_$(B)),aux/$(O).pic.o) >> aux/lang-c.mk &&) $(TRUE)


# INSTALL RULES:

.PHONY: install-cmd-c
install-cmd-c: $(foreach B,$(_BIN) $(_SBIN) $(_LIBEXEC),bin/$(B))
	@$(PRINTF_INFO) '\e[00;01;31mINSTALL\e[34m %s\e[00m\n' "$@"
ifndef COMMAND
ifdef _BIN
	$(Q)$(INSTALL_DIR) -- "$(DESTDIR)$(BINDIR)"
	$(Q)$(INSTALL_PROGRAM) $(__STRIP) $(foreach B,$(_BIN),bin/$(B)) -- "$(DESTDIR)$(BINDIR)"
endif
ifdef _SBIN
	$(Q)$(INSTALL_DIR) -- "$(DESTDIR)$(SBINDIR)"
	$(Q)$(INSTALL_PROGRAM) $(__STRIP) $(foreach B,$(_SBIN),bin/$(B)) -- "$(DESTDIR)$(SBINDIR)"
endif
ifdef _LIBEXEC
	$(Q)$(INSTALL_DIR) -- "$(DESTDIR)$(LIBEXECDIR)/$(PKGNAME)"
	$(Q)$(INSTALL_PROGRAM) $(__STRIP) $(foreach B,$(_LIBEXEC),bin/$(B)) -- "$(DESTDIR)$(LIBEXECDIR)/$(PKGNAME)"
endif
endif
ifdef COMMAND
	$(Q)$(INSTALL_DIR) -- "$(DESTDIR)$($(_BINDIR))"
	$(Q)$(INSTALL_PROGRAM) $(__STRIP) $^ -- "$(DESTDIR)$($(_BINDIR))/$(COMMAND)"
endif
	@$(ECHO_EMPTY)

.PHONY: install-lib-c
install-lib-c: $(foreach B,$(_LIB),bin/$(B).so)
	@$(PRINTF_INFO) '\e[00;01;31mINSTALL\e[34m %s\e[00m\n' "$@"
	$(Q)$(INSTALL_DIR) -- "$(DESTDIR)$(LIBDIR)"
	$(Q)$(foreach B,$(_LIB),$(LN) -sf -- "$(B).so.$(_SO_VERSION_$(B))" "$(DESTDIR)$(LIBDIR)/$(B).so.$(_SO_MAJOR_$(B))" &&) $(TRUE)
	$(Q)$(foreach B,$(_LIB),$(INSTALL_PROGRAM) $(foreach B,$(_LIB),bin/$(B).so) -- "$(DESTDIR)$(LIBDIR)/$(B).so.$(_SO_VERSION_$(B))" &&) $(TRUE)
	$(Q)$(foreach B,$(_LIB),$(LN) -sf -- "$(B).so.$(_SO_VERSION_$(B))" "$(DESTDIR)$(LIBDIR)/$(B).so" &&) $(TRUE)
	$(Q)$(INSTALL_DIR) -- $(foreach H,$(_H),"$(DESTDIR)$(INCLUDEDIR)/$(shell $(DIRNAME) "$(H)")")
	$(Q)$(foreach H,$(_H),$(INSTALL_DATA) "src/$(H).h" -- "$(DESTDIR)$(INCLUDEDIR)/$(H).h" &&) $(TRUE)
	@$(ECHO_EMPTY)


# UNINSTALL RULES:

.PHONY: uninstall-cmd-c
uninstall-cmd-c:
ifdef COMMAND
	-$(Q)$(RM) -- "$(DESTDIR)$($(_BINDIR))/$(COMMAND)"
endif
ifndef COMMAND
ifdef _BIN
	-$(Q)$(RM) -- $(foreach B,$(_BIN),"$(DESTDIR)$(BINDIR)/$(B)")
endif
ifdef _SBIN
	-$(Q)$(RM) -- $(foreach B,$(_SBIN),"$(DESTDIR)$(SBINDIR)/$(B)")
endif
ifdef _LIBEXEC
	-$(Q)$(RM) -- $(foreach B,$(_LIBEXEC),"$(DESTDIR)$(LIBEXECDIR)/$(PKGNAME)/$(B)")
	-$(Q)$(RMDIR) -- "$(DESTDIR)$(LIBEXECDIR)/$(PKGNAME)"
endif
endif

.PHONY: uninstall-lib-c
uninstall-lib-c:
	-$(Q)$(RM) -- $(foreach B,$(_LIB),"$(DESTDIR)$(LIBDIR)/$(B).so")
	-$(Q)$(RM) -- $(foreach B,$(_LIB),"$(DESTDIR)$(LIBDIR)/$(B).so.$(_SO_MAJOR_$(B))")
	-$(Q)$(RM) -- $(foreach B,$(_LIB),"$(DESTDIR)$(LIBDIR)/$(B).so.$(_SO_VERSION_$(B))")
	-$(Q)$(RM) -- $(foreach H,$(_H),"$(DESTDIR)$(INCLUDEDIR)/$(H).h")
	-$(Q)$(foreach H,$(_H),if ! $(TEST) "$(shell $(ECHO) "$(H)" | $(CUT) -d / -f 1)" = "$(H)"; then $(RMDIR) -- "$(DESTDIR)$(INCLUDEDIR)/$(shell $(DIRNAME) "$(H)")"; fi;)

endif