Make organization++
[henge/webcc.git] / make / lib / premake.mk
diff --git a/make/lib/premake.mk b/make/lib/premake.mk
new file mode 100644 (file)
index 0000000..f5aca93
--- /dev/null
@@ -0,0 +1,55 @@
+#PREMAKE_SOURCE_COMPILER#########################################################
+# Compile any source-to-source languages before executing the majority of make ##
+#################################################################################
+define PREMAKE_SOURCE_COMPILER =
+# Find the sources for each source-to-source language
+$(foreach slang,$(SLANGS),
+$(eval SLANG_SRC := $(shell find $(SRC_DIR) -name "*.$(slang)" -not -name ".*"))
+# Foreach target type in the source-to-source language, add this source's
+# targets to the list of the current source-to-source language targets
+$(eval undefine SLANG_TRG)
+$(foreach trg,$($(slang)_TRG),
+$(eval SLANG_TRG += $(SLANG_SRC:%.$(slang)=%.$(if $($(slang)_STEM),$($(slang)_STEM).)$(trg))))
+# Stat the source file's last-modified time to the var SRC_TIME
+$(foreach src,$(SLANG_SRC),
+# Establish a command to run for compiling this file
+$(eval SHELL_CMD := cd $(dir $(src)) && $($(slang)_C) $($(slang)_FLAGS) $(notdir $(src)))
+# Evaluate missing targets
+$(eval FOUND_TRG := $(shell find $(dir $(src)) -name "$(basename $(notdir $(src))).*" -not -name ".*"))
+$(eval MISSING_TRG := $(filter-out $(FOUND_TRG), $(SLANG_TRG)))
+# Check timings of existing files
+$(eval SRC_TIME := $(shell stat -c %Y $(src)))
+# For each of the targets created by this source language, evaluate the
+# last-modified times of each potential target.  If the file does not exist, set
+# the time to '0', otherwise set it to the -c %Y result from statting the file.
+$(foreach srctrg,$(filter $(basename $(src))%, $(SLANG_TRG)),
+$(eval TRG_TIMES += $(if $(wildcard $(srctrg)),$(shell stat -c %Y $(srctrg)),0)==$(srctrg)))
+# Sort TRG_TIMES, which will produce a list of oldest-first files and timestamps
+# of the form [last-modified-deltatime]==[filename]
+$(eval TRG_TIMES := $(shell echo $(sort $(TRG_TIMES)) | $(call AWK_REVERSE_SQUASH)))
+# Evaluate the newest time from our ordered list by splitting the word up by its
+# '==' connectors and looking at the first word
+$(eval NEWEST_TRG_TIME := $(word 1,$(subst ==, ,$(TRG_TIMES))))
+# Find the older of the two times (between SRC_TIME and NEWEST_TRG_TIME)
+$(eval OLDER_TIME := $(firstword $(sort $(NEWEST_TRG_TIME) $(SRC_TIME))))
+# If the older of the two times is the newest target time found, then we need to
+# rebuild, but only if our build rule intends to actually make something.  If it
+# instead does not intend to actually make a target, drop a functional rule that
+# could hypothetically make the target for debugging and analysis purposes
+$(if $(MAKECMDGOALS),
+$(eval BUILDGOALS := $(filter-out clean scrub purge uninstall,$(MAKECMDGOALS))),
+$(eval BUILDGOALS := all))
+$(if $(and $(BUILDGOALS),$(or $(MISSING_TRG), $(filter $(OLDER_TIME),$(NEWEST_TRG_TIME)))),
+$(if $(findstring n,$(MAKEFLAGS)),
+$(SLANG_TRG):
+       $(SHELL_CMD)
+,
+$(info $(SHELL_CMD) $(eval $(shell $(SHELL_CMD)))))
+))
+# Put these targets on the MAKE_TARGETS list to be removed during "clean",
+# regardless of whether or not they were built just now.
+$(eval MAKE_TARGETS += $(SLANG_TRG))
+)
+#/PREMAKE_SOURCE_COMPILER########################################################
+endef
+