Index: common.mk |
diff --git a/common.mk b/common.mk |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a58251a0bc2efe455a049ab8b2b0f2aca82e0079 |
--- /dev/null |
+++ b/common.mk |
@@ -0,0 +1,478 @@ |
+# Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+# |
+# This file provides a common architecture for building C/C++ source trees. |
+# It uses recursive makefile inclusion to create a single make process which |
+# can be built in the source tree or with the build products placed elsewhere. |
+# |
+# To use: |
+# 1. Place common.mk in your top source level |
+# 2. In your top-level Makefile, place "include common.mk" at the top |
+# 3. In all subdirectories, create a 'module.mk' file that starts with: |
+# include common.mk |
+# And then contains the remainder of your targets. |
+# 4. All build targets should look like: |
+# $(OUT)relative/path/target: ... |
+# |
+# See existing makefiles for rule examples. |
+# |
+# Exported macros: |
+# - cc_binary, cxx_binary provide standard compilation steps for binaries |
+# - cxx_library, cc_library provide standard compilation steps for sos |
+# All of the above optionally take an argument for extra flags. |
+# - update_archive creates/updates a given .a target |
+# |
+# Exported variables |
+# - RM_ON_CLEAN - append files to remove on calls to clean |
+# - RMDIR_ON_CLEAN - append dirs to remove on calls to clean |
+# |
+# Exported targets meant to have prerequisites added to: |
+# - all - Your $(OUT)target should be given |
+# - small_tests - requires something, even if it is just NONE |
+# - large_tests - requires something, even if it is just NONE |
+# - NONE - nop target for *_tests |
+# - FORCE - force the given target to run regardless of changes |
+# |
+# Possible command line variables: |
+# - COLOR=[0|1] to set ANSI color output (default: 1) |
+# - VERBOSE=[0|1] to hide/show commands (default: 0) |
+# - MODE=dbg to turn down optimizations (default: opt) |
+# - ARCH=[x86|arm|supported qemu name] (default: from portage or uname -m) |
+# - SPLITDEBUG=[0|1] splits debug info in target.debug (default: 1) |
+# [SPLITDEBUG=0 MODE=opt will disable compiling with -g] |
+# - VALGRIND=[0|1] runs tests under valgrind (default: 0) |
+# - OUT=/path/to/builddir puts all output in given path |
+# (default: $PWD/build-$MODE. Use OUT=. for normal behavior) |
+# - VALGRIND_ARGS="" supplies extra memcheck arguments |
+# |
+# External CXXFLAGS and CFLAGS should be passed via the environment since this |
+# file does not use 'override' to control them. |
+ |
+# Behavior configuration variables |
+SPLITDEBUG ?= 1 |
+VALGRIND ?= 0 |
+COLOR ?= 1 |
+VERBOSE ?= 0 |
+MODE ?= opt |
+ARCH ?= $(shell uname -m) |
+# TODO: profiling support not completed. |
+PROFILING ?= 0 |
+ |
+# Put objects in a separate tree based on makefile locations |
+# This means you can build a tree without touching it: |
+# make -C $SRCDIR # will create ./build |
+# Or |
+# make -C $SRCDIR OUT=$PWD |
+# This variable is extended on subdir calls and doesn't need to be re-called. |
+OUT ?= $(PWD)/build-$(MODE)/ |
+# Ensure a command-line supplied OUT has a slash |
+override OUT := $(abspath $(OUT))/ |
+ |
+# Only call MODULE if we're in a submodule |
+MODULES_LIST := $(filter-out Makefile %.d,$(MAKEFILE_LIST)) |
+ifeq ($(words $(filter-out Makefile common.mk %.d,$(MAKEFILE_LIST))),0) |
+# Setup a top level SRC |
+SRC ?= $(PWD) |
+ |
+# |
+# Helper macros |
+# |
+ |
+# Creates the actual archive with an index. |
+# $(1) is the object suffix modified: pie or pic. |
+define update_archive |
+ $(QUIET)mkdir -p $(dir $@) |
+ $(QUIET)# Create the archive in one step to avoid parallel use accessing it |
+ $(QUIET)# before all the symbols are present. |
+ @$(ECHO) "AR $(subst $(PWD)/,,$(^:.o=.$(1).o)) -> $(subst $(PWD)/,,$@)" |
+ $(QUIET)$(AR) rcs $@ $(^:.o=.$(1).o) |
+endef |
+ |
+# Default compile from objects using pre-requisites but filters out |
+# subdirs and .d files. |
+define cc_binary |
+ $(call COMPILE_BINARY_implementation,CC,$(CFLAGS) $(1)) |
+endef |
+ |
+define cxx_binary |
+ $(call COMPILE_BINARY_implementation,CXX,$(CXXFLAGS) $(1)) |
+endef |
+ |
+# Default compile from objects using pre-requisites but filters out |
+# subdirs and .d files. |
+define cc_library |
+ $(call COMPILE_LIBRARY_implementation,CC,$(CFLAGS) $(1)) |
+endef |
+define cxx_library |
+ $(call COMPILE_LIBRARY_implementation,CXX,$(CXXFLAGS) $(1)) |
+endef |
+ |
+ |
+# Deletes files silently if they exist. Meant for use in any local |
+# clean targets. |
+define silent_rm |
+ $(QUIET)(test -n "$(wildcard $(1))" && \ |
+ $(ECHO) -n '$(COLOR_RED)CLEANFILE$(COLOR_RESET) ' && \ |
+ $(ECHO) '$(subst $(PWD)/,,$(wildcard $(1)))' && \ |
+ $(RM) -f $(1) 2>/dev/null) || true |
+endef |
+define silent_rmdir |
+ $(QUIET)(test -n "$(wildcard $(1))" && \ |
+ $(ECHO) -n '$(COLOR_RED)CLEANDIR$(COLOR_RESET) ' && \ |
+ $(ECHO) '$(subst $(PWD)/,,$(wildcard $(1)))' && \ |
+ $(RMDIR) $(1) 2>/dev/null) || true |
+endef |
+ |
+ |
+ |
+# |
+# Default variables for use in including makefiles |
+# |
+ |
+# All objects for .c files at the top level |
+C_OBJECTS := $(patsubst %.c,$(OUT)%.o,$(wildcard *.c)) |
+ |
+# All objects for .cxx files at the top level |
+CXX_OBJECTS := $(patsubst %.cc,$(OUT)%.o,$(wildcard *.cc)) |
+ |
+# |
+# Default variable values |
+# |
+ |
+OBJCOPY ?= objcopy |
+STRIP ?= strip |
+RMDIR ?= rmdir |
+# Only override CC and CXX if they are from make. |
+ifeq ($(origin CC), default) |
+ CC = gcc |
+endif |
+ifeq ($(origin CXX), default) |
+ CXX = g++ |
+endif |
+ifeq ($(origin RANLIB), default) |
+ RANLIB = ranlib |
+endif |
+RANLIB ?= ranlib |
+ECHO = /bin/echo -e |
+ |
+ifeq ($(PROFILING),1) |
+ $(warning PROFILING=1 disables relocatable executables.) |
+endif |
+ |
+# To update these from an including Makefile: |
+# CXXFLAGS += -mahflag # Append to the list |
+# CXXFLAGS := -mahflag $(CXXFLAGS) # Prepend to the list |
+# CXXFLAGS := $(filter-out badflag,$(CXXFLAGS)) # Filter out a value |
+# The same goes for CFLAGS. |
+CXXFLAGS := $(CXXFLAGS) -Wall -Werror -fstack-protector-all -DFORTIFY_SOURCE \ |
+ -O2 -ggdb3 -DNDEBUG -Wa,--noexecstack |
+CFLAGS := $(CFLAGS) -Wall -Werror -fstack-protector-all -DFORTIFY_SOURCE \ |
+ -O2 -ggdb3 -DNDEBUG -Wa,--noexecstack |
+ |
+ifeq ($(PROFILING),1) |
+ CFLAGS := -pg |
+ CXXFLAGS := -pg |
+endif |
+ |
+ifeq ($(MODE),dbg) |
+ CFLAGS := $(filter-out -O2 -DNDEBUG,$(CFLAGS)) -O1 |
+ CXXFLAGS := $(filter-out -O2 -DNDEBUG,$(CXXFLAGS)) -O1 |
+ # TODO: May need -nopie. need to check gdb |
+else # opt |
+ ifeq ($(SPLITDEBUG),0) |
+ # TODO: do we want -fomit-frame-pointer on x86? |
+ CFLAGS := $(filter-out -ggdb3,$(CFLAGS)) |
+ CXXFLAGS := $(filter-out -ggdb3,$(CXXFLAGS)) |
+ endif |
+endif |
+ |
+LDFLAGS := $(LDFLAGS) -Wl,-z,relro -Wl,-z,noexecstack |
+ |
+# Fancy helpers for color if a prompt is defined |
+ifeq ($(COLOR),1) |
+COLOR_RESET = \x1b[0m |
+COLOR_GREEN = \x1b[32;01m |
+COLOR_RED = \x1b[31;01m |
+COLOR_YELLOW = \x1b[33;01m |
+endif |
+ |
+# By default, silence build output. |
+QUIET = @ |
+ifeq ($(VERBOSE),1) |
+ QUIET= |
+endif |
+ |
+# |
+# Implementation macros for compile helpers above |
+# |
+ |
+# Useful for dealing with pie-broken toolchains. |
+# Call make with PIE=0 to disable default PIE use. |
+OBJ_PIE_FLAG = -fPIE |
+COMPILE_PIE_FLAG = -pie |
+ifeq ($(PIE),0) |
+ OBJ_PIE_FLAG = |
+ COMPILE_PIE_FLAG = |
+endif |
+ |
+# Default compile from objects using pre-requisites but filters out |
+# all non-.o files. |
+define COMPILE_BINARY_implementation |
+ @$(ECHO) "LD$(1) $(subst $(PWD)/,,$@)" |
+ $(QUIET)$($(1)) $(COMPILE_PIE_FLAGS) -o $@ \ |
+ $(filter %.o %.so %.a,$(^:.o=.pie.o)) $(LDFLAGS) $(2) |
+ $(call strip_library) |
+ @$(ECHO) "BIN $(COLOR_GREEN)$(subst $(PWD)/,,$@)$(COLOR_RESET)" |
+ @$(ECHO) " $(COLOR_YELLOW)-----$(COLOR_RESET)" |
+endef |
+ |
+# TODO: add version support extracted from PV environment variable |
+#ifeq ($(PV),9999) |
+#$(warning PV=$(PV). If shared object versions matter, please force PV=.) |
+#endif |
+# Then add -Wl,-soname,$@.$(PV) ? |
+ |
+# Default compile from objects using pre-requisites but filters out |
+# all non-.o values. (Remember to add -L$(OUT) -llib) |
+define COMPILE_LIBRARY_implementation |
+ @$(ECHO) "SHARED$(1) $(subst $(PWD)/,,$@)" |
+ $(QUIET)$($(1)) -shared -Wl,-E -o $@ \ |
+ $(filter %.o %.so %.a,$(^:.o=.pic.o)) $(2) $(LDFLAGS) |
+ $(call strip_library) |
+ @$(ECHO) "LIB $(COLOR_GREEN)$(subst $(PWD)/,,$@)$(COLOR_RESET)" |
+ @$(ECHO) " $(COLOR_YELLOW)-----$(COLOR_RESET)" |
+endef |
+ |
+define strip_library |
+ @$(ECHO) "STRIP $(subst $(PWD)/,,$@)" |
+ $(if $(filter 1,$(SPLITDEBUG)), @$(ECHO) -n "DEBUG "; \ |
+ $(ECHO) "$(COLOR_YELLOW)$(subst $(PWD)/,,$@).debug$(COLOR_RESET)") |
+ $(if $(filter 1,$(SPLITDEBUG)), \ |
+ $(QUIET)$(OBJCOPY) --only-keep-debug "$@" "$@.debug") |
+ $(if $(filter-out dbg,$(MODE)),$(QUIET)$(STRIP) --strip-unneeded "$@",) |
+endef |
+ |
+define strip_binary |
+ @$(ECHO) "STRIP $(subst $(PWD)/,,$@)" |
+ $(if $(filter 1,$(SPLITDEBUG)), @$(ECHO) -n "DEBUG "; \ |
+ $(ECHO) "$(COLOR_YELLOW)$(subst $(PWD)/,,$@).debug$(COLOR_RESET)") |
+ $(if $(filter 1,$(SPLITDEBUG)), \ |
+ $(QUIET)$(OBJCOPY) --only-keep-debug "$@" "$@.debug") |
+ $(if $(filter-out dbg,$(MODE)),$(QUIET)$(STRIP) --strip-unneeded "$@",) |
+endef |
+ |
+# |
+# Pattern rules |
+# |
+ |
+%.o: %.pie.o %.pic.o |
+ $(QUIET)touch $@ |
+ |
+$(OUT)%.pie.o: %.c |
+ $(call OBJECT_PATTERN_implementation,CC,$(CFLAGS) $(OBJ_PIE_FLAG)) |
+ |
+$(OUT)%.pic.o: %.c |
+ $(call OBJECT_PATTERN_implementation,CC,$(CFLAGS) -fPIC) |
+ |
+$(OUT)%.pie.o: %.cc |
+ $(call OBJECT_PATTERN_implementation,CXX,$(CXXFLAGS) $(OBJ_PIE_FLAG)) |
+ |
+$(OUT)%.pic.o: %.cc |
+ $(call OBJECT_PATTERN_implementation,CXX,$(CXXFLAGS) -fPIC) |
+ |
+ |
+define OBJECT_PATTERN_implementation |
+ @$(ECHO) "$(subst $(PWD)/,,$(1)) $(subst $(PWD)/,,$<)" |
+ $(QUIET)mkdir -p $(dir $@) |
+ $(QUIET)$($(1)) -c -MD -MF $(basename $@).d -o $@ $< $(2) |
+ $(QUIET)# Wrap all the deps in $(wildcard) so a missing header |
+ $(QUIET)# won't cause weirdness. First we remove newlines and \, |
+ $(QUIET)# then wrap it. |
+ $(QUIET)sed -i -e :j -e '$$!N;s|\\\s*\n| |;tj' \ |
+ -e 's|^\(.*\s*:\s*\)\(.*\)$$|\1 $$\(wildcard \2\)|' $(basename $@).d |
+endef |
+ |
+# NOTE: A specific rule for archive objects is avoided because parallel |
+# update of the archive causes build flakiness. |
+# Instead, just make the objects the prerequisites and use update_archive |
+# To use the foo.a(obj.o) functionality, targets would need to specify the |
+# explicit object they expect on the prerequisite line. |
+ |
+# |
+# Architecture detection and QEMU wrapping |
+# |
+ |
+ARCH ?= $(shell uname -m) |
+HOST_ARCH ?= $(shell uname -m) |
+# emake will supply "x86" or "arm" for ARCH, but |
+# if uname -m runs and you get x86_64, then this subst |
+# will break. |
+ifeq ($(subst x86,i386,$(ARCH)),i386) |
+ QEMU_ARCH := $(subst x86,i386,$(ARCH)) # x86 -> i386 |
+else |
+ QEMU_ARCH = $(ARCH) |
+endif |
+ |
+# If we're cross-compiling, try to use qemu for running the tests. |
+QEMU_CMD ?= |
+ifneq ($(QEMU_ARCH),$(HOST_ARCH)) |
+ ifeq ($(SYSROOT),) |
+ $(info SYSROOT not defined. qemu-based testing disabled) |
+ else |
+ # A SYSROOT is assumed for QEmu use. |
+ USE_QEMU ?= 1 |
+ endif |
+endif |
+ |
+# |
+# Output full configuration at top level |
+# |
+ |
+# Don't show on clean |
+ifneq ($(MAKECMDGOALS),clean) |
+ $(info build configuration:) |
+ $(info - OUT=$(OUT)) |
+ $(info - MODE=$(MODE)) |
+ $(info - SPLITDEBUG=$(SPLITDEBUG)) |
+ $(info - VALGRIND=$(VALGRIND)) |
+ $(info - COLOR=$(COLOR)) |
+ $(info - ARCH=$(ARCH)) |
+ $(info - QEMU_ARCH=$(QEMU_ARCH)) |
+ $(info - SYSROOT=$(SYSROOT)) |
+ $(info ) |
+endif |
+ |
+# |
+# Standard targets with detection for when they are improperly configured. |
+# |
+ |
+# all does not include tests by default |
+all: |
+ $(QUIET)(test -z "$^" && \ |
+ $(ECHO) "You must add your targets as 'all' prerequisites") || true |
+ $(QUIET)test -n "$^" |
+ |
+# Builds and runs tests for the target arch |
+tests: small_tests large_tests |
+ |
+small_tests: qemu FORCE |
+ $(call TEST_implementation) |
+ |
+large_tests: qemu FORCE |
+ $(call TEST_implementation) |
+ |
+qemu_clean: FORCE |
+ifeq ($(USE_QEMU),1) |
+ $(call silent_rm,$(PWD)/qemu-$(QEMU_ARCH)) |
+endif |
+ |
+qemu: FORCE |
+ifeq ($(USE_QEMU),1) |
+ $(QUIET)$(ECHO) "QEMU Preparing qemu-$(QEMU_ARCH)" |
+ $(QUIET)cp -f /usr/bin/qemu-$(QEMU_ARCH) $(PWD)/qemu-$(QEMU_ARCH) |
+ $(QUIET)chmod a+rx $(PWD)/qemu-$(QEMU_ARCH) |
+endif |
+ |
+# TODO(wad) separate chroot from qemu to make it possible to cross-compile |
+# and test outside of the chroot. |
+ifeq ($(USE_QEMU),1) |
+ export QEMU_CMD = sudo chroot $(SYSROOT) \ |
+ $(subst $(SYSROOT),,$(PWD))/qemu-$(QEMU_ARCH) \ |
+ -drop-ld-preload \ |
+ -E LD_LIBRARY_PATH="$(SYSROOT_LDPATH)" \ |
+ -E HOME="$(HOME)" -- |
+endif |
+ |
+VALGRIND_CMD = |
+ifeq ($(VALGRIND),1) |
+ VALGRIND_CMD = /usr/bin/valgrind --tool=memcheck $(VALGRIND_ARGS) -- |
+endif |
+ |
+define TEST_implementation |
+ $(QUIET)(test -z "$(filter FORCE qemu,$^)" && \ |
+ $(ECHO) "No '$@' prerequisites defined!") || true |
+ $(QUIET)test -n "$^" |
+ $(QUIET)# TODO(wad) take root away after the chroot. |
+ $(QUIET)test "$(filter NONE,$^)" = "NONE" || \ |
+ ((test "1" = "$(VALGRIND)" && test -n "$(USE_QEMU)" && \ |
+ sudo mkdir -p $(SYSROOT)/proc && \ |
+ sudo mount --bind /proc $(SYSROOT)/proc); \ |
+ (status=0 && for tgt in $(subst $(SYSROOT),,$(filter-out FORCE qemu,$^)); \ |
+ do \ |
+ $(ECHO) "TEST $$tgt"; \ |
+ $(QEMU_CMD) $(VALGRIND_CMD) $$tgt $(GTEST_ARGS); \ |
+ status=$$((status + $$?)); \ |
+ done; (test "1" = "$(VALGRIND)" && test -n "$(USE_QEMU)" && \ |
+ sudo umount $(SYSROOT)/proc); exit $$status)) |
+endef |
+ |
+ |
+# Add the defaults from this dir to rm_clean |
+define default_rm_clean |
+ $(OUT)$(1)*.d $(OUT)$(1)*.o $(OUT)$(1)*.debug |
+endef |
+ |
+# Start with the defaults |
+RM_ON_CLEAN = $(call default_rm_clean) |
+RMDIR_ON_CLEAN = $(OUT) |
+ |
+# Recursive list reversal so that we get RMDIR_ON_CLEAN in reverse order. |
+define reverse |
+$(if $(1),$(call reverse,$(wordlist 2,$(words $(1)),$(1)))) $(firstword $(1)) |
+endef |
+ |
+rm_clean: FORCE |
+ $(call silent_rm,$(RM_ON_CLEAN)) |
+ |
+rmdir_clean: FORCE rm_clean |
+ $(call silent_rmdir,$(call reverse,$(RMDIR_ON_CLEAN))) |
+ |
+clean: qemu_clean rmdir_clean |
+ |
+FORCE: ; |
+# Empty rule for use when no special targets are needed, like large_tests |
+NONE: |
+ |
+.PHONY: clean NONE qemu_clean valgrind rm_clean rmdir_clean |
+.DEFAULT_GOAL := all |
+# Don't let make blow away "intermediates" |
+.PRECIOUS: $(OUT)%.pic.o $(OUT)%.pie.o |
+ |
+# Start accruing build info |
+OUT_DIRS = $(OUT) |
+SRC_DIRS = . |
+ |
+include $(wildcard $(OUT)*.d) |
+SUBMODULE_DIRS = $(wildcard */module.mk) |
+include $(SUBMODULE_DIRS) |
+ |
+else ## In duplicate inclusions of common.mk |
+ |
+# Get the current inclusion directory without a trailing slash |
+MODULE := $(patsubst %/,%, \ |
+ $(dir $(lastword $(filter-out %common.mk,$(MAKEFILE_LIST))))) |
+MODULE_NAME := $(subst /,_,$(MODULE)) |
+ |
+# Depth first |
+$(eval OUT_DIRS += $(OUT)/$(MODULE)) |
+$(eval SRC_DIRS += $(MODULE)) |
+ |
+# Add the defaults from this dir to rm_clean |
+$(eval RM_ON_CLEAN += $(call default_rm_clean,$(MODULE)/)) |
+$(eval RMDIR_ON_CLEAN += $(wildcard $(OUT)$(MODULE)/)) |
+ |
+$(info + submodule: $(MODULE_NAME)) |
+# We must eval otherwise they may be dropped. |
+$(eval $(MODULE_NAME)_C_OBJECTS ?= \ |
+ $(patsubst %.c,$(OUT)%.o,$(wildcard $(MODULE)/*.c))) |
+$(eval $(MODULE_NAME)_CXX_OBJECTS ?= \ |
+ $(patsubst %.cc,$(OUT)%.o,$(wildcard $(MODULE)/*.cc))) |
+ |
+# Continue recursive inclusion of module.mk files |
+SUBMODULE_DIRS = $(wildcard $(MODULE)/*/module.mk) |
+ |
+include $(wildcard $(OUT)$(MODULE)/*.d) |
+include $(SUBMODULE_DIRS) |
+endif |
+ |