#### # kbuild: Generic definitions # Convenient variables comma := , squote := ' #' empty := space := $(empty) $(empty) BUILD_DIR_NAME = _build COMPILED_DIR_NAME = _compiled USER_INCLUDE_DIR := $(OUTPUT_DIR)/$(COMPILED_DIR_NAME)/include USER_LIB_DIR := $(OUTPUT_DIR)/$(COMPILED_DIR_NAME)/lib USER_UTILS_DIR := $(OUTPUT_DIR)/$(COMPILED_DIR_NAME)/bin-utils USER_TESTS_DIR := $(OUTPUT_DIR)/$(COMPILED_DIR_NAME)/bin-tests USER_BIN_DIR := $(OUTPUT_DIR)/$(COMPILED_DIR_NAME)/bin USER_BUILD_DIR := $(OUTPUT_DIR)/$(BUILD_DIR_NAME)/user LINK_BUILD_DIR := $(OUTPUT_DIR)/$(BUILD_DIR_NAME)/link USER_OBJS_DIR = $(USER_BUILD_DIR)/$(RELATIVE_DIR) KERN_OBJS_DIR = $(KERN_BUILD_DIR)/$(RELATIVE_DIR) OMK_WORK_DIR = $(USER_OBJS_DIR) strip_out = $(patsubst $(OUTPUT_DIR)/%,%,$(1)) repl_out = $(patsubst $(OUTPUT_DIR)/%,$$(OUTPUT_DIR)/%,$(1)) .PHONY: FORCE ##################### # Build pseudo-pass # ##################### rule_targets = $($(1)_targets) rule_deps = $($(1)_deps) rule_msg = $($(1)_msg) rule_cmd = $($(1)_cmd) # Usage: $(call build_rule,) define build_rule $(rule_target): $(rule_deps) $(omk_inc_file) @$(QUIET_CMD_ECHO) " "$(rule_msg) "$$(call strip_out,$$(@))" $(Q)$(rule_cmd) endef # TODO: Include target.omk only in the subtree -include $(shell true; find $(USER_BUILD_DIR) -name '*omk.inc') # `true' is a hack for MinGW $(foreach rule,$(prepared_rules),$(eval $(call build_rule,$(rule)))) .PHONY: build-pseudo-pass build-pseudo-pass: $(foreach target,$(default_build_targets),$(target)) ################ # Prepare pass # ################ $(eval $(call omk_pass_template,prepare-pass,$(USER_OBJS_DIR),,always)) ### # Name of the prepared rule. This name is used as prefix of variable # names in .omk.inc and is based on the first target omk_inc_rule = $(firstword $(1:$(OUTPUT_DIR)/%=%)) # The name of .omk.inc file is derived from $(omk_inc_rule) and # depends whether the target is under _build or elsewhere. omk_inc_file = $(if $(filter $(BUILD_DIR_NAME)%,$(omk_inc_rule)),\ $(OMK_WORK_DIR)/$(notdir $(omk_inc_rule)).omk.inc,\ $(OMK_WORK_DIR)/$(subst /,_,$(omk_inc_rule)).omk.inc) target_omk_file = $(OMK_WORK_DIR)/$(notdir $(1)).target.omk ### # prepare_rule is used to generate .omk.inc files during prepare-pass. # All paths in this file should be relative to $(OUTPUT_DIR) # Usage: $(call prepare_rule,,,,) define prepare_rule prepare-pass-local: $(omk_inc_file) $(omk_inc_file): FORCE $(Q)echo 'prepared_rules += $(omk_inc_rule)' > $$@.tmp; \ echo '$(omk_inc_rule)_targets = $$(call strip_out,$(1))' >> $$@.tmp; \ echo '$(omk_inc_rule)_deps += $$(call strip_out,$(2))' >> $$@.tmp; \ echo '$(omk_inc_rule)_msg = $(3)' >> $$@.tmp; \ echo '$(omk_inc_rule)_cmd = $$(call repl_out,$(4))' >> $$@.tmp; \ if cmp -s $$@.tmp $$@; then rm $$@.tmp; else mv $$@.tmp $$@; fi endef ### # prepare_rule_default - same as prepare rules but the target is put # as dependency to the default build rule, which causes it to be built # upon calling make define prepare_rule_default $(call prepare_rule,$(1),$(2),$(3),$(4)) prepared_default_build_targets += $(call strip_out,$(1)) endef prepare-pass-local: $(OMK_WORK_DIR)/omk.inc $(OMK_WORK_DIR)/omk.inc: FORCE $(Q)echo 'default_build_targets += $(prepared_default_build_targets)' > $@.tmp; \ if cmp -s $@.tmp $@; then rm $@.tmp; else mv $@.tmp $@; fi ############ # Programs # ############ # Usage: $(call program_template,,) define program_template $(1)_OBJS += $$(patsubst %.c,%.o,$$(filter %.c,$$($(1)_SOURCES))) $(1)_OBJS := $$(addprefix $(USER_OBJS_DIR),$$(sort $$($(1)_OBJS:%/=%))) USER_OBJS += $$($(1)_OBJS) USER_SOURCES += $$($(1)_SOURCES) program_cmd = $$(if $$(filter %.cc,$$($(1)_SOURCES)),$$(CXX),$$(CC)) \ $$($(1)_OBJS) $$($(1)_LIBS:%=-l%) $$(LOADLIBES) $$(LDFLAGS) -Wl,-rpath-link,$(USER_LIB_DIR) \ -Wl,-Map,$(USER_OBJS_DIR)/$(1).exe.map -o $$$$@ $(call prepare_rule_default,\ $(USER_BIN_DIR)/$(1)$(EXE_SUFFIX),\ $$($(1)_OBJS) $$($(1)_LIBS),\ "LINK ",\ $$(program_cmd)) endef c_o_cmd := set -e; cd $$(dir $$@); \ if $$(c_o_COMPILE) $$(CC_DEPFLAGS) -o $$@ -c $$< ; \ then mv -f "$$@.d.tmp" "$$@.d" ; \ else rm -f "$$@.d.tmp" ; \ fi $(foreach prog,$(bin_PROGRAMS),$(eval $(call program_template,$(prog),bin))) $(foreach src,$(filter %.c,$(USER_SOURCES)),$(eval $(call prepare_rule,\ $(USER_OBJS_DIR)/$(src:%.c=%.o),\ $(SOURCES_DIR)/$(src),\ "CC ",\ $(c_o_cmd)))) default: prepare-pass $(MAKE) -qp build-pseudo-pass > make.dp.build-pseudo-pass $(MAKE) build-pseudo-pass