###################################################################### # Some helper functions # ###################################################################### # $(call inspect,LIST) # dump list of variables printing their values and their attributes inspect = $(foreach v,$(1),$(info $(v) [$(origin $(v)),$(flavor $(v))] = $($(v)))) # $(call undefine_default,LIST) # undefine default variables given in LIST) undefine_default = $(foreach v,$(1),$(if $(filter default,$(origin $(v))),$(eval undefine $(v)),)) # $(call setdef_ifdef,VAR,DEFVAR) # if DEFVAR exists, set default value of VAR to $(DEFVAR) setdefault_ifdef = $(if $(filter undefined,$(origin $(2))),,$(eval $(1) ?= $($(2)))) # $(call clean_bool_true,VALUE) # $(call clean_bool_false,VALUE) # $(call clean_bool,VALUE) # clean_bool,clean_bool_true: # if VALUE is identified as true (true, on, yes, enable, 1, ...) returns 1 # clean_bool,clean_bool_false: # if VALUE is identified as false (false, off, no, disable, 0, ...) returns an empty string clean_bool_true = $(if $(filter true TRUE on ON yes YES enable ENABLE,$(1)),1,$(1)) clean_bool_false = $(if $(filter false FALSE off OFF no NO disable DISABLE 0,$(1)),,$(1)) clean_bool = $(call clean_bool_false,$(call clean_bool_true,$(1))) # $(call quote_spaces,STR) # return STR, surrounded by double quotes if it contains spaces quote_spaces = $(if $(filter 0 1,$(words $1)),$1,"$1") # $(call pathsearch,EXEC) # returns the full path of EXEC if it exists somewhere in $PATH # if not found, returns the unmodified EXEC pathsearch = $(if $(filter 1,$(words $(1))),$(firstword $(wildcard $(1) $(addsuffix /$(1),$(subst :, ,$(PATH)))) $(1)),$(1)) # $(call prepend_ccache,PREFIX,EXEC) # return 'ccache EXEC' if ccache is not already detected in EXEC prepend_ccache = $(if $(filter ccache,$(subst /, ,$(1))),$(1),ccache $(1)) # $(call clean_path,PATH) # return a sanitized path: remove //, trailing / clean_path = $(subst //,/,$(patsubst %/,%,$1)) # ($call quiet-command,CMD,MSG) # execute CMD and display MSG # if verbose mode is enabled (with 'make V=1`) print full CMD instead of MSG quiet-command = $(if $(V),$1,$(if $(2),@echo $2 && $1, @$1)) ###################################################################### # Cached configuration support # # variables listed in CONFIG_VARS are stored in CONFIG_MAK file # containing lines `cache_VAR=value` # This file is read on subsequent invocation and set default values # of these variables. # # The file is automatically generated but can be hand-edited. # ###################################################################### CONFIG_MAK = config.mak CONFIG_VARS = max CONFIG_STRING = $(foreach var,$(CONFIG_VARS),$(var)=$(call quote_spaces,$($(var)))) # undefine variables which have a default value set by make itself # (mainly CC and CXX) $(call undefine_default,$(CONFIG_VARS)) # read the cached variables -include $(CONFIG_MAK) # for all undefined variables set their default values from ones # stored in included CONFIG_MAK. $(foreach var,$(CONFIG_VARS),$(call setdefault_ifdef,$(var),cache_$(var))) #default (non false) values # max ?= 10 # cleanup "False" boolean values, set them to empty value $(foreach var,$(CONFIG_VARS),$(eval override $(var):=$(call clean_bool_false,$($(var))))) # print out user configuration # (only once in case the makefile has been reloaded) ifndef MAKE_RESTARTS $(info CONF $(CONFIG_STRING)) endif ###################################################################### # Flags generation # ###################################################################### CFLAGS = ifdef max CFLAGS += -DFIBO_MAX=$(max) endif ###################################################################### # Source and objects collection # ###################################################################### .SUFFIXES: .SUFFIXES: .c .o ifdef srcdir srcdir := $(patsubst %/,%,$(srcdir)) else srcdir := $(patsubst %/,%,$(dir $(realpath $(firstword $(MAKEFILE_LIST))))) endif INCLUDES := src \ src/version \ src/fibo SRCS := src/main.c \ src/version/version_tools.c \ src/fibo/fibo.c OBJS += src/version/version.o OBJS += $(SRCS:%.c=%.o) VPATH += $(srcdir) VPATH += . CFLAGS += $(addprefix -I$(srcdir)/,$(INCLUDES)) GENERATED += $(OBJS) GENERATED += $(DEPDIR) GENERATED += src/version/version.c GENERATED += fibo ###################################################################### # Dependencies tracking # ###################################################################### DEPDIR := .deps DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.Td #generate dependency file in a temporary file #Rename the generated temporary dependency file to the real dependency file. #We do this in a separate step so that failures during the compilation wont leave a corrupted dependency file #in some rare cases dep file can end up beeing newer than object, final touch ensures that object will always #be newer. POSTCOMPILE = @mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d && touch $@ CFLAGS += $(DEPFLAGS) ###################################################################### # Targets # ###################################################################### .SECONDEXPANSION: all: fibo fibo: $(OBJS) $(call quiet-command, $(CC) $^ -o $@, "LINK $@") %.c: %.c.in FORCE @mkdir -p $(@D) @sed -e 's#@@GIT_SHA1@@#$(shell git describe --all --long --dirty)#' $< > $@.tmp @cmp -s $@.tmp $@ || (echo "GEN $@"; mv $@.tmp $@) @rm -f $@.tmp .PRECIOUS: src/version/version.c %.o: %.c | $(DEPDIR)/$$(@D)/ $(call quiet-command, $(CC) $(CFLAGS) $(IFLAGS) -o $@ -c $<, "CC $@") $(POSTCOMPILE) %/: @mkdir -p $@ # Generate the cached configuration make script # - always generated # - file is written out only if modified $(CONFIG_MAK): FORCE @echo "# automatically generated" > $@.tmp @$(foreach var,$(CONFIG_VARS),echo cache_$(var)=$($(var)) >> $@.tmp;) @cmp -s $@.tmp $@ || (echo "GEN $@"; mv $@.tmp $@) @rm -f $@.tmp $(OBJS): $(MAKEFILE_LIST) inspect: $(call inspect,srcdir) $(call inspect,SRCS) $(call inspect,OBJS) $(call inspect,SHELL) clean: $(call quiet-command, rm -rf $(GENERATED), "CLEAN") distclean: $(call quiet-command, rm -rf $(GENERATED) $(CONFIG_MAK) Makefile, "DISTCLEAN") .PHONY: FORCE clean inspect # include all potential dependencies files -include $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRCS)))