## # A set of makefile rules loosely based on kbuild. all: compile ifndef build toplevelrun:=yes ## # Disable default rules and make output pretty. MAKEFLAGS += -rR --no-print-directory Makefile: ; ifdef V ifeq ("$(origin V)", "command line") VERBOSE = $(V) endif endif ifndef VERBOSE VERBOSE = 0 endif ifeq ($(VERBOSE),1) quiet = Q = else quiet=quiet_ Q = @ endif ifneq ($(findstring s,$(MAKEFLAGS)),) quiet=silent_ endif export quiet Q VERBOSE ## # Recursion helpers. srctree := $(CURDIR) objtree := $(CURDIR) export srctree objtree ## # Consult SCM for better version string. TAGPREFIX ?= v GIT_REV := $(shell test -d .git && git describe || echo exported) ifneq ($(GIT_REV), exported) FULL_VERSION := $(patsubst $(TAGPREFIX)%,%,$(GIT_REV)) else FULL_VERSION := $(VERSION) endif RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc -o -name .hg -o -name .git \) -prune -o export FULL_VERSION RCS_FIND_IGNORE ## # Utilities and default flags for them. CROSS_COMPILE ?= CC := $(CROSS_COMPILE)gcc LD := $(CROSS_COMPILE)ld INSTALL := install INSTALLDIR := $(INSTALL) -d CFLAGS ?= -g -O2 CFLAGS_ALL := -Wall -Wstrict-prototypes -D_GNU_SOURCE -std=gnu99 CFLAGS_ALL += $(CFLAGS) LDFLAGS ?= -g LDFLAGS_ALL += $(LDFLAGS) export CC LD INSTALL INSTALLDIR CFLAGS_ALL LDFLAGS_ALL build := endif ## # Reset all variables. ifneq ($(origin targets),file) targets := endif src := obj := src += $(build) obj := $(build) ## # Include directory specific stuff ifneq ($(build),) $(build)/Makefile: ; include $(build)/Makefile endif ## # Rules and helpers PHONY += all compile install clean FORCE # Convinient variables comma := , squote := ' empty := space := $(empty) $(empty) # The temporary file to save gcc -MD generated dependencies must not # contain a comma depfile = $(subst $(comma),_,$(@D)/.$(@F).d) build-dir = $(patsubst %/,%,$(dir $@)) target-dir = $(dir $@) ## # Build rules ifneq ($(NOCMDDEP),1) # Check if both arguments has same arguments. Result in empty string if equal # User may override this check using make NOCMDDEP=1 # Check if both arguments has same arguments. Result is empty string if equal. # User may override this check using make KBUILD_NOCMDDEP=1 arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ $(filter-out $(cmd_$@), $(cmd_$(1))) ) endif # echo command. # Short version is used, if $(quiet) equals `quiet_', otherwise full one. echo-cmd = $(if $($(quiet)cmd_$(1)),\ echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';) make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1))))) # printing commands cmd = @$(echo-cmd) $(cmd_$(1)) # Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o dot-target = $(dir $@).$(notdir $@) # The temporary file to save gcc -MD generated dependencies must not # contain a comma depfile = $(subst $(comma),_,$(dot-target).d) # Escape single quote for use in echo statements escsq = $(subst $(squote),'\$(squote)',$1) # Find any prerequisites that is newer than target or that does not exist. # PHONY targets skipped in both cases. local-target-prereqs = % any-prereq = $(filter $(local-target-prereqs), $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^), $^)) # Execute command if command has changed or prerequisite(s) are updated. # if_changed = $(if $(strip $(any-prereq) $(arg-check)), \ @set -e; \ $(echo-cmd) $(cmd_$(1)); \ echo 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd) # Usage: $(call if_changed_rule,foo) # Will check if $(cmd_foo) or any of the prerequisites changed, # and if so will execute $(rule_foo). if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ), \ @set -e; \ $(rule_$(1))) ##### # Handle options to gcc. c_flags = -Wp,-MD,$(depfile),-MT,$@ $(CFLAGS_ALL) $(CFLAGS_EXTRA) \ $(CFLAGS_$(notdir $@)) ld_flags = $(LDFLAGS_ALL) $(LDFLAGS_EXTRA) $(LDFLAGS_$(notdir $@)) ##### # Compile c-files. quiet_cmd_cc_o_c = CC $@ cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< define rule_cc_o_c $(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \ (echo 'cmd_$@ := $(call make-cmd,cc_o_c)'; echo; cat $(depfile)) \ > $(dot-target).cmd ; \ rm $(depfile) endef $(obj)/%.o: override local-target-prereqs=% $(obj)/%.o: $(src)/%.c FORCE $(call if_changed_rule,cc_o_c) ##### # Link programs # Link an executable based on list of .o files, all plain c # host-cmulti -> executable __progs := $(addprefix $(obj)/,$(sort $(progs-y))) cobjs := $(addprefix $(obj)/,$(sort $(foreach m,$(progs-y),$($(m)-objs)))) quiet_cmd_ld = LD $@ cmd_ld = $(CC) $(ld_flags) -o $@ \ $(addprefix $(obj)/,$($(@F)-objs)) \ $(LIBS) $(LIBS_$(@F)) $(__progs): override local-target-prereqs=$(addprefix $(obj)/,$($(*F)-objs)) $(__progs): $(obj)/%: $(cobjs) FORCE $(call if_changed,ld) targets += $(__progs) $(cobjs) ### # why - tell why a a target got build ifeq ($(VERBOSE),2) why = \ $(if $(filter $@, $(PHONY)),- due to target is PHONY, \ $(if $(wildcard $@), \ $(if $(strip $(any-prereq)),- due to: $(any-prereq), \ $(if $(arg-check), \ $(if $(cmd_$@),- due to command line change: $(arg-check), \ $(if $(filter $@, $(targets)), \ - due to missing .cmd file, \ - due to $(notdir $@) not in $$(targets) \ ) \ ) \ ) \ ), \ - due to target missing \ ) \ ) echo-why = $(call escsq, $(strip $(why))) endif ## # Top level rules. %/: FORCE $(Q)$(MAKE) -f Make.rules build=$(build-dir) $(MAKECMDGOALS) compile: $(targets) @: install: $(targets) FORCE clean: $(filter %/,$(targets)) ifeq ($(toplevelrun),yes) $(Q)find . $(RCS_FIND_IGNORE) \ \( -name '*.[oas]' -o -name '.*.cmd' -o -name '.*.d' \) \ -type f -print | xargs rm -f endif $(Q)rm -rf $(addprefix $(obj)/,$(sort $(progs-y) $(progs-n) $(progs-))) ifeq ($(origin VERSION),command line) DIST_VERSION=$(VERSION) else DIST_VERSION=$(FULL_VERSION) endif dist: git archive --format tar --prefix=$(PACKAGE)-$(DIST_VERSION)/ \ $(TAGPREFIX)$(DIST_VERSION) \ | bzip2 -9 > $(PACKAGE)-$(DIST_VERSION).tar.bz2 FORCE: # Read all saved command lines and dependencies for the $(targets) we # may be building above, using $(if_changed{,_dep}). As an # optimization, we don't need to read them if the target does not # exist, we will rebuild anyway in that case. targets := $(wildcard $(sort $(targets))) cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd)) ifneq ($(cmd_files),) include $(cmd_files) endif # Declare the contents of the .PHONY variable as phony. We keep that # information in a variable se we can use it in if_changed and friends. .PHONY: $(PHONY)