MAKEFLAGS = --no-builtin-rules # ------------------------------------------------------------------ # Stuff common to all makefiles # ------------------------------------------------------------------ MKLIB_C_PATH ?= $(error The 'MKLIB_C_PATH' variable needs to be set) include $(MKLIB_C_PATH)/Defs.mk # Defining this variable (with any value) will cause the C/C++ # dependency checking to be done separately from the compilation. # This variable must be set if automatic dependency checking also # handles generated include files. Currently, MkLib-C doesn't do # that so there's no reason to set this. #SLOW_DEPENDENCY_TECHNIQUE = yes # Set the SHOW variable if you want to see the command line of each # program that is invoked. # SHOW=yes - show only the main commands # SHOW=all - show all commands # Prefix for major commands p1 = @ # Prefix for minor commands p2 = @ ifneq (,$(filter y% Y% t% T% 1,$(SHOW))) # yes, true, 1 p1 = endif ifneq (,$(filter a% A%,$(SHOW))) # all p2 = endif TOOL_BASE ?= # Turn off automatic crap .SUFFIXES: # Arch stuff isn't really working yet. Need to come up with a full # solution. Currently just using `uname -o`-`uname -i` for the directory # name. TARGET_ARCH ?= $(shell uname -o)-$(shell uname -i) EXT_C = c EXT_CPP = cpp # Required variables OUT_DIR ?= $(error Makefile variable "OUT_DIR" must be defined) PROGRAM_NAME ?= $(error Makefile variable "PROGRAM_NAME" must be defined) FLEX ?= flex BISON ?= bison # BE CAREFUL! The 'clean' target will wipe out the contents of these # directories so make you don't point them at directories that have # source files. OBJ_DIR := $(OUT_DIR)/obj GEN_DIR := $(OUT_DIR)/gen PRE_DIR := $(OUT_DIR)/pre DEP_DIR := $(OUT_DIR)/dep IMAGE_DIR ?= $(OUT_DIR) # Tell Make not to delete the generated files. .PRECIOUS: $(GEN_DIR)/%.cpp $(GEN_DIR)/%.c # Takes the './' out of path names remself = $(patsubst ./%,%,$(dir $(1))) # Changes '..' to '__up__', calls 'remself' cleanpath = $(call remself,$(patsubst ../,__up__/,$(1))) # Returns the unit's dependency file depf = $(DEP_DIR)/$(call cleanpath,$(1).d) # Returns the SRC and DEP directories for a unit. This is so that # we can pass the correct include path to the compiler. unitd = $(dir $(SRC_DIR)/$(1)) $(dir $(GEN_DIR)/$(1)) # The options file for a unit optf = $(SRC_DIR)/$(dir $(1))opt.$(2)-$(notdir $(1)) optw = $(wildcard $(call optf,$(1),$(2))) # Figure out which files to compile ifdef UNIT_SELECT # Set pattern to find "units-{module}" and "units-{module}-{arch}" UNIT_PATTERN := $(patsubst %,\%/$(_units)%,$(UNIT_SELECT)) ifdef TARGET_ARCH UNIT_PATTERN += $(patsubst %,\%/$(_units)%-$(TARGET_ARCH),$(UNIT_SELECT)) endif # Find all "units-*" files that match UNIT_PATTERN UNIT_LISTS := $(patsubst $(SRC_DIR)/%,%,$(filter $(UNIT_PATTERN),$(shell find $(SRC_DIR) -type f -name '$(_units)*'))) ifeq ($(UNIT_LISTS),) $(error "Couldn't find $(_units)* files with the extensions: $(UNIT_SELECT)") else # Get a list of all the units from all the units-* files. Blank # lines and lines beginning with '#' are ignored. UNITS := $(foreach UNIT_LIST,$(UNIT_LISTS), \ $(patsubst %,$(call remself,$(UNIT_LIST))%,$(shell grep -E -v '^ *$$|^ *\#' $(SRC_DIR)/$(UNIT_LIST)))) endif else # Calculate the set: (FILTER_UNITS + ADD_UNITS) - DEL_UNITS FILTER_UNITS ?= % ADD_UNITS ?= DEL_UNITS ?= EXTENSIONS := .cpp .c .l .y ALL_UNITS := $(foreach ext,$(EXTENSIONS),$(patsubst $(SRC_DIR)/%$(ext),%,$(shell find $(SRC_DIR) -type f -name '*$(ext)' | grep '[^\.]*.$(ext)'))) ifeq ($(ALL_UNITS),) $(error "Couldn't find any matching source files [$(EXTENSIONS)] in $(SRC_DIR)") else UNITS := $(filter-out $(DEL_UNITS), $(filter $(FILTER_UNITS),$(ALL_UNITS))) $(wildcard $(ADD_UNITS)) endif endif # Compiler DEFINE += C_COMPILER ?= $(TOOL_BASE)gcc CPP_COMPILER ?= $(TOOL_BASE)g++ DEBUG ?= OPTIMIZE ?= ARCH ?= LOCAL_INCLUDES = $(INC_DIRS:%=-I%) INCLUDES ?= $(LOCAL_INCLUDES) C_WARNINGS ?= -Wall -W -Wwrite-strings -Wno-unused-parameter CPP_WARNINGS ?= -Wall -W -Wfloat-equal -Wpointer-arith -Wconversion \ -Wredundant-decls -Wcast-qual -Wwrite-strings -Wno-reorder \ -Wno-unused-parameter -Wno-sign-compare CPPFLAGS ?= $(CFLAGS) C_STANDARD_OPTIONS = $(ARCH) $(CFLAGS) $(C_WARNINGS) $(DEBUG) $(OPTIMIZE) $(INCLUDES) $(DEFINE) CPP_STANDARD_OPTIONS = $(ARCH) $(CPPFLAGS) $(CPP_WARNINGS) $(DEBUG) $(OPTIMIZE) $(INCLUDES) $(DEFINE) # Linker LINKER_LIBS += LINKER_DIRS += # arg 1 = file name define INLINE_FILE $(if $(wildcard $(1)),$(shell sed -e '/^ *\(#.*\)\?$$/d' '$(1)'),) endef # Load custom options. TODO: get options working. For some reason I # can't get the C and CPP files to rebuild when the options file changes. # arg 1 = unit name # arg 2 = options category define LOAD_OPTIONS $(call INLINE_FILE,$(call optf,$(1),$(2))) endef # FUNCTIONS: COMPILE_CPP, COMPILE_C, GENERATE_DEPS_CPP, GENERATE_DEPS_C # arg1: unit name (ex: "Main" or "Crypto/Rijndael") # arg2: file location (ex: "$(SRC_DIR)" or "$(GEN_DIR)") # arg3: additional compiler options ifdef SLOW_DEPENDENCY_TECHNIQUE # Proper dependency technique define GENERATE_DEPS_CPP $(p2)mkdir -p $(dir $(call depf,$(1))) $(p1)$(CPP_COMPILER) \ -MM -MT '$$(OBJ_DIR)/$(1)$(_obj) $$(DEP_DIR)/$(1).d' \ -MF $(DEP_DIR)/$(1).d \ $(patsubst %,-I%,$(call unitd,$*)) \ $(CPP_STANDARD_OPTIONS) $(3) \ $(2)/$(1).cpp endef define GENERATE_DEPS_C $(p2)mkdir -p $(dir $(call depf,$(1))) $(p1)$(C_COMPILER) \ -MM -MT '$$(OBJ_DIR)/$(1)$(_obj) $$(DEP_DIR)/$(1).d' \ -MF $(DEP_DIR)/$(1).d \ $(patsubst %,-I%,$(call unitd,$*)) \ $(CPP_STANDARD_OPTIONS) $(3) \ $(2)/$(1).c endef define COMPILE_CPP $(p2)mkdir -p $(dir $@) $(p1)$(CPP_COMPILER) \ $(patsubst %,-I%,$(call unitd,$*)) \ $(CPP_STANDARD_OPTIONS) $(3) \ -o '$@' -c '$<' endef define COMPILE_C $(p2)mkdir -p $(dir $@) $(p1)$(C_COMPILER) \ $(patsubst %,-I%,$(call unitd,$*)) \ $(C_STANDARD_OPTIONS) $(3) \ -o '$@' -c '$<' endef else # Fast dependency technique define COMPILE_CPP $(p2)mkdir -p $(dir $@) $(p2)mkdir -p $(DEP_DIR)/$(2) $(p1)$(CPP_COMPILER) \ -MMD -MF $(DEP_DIR)/$(1).d \ $(patsubst %,-I%,$(call unitd,$*)) \ $(CPP_STANDARD_OPTIONS) $(3) \ -o '$@' -c '$<' endef define COMPILE_C $(p2)mkdir -p $(dir $@) $(p2)mkdir -p $(DEP_DIR)/$(2) $(p1)$(C_COMPILER) \ -MMD -MF $(DEP_DIR)/$(1).d \ $(patsubst %,-I%,$(call unitd,$*)) \ $(C_STANDARD_OPTIONS) $(3) \ -o '$@' -c '$<' endef endif define PREPROCESS_CPP $(p2)mkdir -p $(dir $@) $(p1)$(CPP_COMPILER) \ $(patsubst %,-I%,$(call unitd,$*)) \ $(CPP_STANDARD_OPTIONS) $(3) \ -E -o '$@' -c '$<' endef define PREPROCESS_C $(p2)mkdir -p $(dir $@) $(p1)$(C_COMPILER) \ $(patsubst %,-I%,$(call unitd,$*)) \ $(C_STANDARD_OPTIONS) $(3) \ -E -o '$@' -c '$<' endef # arg1: unit name (ex: "Main" or "Crypto/Rijndael") # arg2: file location (ex: "$(SRC_DIR)" or "$(GEN_DIR)") # arg3: additional compiler options OBJ_FILES = $(UNITS:%=$(OBJ_DIR)/%$(_obj)) .PHONY: default image compile default: image compile: $(OBJ_FILES) #--------------------------------------------------------------------- # C/C++ Compilation #--------------------------------------------------------------------- define COMMON_TEMPLATE $(PRE_DIR)/%.$$(EXT_$(2)): $$($(1)_DIR)/%.$$(EXT_$(2)) $(DEP_DIR)/%.d # Preprocessing $$*.$$(EXT_$(2)) $$(call PREPROCESS_$(2),$$*,$$($(1)_DIR),) endef # FUNCTION: COMPILATION_TEMPLATE # arg 1: the location of the source file (SRC, GEN) # arg 2: the language (C, CPP) ifdef SLOW_DEPENDENCY_TECHNIQUE # Proper dependency technique define COMPILATION_TEMPLATE $(DEP_DIR)/%.d: $$($(1)_DIR)/%.$$(EXT_$(2)) # (d: $$*.$$(EXT_$(2))) $$(call GENERATE_DEPS_$(2),$$*,$($(1)_DIR),) $(OBJ_DIR)/%$(_obj): $$($(1)_DIR)/%.$$(EXT_$(2)) $(DEP_DIR)/%.d # Compiling $$*.$$(EXT_$(2)) $$(call COMPILE_$(2),$$*,$$($(1)_DIR),) $(call COMMON_TEMPLATE,$(1),$(2)) endef else # Fast dependency technique define COMPILATION_TEMPLATE $(OBJ_DIR)/%$(_obj): $$($(1)_DIR)/%.$$(EXT_$(2)) # Compiling $$*.$$(EXT_$(2)) $$(call COMPILE_$(2),$$*,$$($(1)_DIR),) $(call COMMON_TEMPLATE,$(1),$(2)) endef endif # Invoke the template for every permutation. LANGUAGES := C CPP COMPILE_INPUT_DIRS := SRC GEN $(foreach compile_input_dir,$(COMPILE_INPUT_DIRS),\ $(foreach language,$(LANGUAGES),$(eval $(call COMPILATION_TEMPLATE,$(compile_input_dir),$(language))))) #------------------------------------------ # Generic code-generation rule $(GEN_DIR)/%: $(SRC_DIR)/%.gen # Generating $* $(p2)test -x "$<" || chmod +x "$<" $(p2)mkdir -p $(dir $@) $(p1)(cd $(dir $<) && ./$(notdir $<)) > $@ || (rm "$@" && false) # ----------------------------------------- # For explicit dependencies on generated .h files. # If I could figure out how to do this automatically, I would. # FUNCTION: DEPENDENCY_TEMPLATE # arg 1: C/C++ unit name # arg 2: file that the unit depends on (relative to Source directory) ifdef SLOW_DEPENDENCY_TECHNIQUE # Proper dependency technique define DEPENDENCY_TEMPLATE $(OBJ_DIR)/$(1)$(_obj): $(GEN_DIR)/$(2) $(DEP_DIR)/$(1).d: $(GEN_DIR)/$(2) endef else # Fast dependency technique define DEPENDENCY_TEMPLATE $(OBJ_DIR)/$(1)$(_obj): $(GEN_DIR)/$(2) endef endif ADD_UNIT_DEPENDENCY = $(eval $(call DEPENDENCY_TEMPLATE,$(1),$(2))) # ----------------------------------------- # Include dependencies (unless target is 'clean') ifneq ($(MAKECMDGOALS),clean) -include $(UNITS:%=$(DEP_DIR)/%.d) endif #------------------------------------------ # Flex and Bison $(GEN_DIR)/%.cpp: $(SRC_DIR)/%.l # Flexifying $*.l $(p2)mkdir -p $(dir $@) $(p1)$(FLEX) $(call LOAD_OPTIONS,$*,flex) -o'$@' '$<' define MOVE_IF_EXISTS if [ -f '$(1)' ]; then mv '$(1)' '$(2)'; fi endef $(GEN_DIR)/%.cpp $(GEN_DIR)/%.h: $(SRC_DIR)/%.y % # Bisonizing $*.y $(p2)mkdir -p $(dir $@) $(p1)$(BISON) $(call LOAD_OPTIONS,$*,bison) --output='$(GEN_DIR)/%.cpp' '$<' $(p2)$(call MOVE_IF_EXISTS,$(GEN_DIR)/%.hpp,$(GEN_DIR)/%.h) $(p2)$(call MOVE_IF_EXISTS,$(GEN_DIR)/%.cpp.h,$(GEN_DIR)/%.h) #--------------------------------------------------------------------- # Clean #--------------------------------------------------------------------- FILES_TO_REMOVE = $(wildcard $(GEN_DIR) $(OBJ_DIR) $(DEP_DIR) $(PRE_DIR) $(IMAGE_FILE)) .PHONY: clean clean: ifneq ($(FILES_TO_REMOVE),) rm -r $(FILES_TO_REMOVE) endif