# This makefile manages a build environment targeting native platforms with gcc
# and web platforms with either emscripten or binaryen (js or wasm).
################################################################################
-# Each .c file is automatically compiled into an environment-dependent object
+# Each .c file is autopresidential debate california timematically compiled into an environment-dependent object
# file of compiler-specific format (.o for gcc, .bc for llvm/emcc/em++).
################################################################################
default: all
# Source languages handled by this build system
LANGS := c cpp go
# Source-to-source languages handled by this build system
-SLANGS := y
+SLANGS := y rl
# Language-specific compilers and flags passed in from environment
c_C := $(strip $(notdir $(CC)))
c_FLAGS := $(strip $(CFLAGS)) -I.
go_C := gccgo
go_FLAGS := $(c_FLAGS)
# Source to source languages
+# Bison
y_C := bison
y_FLAGS := -d
y_STEM := tab
y_TRG := c h
+# Ragel
+rl_C := ragel
+rl_FLAGS := -C
+rl_TRG := c
# Compiler-specific associations. Each compiler has a binary object suffix
# (OBJ), an archiver (AR), and an archiver object suffix (AROBJ). Each compiler
# may optionally have defined a linker (LD), and a binary output suffix (OUT).
# binaries.
MODULES := $(filter-out $(DRIVER_DIR),$(subst /,,$(shell ls -d */)))
+#AWK_REVERSE_SQUASH##############################################################
# The following awk program reverses the order of a list while also removing
# duplicate entries. The effect of this when run on the dependency tree is that
# it will remove duplicates occurring in reverse order, allowing the most deeply
-# nested libraries to be built, and linked, first.
+# nested libraries to be built, and linked, first. ##############################
define AWK_REVERSE_SQUASH =
awk \
'
print ""
}
'
+#/AWK_REVERSE_SQUASH#############################################################
endef
-# Compile any source-to-source languages before executing the majority of make
+#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 := $(patsubst ./%,%,$(shell find -name "*.$(slang)")))
+$(eval SLANG_SRC := $(patsubst ./%, %,$(shell find -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)=%.$($(slang)_STEM:%=%.)$(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
# 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
+# rebuild, but only if our build rule intends to actually make something. If it
+# does not intend to make something, drop a functional rule to actually make the
+# target
$(if $(MAKECMDGOALS),
$(eval BUILDGOALS := $(filter-out clean scrub purge uninstall,$(MAKECMDGOALS))),
$(eval BUILDGOALS := all))
-$(if $(and $(BUILDGOALS),$(filter $(OLDER_TIME),$(NEWEST_TRG_TIME))),
-$(eval SHELL_CMD := cd $(dir $(src)) && $($(slang)_C) $($(slang)_FLAGS) $(notdir $(src)))
-$(info $(SHELL_CMD) $(shell $(SHELL_CMD)))
-)
+$(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
# Compile a source language to a language that compiles to binary, but only if
# our build rule intends to build some kind of target
$(filter-out \ %:,$(shell $($2_C) $3 $4 -MG $1 2> /dev/null))
endef
+#SRC_LANG_RULE###################################################################
# Given a source and a language, generate a rule to make the object. The second
# invocation of gcc per file lists only its local includes, and filters out
# anything already caught. Anything remaining should be considered to be
# available in the current working directory of the source file(i.e. if you
# '#include "something.h"' in 'mymodule/horseradish.c', you would expect to
# include 'mymodule/something.h'. this check lets that happen), otherwise it is
-# some kind of user error
+# some kind of user error #######################################################
define SRC_LANG_RULE =
$(if $($1),,$(eval $1 := t)\
$(eval MOD := $(filter $(MODULES),$(firstword $(subst /, ,$(dir $1)))))\
-$(eval FLG := $($2_FLAGS) $(MOD:%=-I% ))\
+$(eval FLG := $(MOD:%=-I% ))\
$(if $(wildcard $1),
$(eval DEPS := $(filter-out \ %:,$(shell $($2_C) $(FLG) -M -MG $1)))\
$(eval MDEPS := $(filter $(MODULES:%=%/%),$(DEPS)))\
$(eval ALLDEPS := $(MDEPS) $(DEPS)),\
$(error Cannot generate deps for: $1, file not found))\
$(eval SRC_OBJ := $(basename $1).$($2_OBJ))\
-$(eval MAKE_TARGETS += $(SRC_OBJ))\
-
+$(eval MAKE_TARGETS += $(SRC_OBJ))
+# Assume that lost dependencies are in the folder with the source
+$(foreach lost,$(LOST),
+$(eval ALLDEPS := $(subst $(lost), $(dir $1)$(lost),$(ALLDEPS))))
+
+# Find any deps that aren't built yet, which the compiler has flagged
+# as missing, but which we know the expected location of libs for
+# this language should have their includes in 'LIBINC_DIR'
+$(eval BUILDDEPS := $(filter $($2_LIBS:%=%/%),$(ALLDEPS)))
+$(eval ALLDEPS := $(filter-out $(BUILDDEPS),$(ALLDEPS)) $(BUILDDEPS:%=$(LIBINC_DIR)/%))
# Object for $1
$(SRC_OBJ): $(ALLDEPS)
$($2_C) $$($2_FLAGS) $(FLG) -c -o $$@ $1
$(eval DBG_OBJ := $(dir $1).$($2_DBG)/$(basename $(notdir $1)).$($2_OBJ))\
$(if $(findstring $(dir $(DBG_OBJ)),$(MAKE_DIRS)),,\
$(eval MAKE_DIRS += $(dir $(DBG_OBJ))))
+$(eval MAKE_TARGETS += $(DBG_OBJ))
# Object for $1 with $($2_DBG) symbols
$(DBG_OBJ): $(ALLDEPS) | $(dir $(DBG_OBJ))
$($2_C) $$($2_FLAGS) $(FLG) -Og -g$($2_DBG) -c -o $$@ $1
))
+#/SRC_LANG_RULE##################################################################
endef
+#SRC_LANG_DRVRULE################################################################
# establish a build and link rule given a source driver and language ############
define SRC_LANG_DRVRULE =
$(eval DRIVER_NAME := $(basename $(notdir $1)))
# any internal modules, the developer may instead create a file with the same
# basename as the driver, but with the '.ld' suffix, which contains a space
# separated list of internal modules to link together during compilation
-$(eval DRIVER_MODULES += $(file <$(1:%.$2=%.ld)))
+$(eval DRIVER_LDVALS := $(file <$(1:%.$2=%.ld)))
+$(eval DRIVER_LFLAGS := $(filter -l%,$(DRIVER_LDVALS)))
+$(eval DRIVER_MODULES += $(filter-out -l%,$(DRIVER_LDVALS)))
# List of module archives to link together during compilation
$(eval DRIVER_ARCHIVES := $(DRIVER_MODULES:%=%.$($2_AROBJ)))
# '_start'). This driver object is then simply linked to its libraries and
# module archives to create an executable binary in the output folder.
# ORDER MATTERS HERE, this is for the linker:
-$(eval DRIVER_SRC := $(DRIVER_DEPS))
-$(eval DRIVER_DBGSRC := $(DRIVER_DBGDEPS))
+$(eval DRIVER_SRC := $(DRIVER_LFLAGS) $(DRIVER_DEPS))
+$(eval DRIVER_DBGSRC := $(DRIVER_LFLAGS) $(DRIVER_DBGDEPS))
# Iterate through the list of libraries in our language and stack commands from
# left to right in the "sources" section of the LD command (or LD section of the
# commandline for the compiler), to preserve ordering and also ensure that it is
$(eval DRIVER_DBGTARG := $(DRIVER_TARG_DIR)$(basename $(notdir $(DRIVER_TARG)))-d$($2_OUT))
$(eval SCRUB_TARGETS += $(DRIVER_DBGTARG))
$(eval MAKE_DIRS += $(DRIVER_TARG_DIR).$($2_DBG)/)
-$(DRIVER_DBGTARG): $(DRIVER_DBGDEPS) | $(DRIVER_TARG_DIR).$($2_DBG)/
+$(DRIVER_DBGTARG): $(DRIVER_DBGDEPS) | $(DRIVER_TARG_DIR)
$($2_C) $($2_FLAGS) $(DRIVER_DBGSRC) -o $$@
# Make a rule to run this driver after building
$(DRIVER_NAME)-run: $(DRIVER_TARG)
$(DRIVER_TARG)
$(DRIVER_NAME)-d: $(DRIVER_DBGTARG)
-#/SRC_LANG_DRVRULE##############################################################
+#/SRC_LANG_DRVRULE###############################################################
endef
+#MODULE_ARCRULE##################################################################
# generate rule for turning an entire module's collection of binary objects into
# a single locally-linked (no external -L libs) object (for simplified linking
-# modules as static libs).
+# modules as static libs).#######################################################
define MODULE_ARCRULE =
$(eval ARCDEPS := $(filter $1/%.$(c_OBJ),$(foreach lang,$(LANGS),$($(lang)_MOD_TRG))))\
-$(eval MAKE_TARGETS += $1.$(c_AROBJ))\
+$(eval MAKE_TARGETS+= $1.$(c_AROBJ))\
+
$1.$(c_AROBJ): $(ARCDEPS)
$(c_AR) cr $$@ $$^
$(if $(c_DBG),
$(eval undefine DBGARCDEPS)
$(foreach arcdep,$(ARCDEPS),$(eval DBGARCDEPS += $(dir $(arcdep)).$(c_DBG)/$(notdir $(arcdep))))
-$(eval MAKE_TARGETS += .$(c_DBG)/$1.$(c_AROBJ))\
+$(eval MAKE_TARGETS+= .$(c_DBG)/$1.$(c_AROBJ))\
.$(c_DBG)/$1.$(c_AROBJ): $(DBGARCDEPS) | .$(c_DBG)/
$(c_AR) cr $$@ $$^
)
+#/MODULE_ARCRULE#################################################################
endef
# LANG_LIB_PARENT_BUILDRULE######################################################
$1_OBJ := $($($1_C)_OBJ)
$1_OUT := $($($1_C)_OUT)
$1_AROBJ := $($($1_C)_AROBJ)
-$1_SOURCES := $(subst ./,,$(shell find -name "*.$1"))
+$1_SOURCES := $(subst ./,,$(shell find -name "*.$1" -not -name ".*"))
$1_DBG := $($($1_C)_DBG)
$1_AR := $($($1_C)_AR)
)
@echo Build Complete
# Rule to make any dirs that we're in charge of
-$(MAKE_DIRS):
+$(sort $(MAKE_DIRS)):
@mkdir -p $@
# Cleaning rules.