.SUFFIXES: # remove all the implicit rules .SECONDARY: # all files are intermediate (keep them) .SECONDEXPANSION: # usefull to automatically build obj directories .PHONY: all tidy clean cleanall # these targets are not files all: # ensures that all is the main target CC=gcc CFLAGS=-Wall -Werror -std=c11 LDFLAGS= LIBS= DEP=.dependencies V ?= 1 red := \e[0;91m green := \e[0;92m yellow := \e[0;93m blue := \e[0;94m magenta := \e[0;95m cyan := \e[0;96m black := \e[0m print = $(if $(filter 1,$(V)),@printf "$(value $1)%14s $(black) %s\n" "$(2)" "$(3)" || exit 0) Q = $(if $(filter 0 1,$(V)),@) dinfo = $(if $(filter 3,$(V)),$(info $(1))) gen-rule = $(call dinfo,$(1)) $(1) all: main main: main.o | $$(@D)/. $(call print,magenta,linking,$(notdir $@)) $(Q)$(CC) $(LDFLAGS) -o $@ $^ $(LIBS) define gcc-rule $(call gen-rule,$(1): $(2) | $$$$(@D)/. $$(call print,cyan,compiling,$$(notdir $$<)) $$(Q)( [ -f $$(DEP) ] && grep -w "$$(@D)/.$$(*F).d" $$(DEP) >/dev/null ) || echo '-include $$(@D)/.$$(*F).d\nclean::\n\t$$$$(Q)rm -f $$(@D)/.$$(*F).d $$@' >> $$(DEP) $$(Q)$(3) -MMD -MP -MT "$$@" -MF "$$(@D)/.$$(*F).d" -c "$$<" -o "$$@") endef $(eval $(call gcc-rule,%.o,%.c,$$(CC) $$(CFLAGS))) -include $(DEP) print-%: $(call print,green,$*,[$($*)]) %/.: $(Q)mkdir -p $@ tidy: $(Q)rm -f *~ \#* clean:: $(Q)rm -f $(DEP) cleanall: clean $(Q)rm -f main