summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--makefiles/Makefile.subdir94
-rw-r--r--makefiles/Makefile.top378
2 files changed, 472 insertions, 0 deletions
diff --git a/makefiles/Makefile.subdir b/makefiles/Makefile.subdir
new file mode 100644
index 0000000..7f8d27e
--- /dev/null
+++ b/makefiles/Makefile.subdir
@@ -0,0 +1,94 @@
+# Child makefile fragment
+#
+# Inputs (reset on exit)
+#
+# DIR_SOURCES List of source files in this directory
+# DIR_TEST_SOURCES List of test source files in this directory
+# DIR_INSTALL_ITEMS Items to install in form <destination>:<file1>;<file2>
+#
+# Toolchain is provided by top-level makefile
+#
+# Variables provided by top-level makefile
+#
+# BUILDDIR The location of the build tree root
+# COMPONENT The name of the component
+# CURDIR The location of the source tree root
+# EXPORTDIR The location of the export directory
+#
+# do_include Canned command sequence to include a child makefile
+#
+# Variables provided by parent makefile:
+#
+# DIR The name of the directory we're in, relative to CURDIR
+#
+# Variables we can manipulate:
+#
+# CLEAN_ITEMS The list of items to remove for "make clean"
+# DISTCLEAN_ITEMS The list of items to remove for "make distclean"
+# TEST_SOURCES The list of sources to build for "make test"
+# TEST_TARGETS The list of target names to run for "make test"
+# INSTALL_ITEMS The list of items to (un)install
+#
+# SOURCES The list of sources to build for $(COMPONENT)
+#
+# Plus anything from the toolchain
+
+# Push parent directory onto the directory stack
+sp := $(sp).x
+dirstack_$(sp) := $(d)
+d := $(DIR)
+
+# Manipulate include paths
+CFLAGS := $(CFLAGS) -I$(d)
+
+# Sources
+SRCS_$(d) := $(DIR_SOURCES)
+TEST_SRCS_$(d) := $(DIR_TEST_SOURCES)
+INSTALL_ITEMS_$(d) := $(DIR_INSTALL_ITEMS)
+
+# Append to sources for component
+SOURCES := $(SOURCES) $(addprefix $(d), $(SRCS_$(d)))
+
+# Test sources
+ifeq ($(MAKECMDGOALS),test)
+ ifneq ($(DIR_TEST_SOURCES),)
+ TEST_SOURCES := $(TEST_SOURCES) $(addprefix $(d), $(TEST_SRCS_$(d)))
+
+ TEST_TARGETS := $(TEST_TARGETS) test_$(d)
+
+ # Target for tests in this directory
+ test_$(d): $(d) $(addprefix $(BUILDDIR)/, \
+ $(subst /,_,$(addprefix $(d), \
+ $(basename $(TEST_SRCS_$(d))))))
+ $(Q)$(TESTRUNNER) $(BUILDDIR) $(CURDIR)/$< $(EXEEXT)
+ endif
+endif
+
+# Install items
+ifneq ($(DIR_INSTALL_ITEMS),)
+ # Extract the destination directory from the variable
+ dest_dir_$(d) = $(firstword $(subst :, ,$(INSTALL_ITEMS_$(d))))
+ # Extract the list of files to install
+ file_list_$(d) = $(lastword $(subst :, ,$(INSTALL_ITEMS_$(d))))
+ # Split file list into words
+ files_$(d) = $(subst ;, ,$(file_list_$(d)))
+
+ # Append items to install (along with install location), prepending $(d)
+ # to each item in the file list
+ INSTALL_ITEMS := $(INSTALL_ITEMS) $(dest_dir_$(d)):$(foreach FILE, \
+ $(files_$(d)),$(addprefix $(d),$(FILE)));
+endif
+
+# Reset the inputs
+DIR_SOURCES :=
+DIR_TEST_SOURCES :=
+DIR_INSTALL_ITEMS :=
+
+# Now include any children we may have
+MAKE_INCLUDES := $(wildcard $(d)*/Makefile)
+$(eval $(foreach INC, $(MAKE_INCLUDES), $(call do_include,$(INC))))
+
+# Pop off the directory stack
+d := $(dirstack_$(sp))
+sp := $(basename $(sp))
+
diff --git a/makefiles/Makefile.top b/makefiles/Makefile.top
new file mode 100644
index 0000000..aa8bf6f
--- /dev/null
+++ b/makefiles/Makefile.top
@@ -0,0 +1,378 @@
+# Top-level Makefile fragment
+#
+# Expected inputs:
+#
+# BUILD Type of build to perform:
+# release - Release build
+# debug - Debug build (default)
+# COMPONENT Name of the component (sans leading "lib" iff a library)
+# COMPONENT_TYPE Type of component:
+# binary - Executable binary
+# lib-static - Static library
+# lib-shared - Shared library
+# TARGET Target platform identifier
+#
+# Optional inputs:
+#
+# BUILDDIR Directory to build into
+# (defaults to build-$(HOST)-$(TARGET)-$(BUILD))
+# CC_CAN_BUILD_AND_DEP Flag whether $(CC) is capable of calculating dependency
+# information at the same time as compiling sources.
+# Set to "yes" if it can.
+# DESTDIR Sandboxed FS root (e.g. for packaging)
+# HOST Host platform identifier
+# PREFIX Absolute installation path prefix
+# (defaults to /usr/local)
+#
+# The client may also override all toolchain settings, including:
+#
+# ARFLAGS Archiver flags for the current compilation
+# CFLAGS C compiler flags for the current compilation
+# LDFLAGS Linker flags for the current compilation
+#
+# TESTCFLAGS Any test-specific CFLAGS
+# TESTLDFLAGS Any test-specific LDFLAGS
+#
+# TESTRUNNER Test runner invocation command
+# The test runner takes a command line in the form
+# <build dir> <test dir> <exeext>
+#
+# Targets provided:
+#
+# all Default target. Builds component using current settings
+# test Build and run test suite, using current settings.
+# coverage Determine test suite coverage (requires lcov)
+# profile Build with profiling support enabled (requires gprof)
+# docs Produce documentation (requires doxygen)
+# clean Clean the build
+# distclean Remove distribution files, too
+# install Install component into prefix.
+# uninstall Remove component from prefix.
+
+###############################################################################
+# Sanity checks
+###############################################################################
+
+# Name of component must be defined by client
+ifeq ($(COMPONENT),)
+ $(error COMPONENT not defined)
+endif
+
+# As must the component type
+ifeq ($(COMPONENT_TYPE),)
+ $(error COMPONENT_TYPE not defined)
+endif
+
+# Target platform must be defined by the client
+ifeq ($(TARGET),)
+ $(error TARGET not defined)
+endif
+
+# Default build type
+ifeq ($(BUILD),)
+ BUILD := debug
+endif
+
+##############################################################################
+# Tool defaults
+##############################################################################
+
+ifeq ($(BUILD),release)
+ CFLAGS ?= -O2
+else
+ CFLAGS ?= -g -O0
+ LDFLAGS ?= -g
+endif
+
+ECHO ?= echo
+
+GENHTML ?= genhtml
+
+INSTALL ?= install
+
+LCOV ?= lcov
+
+MKDIR ?= mkdir
+MKDIRFLAGS ?= -p
+
+PKGCONFIG ?= pkg-config
+
+SED ?= sed
+
+TOUCH ?= touch
+
+##############################################################################
+# Makefile variables
+##############################################################################
+
+Q ?= @
+VQ ?= @
+
+##############################################################################
+# Build environment
+##############################################################################
+
+# Build directory
+BUILDDIR ?= build-$(HOST)-$(TARGET)-$(BUILD)
+
+# Build tree subdirs
+COVERAGEDIR := $(BUILDDIR)/coverage
+DOCDIR := $(BUILDDIR)/docs
+
+# Default prefix
+PREFIX ?= /usr/local
+
+# List of items to delete on clean
+CLEAN_ITEMS :=
+# List of items to delete on distclean
+DISTCLEAN_ITEMS :=
+
+# List of sources to build for testing
+TEST_SOURCES :=
+# List of targets to run for testing
+TEST_TARGETS :=
+
+# List of items to (un)install
+INSTALL_ITEMS :=
+
+# Source files
+SOURCES :=
+
+# Include configuration Makefile fragment
+-include Makefile.config
+
+# Include Makefile fragments in subdirectories
+
+define do_include
+DIR := $$(dir $(1))
+include $(1)
+
+endef
+
+MAKE_INCLUDES := $(wildcard */Makefile)
+$(eval $(foreach INC, $(MAKE_INCLUDES), $(call do_include,$(INC))))
+
+# Calculate objects to build
+OBJECTS := $(addprefix $(BUILDDIR)/,$(subst /,_,$(subst .c,.o,$(SOURCES))))
+
+TEST_OBJECTS := $(addprefix $(BUILDDIR)/,$(subst /,_, \
+ $(subst .c,.o,$(TEST_SOURCES))))
+TEST_BINARIES := $(addprefix $(BUILDDIR)/,$(subst /,_, \
+ $(basename $(TEST_SOURCES))))
+
+# And the output filename
+ifeq ($(findstring lib,$(COMPONENT_TYPE)),lib)
+ OUTPUT := $(BUILDDIR)/lib$(COMPONENT)$(LIBEXT)
+else
+ OUTPUT := $(BUILDDIR)/$(COMPONENT)$(EXEEXT)
+endif
+
+###############################################################################
+# Build targets
+###############################################################################
+
+.PHONY: all test coverage profile docs clean distclean install uninstall
+
+# Default target
+all: $(OUTPUT)
+
+# Build and execute testsuite
+test: $(OUTPUT) $(TEST_BINARIES) $(TEST_TARGETS)
+ $(VQ)$(ECHO) $(ECHOFLAGS) " TEST: Testing complete"
+
+# Compute coverage
+coverage: clean
+ $(Q)$(LCOV) --directory . --zerocounters
+ $(Q)$(MAKE) test CFLAGS="$(CFLAGS) -fprofile-arcs -ftest-coverage" \
+ LDFLAGS="$(LDFLAGS) -lgcov"
+ $(Q)$(LCOV) --directory $(BUILDDIR) --base-directory $(CURDIR) \
+ --capture --output-file $(COVERAGEDIR)/$(COMPONENT)_tmp.info
+ $(Q)$(LCOV) --extract $(COVERAGEDIR)/$(COMPONENT)_tmp.info \
+ "$(CURDIR)/src*" -o $(COVERAGEDIR)/$(COMPONENT).info
+ $(Q)$(RM) $(RMFLAGS) $(COVERAGEDIR)/$(COMPONENT)_tmp.info
+ $(Q)$(GENHTML) -o $(COVERAGEDIR) --num-spaces 2 \
+ $(COVERAGEDIR)/$(COMPONENT).info
+
+# Build for profiling
+profile: clean
+ $(Q)$(MAKE) test CFLAGS="$(CFLAGS) -pg" LDFLAGS="-pg $(LDFLAGS)"
+
+# Compile documentation
+docs: $(BUILDDIR)/stamp
+ $(Q)$(DOXYGEN) build/Doxyfile
+
+# Clean build tree
+clean:
+ -$(Q)$(RM) $(RMFLAGS) $(CLEAN_ITEMS)
+ -$(Q)$(RM) $(RMFLAGS) gmon.out
+ -$(Q)$(RM) $(RMFLAGS) -r $(BUILDDIR)
+
+# Remove auto-generated non-build-tree items
+distclean: clean
+ -$(Q)$(RM) $(RMFLAGS) $(DISTCLEAN_ITEMS)
+
+# The installation target, and associated canned command sequences.
+# For reference, the syntax of INSTALL_ITEMS is:
+#
+# <destination>:<file>[';'<file>]*
+#
+# We also permit a trailing ';' in the file list.
+
+# Install a pkg-config control file ($1) to the specified location ($2)
+define install_pkgconfig
+ $(Q)$(SED) -e 's#PREFIX#$(PREFIX)#' $1 >$(BUILDDIR)/$(1:.in=)
+ $(INSTALL) $(INSTALLFLAGS) -m 644 $(BUILDDIR)/$(1:.in=) $2
+
+endef
+
+# Install a file ($1) to the specified location ($2)
+define install_file
+ $(if $1, \
+ $(if $(findstring .pc.in,$1), \
+ $(call install_pkgconfig,$1,$2), \
+ $(INSTALL) $(INSTALLFLAGS) -m 644 $1 $2))
+
+endef
+
+# Install a list of files ($2) to the specified location ($1)
+# We create the installation location if it doesn't already exist
+define install_to_dest
+ $(Q)$(MKDIR) $(MKDIRFLAGS) $(DESTDIR)$(PREFIX)$1
+ $(foreach FILE,$(strip $(subst ;, ,$2)), \
+ $(call install_file,$(FILE),$(DESTDIR)$(PREFIX)$1))
+
+endef
+
+install: $(OUTPUT)
+ $(foreach ITEM,$(INSTALL_ITEMS), \
+ $(call install_to_dest,$(firstword $(subst :, ,$(ITEM))), \
+ $(lastword $(subst :, ,$(ITEM)))))
+
+# Uninstallation
+
+# Uninstall a file ($1) from the specified location ($2)
+define uninstall_file
+ $(if $1, \
+ $(if $(findstring .pc.in,$1), \
+ $(RM) $(RMFLAGS) $2/$(notdir $(1:.in=)), \
+ $(RM) $(RMFLAGS) $2/$(notdir $1)))
+
+endef
+
+# Uninstall a list of files ($2) from the specified location ($1)
+# TODO: Come up with a safe way of removing directories, too
+define uninstall_from_dest
+ $(foreach FILE,$(strip $(subst ;, ,$2)), \
+ $(call uninstall_file,$(FILE),$(DESTDIR)$(PREFIX)$1))
+
+endef
+
+uninstall:
+ $(foreach ITEM,$(INSTALL_ITEMS), \
+ $(call uninstall_from_dest,$(firstword $(subst :, ,$(ITEM))), \
+ $(lastword $(subst :, ,$(ITEM)))))
+
+###############################################################################
+# Actual rules
+###############################################################################
+
+$(BUILDDIR)/stamp:
+ $(Q)$(MKDIR) $(MKDIRFLAGS) $(BUILDDIR)
+ $(Q)$(MKDIR) $(MKDIRFLAGS) $(COVERAGEDIR)
+ $(Q)$(MKDIR) $(MKDIRFLAGS) $(DOCDIR)
+ $(Q)$(TOUCH) $(BUILDDIR)/stamp
+
+$(OUTPUT): $(BUILDDIR)/stamp $(OBJECTS)
+ifeq ($(COMPONENT_TYPE),lib-static)
+ $(VQ)$(ECHO) $(ECHOFLAGS) " AR: $@"
+ $(Q)$(AR) $(ARFLAGS) $@ $(OBJECTS)
+else
+ $(VQ)$(ECHO) $(ECHOFLAGS) " LINK: $@"
+ $(Q)$(LD) -o $@ $(OBJECTS) $(LDFLAGS)
+endif
+
+###############################################################################
+# Autogenerated, implied rules
+###############################################################################
+
+DEPFILES :=
+
+ifeq ($(CC_CAN_BUILD_AND_DEP),yes)
+ # C compiler can compile and dep simultaneously
+
+ define dep_c
+ $$(BUILDDIR)/$2: $$(BUILDDIR)/stamp $1
+
+ DEPFILES += $$(BUILDDIR)/$2
+
+ endef
+
+ define build_c
+ $$(BUILDDIR)/$2: $$(BUILDDIR)/stamp $1
+ $$(VQ)$$(ECHO) $$(ECHOFLAGS) " COMPILE: $1"
+ $$(Q)$$(CC) -MMD -MP $($3) -o $$@ -c $1
+
+ endef
+else
+ # C compiler must calculate dependencies first, then compile (default)
+
+ define dep_c
+ $$(BUILDDIR)/$2: $$(BUILDDIR)/stamp $1
+ $$(VQ)$$(ECHO) $$(ECHOFLAGS) " DEP: $1"
+ $$(Q)$$(RM)$($@)
+ $$(Q)$$(CC) $($3) -MM $1 > $$@
+ $$(Q)$$(SED) $$(SEDFLAGS) -i 's,^.*:,$$@ $$(@:.d=.o):,' $$@
+
+ DEPFILES += $$(BUILDDIR)/$2
+
+ endef
+
+ define build_c
+ $$(BUILDDIR)/$2: $$(BUILDDIR)/stamp $1
+ $$(VQ)$$(ECHO) $$(ECHOFLAGS) " COMPILE: $1"
+ $$(Q)$$(CC) $($3) -o $$@ -c $1
+
+ endef
+endif
+
+# Generate dependency rules
+$(eval $(foreach SOURCE,$(filter %.c,$(SOURCES)), \
+ $(call dep_c,$(SOURCE),$(subst /,_,$(SOURCE:.c=.d)),CFLAGS)))
+
+# Generate compilation rules
+$(eval $(foreach SOURCE,$(filter %.c,$(SOURCES)), \
+ $(call build_c,$(SOURCE),$(subst /,_,$(SOURCE:.c=.o)),CFLAGS)))
+
+# Similarly for test sources
+ifeq ($(MAKECMDGOALS),test)
+ TESTCFLAGS := $(TESTCFLAGS) $(CFLAGS)
+ TESTLDFLAGS := $(TESTLDFLAGS) $(LDFLAGS)
+
+ ifeq ($(findstring lib,$(COMPONENT_TYPE)),lib)
+ TESTLIB := $(OUTPUT)
+ TESTLDFLAGS := $(TESTLDFLAGS) -L$(BUILDDIR)/ -l$(COMPONENT)
+ endif
+
+ define link_test
+ $2: $($3) $1
+ $$(VQ)$$(ECHO) $$(ECHOFLAGS) " LINK: $2"
+ $$(Q)$$(CC) -o $$@ $1 $($4)
+
+ endef
+
+$(eval $(foreach SOURCE,$(filter %.c,$(TEST_SOURCES)), \
+ $(call dep_c,$(SOURCE),$(subst /,_,$(SOURCE:.c=.d)),TESTCFLAGS)))
+
+$(eval $(foreach SOURCE,$(filter %.c,$(TEST_SOURCES)), \
+ $(call build_c,$(SOURCE),$(subst /,_,$(SOURCE:.c=.o)),TESTCFLAGS)))
+
+$(eval $(foreach BINARY,$(TEST_BINARIES), \
+ $(call link_test, \
+ $(addsuffix .o,$(BINARY)),$(BINARY),TESTLIB,TESTLDFLAGS)))
+endif
+
+# Include dependency makefiles
+ifneq ($(findstring clean,$(MAKECMDGOALS)),clean)
+-include $(sort $(DEPFILES))
+endif
+