aboutsummaryrefslogtreecommitdiffstats
path: root/mk/lang-c.mk
diff options
context:
space:
mode:
Diffstat (limited to 'mk/lang-c.mk')
-rw-r--r--mk/lang-c.mk307
1 files changed, 307 insertions, 0 deletions
diff --git a/mk/lang-c.mk b/mk/lang-c.mk
new file mode 100644
index 0000000..63015fb
--- /dev/null
+++ b/mk/lang-c.mk
@@ -0,0 +1,307 @@
+# 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
+