empty :=
space := $(empty) $(empty)
+###
+# Escape single quote for use in echo statements
+escsq = $(subst $(squote),'\$(squote)',$1)
+
BUILD_DIR_NAME = _build
COMPILED_DIR_NAME = _compiled
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)
+# Avoid double slash at the end in the top-level directory
+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))
target_omk_file = $(OMK_WORK_DIR)/$(notdir $(1)).target.omk
+# >'< substitution is for echo to work,
+# >$< substitution to preserve $ when reloading .omk.inc file
+subst-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(1))))
+
###
# prepare_rule is used to generate .omk.inc files during prepare-pass.
# All paths in this file should be relative to $(OUTPUT_DIR)
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; \
+ echo '$(omk_inc_rule)_cmd = $$(call subst-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
+# prepare_rule_goal - same as prepare rules but the target is put
+# as dependency to the default goal, which causes it to be built
# upon calling make
-define prepare_rule_default
+define prepare_rule_goal
$(call prepare_rule,$(1),$(2),$(3),$(4))
-prepared_default_build_targets += $(call strip_out,$(1))
+prepared_goals += $(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; \
+ $(Q)echo 'omk_goals += $(prepared_goals)' > $@.tmp; \
if cmp -s $@.tmp $@; then rm $@.tmp; else mv $@.tmp $@; fi
# Programs #
############
+# Check GCC version for user build
+ifndef CC_MAJOR_VERSION
+CC_MAJOR_VERSION := $(shell $(CC) -dumpversion | sed -e 's/\([^.]\)\..*/\1/')
+endif
+# Prepare suitable define for dependency building
+ifeq ($(CC_MAJOR_VERSION),2)
+CC_DEPFLAGS = -Wp,-MD,"$@.d.tmp"
+else
+CC_DEPFLAGS = -MT $@ -MD -MP -MF "$@.d.tmp"
+endif
+
+c_o_COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -DOMK_FOR_USER
+
+c_o_cmd = set -e; \
+ if $$(c_o_COMPILE) $$(CC_DEPFLAGS) -o $$$$@ -c $$$$< ; \
+ then mv -f "$$@.d.tmp" "$$@.d" ; \
+ else rm -f "$$@.d.tmp" ; \
+ fi
+
+
# Usage: $(call program_template,<executable-name>,<bin|utils|test>)
define program_template
$(1)_OBJS += $$(patsubst %.c,%.o,$$(filter %.c,$$($(1)_SOURCES)))
-$(1)_OBJS := $$(addprefix $(USER_OBJS_DIR),$$(sort $$($(1)_OBJS:%/=%)))
+$(1)_OBJS := $$(addprefix $(USER_OBJS_DIR)/,$$(sort $$($(1)_OBJS:%/=%)))
USER_OBJS += $$($(1)_OBJS)
USER_SOURCES += $$($(1)_SOURCES)
$$($(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,\
+$(call prepare_rule_goal,\
$(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),\
"CC ",\
$(c_o_cmd))))
+# OUTPUT_DIR is not defined in Makefile.build so we has to pass it on
+# command-line. After this file will be merged with Makefile.rules, it
+# will not be necessary to pass it.
default: check-dir prepare-pass
- $(MAKE) -qp -f Makefile.build > make.db.build-pseudo-pass; \
- $(MAKE) -f Makefile.build
+ -$(MAKE) -qp -f Makefile.build OUTPUT_DIR=$(OUTPUT_DIR) > make.db.build-pseudo-pass;
+ $(MAKE) -f Makefile.build OUTPUT_DIR=$(OUTPUT_DIR)
check-dir:
@$(call mkdir_def,$(USER_BUILD_DIR))
@$(call mkdir_def,$(USER_BIN_DIR))
@$(call mkdir_def,$(USER_UTILS_DIR))
@$(call mkdir_def,$(USER_TESTS_DIR))
+
+# Local Variables:
+# mode: makefile-gmake
+# compile-command:"make -qp V=2 > make.db; make V=2"
+# End: