[Pkg-virtualbox-commits] [kbuild] 01/03: Imported Upstream version 0.1.9998svn2780+dfsg

Gianfranco Costamagna locutusofborg-guest at moszumanska.debian.org
Tue Apr 28 19:01:23 UTC 2015


This is an automated email from the git hooks/post-receive script.

locutusofborg-guest pushed a commit to branch master
in repository kbuild.

commit 98ec982ba2a4ca945cb58d5ad187b936b5aff8e6
Author: Gianfranco Costamagna <costamagnagianfranco at yahoo.it>
Date:   Mon Apr 27 00:27:04 2015 +0200

    Imported Upstream version 0.1.9998svn2780+dfsg
---
 kBuild/footer-pass1.kmk                   |   42 +-
 kBuild/footer-pass2-compiling-targets.kmk |   32 +-
 kBuild/header.kmk                         |   30 +-
 kBuild/subfooter.kmk                      |   26 +-
 kBuild/subheader.kmk                      |   25 +-
 kBuild/tools/ALP.kmk                      |    4 +-
 kBuild/tools/GCC3.kmk                     |   26 +-
 kBuild/tools/GCC32.kmk                    |   26 +-
 kBuild/tools/GCC3OMF.kmk                  |   40 +-
 kBuild/tools/GCC64.kmk                    |   20 +-
 kBuild/tools/GXX3.kmk                     |   26 +-
 kBuild/tools/GXX32.kmk                    |   26 +-
 kBuild/tools/GXX3OMF.kmk                  |   42 +-
 kBuild/tools/GXX64.kmk                    |   20 +-
 kBuild/tools/JWASM.kmk                    |    6 +-
 kBuild/tools/MASM510.kmk                  |    4 +-
 kBuild/tools/MASM600.kmk                  |    4 +-
 kBuild/tools/MASM610.kmk                  |    4 +-
 kBuild/tools/MASM6PLUS.kmk                |    6 +-
 kBuild/tools/MASM710.kmk                  |    4 +-
 kBuild/tools/MINGW32.kmk                  |    4 +-
 kBuild/tools/MINGWW64.kmk                 |    4 +-
 kBuild/tools/NASM.kmk                     |    4 +-
 kBuild/tools/OPENWATCOM-16.kmk            |   16 +-
 kBuild/tools/OPENWATCOM-WL.kmk            |    4 +-
 kBuild/tools/OPENWATCOM.kmk               |   25 +-
 kBuild/tools/TAR.kmk                      |    6 +-
 kBuild/tools/VAC308.kmk                   |    6 +-
 kBuild/tools/WATCOMC11C-16.kmk            |   14 +-
 kBuild/tools/WATCOMC11C-WL.kmk            |    4 +-
 kBuild/tools/WATCOMC11C.kmk               |   23 +-
 kBuild/tools/WGET.kmk                     |    6 +-
 kBuild/tools/XGCCAMD64LINUX.kmk           |    4 +-
 kBuild/tools/YASM.kmk                     |    4 +-
 kBuild/tools/ZIP.kmk                      |   14 +-
 src/kmk/Makefile.kmk                      |   22 +-
 src/kmk/commands.c                        |   21 +
 src/kmk/commands.h                        |    3 +
 src/kmk/config.h.win                      |   27 +-
 src/kmk/dir.c                             |    4 +
 src/kmk/expand.c                          |  101 +-
 src/kmk/function.c                        |   91 +-
 src/kmk/job.c                             |   19 +-
 src/kmk/kbuild.c                          |    9 +-
 src/kmk/kmk_cc_exec.c                     | 2027 +++++++++++++++++++++++++++++
 src/kmk/kmk_cc_exec.h                     |   45 +
 src/kmk/kmkbuiltin/append.c               |   10 +-
 src/kmk/kmkbuiltin/echo.c                 |    8 +
 src/kmk/kmkbuiltin/kDepObj.c              |    3 +-
 src/kmk/kmkbuiltin/mscfakes.c             |  167 ++-
 src/kmk/kmkbuiltin/mscfakes.h             |   33 +-
 src/kmk/kmkbuiltin/redirect.c             |   74 +-
 src/kmk/main.c                            |   19 +-
 src/kmk/make.h                            |    7 +
 src/kmk/read.c                            |   10 +
 src/kmk/remake.c                          |    7 +
 src/kmk/variable.c                        |  226 +++-
 src/kmk/variable.h                        |   58 +-
 58 files changed, 3172 insertions(+), 370 deletions(-)

diff --git a/kBuild/footer-pass1.kmk b/kBuild/footer-pass1.kmk
index d77c59e..141e618 100644
--- a/kBuild/footer-pass1.kmk
+++ b/kBuild/footer-pass1.kmk
@@ -1,4 +1,4 @@
-# $Id: footer-pass1.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: footer-pass1.kmk 2764 2015-01-28 18:51:46Z bird $
 ## @file
 # kBuild - Footer - Target lists - Pass 1.
 #
@@ -107,13 +107,9 @@ ifeq ($(insttype),)
    local insttype := both
  endif
 endif
-ifn1of ($(insttype), none both stage)
- $(error kBuild: Unknown value '$(insttype)' for '$(target)_INSTTYPE'. Valid values are 'none', 'both' and 'stage'.)
-endif
 $(target)_1_INSTTYPE := $(insttype)
 
-if1of ($(insttype), stage both)
- local inst := $(strip $(firstdefined \
+local inst := $(strip $(firstdefined \
 	$(target)_INST.$(bld_trg).$(bld_trg_arch).$(bld_type) \
 	$(target)_INST.$(bld_trg).$(bld_trg_arch) \
 	$(target)_INST.$(bld_trg).$(bld_type) \
@@ -124,7 +120,7 @@ if1of ($(insttype), stage both)
 	$(target)_INST \
 	definst \
 	,value))
- local stage := $(strip $(firstdefined \
+local stage := $(strip $(firstdefined \
 	$(target)_STAGE.$(bld_trg).$(bld_trg_arch).$(bld_type) \
 	$(target)_STAGE.$(bld_trg).$(bld_trg_arch) \
 	$(target)_STAGE.$(bld_trg).$(bld_type) \
@@ -135,6 +131,7 @@ if1of ($(insttype), stage both)
 	$(target)_STAGE \
 	inst \
 	,value))
+if1of ($(insttype), stage both)
  $(target)_1_STAGE := $(stage)
  if "$(substr $(stage),-1,1)" == "/" # Multicast support requires addprefix/suffix.
   $(target)_1_STAGE_TARGET := $(addprefix $(PATH_STAGE)/,$(addsuffix $(notdir $(out)),$(stage)))
@@ -143,9 +140,11 @@ if1of ($(insttype), stage both)
  else
   $(target)_1_STAGE_TARGET := $(addprefix $(PATH_STAGE)/,$(stage))
  endif
-else
+else if1of ($(insttype), none)
  $(target)_1_STAGE :=
  $(target)_1_STAGE_TARGET :=
+else
+ $(error kBuild: Unknown value '$(insttype)' for '$(target)_INSTTYPE'. Valid values are 'none', 'both' and 'stage'.)
 endif
 INSTARGET_$(target) := $($(target)_1_STAGE_TARGET)
 
@@ -174,9 +173,6 @@ local debug_insttype := $(firstword \
 	$($(target)_DEBUG_INSTTYPE.$(bld_type)) \
 	$($(target)_DEBUG_INSTTYPE) \
 	$(insttype) )
-ifn1of ($(debug_insttype), none both stage)
- $(error kBuild: Unknown value '$(debug_insttype)' for '$(target)_DEBUG_INSTTYPE'. Valid values are 'none', 'both' and 'stage'.)
-endif
 $(target)_1_DEBUG_INSTTYPE := $(debug_insttype)
 
 if1of ($(debug_insttype), stage both)
@@ -205,8 +201,10 @@ if1of ($(debug_insttype), stage both)
  ifndef $(target)_1_DEBUG_STAGE
   $(target)_1_DEBUG_STAGE := ./
  endif
-else
+else if1of ($(debug_insttype), none)
  $(target)_1_DEBUG_STAGE :=
+else
+ $(error kBuild: Unknown value '$(debug_insttype)' for '$(target)_DEBUG_INSTTYPE'. Valid values are 'none', 'both' and 'stage'.)
 endif
 
 if1of ($(debug_insttype), both)
@@ -244,7 +242,7 @@ define def_pass1_bldprog
 ifndef $(target)_INST
 $(target)_INSTTYPE := none
 endif
-$(evalval def_pass1_link_common)
+$(evalvalctx def_pass1_link_common)
 endef
 
 EXT     := EXE
@@ -253,7 +251,7 @@ definst := $(INST_BIN)
 tool_prefix := LD
 bld_trg_base_var := PLATFORM
 $(foreach target, $(_ALL_BLDPROGS), \
-	$(evalval def_pass1_bldprog))
+	$(evalvalctx def_pass1_bldprog))
 
 
 #
@@ -265,7 +263,7 @@ definst := $(INST_LIB)
 tool_prefix := AR
 bld_trg_base_var := TARGET
 $(foreach target, $(_ALL_LIBRARIES), \
-	$(evalval def_pass1_link_common))
+	$(evalvalctx def_pass1_link_common))
 
 
 #
@@ -277,7 +275,7 @@ definst := $(INST_DLL)
 tool_prefix := LD
 bld_trg_base_var := TARGET
 $(foreach target, $(_ALL_DLLS), \
-	$(evalval def_pass1_link_common))
+	$(evalvalctx def_pass1_link_common))
 
 
 #
@@ -293,7 +291,7 @@ if1of ($(KBUILD_TARGET), nt os2 win win64 win32)
  tool_prefix := AR
  bld_trg_base_var := TARGET
  $(foreach target, $(_ALL_IMPORT_LIBS), \
-	$(evalval def_pass1_link_common))
+	$(evalvalctx def_pass1_link_common))
 else
  EXT     := DLL
  EXTPRE  :=
@@ -301,7 +299,7 @@ else
  tool_prefix := LD
  bld_trg_base_var := TARGET
  $(foreach target, $(_ALL_IMPORT_LIBS), \
-	$(evalval def_pass1_link_common))
+	$(evalvalctx def_pass1_link_common))
 endif
 
 
@@ -314,7 +312,7 @@ definst := $(INST_BIN)
 tool_prefix := LD
 bld_trg_base_var := TARGET
 $(foreach target, $(_ALL_PROGRAMS), \
-	$(evalval def_pass1_link_common))
+	$(evalvalctx def_pass1_link_common))
 
 
 #
@@ -326,7 +324,7 @@ definst := $(INST_SYS)
 tool_prefix := LD
 bld_trg_base_var := TARGET
 $(foreach target, $(_ALL_SYSMODS), \
-	$(evalval def_pass1_link_common))
+	$(evalvalctx def_pass1_link_common))
 
 
 #
@@ -338,7 +336,7 @@ definst := $(INST_BIN)
 tool_prefix := LD
 bld_trg_base_var := TARGET
 $(foreach target, $(_ALL_MISCBINS), \
-	$(evalval def_pass1_link_common))
+	$(evalvalctx def_pass1_link_common))
 
 
 #
@@ -452,7 +450,7 @@ endef # def_pass1_install
 $(eval-opt-var def_pass1_install)
 
 $(foreach target, $(_ALL_INSTALLS), \
-	$(evalval def_pass1_install))
+	$(evalvalctx def_pass1_install))
 
 ifdef KBUILD_PROFILE_SELF
  $(evalcall def_profile_self, done pass 1)
diff --git a/kBuild/footer-pass2-compiling-targets.kmk b/kBuild/footer-pass2-compiling-targets.kmk
index 98f2866..23a5337 100644
--- a/kBuild/footer-pass2-compiling-targets.kmk
+++ b/kBuild/footer-pass2-compiling-targets.kmk
@@ -1,4 +1,4 @@
-# $Id: footer-pass2-compiling-targets.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: footer-pass2-compiling-targets.kmk 2762 2015-01-28 18:17:54Z bird $
 ## @file
 # kBuild - Footer - Target lists - Pass 2 - Compiling Targets.
 #
@@ -270,7 +270,7 @@ $(foreach source,\
 	$($(target)_SOURCES.$(bld_trg_arch))\
 	$($(target)_SOURCES.$(bld_trg_cpu))\
 	$($(target)_SOURCES.$(bld_type))\
-	,$(evalval def_src_handler_one) )
+	,$(evalvalctx def_src_handler_one) )
 
 $(foreach source,\
 	$($(target)_GEN_SOURCES_)\
@@ -281,7 +281,7 @@ $(foreach source,\
 	$($(target)_GEN_SOURCES_.$(bld_trg_arch))\
 	$($(target)_GEN_SOURCES_.$(bld_trg_cpu))\
 	$($(target)_GEN_SOURCES_.$(bld_type))\
-	,$(evalval def_src_handler_one) )
+	,$(evalvalctx def_src_handler_one) )
 endef # def_target_sources
 $(eval-opt-var def_target_sources)
 
@@ -406,18 +406,18 @@ if  (   defined($(target)_2_OUTPUT_DEBUG_DIRS) \
   local debug_inst_path   := $(PATH_INS)
   local debug_install_cmd := $(INSTALL)
   local debug_var         := INSTALL
-  $(foreach debug_inst, $($(target)_1_DEBUG_INST), $(evalval def_target_install_only_debug))
+  $(foreach debug_inst, $($(target)_1_DEBUG_INST), $(evalvalctx def_target_install_only_debug))
  endif
 
  local debug_inst_path    := $(PATH_STAGE)
  local debug_install_cmd  := $(INSTALL_STAGING)
  local debug_var          := STAGE
  if1of ($($(target)_1_DEBUG_INSTTYPE), stage both)
-  $(foreach debug_inst, $($(target)_1_DEBUG_STAGE), $(evalval def_target_install_only_debug))
+  $(foreach debug_inst, $($(target)_1_DEBUG_STAGE), $(evalvalctx def_target_install_only_debug))
  endif
  if1of ($($(target)_1_INSTTYPE), stage both)
   ifndef debug_nostage
-   $(foreach debug_inst,$($(target)_1_STAGE), $(evalval def_target_install_only_debug))
+   $(foreach debug_inst,$($(target)_1_STAGE), $(evalvalctx def_target_install_only_debug))
   endif
  endif
 
@@ -488,7 +488,7 @@ local units       := \
 	$($(target)_USES.$(bld_trg))\
 	$($(target)_USES.$(bld_type))\
 	$($(target)_USES)
-$(foreach unit,$(units),$(evalval def_unit_$(unit)_target_pre))
+$(foreach unit,$(units),$(evalvalctx def_unit_$(unit)_target_pre))
 
 # source -> object
 $(evalval def_target_sources)
@@ -628,7 +628,7 @@ $(eval-opt-var def_lib)
 typevar := _LIBS
 tool_do := LINK_LIBRARY
 mode := 0644
-$(foreach target, $(_ALL_LIBRARIES), $(evalval def_lib))
+$(foreach target, $(_ALL_LIBRARIES), $(evalvalctx def_lib))
 
 ifdef KBUILD_PROFILE_SELF
  $(evalcall def_profile_self, done library targets)
@@ -691,7 +691,7 @@ local units       := \
 	$($(target)_USES.$(bld_trg))\
 	$($(target)_USES.$(bld_type))\
 	$($(target)_USES)
-$(foreach unit,$(units),$(evalval def_unit_$(unit)_target_pre))
+$(foreach unit,$(units),$(evalvalctx def_unit_$(unit)_target_pre))
 
 # source -> object
 $(evalval def_target_sources)
@@ -967,7 +967,7 @@ tool_do := LINK_PROGRAM
 typevar := _BLDPROGS
 mode    := 0755
 bld_trg_base_var := PLATFORM
-$(foreach target, $(_ALL_BLDPROGS), $(evalval def_link_common))
+$(foreach target, $(_ALL_BLDPROGS), $(evalvalctx def_link_common))
 
 ifdef KBUILD_PROFILE_SELF
  $(evalcall def_profile_self, done build program targets)
@@ -985,7 +985,7 @@ tool_do := LINK_DLL
 typevar := _DLLS
 mode    := 0644
 bld_trg_base_var := TARGET
-$(foreach target, $(_ALL_DLLS), $(evalval def_link_common))
+$(foreach target, $(_ALL_DLLS), $(evalvalctx def_link_common))
 
 ifdef KBUILD_PROFILE_SELF
  $(evalcall def_profile_self, done dll targets)
@@ -1005,11 +1005,11 @@ bld_trg_base_var := TARGET
 ifeq ($(filter-out nt os2 win win64 win32,$(KBUILD_TARGET)),)
  EXT     := LIB
  tool_do := LINK_LIBRARY
- $(foreach target, $(_ALL_IMPORT_LIBS), $(evalval def_lib))
+ $(foreach target, $(_ALL_IMPORT_LIBS), $(evalvalctx def_lib))
 else
  EXT     := DLL
  tool_do := LINK_DLL
- $(foreach target, $(_ALL_IMPORT_LIBS), $(evalval def_link_common))
+ $(foreach target, $(_ALL_IMPORT_LIBS), $(evalvalctx def_link_common))
 endif
 
 ifdef KBUILD_PROFILE_SELF
@@ -1028,7 +1028,7 @@ tool_do := LINK_PROGRAM
 typevar := _PROGRAMS
 mode    := 0755
 bld_trg_base_var := TARGET
-$(foreach target, $(_ALL_PROGRAMS), $(evalval def_link_common))
+$(foreach target, $(_ALL_PROGRAMS), $(evalvalctx def_link_common))
 
 ifdef KBUILD_PROFILE_SELF
  $(evalcall def_profile_self, done program targets)
@@ -1046,7 +1046,7 @@ tool_do := LINK_SYSMOD
 typevar := _SYSMODS
 mode    := 0644
 bld_trg_base_var := TARGET
-$(foreach target, $(_ALL_SYSMODS), $(evalval def_link_common))
+$(foreach target, $(_ALL_SYSMODS), $(evalvalctx def_link_common))
 
 ifdef KBUILD_PROFILE_SELF
  $(evalcall def_profile_self, done sysmod targets)
@@ -1064,7 +1064,7 @@ tool_do := LINK_MISCBIN
 typevar := _MISCBINS
 mode    := 0644
 bld_trg_base_var := TARGET
-$(foreach target, $(_ALL_MISCBINS), $(evalval def_link_common))
+$(foreach target, $(_ALL_MISCBINS), $(evalvalctx def_link_common))
 
 ifdef KBUILD_PROFILE_SELF
  $(evalcall def_profile_self, done misc binary targets)
diff --git a/kBuild/header.kmk b/kBuild/header.kmk
index d2774f1..4d0f1f0 100644
--- a/kBuild/header.kmk
+++ b/kBuild/header.kmk
@@ -1,10 +1,10 @@
-# $Id: header.kmk 2729 2014-03-16 00:21:49Z bird $
+# $Id: header.kmk 2763 2015-01-28 18:25:31Z bird $
 ## @file
 # kBuild - File included at top of a makefile.
 #
 
 #
-# Copyright (c) 2004-2014 knut st. osmundsen <bird-kBuild-spam-xiv at anduin.net>
+# Copyright (c) 2004-2015 knut st. osmundsen <bird-kBuild-spam-xiv at anduin.net>
 #
 # This file is part of kBuild.
 #
@@ -79,7 +79,7 @@ endif
 # The revision in which this file was last modified.
 # This can be useful when using development versions of kBuild.
 #
-KMK_REVISION := $(patsubst %:,,  $Rev: 2729 $  )
+KMK_REVISION := $(patsubst %:,,  $Rev: 2763 $  )
 
 
 #
@@ -516,6 +516,7 @@ endif
 # Deprecated legacy names.
 PATH_DEVTOOLS         ?= $(KBUILD_DEVTOOLS)
 PATH_DEVTOOLS_TRG     ?= $(KBUILD_DEVTOOLS_TRG)
+PATH_DEVTOOLS_BLD     ?= $(KBUILD_DEVTOOLS_TRG)
 PATH_DEVTOOLS_TRG_ALT ?= $(KBUILD_DEVTOOLS_TRG_ALT)
 PATH_DEVTOOLS_HST     ?= $(KBUILD_DEVTOOLS_HST)
 PATH_DEVTOOLS_HST_ALT ?= $(KBUILD_DEVTOOLS_HST_ALT)
@@ -1565,6 +1566,29 @@ endif
 
 
 #
+# An internal define used by subheader.kmk and subfooter.kmk.
+# We keep them here to avoid redefining them for each sub-makefile.
+#
+define def_subfooter_header_target_pass
+ ifndef $(target)_PATH
+  ifndef $(target)_DEFPATH
+   $(target)_DEFPATH := $(PATH_SUB_CURRENT)
+  endif
+  $(call KB_FN_ASSIGN_DEPRECATED,$(target)_PATH,$($(target)_DEFPATH), $(target)_DEFPATH)
+ else ifndef $(target)_DEFPATH
+  $(target)_DEFPATH := $($(target)_PATH)
+ endif
+ ifndef $(target)_MAKEFILE
+  $(target)_MAKEFILE := $(MAKEFILE_CURRENT)
+ endif
+ ifndef $(target)_0_OUTDIR
+  $(target)_0_OUTDIR := $(call TARGET_PATH,$(target))
+  $(call KB_FN_ASSIGN_DEPRECATED,PATH_$(target),$($(target)_0_OUTDIR), $(target)_0_OUTDIR)
+ endif
+endef
+
+
+#
 # Validate any KBUILD_BLD_TYPES additions and finally the KBUILD_TYPE.
 #
 if1of ($(KBUILD_BLD_TYPES), $(KBUILD_OSES))
diff --git a/kBuild/subfooter.kmk b/kBuild/subfooter.kmk
index c87dfd0..baf1a03 100644
--- a/kBuild/subfooter.kmk
+++ b/kBuild/subfooter.kmk
@@ -1,10 +1,10 @@
-# $Id: subfooter.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: subfooter.kmk 2763 2015-01-28 18:25:31Z bird $
 ## @file
 # kBuild - File included at bottom of a makefile or sub-makefile.
 #
 
 #
-# Copyright (c) 2006-2014 knut st. osmundsen <bird-kBuild-spam-xiv at anduin.net>
+# Copyright (c) 2006-2015 knut st. osmundsen <bird-kBuild-spam-xiv at anduin.net>
 #
 # This file is part of kBuild.
 #
@@ -41,24 +41,7 @@ endif
 #
 # Set the default path for all new targets.
 #
-define def_subheader
- ifndef $(target)_PATH
-  ifndef $(target)_DEFPATH
-   $(target)_DEFPATH := $(PATH_SUB_CURRENT)
-  endif
-  $(call KB_FN_ASSIGN_DEPRECATED,$(target)_PATH,$($(target)_DEFPATH),$(target)_DEFPATH)
- else ifndef $(target)_DEFPATH
-  $(target)_DEFPATH := $($(target)_PATH)
- endif
- ifndef $(target)_MAKEFILE
-  $(target)_MAKEFILE := $(MAKEFILE_CURRENT)
- endif
- ifndef $(target)_0_OUTDIR
-  $(target)_0_OUTDIR := $(call TARGET_PATH,$(target))
-  $(call KB_FN_ASSIGN_DEPRECATED,PATH_$(target),$($(target)_0_OUTDIR),$(target)_0_OUTDIR)
- endif
-endef
-
+## @todo Wish there was an easy way of only enumerating only new targets...
 $(foreach target,\
 	$(ALL_TARGETS) \
 	$(FETCHES)     $(FETCHES.$(KBUILD_TARGET))      $(FETCHES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH))     $(FETCHES.$(KBUILD_TARGET_ARCH))     $(FETCHES.$(KBUILD_TARGET_CPU))     $(FETCHES.$(KBUILD_TYPE))     \
@@ -72,8 +55,7 @@ $(foreach target,\
 	$(MISCBINS)    $(MISCBINS.$(KBUILD_TARGET))     $(MISCBINS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH))    $(MISCBINS.$(KBUILD_TARGET_ARCH))    $(MISCBINS.$(KBUILD_TARGET_CPU))    $(MISCBINS.$(KBUILD_TYPE))    \
 	$(INSTALLS)    $(INSTALLS.$(KBUILD_TARGET))     $(INSTALLS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH))    $(INSTALLS.$(KBUILD_TARGET_ARCH))    $(INSTALLS.$(KBUILD_TARGET_CPU))    $(INSTALLS.$(KBUILD_TYPE))    \
 	$(OTHERS)      $(OTHERS.$(KBUILD_TARGET))       $(OTHERS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH))      $(OTHERS.$(KBUILD_TARGET_ARCH))      $(OTHERS.$(KBUILD_TARGET_CPU))      $(OTHERS.$(KBUILD_TYPE))      \
-,$(evalval def_subheader))
-
+,$(if-expr defined($(target)_0_OUTDIR),,$(evalval def_subfooter_header_target_pass)))
 
 
 ifneq ($(_SUB_MAKEFILE_STACK),)
diff --git a/kBuild/subheader.kmk b/kBuild/subheader.kmk
index 830e3ce..91d1059 100644
--- a/kBuild/subheader.kmk
+++ b/kBuild/subheader.kmk
@@ -1,10 +1,10 @@
-# $Id: subheader.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: subheader.kmk 2763 2015-01-28 18:25:31Z bird $
 ## @file
 # kBuild - File included at top of a makefile or sub-makefile.
 #
 
 #
-# Copyright (c) 2006-2014 knut st. osmundsen <bird-kBuild-spam-xiv at anduin.net>
+# Copyright (c) 2006-2015 knut st. osmundsen <bird-kBuild-spam-xiv at anduin.net>
 #
 # This file is part of kBuild.
 #
@@ -52,24 +52,7 @@ else
  #
  # Set the default path and makefile for all new targets.
  #
- define def_subfooter
-  ifndef $(target)_PATH
-   ifndef $(target)_DEFPATH
-    $(target)_DEFPATH := $(PATH_SUB_CURRENT)
-   endif
-   $(call KB_FN_ASSIGN_DEPRECATED,$(target)_PATH,$($(target)_DEFPATH), $(target)_DEFPATH)
-  else ifndef $(target)_DEFPATH
-   $(target)_DEFPATH := $($(target)_PATH)
-  endif
-  ifndef $(target)_MAKEFILE
-   $(target)_MAKEFILE := $(MAKEFILE_CURRENT)
-  endif
-  ifndef $(target)_0_OUTDIR
-   $(target)_0_OUTDIR := $(call TARGET_PATH,$(target))
-   $(call KB_FN_ASSIGN_DEPRECATED,PATH_$(target),$($(target)_0_OUTDIR), $(target)_0_OUTDIR)
-  endif
- endef
-
+ ## @todo Wish there was an easy way of only enumerating only new targets...
  $(foreach target,\
 	$(ALL_TARGETS) \
 	$(FETCHES)     $(FETCHES.$(KBUILD_TARGET))      $(FETCHES.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH))     $(FETCHES.$(KBUILD_TARGET_ARCH))     $(FETCHES.$(KBUILD_TARGET_CPU))     $(FETCHES.$(KBUILD_TYPE))     \
@@ -83,7 +66,7 @@ else
 	$(MISCBINS)    $(MISCBINS.$(KBUILD_TARGET))     $(MISCBINS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH))    $(MISCBINS.$(KBUILD_TARGET_ARCH))    $(MISCBINS.$(KBUILD_TARGET_CPU))    $(MISCBINS.$(KBUILD_TYPE))    \
 	$(INSTALLS)    $(INSTALLS.$(KBUILD_TARGET))     $(INSTALLS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH))    $(INSTALLS.$(KBUILD_TARGET_ARCH))    $(INSTALLS.$(KBUILD_TARGET_CPU))    $(INSTALLS.$(KBUILD_TYPE))    \
 	$(OTHERS)      $(OTHERS.$(KBUILD_TARGET))       $(OTHERS.$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH))      $(OTHERS.$(KBUILD_TARGET_ARCH))      $(OTHERS.$(KBUILD_TARGET_CPU))      $(OTHERS.$(KBUILD_TYPE))      \
- ,$(evalval def_subfooter))
+ ,$(if-expr defined($(target)_0_OUTDIR),,$(evalval def_subfooter_header_target_pass)))
 
 
  #
diff --git a/kBuild/tools/ALP.kmk b/kBuild/tools/ALP.kmk
index 82971cd..42ef67d 100644
--- a/kBuild/tools/ALP.kmk
+++ b/kBuild/tools/ALP.kmk
@@ -1,4 +1,4 @@
-# $Id: ALP.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: ALP.kmk 2750 2015-01-23 12:24:02Z bird $
 ## @file
 # kBuild Tool Config - ALP or later.
 #
@@ -35,7 +35,7 @@ TOOL_ALP := The IBM Assembly Language Processor
 
 # Tool Specific Properties
 ifndef PATH_TOOL_ALP
- PATH_TOOL_ALP := $(sort $(wildcard $(KBUILD_DEVTOOLS_BLD)/alp/v*.*))
+ PATH_TOOL_ALP := $(sort $(wildcard $(KBUILD_DEVTOOLS_HST)/alp/v*.*))
  ifneq ($(PATH_TOOL_ALP),)
   PATH_TOOL_ALP := $(call lastword,$(PATH_TOOL_ALP))
  endif
diff --git a/kBuild/tools/GCC3.kmk b/kBuild/tools/GCC3.kmk
index 4142bda..fd6c6b8 100644
--- a/kBuild/tools/GCC3.kmk
+++ b/kBuild/tools/GCC3.kmk
@@ -1,4 +1,4 @@
-# $Id: GCC3.kmk 2541 2011-08-03 09:51:30Z bird $
+# $Id: GCC3.kmk 2775 2015-02-03 20:00:15Z bird $
 ## @file
 # kBuild Tool Config - Generic GCC v3.2.x or later Using The System GCC and Binutils.
 #
@@ -237,9 +237,9 @@ define TOOL_GCC3_LINK_LIBRARY_CMDS
 	$(QUIET)$(APPEND) $(out).ar-script 'CREATE $(out)'
 	$(QUIET)$(APPEND) -n $(out).ar-script \
 		$(foreach o,$(objs), 'ADDMOD $(o)') \
-		$(foreach o,$(filter-out %.def %.imp,$(othersrc)), 'ADDLIB $(o)')
-	$(if $(filter %.def %.imp,$(othersrc))\
-		,$(TOOL_GCC3_AR_IMP) -o $(outbase).imp.a $(filter %.def %.imp,$(othersrc))\
+		$(foreach o,$(filter-out %.def %.imp %.dll,$(othersrc)), 'ADDLIB $(o)')
+	$(if $(filter %.def %.imp %.dll,$(othersrc))\
+		,$(TOOL_GCC3_AR_IMP) -o $(outbase).imp.a $(filter %.def %.imp %.dll,$(othersrc))\
 		 $(NL)$(TAB)$(QUIET)$(APPEND) $(out).ar-script 'ADDLIB $(outbase).imp.a')
 	$(QUIET)$(APPEND) $(out).ar-script 'SAVE'
 	$(QUIET)$(APPEND) $(out).ar-script 'END'
@@ -274,9 +274,9 @@ define TOOL_GCC3_LINK_PROGRAM_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GCC3_LD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GCC3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GCC3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GCC3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GCC3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
@@ -310,9 +310,9 @@ define TOOL_GCC3_LINK_DLL_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GCC3_LD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GCC3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GCC3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GCC3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GCC3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
@@ -344,9 +344,9 @@ define TOOL_GCC3_LINK_SYSMOD_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GCC3_LD_SYSMOD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GCC3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GCC3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GCC3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GCC3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
diff --git a/kBuild/tools/GCC32.kmk b/kBuild/tools/GCC32.kmk
index cf3ed32..595e78a 100644
--- a/kBuild/tools/GCC32.kmk
+++ b/kBuild/tools/GCC32.kmk
@@ -1,4 +1,4 @@
-# $Id: GCC32.kmk 2541 2011-08-03 09:51:30Z bird $
+# $Id: GCC32.kmk 2775 2015-02-03 20:00:15Z bird $
 ## @file
 # kBuild Tool Config - Generic 32-bit GCC v3.2.x or later Using The System GCC.
 #
@@ -232,9 +232,9 @@ define TOOL_GCC32_LINK_LIBRARY_CMDS
 	$(QUIET)$(APPEND) $(out).ar-script 'CREATE $(out)'
 	$(QUIET)$(APPEND) -n $(out).ar-script \
 		$(foreach o,$(objs), 'ADDMOD $(o)') \
-		$(foreach o,$(filter-out %.def %.imp,$(othersrc)), 'ADDLIB $(o)')
-	$(if $(filter %.def %.imp,$(othersrc))\
-		,$(TOOL_GCC32_AR_IMP) -o $(outbase).imp.a $(filter %.def %.imp,$(othersrc))\
+		$(foreach o,$(filter-out %.def %.imp %.dll,$(othersrc)), 'ADDLIB $(o)')
+	$(if $(filter %.def %.imp %.dll,$(othersrc))\
+		,$(TOOL_GCC32_AR_IMP) -o $(outbase).imp.a $(filter %.def %.imp %.dll,$(othersrc))\
 		 $(NL)$(TAB)$(QUIET)$(APPEND) $(out).ar-script 'ADDLIB $(outbase).imp.a')
 	$(QUIET)$(APPEND) $(out).ar-script 'SAVE'
 	$(QUIET)$(APPEND) $(out).ar-script 'END'
@@ -268,9 +268,9 @@ define TOOL_GCC32_LINK_PROGRAM_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GCC32_LD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GCC32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GCC32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GCC32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GCC32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
@@ -303,9 +303,9 @@ define TOOL_GCC32_LINK_DLL_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GCC32_LD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GCC32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GCC32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GCC32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GCC32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
@@ -337,9 +337,9 @@ define TOOL_GCC32_LINK_SYSMOD_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GCC32_LD_SYSMOD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GCC32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GCC32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GCC32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GCC32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
diff --git a/kBuild/tools/GCC3OMF.kmk b/kBuild/tools/GCC3OMF.kmk
index eb86dfd..e7a97e8 100644
--- a/kBuild/tools/GCC3OMF.kmk
+++ b/kBuild/tools/GCC3OMF.kmk
@@ -1,4 +1,4 @@
-# $Id: GCC3OMF.kmk 2545 2011-09-13 19:09:05Z bird $
+# $Id: GCC3OMF.kmk 2776 2015-02-03 20:38:12Z bird $
 ## @file
 # kBuild Tool Config - GCC v3 targeting OS/2 OMF.
 #
@@ -49,6 +49,7 @@ endif
 TOOL_GCC3OMF_LDFLAGS.sysmod ?= -nostdlib
 TOOL_GCC3OMF_LD_MAP ?= -Zmap=$(1)
 TOOL_GCC3OMF_LD_SYSMOD_MAP ?= -Zmap=$(1)
+TOOL_GCC3OMF_RC = rc$(HOSTSUFF_EXE)
 
 ifdef SLKRUNS
 TOOL_GCC3OMF_CC  += -fmessage-length=0
@@ -78,6 +79,11 @@ TOOL_GCC3OMF_ASFLAGS.debug    ?= -g
 TOOL_GCC3OMF_ASFLAGS.profile  ?= -g
 TOOL_GCC3OMF_ASOBJSUFF        ?= .obj
 
+TOOL_GCC3OMF_RCOBJSUFF        ?= .res
+TOOL_GCC3OMF_RCFLAGS          ?= -n
+TOOL_GCC3OMF_RCINCS           ?= $(shell $(TOOL_GCC3OMF_CXX) -E -x c++ - 2>&1 < /dev/null \
+	| $(SED_EXT) -e "/search starts here/,/[Ee]nd of search list/!d" -e "/^ /!d")
+
 TOOL_GCC3OMF_ARFLAGS          ?= cr
 TOOL_GCC3OMF_ARLIBSUFF        ?= .lib
 
@@ -202,6 +208,28 @@ define TOOL_GCC3OMF_COMPILE_AS_CMDS
 endef
 
 
+## Compile resource source.
+# @param    $(target)   Normalized main target name.
+# @param    $(source)   Source filename (relative).
+# @param    $(obj)      Object file name. This shall be (re)created by the compilation.
+# @param    $(dep)      Dependcy file. This shall be (re)created by the compilation.
+# @param    $(flags)    Flags.
+# @param    $(defs)     Definitions. No -D or something.
+# @param    $(incs)     Includes. No -I or something.
+# @param    $(dirdep)   Directory creation dependency.
+# @param    $(deps)     Other dependencies.
+#
+# @param    $(outbase)  Output basename (full). Use this for list files and such.
+# @param    $(objsuff)  Object suffix.
+TOOL_GCC3OMF_COMPILE_RC_OUTPUT =
+TOOL_GCC3OMF_COMPILE_RC_DEPEND =
+TOOL_GCC3OMF_COMPILE_RC_DEPORD =
+define TOOL_GCC3OMF_COMPILE_RC_CMDS
+	$(QUIET)$(REDIRECT) -E 'INCLUDE=' -- $(TOOL_GCC3OMF_RC) -r \
+		$(flags) $(addprefix -i, $(subst /,\\,$(subst /@unixroot,$(UNIXROOT),$(incs)))) $(addprefix -d, $(defs))\
+		$(subst /,\\,$(abspath $(source))) \
+		$(obj)
+endef
 ## Link library
 # @param    $(target)   Normalized main target name.
 # @param    $(out)		Library name.
@@ -216,12 +244,12 @@ TOOL_GCC3OMF_LINK_LIBRARY_OUTPUT = $(outbase).rsp
 TOOL_GCC3OMF_LINK_LIBRARY_DEPEND = $(othersrc)
 TOOL_GCC3OMF_LINK_LIBRARY_DEPORD =
 define TOOL_GCC3OMF_LINK_LIBRARY_CMDS
-	$(if $(filter %.def %.imp,$(othersrc))\
-		,$(QUIET)$(APPEND) -n $(outbase).rsp $(filter %.def %.imp,$(othersrc))\
+	$(if $(filter %.def %.imp %.dll,$(othersrc))\
+		,$(QUIET)$(APPEND) -n $(outbase).rsp $(filter %.def %.imp %.dll,$(othersrc))\
 		 $(NL)$(TAB)$(QUIET)$(QUIET)$(TOOL_GCC3OMF_AR_IMP) -o $(out) @$(outbase).rsp\
 		 $(NL)$(TAB)$(QUIET)$(RM) -f $(outbase).rsp)
-	$(QUIET)$(APPEND) -n $(outbase).rsp $(flags) $(out) $(objs) $(filter-out %.def %.imp,$(othersrc))
-	$(TOOL_GCC3OMF_AR) @$(outbase).rsp
+	$(QUIET)$(APPEND) -n $(outbase).rsp $(flags) $(out) $(objs) $(filter-out %.def %.imp %.dll,$(othersrc))
+	$(QUIET)$(TOOL_GCC3OMF_AR) @$(outbase).rsp
 endef
 
 
@@ -282,7 +310,7 @@ define TOOL_GCC3OMF_LINK_DLL_CMDS
 		$(othersrc)\
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		-Zmap=$(outbase).map
-	$(TOOL_GCC3OMF_LD) @$(outbase).rsp
+	$(QUIET)$(TOOL_GCC3OMF_LD) @$(outbase).rsp
 endef
 
 
diff --git a/kBuild/tools/GCC64.kmk b/kBuild/tools/GCC64.kmk
index d2a8b27..586f737 100644
--- a/kBuild/tools/GCC64.kmk
+++ b/kBuild/tools/GCC64.kmk
@@ -1,4 +1,4 @@
-# $Id: GCC64.kmk 2541 2011-08-03 09:51:30Z bird $
+# $Id: GCC64.kmk 2774 2015-02-03 19:56:24Z bird $
 ## @file
 # kBuild Tool Config - Generic 64-bit GCC v3.2.x or later Using The System GCC.
 #
@@ -263,9 +263,9 @@ define TOOL_GCC64_LINK_PROGRAM_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GCC64_LD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GCC64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GCC64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GCC64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GCC64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
@@ -297,9 +297,9 @@ define TOOL_GCC64_LINK_DLL_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GCC64_LD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GCC64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GCC64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GCC64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GCC64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
@@ -329,9 +329,9 @@ define TOOL_GCC64_LINK_SYSMOD_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GCC64_LD_SYSMOD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GCC64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GCC64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GCC64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GCC64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
diff --git a/kBuild/tools/GXX3.kmk b/kBuild/tools/GXX3.kmk
index b1e3fa4..64cbd1d 100644
--- a/kBuild/tools/GXX3.kmk
+++ b/kBuild/tools/GXX3.kmk
@@ -1,4 +1,4 @@
-# $Id: GXX3.kmk 2541 2011-08-03 09:51:30Z bird $
+# $Id: GXX3.kmk 2775 2015-02-03 20:00:15Z bird $
 ## @file
 # kBuild Tool Config - Generic GCC v3.2.x using the system GCC and Binutils, for building C++ code.
 #
@@ -237,9 +237,9 @@ define TOOL_GXX3_LINK_LIBRARY_CMDS
 	$(QUIET)$(APPEND) $(out).ar-script 'CREATE $(out)'
 	$(QUIET)$(APPEND) -n $(out).ar-script \
 		$(foreach o,$(objs), 'ADDMOD $(o)') \
-		$(foreach o,$(filter-out %.def %.imp,$(othersrc)), 'ADDLIB $(o)')
-	$(if $(filter %.def %.imp,$(othersrc))\
-		,$(TOOL_GXX3_AR_IMP) -o $(outbase).imp.a $(filter %.def %.imp,$(othersrc))\
+		$(foreach o,$(filter-out %.def %.imp %.dll,$(othersrc)), 'ADDLIB $(o)')
+	$(if $(filter %.def %.imp %.dll,$(othersrc))\
+		,$(TOOL_GXX3_AR_IMP) -o $(outbase).imp.a $(filter %.def %.imp %.dll,$(othersrc))\
 		 $(NL)$(TAB)$(QUIET)$(APPEND) $(out).ar-script 'ADDLIB $(outbase).imp.a')
 	$(QUIET)$(APPEND) $(out).ar-script 'SAVE'
 	$(QUIET)$(APPEND) $(out).ar-script 'END'
@@ -274,9 +274,9 @@ define TOOL_GXX3_LINK_PROGRAM_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GXX3_LD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GXX3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GXX3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GXX3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GXX3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
@@ -310,9 +310,9 @@ define TOOL_GXX3_LINK_DLL_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GXX3_LD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GXX3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GXX3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GXX3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GXX3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
@@ -344,9 +344,9 @@ define TOOL_GXX3_LINK_SYSMOD_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GXX3_LD_SYSMOD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GXX3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GXX3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GXX3_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GXX3_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
diff --git a/kBuild/tools/GXX32.kmk b/kBuild/tools/GXX32.kmk
index 6c5b82e..49463d2 100644
--- a/kBuild/tools/GXX32.kmk
+++ b/kBuild/tools/GXX32.kmk
@@ -1,4 +1,4 @@
-# $Id: GXX32.kmk 2541 2011-08-03 09:51:30Z bird $
+# $Id: GXX32.kmk 2775 2015-02-03 20:00:15Z bird $
 ## @file
 # kBuild Tool Config - Generic 32-bit GCC v3.2.x or later using the system GCC, for building C++ code.
 #
@@ -231,9 +231,9 @@ define TOOL_GXX32_LINK_LIBRARY_CMDS
 	$(QUIET)$(APPEND) $(out).ar-script 'CREATE $(out)'
 	$(QUIET)$(APPEND) -n $(out).ar-script \
 		$(foreach o,$(objs), 'ADDMOD $(o)') \
-		$(foreach o,$(filter-out %.def %.imp,$(othersrc)), 'ADDLIB $(o)')
-	$(if $(filter %.def %.imp,$(othersrc))\
-		,$(TOOL_GXX3_AR_IMP) -o $(outbase).imp.a $(filter %.def %.imp,$(othersrc))\
+		$(foreach o,$(filter-out %.def %.imp %.dll,$(othersrc)), 'ADDLIB $(o)')
+	$(if $(filter %.def %.imp %.dll,$(othersrc))\
+		,$(TOOL_GXX3_AR_IMP) -o $(outbase).imp.a $(filter %.def %.imp %.dll,$(othersrc))\
 		 $(NL)$(TAB)$(QUIET)$(APPEND) $(out).ar-script 'ADDLIB $(outbase).imp.a')
 	$(QUIET)$(APPEND) $(out).ar-script 'SAVE'
 	$(QUIET)$(APPEND) $(out).ar-script 'END'
@@ -267,9 +267,9 @@ define TOOL_GXX32_LINK_PROGRAM_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GXX32_LD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GXX32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GXX32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GXX32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GXX32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
@@ -302,9 +302,9 @@ define TOOL_GXX32_LINK_DLL_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GXX32_LD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GXX32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GXX32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GXX32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GXX32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
@@ -336,9 +336,9 @@ define TOOL_GXX32_LINK_SYSMOD_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GXX32_LD_SYSMOD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GXX32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GXX32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GXX32_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GXX32_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
diff --git a/kBuild/tools/GXX3OMF.kmk b/kBuild/tools/GXX3OMF.kmk
index bb38527..f54b775 100644
--- a/kBuild/tools/GXX3OMF.kmk
+++ b/kBuild/tools/GXX3OMF.kmk
@@ -1,4 +1,4 @@
-# $Id: GXX3OMF.kmk 2545 2011-09-13 19:09:05Z bird $
+# $Id: GXX3OMF.kmk 2776 2015-02-03 20:38:12Z bird $
 ## @file
 # kBuild Tool Config - GCC v3 targeting OS/2 OMF, for building C++ code.
 #
@@ -49,6 +49,7 @@ endif
 TOOL_GXX3OMF_LDFLAGS.sysmod ?= -nostdlib
 TOOL_GXX3OMF_LD_MAP ?= -Zmap=$(1)
 TOOL_GXX3OMF_LD_SYSMOD_MAP ?= -Zmap=$(1)
+TOOL_GXX3OMF_RC = rc$(HOSTSUFF_EXE)
 
 ifdef SLKRUNS
 TOOL_GXX3OMF_CC  += -fmessage-length=0
@@ -78,6 +79,11 @@ TOOL_GXX3OMF_ASFLAGS.debug    ?= -g
 TOOL_GXX3OMF_ASFLAGS.profile  ?= -g
 TOOL_GXX3OMF_ASOBJSUFF        ?= .obj
 
+TOOL_GXX3OMF_RCOBJSUFF        ?= .res
+TOOL_GXX3OMF_RCFLAGS          ?= -n
+TOOL_GXX3OMF_RCINCS           ?= $(shell $(TOOL_GXX3OMF_CXX) -E -x c++ - 2>&1 < /dev/null \
+	| $(SED_EXT) -e "/search starts here/,/[Ee]nd of search list/!d" -e "/^ /!d")
+
 TOOL_GXX3OMF_ARFLAGS          ?= cr
 TOOL_GXX3OMF_ARLIBSUFF        ?= .lib
 
@@ -202,6 +208,30 @@ define TOOL_GXX3OMF_COMPILE_AS_CMDS
 endef
 
 
+## Compile resource source.
+# @param    $(target)   Normalized main target name.
+# @param    $(source)   Source filename (relative).
+# @param    $(obj)      Object file name. This shall be (re)created by the compilation.
+# @param    $(dep)      Dependcy file. This shall be (re)created by the compilation.
+# @param    $(flags)    Flags.
+# @param    $(defs)     Definitions. No -D or something.
+# @param    $(incs)     Includes. No -I or something.
+# @param    $(dirdep)   Directory creation dependency.
+# @param    $(deps)     Other dependencies.
+#
+# @param    $(outbase)  Output basename (full). Use this for list files and such.
+# @param    $(objsuff)  Object suffix.
+TOOL_GXX3OMF_COMPILE_RC_OUTPUT =
+TOOL_GXX3OMF_COMPILE_RC_DEPEND =
+TOOL_GXX3OMF_COMPILE_RC_DEPORD =
+define TOOL_GXX3OMF_COMPILE_RC_CMDS
+	$(QUIET)$(REDIRECT) -E 'INCLUDE=' -- $(TOOL_GXX3OMF_RC) -r \
+		$(flags) $(addprefix -i, $(subst /,\\,$(subst /@unixroot,$(UNIXROOT),$(incs)))) $(addprefix -d, $(defs))\
+		$(subst /,\\,$(abspath $(source))) \
+		$(obj)
+endef
+
+
 ## Link library
 # @param    $(target)   Normalized main target name.
 # @param    $(out)		Library name.
@@ -216,12 +246,12 @@ TOOL_GXX3OMF_LINK_LIBRARY_OUTPUT = $(outbase).rsp
 TOOL_GXX3OMF_LINK_LIBRARY_DEPEND = $(othersrc)
 TOOL_GXX3OMF_LINK_LIBRARY_DEPORD =
 define TOOL_GXX3OMF_LINK_LIBRARY_CMDS
-	$(if $(filter %.def %.imp,$(othersrc))\
-		,$(QUIET)$(APPEND) -n $(outbase).rsp $(filter %.def %.imp,$(othersrc))\
+	$(if $(filter %.def %.imp %.dll,$(othersrc))\
+		,$(QUIET)$(APPEND) -n $(outbase).rsp $(filter %.def %.imp %.dll,$(othersrc))\
 		 $(NL)$(TAB)$(QUIET)$(QUIET)$(TOOL_GXX3OMF_AR_IMP) -o $(out) @$(outbase).rsp\
 		 $(NL)$(TAB)$(QUIET)$(RM) -f $(outbase).rsp)
-	$(QUIET)$(APPEND) -n $(outbase).rsp $(flags) $(out) $(objs) $(filter-out %.def %.imp,$(othersrc))
-	$(TOOL_GXX3OMF_AR) @$(outbase).rsp
+	$(QUIET)$(APPEND) -n $(outbase).rsp $(flags) $(out) $(objs) $(filter-out %.def %.imp %.dll,$(othersrc))
+	$(QUIET)$(TOOL_GXX3OMF_AR) @$(outbase).rsp
 endef
 
 
@@ -282,7 +312,7 @@ define TOOL_GXX3OMF_LINK_DLL_CMDS
 		$(othersrc)\
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		-Zmap=$(outbase).map
-	$(TOOL_GXX3OMF_LD) @$(outbase).rsp
+	$(QUIET)$(TOOL_GXX3OMF_LD) @$(outbase).rsp
 endef
 
 
diff --git a/kBuild/tools/GXX64.kmk b/kBuild/tools/GXX64.kmk
index 35cabfc..03973fc 100644
--- a/kBuild/tools/GXX64.kmk
+++ b/kBuild/tools/GXX64.kmk
@@ -1,4 +1,4 @@
-# $Id: GXX64.kmk 2541 2011-08-03 09:51:30Z bird $
+# $Id: GXX64.kmk 2774 2015-02-03 19:56:24Z bird $
 ## @file
 # kBuild Tool Config - Generic 64-bit GCC v3.2.x or later using the system GCC, for building C++ code.
 #
@@ -263,9 +263,9 @@ define TOOL_GXX64_LINK_PROGRAM_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GXX64_LD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GXX64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GXX64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GXX64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GXX64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
@@ -297,9 +297,9 @@ define TOOL_GXX64_LINK_DLL_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GXX64_LD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GXX64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GXX64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GXX64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GXX64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
@@ -329,9 +329,9 @@ define TOOL_GXX64_LINK_SYSMOD_CMDS
 		$(foreach lib,$(libs), $(if $(findstring $(lib),$(subst /,x,$(lib))), -l$(patsubst lib%,%,$(lib)), $(lib)))\
 		$(call TOOL_GXX64_LD_SYSMOD_MAP,$(outbase).map)
  ifeq ($(ld_debug),split)
-	$(TOOL_GXX64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
-	$(CHMOD) a-x $(outbase).debug
-	$(TOOL_GXX64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
+	$(QUIET)$(TOOL_GXX64_OBJCOPY) --only-keep-debug $(out) $(outbase).debug
+	$(QUIET)$(CHMOD) a-x $(outbase).debug
+	$(QUIET)$(TOOL_GXX64_OBJCOPY) --strip-debug --strip-unneeded --add-gnu-debuglink=$(outbase).debug $(out)
  endif
 endef
 
diff --git a/kBuild/tools/JWASM.kmk b/kBuild/tools/JWASM.kmk
index 5e99194..fb8ab22 100644
--- a/kBuild/tools/JWASM.kmk
+++ b/kBuild/tools/JWASM.kmk
@@ -1,4 +1,4 @@
-# $Id: JWASM.kmk 2730 2014-03-16 20:30:59Z bird $
+# $Id: JWASM.kmk 2774 2015-02-03 19:56:24Z bird $
 ## @file
 # kBuild Tool Config - JWasm
 #
@@ -36,7 +36,7 @@ TOOL_JWASM := JWasm - MASM clone based on the Open Watcom assembler.
 
 # Tool Specific Properties
 ifndef TOOL_JWASM_AS
- TOOL_JWASM_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_BLD)/jwasm/*/jwasm$(HOSTSUFF_EXE))))
+ TOOL_JWASM_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/jwasm/*/jwasm$(HOSTSUFF_EXE))))
  ifeq ($(TOOL_JWASM_AS),)
   TOOL_JWASM_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_TRG)/jwasm/*/jwasm$(HOSTSUFF_EXE))))
  endif
@@ -52,7 +52,7 @@ TOOL_JWASM_COMPILE_AS_OUTPUT = $(outbase).lst
 TOOL_JWASM_COMPILE_AS_DEPEND =
 TOOL_JWASM_COMPILE_AS_DEPORD =
 define TOOL_JWASM_COMPILE_AS_CMDS
-	$(TOOL_JWASM_AS) -c \
+	$(QUIET)$(TOOL_JWASM_AS) -c \
 			$(strip $(flags)) \
 			$(addprefix -D,$(defs)) \
 			$(addprefix -I,$(incs)) \
diff --git a/kBuild/tools/MASM510.kmk b/kBuild/tools/MASM510.kmk
index 91778e8..bd00786 100644
--- a/kBuild/tools/MASM510.kmk
+++ b/kBuild/tools/MASM510.kmk
@@ -1,4 +1,4 @@
-# $Id: MASM510.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: MASM510.kmk 2750 2015-01-23 12:24:02Z bird $
 ## @file
 # kBuild Tool Config - MASM v5.10
 #
@@ -35,7 +35,7 @@ TOOL_MASM510 := Microsoft Macro Assembler v5.10
 
 # Tool Specific Properties
 ifndef TOOL_MASM510_AS
- TOOL_MASM510_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_BLD)/masm/v5.10*/masm$(HOSTSUFF_EXE))))
+ TOOL_MASM510_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/masm/v5.10*/masm$(HOSTSUFF_EXE))))
  ifeq ($(TOOL_MASM510_AS),)
   TOOL_MASM510_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_TRG)/masm/v5.10*/masm$(HOSTSUFF_EXE))))
  endif
diff --git a/kBuild/tools/MASM600.kmk b/kBuild/tools/MASM600.kmk
index d8ea283..e1a300c 100644
--- a/kBuild/tools/MASM600.kmk
+++ b/kBuild/tools/MASM600.kmk
@@ -1,4 +1,4 @@
-# $Id: MASM600.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: MASM600.kmk 2750 2015-01-23 12:24:02Z bird $
 ## @file
 # kBuild Tool Config - MASM v6.00
 #
@@ -35,7 +35,7 @@ TOOL_MASM600 := Microsoft Macro Assembler v6.00
 
 # Tool Specific Properties
 ifndef TOOL_MASM600_AS
- TOOL_MASM600_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_BLD)/masm/v6.00*/binp/ml$(HOSTSUFF_EXE))))
+ TOOL_MASM600_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/masm/v6.00*/binp/ml$(HOSTSUFF_EXE))))
  ifeq ($(TOOL_MASM600_AS),)
   TOOL_MASM600_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_TRG)/masm/v6.00*/binp/ml$(HOSTSUFF_EXE))))
  endif
diff --git a/kBuild/tools/MASM610.kmk b/kBuild/tools/MASM610.kmk
index d07636f..e920bda 100644
--- a/kBuild/tools/MASM610.kmk
+++ b/kBuild/tools/MASM610.kmk
@@ -1,4 +1,4 @@
-# $Id: MASM610.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: MASM610.kmk 2750 2015-01-23 12:24:02Z bird $
 ## @file
 # kBuild Tool Config - MASM v6.10
 #
@@ -35,7 +35,7 @@ TOOL_MASM610 := Microsoft Macro Assembler v6.10
 
 # Tool Specific Properties
 ifndef TOOL_MASM610_AS
- TOOL_MASM610_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_BLD)/masm/v6.10*/binp/ml$(HOSTSUFF_EXE))))
+ TOOL_MASM610_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/masm/v6.10*/binp/ml$(HOSTSUFF_EXE))))
  ifeq ($(TOOL_MASM610_AS),)
   TOOL_MASM610_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_TRG)/masm/v6.10*/binp/ml$(HOSTSUFF_EXE))))
  endif
diff --git a/kBuild/tools/MASM6PLUS.kmk b/kBuild/tools/MASM6PLUS.kmk
index a155876..b6023f2 100644
--- a/kBuild/tools/MASM6PLUS.kmk
+++ b/kBuild/tools/MASM6PLUS.kmk
@@ -1,4 +1,4 @@
-# $Id: MASM6PLUS.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: MASM6PLUS.kmk 2750 2015-01-23 12:24:02Z bird $
 ## @file
 # kBuild Tool Config - MASM v6 and later.
 #
@@ -36,11 +36,11 @@ TOOL_MASM6PLUS := Microsoft Macro Assembler v6 and later.
 # Tool Specific Properties
 ifndef TOOL_MASM6PLUS_AS
  TOOL_MASM6PLUS_AS := $(firstword $(rsort $(wildcard \
-	$(KBUILD_DEVTOOLS_BLD)/masm/*/bin$(if $(eq $(KBUILD_HOST),os2),p,)/ml$(HOSTSUFF_EXE)\
+	$(KBUILD_DEVTOOLS_HST)/masm/*/bin$(if $(eq $(KBUILD_HOST),os2),p,)/ml$(HOSTSUFF_EXE)\
 	)))
  ifeq ($(TOOL_MASM6PLUS_AS),)
   TOOL_MASM6PLUS_AS := $(firstword $(rsort $(wildcard \
-	$(KBUILD_DEVTOOLS_BLD)/vcc/*/bin/ml$(HOSTSUFF_EXE) \
+	$(KBUILD_DEVTOOLS_HST)/vcc/*/bin/ml$(HOSTSUFF_EXE) \
 	)))
  endif
  ifeq ($(TOOL_MASM6PLUS_AS),)
diff --git a/kBuild/tools/MASM710.kmk b/kBuild/tools/MASM710.kmk
index 877c38e..812a8ae 100644
--- a/kBuild/tools/MASM710.kmk
+++ b/kBuild/tools/MASM710.kmk
@@ -1,4 +1,4 @@
-# $Id: MASM710.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: MASM710.kmk 2750 2015-01-23 12:24:02Z bird $
 ## @file
 # kBuild Tool Config - MASM v7.10
 #
@@ -35,7 +35,7 @@ TOOL_MASM710 := Microsoft Macro Assembler v7.10
 
 # Tool Specific Properties
 ifndef TOOL_MASM710_AS
- TOOL_MASM710_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_BLD)/masm/v7.10*/binp/ml$(HOSTSUFF_EXE))))
+ TOOL_MASM710_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/masm/v7.10*/binp/ml$(HOSTSUFF_EXE))))
  ifeq ($(TOOL_MASM710_AS),)
   TOOL_MASM710_AS := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_TRG)/masm/v7.10*/binp/ml$(HOSTSUFF_EXE))))
  endif
diff --git a/kBuild/tools/MINGW32.kmk b/kBuild/tools/MINGW32.kmk
index e28e0f3..e9b32a3 100644
--- a/kBuild/tools/MINGW32.kmk
+++ b/kBuild/tools/MINGW32.kmk
@@ -1,4 +1,4 @@
-# $Id: MINGW32.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: MINGW32.kmk 2750 2015-01-23 12:24:02Z bird $
 ## @file
 # kBuild Tool Config - MinGW32 GCC v3.3+.
 #
@@ -38,7 +38,7 @@ TOOL_MINGW32 := MinGW32 GCC v3.3+.
 
 # Tool Specific Properties
 ifndef PATH_TOOL_MINGW32
- PATH_TOOL_MINGW32 := $(wildcard $(KBUILD_DEVTOOLS_BLD)/mingw32/v*.*)
+ PATH_TOOL_MINGW32 := $(wildcard $(KBUILD_DEVTOOLS_HST)/mingw32/v*.*)
  ifeq ($(PATH_TOOL_MINGW32),)
   PATH_TOOL_MINGW32 := $(wildcard $(KBUILD_DEVTOOLS)/win.x86/mingw32/v*.*)
  endif
diff --git a/kBuild/tools/MINGWW64.kmk b/kBuild/tools/MINGWW64.kmk
index c6143fe..b14f673 100644
--- a/kBuild/tools/MINGWW64.kmk
+++ b/kBuild/tools/MINGWW64.kmk
@@ -1,4 +1,4 @@
-# $Id: MINGWW64.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: MINGWW64.kmk 2750 2015-01-23 12:24:02Z bird $
 ## @file
 # kBuild Tool Config - MinGW-W64.
 #
@@ -38,7 +38,7 @@ TOOL_MINGWW64 := MinGW-W64 - The incomprehensible 64-bit GCC port to Windows.
 
 # Tool Specific Properties
 ifndef PATH_TOOL_MINGWW64
- PATH_TOOL_MINGWW64 := $(wildcard $(KBUILD_DEVTOOLS_BLD)/mingw-w64/r*)
+ PATH_TOOL_MINGWW64 := $(wildcard $(KBUILD_DEVTOOLS_HST)/mingw-w64/r*)
  ifeq ($(PATH_TOOL_MINGWW64),)
   PATH_TOOL_MINGWW64 := $(wildcard $(KBUILD_DEVTOOLS)/win.amd64/mingw-w64/r*)
  endif
diff --git a/kBuild/tools/NASM.kmk b/kBuild/tools/NASM.kmk
index 660ce59..41e4512 100644
--- a/kBuild/tools/NASM.kmk
+++ b/kBuild/tools/NASM.kmk
@@ -1,4 +1,4 @@
-# $Id: NASM.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: NASM.kmk 2750 2015-01-23 12:24:02Z bird $
 ## @file
 # kBuild Tool Config - Netwide Assembler v0.98+.
 #
@@ -35,7 +35,7 @@ TOOL_NASM := Netwide Assembler v0.98+
 
 # Tool Specific Properties
 ifndef PATH_TOOL_NASM
- PATH_TOOL_NASM := $(sort $(wildcard $(KBUILD_DEVTOOLS_BLD)/nasm/v*.*))
+ PATH_TOOL_NASM := $(sort $(wildcard $(KBUILD_DEVTOOLS_HST)/nasm/v*.*))
  ifneq ($(PATH_TOOL_NASM),)
   PATH_TOOL_NASM := $(call lastword,$(PATH_TOOL_NASM))
  endif
diff --git a/kBuild/tools/OPENWATCOM-16.kmk b/kBuild/tools/OPENWATCOM-16.kmk
index 830a760..153b871 100644
--- a/kBuild/tools/OPENWATCOM-16.kmk
+++ b/kBuild/tools/OPENWATCOM-16.kmk
@@ -1,4 +1,4 @@
-# $Id: OPENWATCOM-16.kmk 2731 2014-06-28 14:58:12Z bird $
+# $Id: OPENWATCOM-16.kmk 2749 2015-01-23 01:01:02Z bird $
 ## @file
 # kBuild Tool Config - Open Watcom v1.4 and later, 16-bit targets.
 #
@@ -45,7 +45,7 @@ TOOL_OPENWATCOM-16_COMPILE_AS_DEPEND =
 TOOL_OPENWATCOM-16_COMPILE_AS_DEPORD =
 TOOL_OPENWATCOM-16_COMPILE_AS_OUTPUT = $(obj).err
 define TOOL_OPENWATCOM-16_COMPILE_AS_CMDS
-	$(QUIET) $(call TOOL_OPENWATCOM_ENV_SETUP) $(TOOL_OPENWATCOM_AS) \
+	$(QUIET) $(call TOOL_OPENWATCOM_ENV_SETUP_BD) $(TOOL_OPENWATCOM_AS) \
 		$(flags) \
 		$(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \
 		$(addprefix -d, $(defs)) \
@@ -60,7 +60,7 @@ TOOL_OPENWATCOM-16_COMPILE_C_DEPEND =
 TOOL_OPENWATCOM-16_COMPILE_C_DEPORD =
 TOOL_OPENWATCOM-16_COMPILE_C_OUTPUT = $(obj).err
 define TOOL_OPENWATCOM-16_COMPILE_C_CMDS
-	$(QUIET) $(call TOOL_OPENWATCOM_ENV_SETUP) $(TOOL_OPENWATCOM_CC16) \
+	$(QUIET) $(call TOOL_OPENWATCOM_ENV_SETUP_BD) $(TOOL_OPENWATCOM_CC16) \
 		$(flags) \
 		$(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \
 		$(addprefix -d, $(defs)) \
@@ -75,7 +75,7 @@ TOOL_OPENWATCOM-16_COMPILE_CXX_DEPEND =
 TOOL_OPENWATCOM-16_COMPILE_CXX_DEPORD =
 TOOL_OPENWATCOM-16_COMPILE_CXX_OUTPUT = $(obj).err
 define TOOL_OPENWATCOM-16_COMPILE_CXX_CMDS
-	$(QUIET) $(call TOOL_OPENWATCOM_ENV_SETUP) $(TOOL_OPENWATCOM_CXX16) \
+	$(QUIET) $(call TOOL_OPENWATCOM_ENV_SETUP_BD) $(TOOL_OPENWATCOM_CXX16) \
 		$(flags) \
 		$(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \
 		$(addprefix -d, $(defs)) \
@@ -104,7 +104,7 @@ TOOL_OPENWATCOM-16_LINK_LIBRARY_DEPEND = $(othersrc)
 TOOL_OPENWATCOM-16_LINK_LIBRARY_DEPORD =
 define TOOL_OPENWATCOM-16_LINK_LIBRARY_CMDS
 	$(QUIET)$(APPEND) -tn $(outbase).rsp $(foreach obj,$(call TOOL_OPENWATCOM_FIX_SLASHES,$(objs) $(othersrc)),'+"$(obj)"')
-	$(QUIET)$(TOOL_OPENWATCOM_ENV_SETUP) $(TOOL_OPENWATCOM_AR) $(flags) $(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) @$(outbase).rsp
+	$(QUIET)$(TOOL_OPENWATCOM_ENV_SETUP_BD) $(TOOL_OPENWATCOM_AR) $(flags) $(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) @$(outbase).rsp
 endef
 
 TOOL_OPENWATCOM-16_LINK_PROGRAM_OUTPUT = $(outbase).map
@@ -112,7 +112,7 @@ TOOL_OPENWATCOM-16_LINK_PROGRAM_OUTPUT_MAYBE = $(outbase).sym
 TOOL_OPENWATCOM-16_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc)
 TOOL_OPENWATCOM-16_LINK_PROGRAM_DEPORD =
 define TOOL_OPENWATCOM-16_LINK_PROGRAM_CMDS
-	$(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
+	$(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
 		$(TOOL_OPENWATCOM_LD16) \
 		$(flags) \
 		-fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \
@@ -132,7 +132,7 @@ TOOL_OPENWATCOM-16_LINK_DLL_OUTPUT_MAYBE = $(outbase).sym
 TOOL_OPENWATCOM-16_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc)
 TOOL_OPENWATCOM-16_LINK_DLL_DEPORD =
 define TOOL_OPENWATCOM-16_LINK_DLL_CMDS
-	$(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
+	$(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
 		$(TOOL_OPENWATCOM_LD16) \
 		$(flags) \
 		-fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \
@@ -152,7 +152,7 @@ TOOL_OPENWATCOM-16_LINK_SYSMOD_OUTPUT_MAYBE = $(outbase).sym
 TOOL_OPENWATCOM-16_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc)
 TOOL_OPENWATCOM-16_LINK_SYSMOD_DEPORD =
 define TOOL_OPENWATCOM-16_LINK_SYSMOD_CMDS
-	$(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
+	$(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
 		$(TOOL_OPENWATCOM_LD16) \
 		$(flags) \
 		-fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \
diff --git a/kBuild/tools/OPENWATCOM-WL.kmk b/kBuild/tools/OPENWATCOM-WL.kmk
index 7d28629..22fa44f 100644
--- a/kBuild/tools/OPENWATCOM-WL.kmk
+++ b/kBuild/tools/OPENWATCOM-WL.kmk
@@ -1,4 +1,4 @@
-# $Id: OPENWATCOM-WL.kmk 2663 2012-10-15 13:13:45Z bird $
+# $Id: OPENWATCOM-WL.kmk 2749 2015-01-23 01:01:02Z bird $
 ## @file
 # kBuild Tool Config - Open Watcom v1.4 and later, using wlink.
 #
@@ -54,7 +54,7 @@ define TOOL_OPENWATCOM-WL_LINK_PROGRAM_CMDS
 		$(foreach p,$(call TOOL_OPENWATCOM_FIX_SLASHES_SQ,$(libpath)),'LIBPath $p') \
         	$(foreach o,$(call TOOL_OPENWATCOM_FIX_SLASHES_SQ,$(filter-out %.res,$(objs)) $(othersrc)),'$(if $(filter %.lib %.a,$l),LIB,)File $o') \
 		$(foreach l,$(call TOOL_OPENWATCOM_FIX_SLASHES_SQ,$(libs)),'Library $l')
-	$(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP) \
+	$(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD) \
 		$(TOOL_OPENWATCOM_WLINK) @$(outbase).rsp
 	$(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP) \
 		$(TOOL_OPENWATCOM_RC) \
diff --git a/kBuild/tools/OPENWATCOM.kmk b/kBuild/tools/OPENWATCOM.kmk
index 2ced379..26fb276 100644
--- a/kBuild/tools/OPENWATCOM.kmk
+++ b/kBuild/tools/OPENWATCOM.kmk
@@ -1,4 +1,4 @@
-# $Id: OPENWATCOM.kmk 2732 2014-06-28 16:02:41Z bird $
+# $Id: OPENWATCOM.kmk 2750 2015-01-23 12:24:02Z bird $
 ## @file
 # kBuild Tool Config - Open Watcom v1.4 and later.
 #
@@ -35,7 +35,7 @@ TOOL_OPENWATCOM = Open Watcom v1.4 and later (generic)
 
 ifeq ($(PATH_TOOL_OPENWATCOM),)
  ifeq ($(PATH_TOOL_OPENWATCOM),)
-  PATH_TOOL_OPENWATCOM := $(wildcard $(KBUILD_DEVTOOLS_BLD)/openwatcom/v*)
+  PATH_TOOL_OPENWATCOM := $(wildcard $(KBUILD_DEVTOOLS_HST)/openwatcom/v*)
  endif
  ifeq ($(PATH_TOOL_OPENWATCOM),)
   PATH_TOOL_OPENWATCOM := $(wildcard $(KBUILD_DEVTOOLS_TRG)/openwatcom/v*)
@@ -147,6 +147,13 @@ else
 
 endif
 
+if $(KBUILD_KMK_REVISION) >= 2747
+ TOOL_OPENWATCOM_ENV_SETUP_BD ?= $(call TOOL_OPENWATCOM_ENV_SETUP,$1,$2 --wcc-brain-damage)
+else
+ TOOL_OPENWATCOM_ENV_SETUP_BD ?= $(call TOOL_OPENWATCOM_ENV_SETUP,$1,$2)
+endif
+
+
 # Functions for changing slashes (SQ = single quoted).
 if1of ($(KBUILD_HOST), os2 win)
  TOOL_OPENWATCOM_FIX_SLASHES = $(subst /,\\,$1)
@@ -202,7 +209,7 @@ TOOL_OPENWATCOM_COMPILE_AS_DEPEND =
 TOOL_OPENWATCOM_COMPILE_AS_DEPORD =
 TOOL_OPENWATCOM_COMPILE_AS_OUTPUT = $(obj).err
 define TOOL_OPENWATCOM_COMPILE_AS_CMDS
-	$(QUIET) $(call TOOL_OPENWATCOM_ENV_SETUP) $(TOOL_OPENWATCOM_AS) \
+	$(QUIET) $(call TOOL_OPENWATCOM_ENV_SETUP_BD) $(TOOL_OPENWATCOM_AS) \
 		$(flags) \
 		$(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \
 		$(addprefix -d, $(defs)) \
@@ -218,7 +225,7 @@ TOOL_OPENWATCOM_COMPILE_C_DEPEND =
 TOOL_OPENWATCOM_COMPILE_C_DEPORD =
 TOOL_OPENWATCOM_COMPILE_C_OUTPUT = $(obj).err
 define TOOL_OPENWATCOM_COMPILE_C_CMDS
-	$(QUIET) $(call TOOL_OPENWATCOM_ENV_SETUP) $(TOOL_OPENWATCOM_CC) \
+	$(QUIET) $(call TOOL_OPENWATCOM_ENV_SETUP_BD) $(TOOL_OPENWATCOM_CC) \
 		$(flags) \
 		$(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \
 		$(addprefix -d, $(defs)) \
@@ -233,7 +240,7 @@ TOOL_OPENWATCOM_COMPILE_CXX_DEPEND =
 TOOL_OPENWATCOM_COMPILE_CXX_DEPORD =
 TOOL_OPENWATCOM_COMPILE_CXX_OUTPUT = $(obj).err
 define TOOL_OPENWATCOM_COMPILE_CXX_CMDS
-	$(QUIET) $(call TOOL_OPENWATCOM_ENV_SETUP) $(TOOL_OPENWATCOM_CXX) \
+	$(QUIET) $(call TOOL_OPENWATCOM_ENV_SETUP_BD) $(TOOL_OPENWATCOM_CXX) \
 		$(flags) \
 		$(addsuffix , $(addprefix -i=, $(call TOOL_OPENWATCOM_FIX_SLASHES,$(incs)))) \
 		$(addprefix -d, $(defs)) \
@@ -272,14 +279,14 @@ define TOOL_OPENWATCOM_LINK_LIBRARY_CMDS
        	$(filter %.imp,$(othersrc)) \
                --append $(outbase).rsp \
 	)
-	$(QUIET)$(TOOL_OPENWATCOM_ENV_SETUP) $(TOOL_OPENWATCOM_AR) $(flags) $(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) @$(outbase).rsp
+	$(QUIET)$(TOOL_OPENWATCOM_ENV_SETUP_BD) $(TOOL_OPENWATCOM_AR) $(flags) $(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) @$(outbase).rsp
 endef
 
 TOOL_OPENWATCOM_LINK_PROGRAM_OUTPUT = $(outbase).map
 TOOL_OPENWATCOM_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc)
 TOOL_OPENWATCOM_LINK_PROGRAM_DEPORD =
 define TOOL_OPENWATCOM_LINK_PROGRAM_CMDS
-	$(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
+	$(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
 		$(TOOL_OPENWATCOM_LD) \
 		$(flags) \
 		-fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \
@@ -298,7 +305,7 @@ TOOL_OPENWATCOM_LINK_DLL_OUTPUT = $(outbase).map
 TOOL_OPENWATCOM_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc)
 TOOL_OPENWATCOM_LINK_DLL_DEPORD =
 define TOOL_OPENWATCOM_LINK_DLL_CMDS
-	$(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
+	$(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
 		$(TOOL_OPENWATCOM_LD) \
 		$(flags) \
 		-fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \
@@ -317,7 +324,7 @@ TOOL_OPENWATCOM_LINK_SYSMOD_OUTPUT = $(outbase).map
 TOOL_OPENWATCOM_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc)
 TOOL_OPENWATCOM_LINK_SYSMOD_DEPORD =
 define TOOL_OPENWATCOM_LINK_SYSMOD_CMDS
-	$(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
+	$(QUIET)$(call TOOL_OPENWATCOM_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
 		$(TOOL_OPENWATCOM_LD) \
 		$(flags) \
 		-fe=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(out)) \
diff --git a/kBuild/tools/TAR.kmk b/kBuild/tools/TAR.kmk
index 825daed..cde01cf 100644
--- a/kBuild/tools/TAR.kmk
+++ b/kBuild/tools/TAR.kmk
@@ -1,4 +1,4 @@
-# $Id: TAR.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: TAR.kmk 2750 2015-01-23 12:24:02Z bird $
 ## @file
 # kBuild Tool Config - tar unpacker.
 #
@@ -35,9 +35,9 @@ TOOL_TAR := tar unpacker.
 
 # Tool Specific Properties
 ifndef TOOL_TAR_TAR
- TOOL_TAR_TAR := $(wildcard $(KBUILD_DEVTOOLS_BLD)/tar/v*/tar$(HOSTSUFF_EXE))
+ TOOL_TAR_TAR := $(wildcard $(KBUILD_DEVTOOLS_HST)/tar/v*/tar$(HOSTSUFF_EXE))
  ifeq ($(TOOL_TAR_TAR),)
-  TOOL_TAR_TAR := $(wildcard $(KBUILD_DEVTOOLS_BLD)/bin/tar$(HOSTSUFF_EXE))
+  TOOL_TAR_TAR := $(wildcard $(KBUILD_DEVTOOLS_HST)/bin/tar$(HOSTSUFF_EXE))
  endif
  ifneq ($(TOOL_TAR_TAR),)
   TOOL_TAR_TAR := $(lastword $(sort $(TOOL_TAR_TAR)))
diff --git a/kBuild/tools/VAC308.kmk b/kBuild/tools/VAC308.kmk
index fad15b2..8a12242 100644
--- a/kBuild/tools/VAC308.kmk
+++ b/kBuild/tools/VAC308.kmk
@@ -1,4 +1,4 @@
-# $Id: VAC308.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: VAC308.kmk 2750 2015-01-23 12:24:02Z bird $
 ## @file
 # kBuild Tool Config - VisualAge for C++ v3.08.
 #
@@ -35,9 +35,9 @@ TOOL_VAC308 := VisualAge for C++ v3.08
 
 # Determin VAC308 location.
 ifndef PATH_TOOL_VAC308
- PATH_TOOL_VAC308 := $(wildcard $(KBUILD_DEVTOOLS_BLD)/vac/v3.0.8*)
+ PATH_TOOL_VAC308 := $(wildcard $(KBUILD_DEVTOOLS_HST)/vac/v3.0.8*)
  ifeq ($(PATH_TOOL_VAC308),)
-  PATH_TOOL_VAC308 := $(wildcard $(KBUILD_DEVTOOLS_BLD)/vac/v308*)
+  PATH_TOOL_VAC308 := $(wildcard $(KBUILD_DEVTOOLS_HST)/vac/v308*)
  endif
  ifeq ($(PATH_TOOL_VAC308),)
   PATH_TOOL_VAC308 := $(wildcard $(KBUILD_DEVTOOLS_TRG)/vac/v3.0.8*)
diff --git a/kBuild/tools/WATCOMC11C-16.kmk b/kBuild/tools/WATCOMC11C-16.kmk
index be907ec..a024628 100644
--- a/kBuild/tools/WATCOMC11C-16.kmk
+++ b/kBuild/tools/WATCOMC11C-16.kmk
@@ -1,4 +1,4 @@
-# $Id: WATCOMC11C-16.kmk 2731 2014-06-28 14:58:12Z bird $
+# $Id: WATCOMC11C-16.kmk 2749 2015-01-23 01:01:02Z bird $
 ## @file
 # kBuild Tool Config - Watcom C v11.0c, 16-bit targets.
 #
@@ -44,7 +44,7 @@ TOOL_WATCOMC11C-16_COMPILE_C_DEPEND =
 TOOL_WATCOMC11C-16_COMPILE_C_DEPORD =
 TOOL_WATCOMC11C-16_COMPILE_C_OUTPUT = $(obj).err
 define TOOL_WATCOMC11C-16_COMPILE_C_CMDS
-	$(QUIET) $(call TOOL_WATCOMC11C_ENV_SETUP) $(TOOL_WATCOMC11C_CC16) \
+	$(QUIET) $(call TOOL_WATCOMC11C_ENV_SETUP_BD) $(TOOL_WATCOMC11C_CC16) \
 		$(flags) \
 		$(addsuffix , $(addprefix -i=, $(subst /,\\,$(incs)))) \
 		$(addprefix -d, $(defs)) \
@@ -59,7 +59,7 @@ TOOL_WATCOMC11C-16_COMPILE_CXX_DEPEND =
 TOOL_WATCOMC11C-16_COMPILE_CXX_DEPORD =
 TOOL_WATCOMC11C-16_COMPILE_CXX_OUTPUT = $(obj).err
 define TOOL_WATCOMC11C-16_COMPILE_CXX_CMDS
-	$(QUIET) $(call TOOL_WATCOMC11C_ENV_SETUP) $(TOOL_WATCOMC11C_CXX16) \
+	$(QUIET) $(call TOOL_WATCOMC11C_ENV_SETUP_BD) $(TOOL_WATCOMC11C_CXX16) \
 		$(flags) \
 		$(addsuffix , $(addprefix -i=, $(subst /,\\,$(incs)))) \
 		$(addprefix -d, $(defs)) \
@@ -88,14 +88,14 @@ TOOL_WATCOMC11C-16_LINK_LIBRARY_DEPEND = $(othersrc)
 TOOL_WATCOMC11C-16_LINK_LIBRARY_DEPORD =
 define TOOL_WATCOMC11C-16_LINK_LIBRARY_CMDS
 	$(QUIET)$(APPEND) -tn $(outbase).rsp $(foreach obj,$(subst /,\,$(objs) $(othersrc)),'+"$(obj)"')
-	$(QUIET)$(TOOL_WATCOMC11C_ENV_SETUP) $(TOOL_WATCOMC11C_AR) $(flags) $(subst /,\\,$(out)) @$(outbase).rsp
+	$(QUIET)$(TOOL_WATCOMC11C_ENV_SETUP_BD) $(TOOL_WATCOMC11C_AR) $(flags) $(subst /,\\,$(out)) @$(outbase).rsp
 endef
 
 TOOL_WATCOMC11C-16_LINK_PROGRAM_OUTPUT = $(outbase).map
 TOOL_WATCOMC11C-16_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc)
 TOOL_WATCOMC11C-16_LINK_PROGRAM_DEPORD =
 define TOOL_WATCOMC11C-16_LINK_PROGRAM_CMDS
-	$(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
+	$(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
 		$(TOOL_WATCOMC11C_LD16) \
 		$(flags) \
 		-fe=$(subst /,\\,$(out)) \
@@ -114,7 +114,7 @@ TOOL_WATCOMC11C-16_LINK_DLL_OUTPUT = $(outbase).map
 TOOL_WATCOMC11C-16_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc)
 TOOL_WATCOMC11C-16_LINK_DLL_DEPORD =
 define TOOL_WATCOMC11C-16_LINK_DLL_CMDS
-	$(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
+	$(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
 		$(TOOL_WATCOMC11C_LD16) \
 		$(flags) \
 		-fe=$(subst /,\\,$(out)) \
@@ -133,7 +133,7 @@ TOOL_WATCOMC11C-16_LINK_SYSMOD_OUTPUT = $(outbase).map
 TOOL_WATCOMC11C-16_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc)
 TOOL_WATCOMC11C-16_LINK_SYSMOD_DEPORD =
 define TOOL_WATCOMC11C-16_LINK_SYSMOD_CMDS
-	$(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
+	$(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
 		$(TOOL_WATCOMC11C_LD16) \
 		$(flags) \
 		-fe=$(subst /,\\,$(out)) \
diff --git a/kBuild/tools/WATCOMC11C-WL.kmk b/kBuild/tools/WATCOMC11C-WL.kmk
index e494af5..34919e3 100644
--- a/kBuild/tools/WATCOMC11C-WL.kmk
+++ b/kBuild/tools/WATCOMC11C-WL.kmk
@@ -1,4 +1,4 @@
-# $Id: WATCOMC11C-WL.kmk 2413 2010-09-11 17:43:04Z bird $
+# $Id: WATCOMC11C-WL.kmk 2749 2015-01-23 01:01:02Z bird $
 ## @file
 # kBuild Tool Config - Watcom C/C++ v11.0c, using wlink.
 #
@@ -53,7 +53,7 @@ define TOOL_WATCOMC11C-WL_LINK_PROGRAM_CMDS
 		$(foreach p,$(subst /,\,$(libpath)),'LIBPath $p') \
         $(foreach o,$(subst /,\,$(filter-out %.res,$(objs)) $(othersrc)),'$(if $(filter %.lib %.a,$l),LIB,)File $o') \
 		$(foreach l,$(subst /,\,$(libs)),'Library $l')
-	$(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP) \
+	$(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP_BD) \
 		$(TOOL_WATCOMC11C_WLINK) @$(outbase).rsp
 	$(if $(filter %.res,$(objs)), $(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP) \
 		$(TOOL_WATCOMC11C_RC) \
diff --git a/kBuild/tools/WATCOMC11C.kmk b/kBuild/tools/WATCOMC11C.kmk
index 44bb885..f33dd6b 100644
--- a/kBuild/tools/WATCOMC11C.kmk
+++ b/kBuild/tools/WATCOMC11C.kmk
@@ -1,4 +1,4 @@
-# $Id: WATCOMC11C.kmk 2731 2014-06-28 14:58:12Z bird $
+# $Id: WATCOMC11C.kmk 2750 2015-01-23 12:24:02Z bird $
 ## @file
 # kBuild Tool Config - Watcom C v11.0c
 #
@@ -35,7 +35,7 @@ TOOL_WATCOMC11C = Watcom C/C++ v11.0c (generic)
 
 ifeq ($(PATH_TOOL_WATCOMC11C),)
  ifeq ($(PATH_TOOL_WATCOMC11C),)
-  PATH_TOOL_WATCOMC11C := $(wildcard $(KBUILD_DEVTOOLS_BLD)/watcom/v11.0c*)
+  PATH_TOOL_WATCOMC11C := $(wildcard $(KBUILD_DEVTOOLS_HST)/watcom/v11.0c*)
  endif
  ifeq ($(PATH_TOOL_WATCOMC11C),)
   PATH_TOOL_WATCOMC11C := $(wildcard $(KBUILD_DEVTOOLS_TRG)/watcom/v11.0c*)
@@ -113,6 +113,13 @@ else
 
 endif
 
+if $(KBUILD_KMK_REVISION) >= 2747
+ TOOL_WATCOMC11C_ENV_SETUP_BD ?= $(call TOOL_WATCOMC11C_ENV_SETUP,$1,$2 --wcc-brain-damage)
+else
+ TOOL_WATCOMC11C_ENV_SETUP_BD ?= $(call TOOL_WATCOMC11C_ENV_SETUP,$1,$2)
+endif
+
+
 # General Properties used by kBuild
 TOOL_WATCOMC11C_COBJSUFF         ?= .obj
 TOOL_WATCOMC11C_CFLAGS           ?= -zq
@@ -151,7 +158,7 @@ TOOL_WATCOMC11C_COMPILE_C_DEPEND =
 TOOL_WATCOMC11C_COMPILE_C_DEPORD =
 TOOL_WATCOMC11C_COMPILE_C_OUTPUT = $(obj).err
 define TOOL_WATCOMC11C_COMPILE_C_CMDS
-	$(QUIET) $(call TOOL_WATCOMC11C_ENV_SETUP) $(TOOL_WATCOMC11C_CC) \
+	$(QUIET) $(call TOOL_WATCOMC11C_ENV_SETUP_BD) $(TOOL_WATCOMC11C_CC) \
 		$(flags) \
 		$(addsuffix , $(addprefix -i=, $(subst /,\\,$(incs)))) \
 		$(addprefix -d, $(defs)) \
@@ -166,7 +173,7 @@ TOOL_WATCOMC11C_COMPILE_CXX_DEPEND =
 TOOL_WATCOMC11C_COMPILE_CXX_DEPORD =
 TOOL_WATCOMC11C_COMPILE_CXX_OUTPUT = $(obj).err
 define TOOL_WATCOMC11C_COMPILE_CXX_CMDS
-	$(QUIET) $(call TOOL_WATCOMC11C_ENV_SETUP) $(TOOL_WATCOMC11C_CXX) \
+	$(QUIET) $(call TOOL_WATCOMC11C_ENV_SETUP_BD) $(TOOL_WATCOMC11C_CXX) \
 		$(flags) \
 		$(addsuffix , $(addprefix -i=, $(subst /,\\,$(incs)))) \
 		$(addprefix -d, $(defs)) \
@@ -195,14 +202,14 @@ TOOL_WATCOMC11C_LINK_LIBRARY_DEPEND = $(othersrc)
 TOOL_WATCOMC11C_LINK_LIBRARY_DEPORD =
 define TOOL_WATCOMC11C_LINK_LIBRARY_CMDS
 	$(QUIET)$(APPEND) -tn $(outbase).rsp $(foreach obj,$(subst /,\,$(objs) $(othersrc)),'+"$(obj)"')
-	$(QUIET)$(TOOL_WATCOMC11C_ENV_SETUP) $(TOOL_WATCOMC11C_AR) $(flags) $(subst /,\\,$(out)) @$(outbase).rsp
+	$(QUIET)$(TOOL_WATCOMC11C_ENV_SETUP_BD) $(TOOL_WATCOMC11C_AR) $(flags) $(subst /,\\,$(out)) @$(outbase).rsp
 endef
 
 TOOL_WATCOMC11C_LINK_PROGRAM_OUTPUT = $(outbase).map
 TOOL_WATCOMC11C_LINK_PROGRAM_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc)
 TOOL_WATCOMC11C_LINK_PROGRAM_DEPORD =
 define TOOL_WATCOMC11C_LINK_PROGRAM_CMDS
-	$(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
+	$(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
 		$(TOOL_WATCOMC11C_LD) \
 		$(flags) \
 		-fe=$(subst /,\\,$(out)) \
@@ -221,7 +228,7 @@ TOOL_WATCOMC11C_LINK_DLL_OUTPUT = $(outbase).map
 TOOL_WATCOMC11C_LINK_DLL_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc)
 TOOL_WATCOMC11C_LINK_DLL_DEPORD =
 define TOOL_WATCOMC11C_LINK_DLL_CMDS
-	$(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
+	$(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
 		$(TOOL_WATCOMC11C_LD) \
 		$(flags) \
 		-fe=$(subst /,\\,$(out)) \
@@ -240,7 +247,7 @@ TOOL_WATCOMC11C_LINK_SYSMOD_OUTPUT = $(outbase).map
 TOOL_WATCOMC11C_LINK_SYSMOD_DEPEND = $(foreach lib,$(libs),$(if $(findstring $(lib),$(subst /,x,$(lib))),, $(lib))) $(othersrc)
 TOOL_WATCOMC11C_LINK_SYSMOD_DEPORD =
 define TOOL_WATCOMC11C_LINK_SYSMOD_CMDS
-	$(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
+	$(QUIET)$(call TOOL_WATCOMC11C_ENV_SETUP_BD,$(subst $(SP),,$(addsuffix ;,$(libpath))),-C $(dir $(out))) \
 		$(TOOL_WATCOMC11C_LD) \
 		$(flags) \
 		-fe=$(subst /,\\,$(out)) \
diff --git a/kBuild/tools/WGET.kmk b/kBuild/tools/WGET.kmk
index 2bd0670..c644c36 100644
--- a/kBuild/tools/WGET.kmk
+++ b/kBuild/tools/WGET.kmk
@@ -1,4 +1,4 @@
-# $Id: WGET.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: WGET.kmk 2750 2015-01-23 12:24:02Z bird $
 ## @file
 # kBuild Tool Config - wget fetchers.
 #
@@ -35,9 +35,9 @@ TOOL_WGET := wget fetcher.
 
 # Tool Specific Properties
 ifndef TOOL_WGET_FETCH
- TOOL_WGET_FETCH := $(wildcard $(KBUILD_DEVTOOLS_BLD)/wget/v*/wget$(HOSTSUFF_EXE))
+ TOOL_WGET_FETCH := $(wildcard $(KBUILD_DEVTOOLS_HST)/wget/v*/wget$(HOSTSUFF_EXE))
  ifneq ($(TOOL_WGET_FETCH),)
-  TOOL_WGET_FETCH := $(wildcard $(KBUILD_DEVTOOLS_BLD)/bin/wget$(HOSTSUFF_EXE))
+  TOOL_WGET_FETCH := $(wildcard $(KBUILD_DEVTOOLS_HST)/bin/wget$(HOSTSUFF_EXE))
  endif
  ifneq ($(TOOL_WGET_FETCH),)
   TOOL_WGET_FETCH := $(lastword $(sort $(TOOL_WGET_FETCH)))
diff --git a/kBuild/tools/XGCCAMD64LINUX.kmk b/kBuild/tools/XGCCAMD64LINUX.kmk
index 2430a8b..4b81f42 100644
--- a/kBuild/tools/XGCCAMD64LINUX.kmk
+++ b/kBuild/tools/XGCCAMD64LINUX.kmk
@@ -1,4 +1,4 @@
-# $Id: XGCCAMD64LINUX.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: XGCCAMD64LINUX.kmk 2750 2015-01-23 12:24:02Z bird $
 ## @file
 # kBuild Tool Config - GCC Cross compiler for AMD64+Linux.
 #
@@ -43,7 +43,7 @@ else # x-compile:
  ifndef TOOL_XGCCAMD64LINUX_PREFIX
   TOOL_XGCCAMD64LINUX_PREFIX := x86_64-unknown-linux-gnu-
   ifndef PATH_TOOL_XGCCAMD64LINUX
-   PATH_TOOL_XGCCAMD64LINUX := $(sort $(wildcard $(KBUILD_DEVTOOLS_BLD)/x86_64-unknown-linux-gnu/*))
+   PATH_TOOL_XGCCAMD64LINUX := $(sort $(wildcard $(KBUILD_DEVTOOLS_HST)/x86_64-unknown-linux-gnu/*))
    ifeq ($(PATH_TOOL_XGCCAMD64LINUX),)
     ifeq ($(filter-out win.amd64,$(KBUILD_HOST).$(KBUILD_HOST_ARCH)),) # these can use the windows build.
      TOOL_XGCCAMD64LINUX_EXEC_PREFIX ?= $(EXEC_X86_WIN32)
diff --git a/kBuild/tools/YASM.kmk b/kBuild/tools/YASM.kmk
index 24a2041..725402c 100644
--- a/kBuild/tools/YASM.kmk
+++ b/kBuild/tools/YASM.kmk
@@ -1,4 +1,4 @@
-# $Id: YASM.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: YASM.kmk 2750 2015-01-23 12:24:02Z bird $
 ## @file
 # kBuild Tool Config - YASM 0.4.0 or later.
 #
@@ -35,7 +35,7 @@ TOOL_YASM := YASM v0.4.0+
 
 # Tool Specific Properties
 ifndef PATH_TOOL_YASM
- PATH_TOOL_YASM := $(sort $(wildcard $(KBUILD_DEVTOOLS_BLD)/yasm/v*.*))
+ PATH_TOOL_YASM := $(sort $(wildcard $(KBUILD_DEVTOOLS_HST)/yasm/v*.*))
  ifneq ($(PATH_TOOL_YASM),)
   PATH_TOOL_YASM := $(call lastword,$(PATH_TOOL_YASM))
  endif
diff --git a/kBuild/tools/ZIP.kmk b/kBuild/tools/ZIP.kmk
index b84f2a4..d5a0217 100644
--- a/kBuild/tools/ZIP.kmk
+++ b/kBuild/tools/ZIP.kmk
@@ -1,4 +1,4 @@
-# $Id: ZIP.kmk 2726 2014-02-26 23:23:54Z bird $
+# $Id: ZIP.kmk 2750 2015-01-23 12:24:02Z bird $
 ## @file
 # kBuild Tool Config - The zip/unzip packer/unpacker.
 #
@@ -35,12 +35,12 @@ TOOL_ZIP := The zip/unzip packer/unpacker.
 
 # Tool Specific Properties
 ifndef TOOL_ZIP_UNPACK
- TOOL_ZIP_UNPACK := $(wildcard $(KBUILD_DEVTOOLS_BLD)/unzip/v*/unzip$(HOSTSUFF_EXE))
+ TOOL_ZIP_UNPACK := $(wildcard $(KBUILD_DEVTOOLS_HST)/unzip/v*/unzip$(HOSTSUFF_EXE))
  ifeq ($(TOOL_ZIP_UNPACK),)
-  TOOL_ZIP_UNPACK := $(wildcard $(KBUILD_DEVTOOLS_BLD)/zip/v*/unzip$(HOSTSUFF_EXE))
+  TOOL_ZIP_UNPACK := $(wildcard $(KBUILD_DEVTOOLS_HST)/zip/v*/unzip$(HOSTSUFF_EXE))
  endif
  ifeq ($(TOOL_ZIP_UNPACK),)
-  TOOL_ZIP_UNPACK := $(wildcard $(KBUILD_DEVTOOLS_BLD)/bin/unzip$(HOSTSUFF_EXE))
+  TOOL_ZIP_UNPACK := $(wildcard $(KBUILD_DEVTOOLS_HST)/bin/unzip$(HOSTSUFF_EXE))
  endif
  ifneq ($(TOOL_ZIP_UNPACK),)
   TOOL_ZIP_UNPACK := $(lastword $(sort $(TOOL_ZIP_UNPACK)))
@@ -51,12 +51,12 @@ else
  TOOL_ZIP_UNPACK := $(TOOL_ZIP_UNPACK)
 endif
 #ifndef TOOL_ZIP_PACK
-# TOOL_ZIP_PACK := $(wildcard $(KBUILD_DEVTOOLS_BLD)/zip/v*/zip$(HOSTSUFF_EXE))
+# TOOL_ZIP_PACK := $(wildcard $(KBUILD_DEVTOOLS_HST)/zip/v*/zip$(HOSTSUFF_EXE))
 # ifeq ($(TOOL_ZIP_PACK),)
-#  TOOL_ZIP_PACK := $(wildcard $(KBUILD_DEVTOOLS_BLD)/unzip/v*/zip$(HOSTSUFF_EXE))
+#  TOOL_ZIP_PACK := $(wildcard $(KBUILD_DEVTOOLS_HST)/unzip/v*/zip$(HOSTSUFF_EXE))
 # endif
 # ifeq ($(TOOL_ZIP_PACK),)
-#  TOOL_ZIP_PACK := $(wildcard $(KBUILD_DEVTOOLS_BLD)/bin/zip$(HOSTSUFF_EXE))
+#  TOOL_ZIP_PACK := $(wildcard $(KBUILD_DEVTOOLS_HST)/bin/zip$(HOSTSUFF_EXE))
 # endif
 # ifneq ($(TOOL_ZIP_PACK),)
 #  TOOL_ZIP_PACK := $(lastword $(sort $(TOOL_ZIP_PACK)))
diff --git a/src/kmk/Makefile.kmk b/src/kmk/Makefile.kmk
index 7b7e11c..83efb22 100644
--- a/src/kmk/Makefile.kmk
+++ b/src/kmk/Makefile.kmk
@@ -1,4 +1,4 @@
-# $Id: Makefile.kmk 2719 2014-01-01 17:40:56Z bird $
+# $Id: Makefile.kmk 2765 2015-01-30 00:27:51Z bird $
 ## @file
 # Sub-makefile for kmk / GNU Make.
 #
@@ -192,6 +192,7 @@ kmk_DEFS = \
 	CONFIG_WITH_RDONLY_VARIABLE_VALUE \
 	CONFIG_WITH_LAZY_DEPS_VARS \
 	CONFIG_WITH_MEMORY_OPTIMIZATIONS \
+	CONFIG_WITH_COMPILER \
 	\
 	KBUILD_HOST=\"$(KBUILD_TARGET)\" \
 	KBUILD_HOST_ARCH=\"$(KBUILD_TARGET_ARCH)\" \
@@ -200,17 +201,15 @@ kmk_DEFS.x86 = CONFIG_WITH_OPTIMIZATION_HACKS
 kmk_DEFS.amd64 = CONFIG_WITH_OPTIMIZATION_HACKS
 kmk_DEFS.win = CONFIG_NEW_WIN32_CTRL_EVENT CONFIG_WITH_FAST_IS_SPACE
 kmk_DEFS.debug = CONFIG_WITH_MAKE_STATS
+ifdef CONFIG_WITH_MAKE_STATS
+ kmk_DEFS += CONFIG_WITH_MAKE_STATS
+endif
 
 kmk_SOURCES = \
 	main.c \
-	kbuild.c \
-	kbuild-object.c \
 	read.c \
-	expreval.c \
-	incdep.c \
 	hash.c \
 	strcache.c \
-	strcache2.c \
 	variable.c \
 	ar.c \
 	arscan.c \
@@ -223,13 +222,20 @@ kmk_SOURCES = \
 	implicit.c \
 	job.c \
 	misc.c \
-	alloccache.c \
 	remake.c \
 	rule.c \
 	signame.c \
 	version.c \
 	vpath.c \
-	remote-stub.c
+	remote-stub.c \
+       \
+	alloccache.c \
+	expreval.c \
+	incdep.c \
+	strcache2.c \
+       kmk_cc_exec.c \
+	kbuild.c \
+	kbuild-object.c
 
 kmk_DEFS.freebsd.x86 = CONFIG_WITHOUT_THREADS
 
diff --git a/src/kmk/commands.c b/src/kmk/commands.c
index bc74e18..6e4bd21 100644
--- a/src/kmk/commands.c
+++ b/src/kmk/commands.c
@@ -629,6 +629,27 @@ chop_commands (struct commands *cmds)
     }
 }
 

+#ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS
+/* This is for saving memory in func_commands. */
+void
+free_chopped_commands (struct commands *cmds)
+{
+  if (   cmds
+      && cmds->command_lines != 0
+      && cmds->refs == 0)
+    {
+      unsigned idx = cmds->ncommand_lines;
+      while (idx-- > 0)
+        free (cmds->command_lines[idx]);
+      free (cmds->command_lines);
+      free (cmds->lines_flags);
+      cmds->command_lines = 0;
+      cmds->lines_flags = 0;
+      cmds->ncommand_lines = 0;
+    }
+}
+

+#endif /* CONFIG_WITH_MEMORY_OPTIMIZATIONS */
 /* Execute the commands to remake FILE.  If they are currently executing,
    return or have already finished executing, just return.  Otherwise,
    fork off a child process to run the first command line in the sequence.  */
diff --git a/src/kmk/commands.h b/src/kmk/commands.h
index df4ab4c..581713d 100644
--- a/src/kmk/commands.h
+++ b/src/kmk/commands.h
@@ -56,6 +56,9 @@ void execute_file_commands (struct file *file);
 void print_commands (const struct commands *cmds);
 void delete_child_targets (struct child *child);
 void chop_commands (struct commands *cmds);
+#ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS
+void free_chopped_commands (struct commands *cmd);
+#endif
 #if defined(CONFIG_WITH_COMMANDS_FUNC) || defined (CONFIG_WITH_DOT_MUST_MAKE)
 void set_file_variables (struct file *file, int called_early);
 #else
diff --git a/src/kmk/config.h.win b/src/kmk/config.h.win
index 4cb172a..64e42d7 100644
--- a/src/kmk/config.h.win
+++ b/src/kmk/config.h.win
@@ -16,6 +16,9 @@ You should have received a copy of the GNU General Public License along with
 GNU Make; see the file COPYING.  If not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.  */
 
+#ifndef ___config_h_win
+#define ___config_h_win
+
 /* Suppress some Visual C++ warnings.
    Maybe after the code cleanup for ISO C we can remove some/all of these.  */
 #if _MSC_VER > 1000
@@ -218,7 +221,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.  */
 #define HAVE_STDARG_H 1
 
 /* Define to 1 if you have the <stdint.h> header file. */
-/*#define HAVE_STDINT_H 1*/
+#if _MSC_VER >= 1600
+# define HAVE_STDINT_H 1
+#endif
 
 /* Define to 1 if you have the <stdlib.h> header file. */
 #define HAVE_STDLIB_H 1
@@ -443,10 +448,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.  */
 #define uid_t int
 
 /* Define uintmax_t if not defined in <stdint.h> or <inttypes.h>. */
-#if 0
-#define uintmax_t unsigned long
-#else
-#define uintmax_t unsigned __int64
+#if _MSC_VER < 1600
+# if 0
+#  define uintmax_t unsigned long
+# else
+#  define uintmax_t unsigned __int64
+# endif
 #endif
 
 /* Define as `fork' if `vfork' does not work. */
@@ -533,8 +540,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.  */
 #define _DIRENT_HAVE_D_NAMLEN 1
 #define _DIRENT_HAVE_D_TYPE   1
 
-
-/* cygwin sucks to much in one end or the other. */
+/* bird: Not sure if this is necessary any more... */
 #define BATCH_MODE_ONLY_SHELL
 
 #include "inlined_memchr.h"
@@ -556,3 +562,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.  */
 extern char space_map[space_map_size];
 #endif
 
+/* bird: Include mscfakes.h to make sure we have all it's tricks applied. */
+#ifndef ___mscfakes_h
+# include "kmkbuiltin/mscfakes.h"
+#endif
+
+#endif /* bird */
+
diff --git a/src/kmk/dir.c b/src/kmk/dir.c
index 335c2f8..2bef610 100644
--- a/src/kmk/dir.c
+++ b/src/kmk/dir.c
@@ -1310,7 +1310,11 @@ print_dir_data_base (void)
 

 /* Hooks for globbing.  */
 
+#if defined(KMK) && !defined(__OS2__)
+# include "glob/glob.h"
+#else
 #include <glob.h>
+#endif
 
 /* Structure describing state of iterating through a directory hash table.  */
 
diff --git a/src/kmk/expand.c b/src/kmk/expand.c
index c93e197..7deeb99 100644
--- a/src/kmk/expand.c
+++ b/src/kmk/expand.c
@@ -25,6 +25,9 @@ this program.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "commands.h"
 #include "variable.h"
 #include "rule.h"
+#ifdef CONFIG_WITH_COMPILER
+# include "kmk_cc_exec.h"
+#endif
 
 /* Initially, any errors reported when expanding strings will be reported
    against the file where the error appears.  */
@@ -185,7 +188,19 @@ recursively_expand_for_file (struct variable *v, struct file *file,
     value = allocated_variable_expand (v->value);
 #else  /* CONFIG_WITH_VALUE_LENGTH */
   if (!v->append)
-    value = allocated_variable_expand_2 (v->value, v->value_length, value_lenp);
+    {
+      if (!IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR (v))
+        value = allocated_variable_expand_2 (v->value, v->value_length, value_lenp);
+      else
+        {
+          unsigned int len = v->value_length;
+          value = xmalloc (len + 2);
+          memcpy (value, v->value, len + 1);
+          value[len + 1] = '\0'; /* Extra terminator like allocated_variable_expand_2 returns. Why? */
+          if (value_lenp)
+            *value_lenp = len;
+        }
+    }
   else
     {
       value = allocated_variable_append (v);
@@ -207,11 +222,11 @@ recursively_expand_for_file (struct variable *v, struct file *file,
 }
 
 #ifdef CONFIG_WITH_VALUE_LENGTH
-/* Static worker for reference_variable() that expands the recursive
+/* Worker for reference_variable() and kmk_exec_* that expands the recursive
    variable V. The main difference between this and
    recursively_expand[_for_file] is that this worker avoids the temporary
    buffer and outputs directly into the current variable buffer (O).  */
-static char *
+char *
 reference_recursive_variable (char *o, struct variable *v)
 {
   const struct floc *this_var;
@@ -246,8 +261,20 @@ reference_recursive_variable (char *o, struct variable *v)
 
   v->expanding = 1;
   if (!v->append)
-    /* Expand directly into the variable buffer.  */
-    variable_expand_string_2 (o, v->value, v->value_length, &o);
+    {
+      /* Expand directly into the variable buffer.  */
+# ifdef CONFIG_WITH_COMPILER
+      v->expand_count++;
+      if (   v->expandprog
+          || (v->expand_count == 3 && kmk_cc_compile_variable_for_expand (v)) )
+        o = kmk_exec_expand_to_var_buf (v, o);
+      else
+        variable_expand_string_2 (o, v->value, v->value_length, &o);
+# else
+      MAKE_STATS_2 (v->expand_count++);
+      variable_expand_string_2 (o, v->value, v->value_length, &o);
+# endif
+    }
   else
     {
       /* XXX: Feel free to optimize appending target variables as well.  */
@@ -295,7 +322,7 @@ reference_variable (char *o, const char *name, unsigned int length)
 
 #ifdef CONFIG_WITH_VALUE_LENGTH
   assert (v->value_length == strlen (v->value));
-  if (!v->recursive)
+  if (!v->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR (v))
     o = variable_buffer_output (o, v->value, v->value_length);
   else
     o = reference_recursive_variable (o, v);
@@ -987,7 +1014,7 @@ variable_append (const char *name, unsigned int length,
 #endif
 
   /* Either expand it or copy it, depending.  */
-  if (! v->recursive)
+  if (! v->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR (v))
 #ifdef CONFIG_WITH_VALUE_LENGTH
     return variable_buffer_output (buf, v->value, v->value_length);
 #else
@@ -1058,6 +1085,7 @@ append_expanded_string_to_variable (struct variable *v, const char *value,
       v->value = variable_buffer;
       v->value_length = p - v->value;
       v->value_alloc_len = variable_buffer_length;
+      VARIABLE_CHANGED(v);
 
       /* Restore the variable buffer, but without freeing the current. */
       variable_buffer = NULL;
@@ -1195,8 +1223,42 @@ install_variable_buffer (char **bufp, unsigned int *lenp)
   initialize_variable_output ();
 }
 
-/* Restore a previously-saved variable_buffer setting (free the current one).
- */
+#ifdef CONFIG_WITH_COMPILER
+/* Same as install_variable_buffer, except we supply a size hint.  */
+
+char *
+install_variable_buffer_with_hint (char **bufp, unsigned int *lenp, unsigned int size_hint)
+{
+  struct recycled_buffer *recycled;
+  char *buf;
+
+  *bufp = variable_buffer;
+  *lenp = variable_buffer_length;
+
+  recycled = recycled_head;
+  if (recycled)
+    {
+      recycled_head = recycled->next;
+      variable_buffer_length = recycled->length;
+      variable_buffer = buf = (char *)recycled;
+    }
+  else
+    {
+      if (size_hint < 512)
+        variable_buffer_length = (size_hint + 1 + 63) & ~(unsigned int)63;
+      else if (size_hint < 4096)
+        variable_buffer_length = (size_hint + 1 + 1023) & ~(unsigned int)1023;
+      else
+        variable_buffer_length = (size_hint + 1 + 4095) & ~(unsigned int)4095;
+      variable_buffer = buf = xmalloc (variable_buffer_length);
+    }
+  buf[0] = '\0';
+  return buf;
+}
+#endif /* CONFIG_WITH_COMPILER */
+
+/* Restore a previously-saved variable_buffer setting (free the
+   current one). */
 
 void
 restore_variable_buffer (char *buf, unsigned int len)
@@ -1211,3 +1273,24 @@ restore_variable_buffer (char *buf, unsigned int len)
   variable_buffer = buf;
   variable_buffer_length = len;
 }
+
+
+/* Used to make sure there is at least SIZE bytes of buffer space
+   available starting at PTR.  */
+char *
+ensure_variable_buffer_space(char *ptr, unsigned int size)
+{
+  unsigned int offset = (unsigned int)(ptr - variable_buffer);
+  assert(offset <= variable_buffer_length);
+  if (variable_buffer_length - offset < size)
+    {
+      unsigned minlen = size + offset;
+      variable_buffer_length *= 2;
+      if (variable_buffer_length < minlen + 100)
+        variable_buffer_length = (minlen + 100 + 63) & ~(unsigned int)63;
+      variable_buffer = xrealloc (variable_buffer, variable_buffer_length);
+      ptr = variable_buffer + offset;
+    }
+  return ptr;
+}
+
diff --git a/src/kmk/function.c b/src/kmk/function.c
index 68409f7..6852a84 100644
--- a/src/kmk/function.c
+++ b/src/kmk/function.c
@@ -43,6 +43,9 @@ this program.  If not, see <http://www.gnu.org/licenses/>.  */
 #  include <limits.h>
 # endif
 #endif
+#ifdef CONFIG_WITH_COMPILER
+# include "kmk_cc_exec.h"
+#endif
 #include <assert.h> /* bird */
 
 #if defined (CONFIG_WITH_MATH) || defined (CONFIG_WITH_NANOTS) || defined (CONFIG_WITH_FILE_SIZE) /* bird */
@@ -1349,6 +1352,7 @@ func_foreach (char *o, char **argv, const char *funcname UNUSED)
       memcpy (var->value, p, len);
       var->value[len] = '\0';
       var->value_length = len;
+      VARIABLE_CHANGED (var);
 
       variable_expand_string_2 (o, body, body_len, &o);
       o = variable_buffer_output (o, " ", 1);
@@ -1741,7 +1745,8 @@ func_sort (char *o, char **argv, const char *funcname UNUSED)
   wordi = 0;
   while ((p = find_next_token (&t, &len)) != 0)
     {
-      ++t;
+      if (*t != '\0') /* bird: Fixes access beyond end of string and overflowing words array. */
+        ++t;
       p[len] = '\0';
       words[wordi++] = p;
     }
@@ -2033,31 +2038,52 @@ func_evalval (char *o, char **argv, const char *funcname)
       int var_ctx;
       size_t off;
       const struct floc *reading_file_saved = reading_file;
+# ifdef CONFIG_WITH_MAKE_STATS
+      unsigned long long uStartTick = CURRENT_CLOCK_TICK();
+#  ifndef CONFIG_WITH_COMPILER
+      MAKE_STATS_2(v->evalval_count++);
+#  endif
+# endif
 
-      /* Make a copy of the value to the variable buffer since
-         eval_buffer will make changes to its input. */
-
-      off = o - variable_buffer;
-      variable_buffer_output (o, v->value, v->value_length + 1);
-      o = variable_buffer + off;
-
-      /* Eval the value.  Pop the current variable buffer setting so that the
-         eval'd code can use its own without conflicting. (really necessary?)  */
-
-      install_variable_buffer (&buf, &len);
       var_ctx = !strcmp (funcname, "evalvalctx");
       if (var_ctx)
         push_new_variable_scope ();
       if (v->fileinfo.filenm)
         reading_file = &v->fileinfo;
 
-      assert (!o[v->value_length]);
-      eval_buffer (o, o + v->value_length);
+# ifdef CONFIG_WITH_COMPILER
+      /* If this variable has been evaluated more than a few times, it make
+         sense to compile it to speed up the processing. */
+
+      v->evalval_count++;
+      if (   v->evalprog
+          || (v->evalval_count == 3 && kmk_cc_compile_variable_for_eval (v)))
+        {
+          install_variable_buffer (&buf, &len); /* Really necessary? */
+          kmk_exec_evalval (v);
+          restore_variable_buffer (buf, len);
+        }
+      else
+# endif
+      {
+        /* Make a copy of the value to the variable buffer first since
+           eval_buffer will make changes to its input. */
+
+        off = o - variable_buffer;
+        variable_buffer_output (o, v->value, v->value_length + 1);
+        o = variable_buffer + off;
+        assert (!o[v->value_length]);
+
+        install_variable_buffer (&buf, &len); /* Really necessary? */
+        eval_buffer (o, o + v->value_length);
+        restore_variable_buffer (buf, len);
+      }
 
       reading_file = reading_file_saved;
       if (var_ctx)
         pop_variable_scope ();
-      restore_variable_buffer (buf, len);
+
+      MAKE_STATS_2(v->cTicksEvalVal += CURRENT_CLOCK_TICK() - uStartTick);
     }
 
   return o;
@@ -2126,6 +2152,17 @@ func_eval_optimize_variable (char *o, char **argv, const char *funcname)
               *dst = '\0';
               v->value_length = dst - v->value;
             }
+
+          VARIABLE_CHANGED (v);
+
+# ifdef CONFIG_WITH_COMPILER
+          /* Compile the variable for evalval, evalctx and expansion. */
+
+          if (   v->recursive
+              && !IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR (v))
+                kmk_cc_compile_variable_for_expand (v);
+          kmk_cc_compile_variable_for_eval (v);
+# endif
         }
       else if (v)
         error (NILF, _("$(%s ): variable `%s' is of the wrong type\n"), funcname, v->name);
@@ -4067,7 +4104,8 @@ func_comp_vars (char *o, char **argv, const char *funcname)
     return variable_buffer_output (o, argv[2], strlen(argv[2]));
   if (var1->value == var2->value)
     return variable_buffer_output (o, "", 0);       /* eq */
-  if (!var1->recursive && !var2->recursive)
+  if (   (!var1->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR (var1))
+      && (!var2->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR (var2)) )
   {
     if (    var1->value_length == var2->value_length
         &&  !memcmp (var1->value, var2->value, var1->value_length))
@@ -4597,6 +4635,7 @@ func_stack_pop_top (char *o, char **argv, const char *funcname)
 #ifdef CONFIG_WITH_VALUE_LENGTH
               stack_var->value_length = lastitem - stack_var->value;
 #endif
+              VARIABLE_CHANGED (stack_var);
             }
         }
     }
@@ -5755,6 +5794,24 @@ handle_function (char **op, const char **stringp, const char *nameend, const cha
   return handle_function2 (entry_p, op, stringp);
 }
 #endif /* CONFIG_WITH_VALUE_LENGTH */
+
+#ifdef CONFIG_WITH_COMPILER
+/* Used by the "compiler" to get all info about potential functions. */
+make_function_ptr_t
+lookup_function_for_compiler (const char *name, unsigned int len,
+                              unsigned char *minargsp, unsigned char *maxargsp,
+                              char *expargsp, const char **funcnamep)
+{
+  const struct function_table_entry *entry_p = lookup_function (name, len);
+  if (!entry_p)
+    return 0;
+  *minargsp  = entry_p->minimum_args;
+  *maxargsp  = entry_p->maximum_args;
+  *expargsp  = entry_p->expand_args;
+  *funcnamep = entry_p->name;
+  return entry_p->func_ptr;
+}
+#endif /* CONFIG_WITH_COMPILER */
 

 
 /* User-defined functions.  Expand the first argument as either a builtin
@@ -5929,7 +5986,7 @@ func_call (char *o, char **argv, const char *funcname UNUSED)
                                   current_variable_set_list->set);
       if (v && v->value_length)
         {
-          if (v->recursive)
+          if (v->recursive && !IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR (v))
             {
               v->exp_count = EXP_COUNT_MAX;
               variable_expand_string_2 (o, v->value, v->value_length, &o);
diff --git a/src/kmk/job.c b/src/kmk/job.c
index 46c5939..340420e 100644
--- a/src/kmk/job.c
+++ b/src/kmk/job.c
@@ -1010,23 +1010,8 @@ free_child (struct child *child)
 
   child->file->cmds->refs--;
   if (   !child->file->intermediate
-      && !child->file->pat_variables
-      && child->file->cmds->refs == 0)
-    {
-      struct commands *cmds = child->file->cmds;
-      unsigned int i;
-
-      for (i = 0; i < cmds->ncommand_lines; ++i)
-        {
-          free (cmds->command_lines[i]);
-          cmds->command_lines[i] = 0;
-        }
-      free (cmds->command_lines);
-      cmds->command_lines = 0;
-      free (cmds->lines_flags);
-      cmds->lines_flags = 0;
-      cmds->ncommand_lines = 0;
-    }
+      && !child->file->pat_variables)
+    free_chopped_commands(child->file->cmds);
 #endif /* CONFIG_WITH_MEMORY_OPTIMIZATIONS */
 
   free (child);
diff --git a/src/kmk/kbuild.c b/src/kmk/kbuild.c
index 28a24cb..5dcd397 100644
--- a/src/kmk/kbuild.c
+++ b/src/kmk/kbuild.c
@@ -1,4 +1,4 @@
-/* $Id: kbuild.c 2540 2011-08-02 20:13:24Z bird $ */
+/* $Id: kbuild.c 2771 2015-02-01 20:48:36Z bird $ */
 /** @file
  * kBuild specific make functionality.
  */
@@ -569,6 +569,7 @@ kbuild_simplify_variable(struct variable *pVar)
         pVar->value_alloc_len = value_len + 1;
     }
     pVar->recursive = 0;
+    VARIABLE_CHANGED(pVar);
     return pVar;
 }
 
@@ -1573,8 +1574,8 @@ kbuild_collect_source_prop(struct variable *pTarget, struct variable *pSource,
         if (pVar) \
         { \
             paVars[iVar].pVar = pVar; \
-            if (    !pVar->recursive \
-                ||  !memchr(pVar->value, '$', pVar->value_length)) \
+            if (   !pVar->recursive \
+                || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar)) \
             { \
                 paVars[iVar].pszExp = pVar->value; \
                 paVars[iVar].cchExp = pVar->value_length; \
@@ -2620,6 +2621,8 @@ func_kbuild_expand_template(char *o, char **argv, const char *pszFuncName)
                 off--;
             pDefTemplate->value_length = off;
             pDefTemplate->value[off] = '\0';
+
+            VARIABLE_CHANGED(pDefTemplate);
         }
 
         if (!pDefTemplate->value_length)
diff --git a/src/kmk/kmk_cc_exec.c b/src/kmk/kmk_cc_exec.c
new file mode 100644
index 0000000..f49951d
--- /dev/null
+++ b/src/kmk/kmk_cc_exec.c
@@ -0,0 +1,2027 @@
+#ifdef CONFIG_WITH_COMPILER
+/* $Id: kmk_cc_exec.c 2777 2015-02-03 21:06:31Z bird $ */
+/** @file
+ * kmk_cc - Make "Compiler".
+ */
+
+/*
+ * Copyright (c) 2015 knut st. osmundsen <bird-kBuild-spamx at anduin.net>
+ *
+ * This file is part of kBuild.
+ *
+ * kBuild is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * kBuild is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "make.h"
+
+#include "dep.h"
+#include "variable.h"
+#include "rule.h"
+#include "debug.h"
+#include "hash.h"
+#include <ctype.h>
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#include <stdarg.h>
+#include <assert.h>
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/** @def KMK_CC_WITH_STATS
+ * Enables the collection of extra statistics. */
+#ifndef KMK_CC_WITH_STATS
+# ifdef CONFIG_WITH_MAKE_STATS
+#  define KMK_CC_WITH_STATS
+# endif
+#endif
+
+/** @def KMK_CC_STRICT
+ * Indicates whether assertions and other checks are enabled. */
+#ifndef KMK_CC_STRICT
+# ifndef NDEBUG
+#  define KMK_CC_STRICT
+# endif
+#endif
+
+#ifdef KMK_CC_STRICT
+# ifdef _MSC_VER
+#  define KMK_CC_ASSERT(a_TrueExpr)         do { if (!(a_TrueExpr)) __debugbreak(); } while (0)
+# else
+#  define KMK_CC_ASSERT(a_TrueExpr)         assert(a_TrueExpr)
+# endif
+#else
+# define KMK_CC_ASSERT(a_TrueExpr)          do {} while (0)
+#endif
+#define KMK_CC_ASSERT_ALIGNED(a_uValue, a_uAlignment) \
+    KMK_CC_ASSERT( ((a_uValue) & ((a_uAlignment) - 1)) == 0 )
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * Block of expand instructions.
+ *
+ * To avoid wasting space on "next" pointers, as well as a lot of time walking
+ * these chains when destroying programs, we work with blocks of instructions.
+ */
+typedef struct kmk_cc_block
+{
+    /** The pointer to the next block (LIFO). */
+    struct kmk_cc_block        *pNext;
+    /** The size of this block. */
+    uint32_t                    cbBlock;
+    /** The offset of the next free byte in the block.  When set to cbBlock the
+     *  block is 100% full. */
+    uint32_t                    offNext;
+} KMKCCBLOCK;
+typedef KMKCCBLOCK *PKMKCCBLOCK;
+
+/**
+ * String expansion statistics.
+ */
+typedef struct KMKCCEXPSTATS
+{
+    /** Recent average size. */
+    uint32_t                    cchAvg;
+} KMKCCEXPSTATS;
+typedef KMKCCEXPSTATS *PKMKCCEXPSTATS;
+
+/**
+ * Expansion instructions.
+ */
+typedef enum KMKCCEXPINSTR
+{
+    /** Copy a plain string. */
+    kKmkCcExpInstr_CopyString = 0,
+    /** Insert an expanded variable value, which name we already know.  */
+    kKmkCcExpInstr_PlainVariable,
+    /** Insert an expanded variable value, the name is dynamic (sub prog). */
+    kKmkCcExpInstr_DynamicVariable,
+    /** Insert an expanded variable value, which name we already know, doing
+     * search an replace on a string. */
+    kKmkCcExpInstr_SearchAndReplacePlainVariable,
+    /** Insert the output of function that requires no argument expansion. */
+    kKmkCcExpInstr_PlainFunction,
+    /** Insert the output of function that requires dynamic expansion of one ore
+     * more arguments.  (Dynamic is perhaps not such a great name, but whatever.) */
+    kKmkCcExpInstr_DynamicFunction,
+    /** Jump to a new instruction block. */
+    kKmkCcExpInstr_Jump,
+    /** We're done, return.  Has no specific structure. */
+    kKmkCcExpInstr_Return,
+    /** The end of valid instructions (exclusive). */
+    kKmkCcExpInstr_End
+} KMKCCEXPANDINSTR;
+
+/** Instruction core. */
+typedef struct kmk_cc_exp_core
+{
+    /** The instruction opcode number (KMKCCEXPANDINSTR). */
+    KMKCCEXPANDINSTR        enmOpCode;
+} KMKCCEXPCORE;
+typedef KMKCCEXPCORE *PKMKCCEXPCORE;
+
+/**
+ * String expansion sub program.
+ */
+typedef struct kmk_cc_exp_subprog
+{
+    /** Pointer to the first instruction. */
+    PKMKCCEXPCORE           pFirstInstr;
+    /** Statistics. */
+    KMKCCEXPSTATS           Stats;
+} KMKCCEXPSUBPROG;
+typedef KMKCCEXPSUBPROG *PKMKCCEXPSUBPROG;
+
+/**
+ * kKmkCcExpInstr_CopyString instruction format.
+ */
+typedef struct kmk_cc_exp_copy_string
+{
+    /** The core instruction. */
+    KMKCCEXPCORE            Core;
+    /** The number of bytes to copy. */
+    uint32_t                cchCopy;
+    /** Pointer to the source string (not terminated at cchCopy). */
+    const char             *pachSrc;
+} KMKCCEXPCOPYSTRING;
+typedef KMKCCEXPCOPYSTRING *PKMKCCEXPCOPYSTRING;
+
+/**
+ * kKmkCcExpInstr_PlainVariable instruction format.
+ */
+typedef struct kmk_cc_exp_plain_variable
+{
+    /** The core instruction. */
+    KMKCCEXPCORE            Core;
+    /** The name of the variable (points into variable_strcache). */
+    const char             *pszName;
+} KMKCCEXPPLAINVAR;
+typedef KMKCCEXPPLAINVAR *PKMKCCEXPPLAINVAR;
+
+/**
+ * kKmkCcExpInstr_DynamicVariable instruction format.
+ */
+typedef struct kmk_cc_exp_dynamic_variable
+{
+    /** The core instruction. */
+    KMKCCEXPCORE            Core;
+    /** Where to continue after this instruction.  (This is necessary since the
+     * instructions of the subprogram are emitted after this instruction.) */
+    PKMKCCEXPCORE           pNext;
+    /** The subprogram that will give us the variable name. */
+    KMKCCEXPSUBPROG         SubProg;
+} KMKCCEXPDYNVAR;
+typedef KMKCCEXPDYNVAR *PKMKCCEXPDYNVAR;
+
+/**
+ * kKmkCcExpInstr_SearchAndReplacePlainVariable instruction format.
+ */
+typedef struct kmk_cc_exp_sr_plain_variable
+{
+    /** The core instruction. */
+    KMKCCEXPCORE            Core;
+    /** Where to continue after this instruction.  (This is necessary since the
+     * instruction contains string data of variable size.) */
+    PKMKCCEXPCORE           pNext;
+    /** The name of the variable (points into variable_strcache). */
+    const char             *pszName;
+    /** Search pattern.  */
+    const char             *pszSearchPattern;
+    /** Replacement pattern. */
+    const char             *pszReplacePattern;
+    /** Offset into pszSearchPattern of the significant '%' char. */
+    uint32_t                offPctSearchPattern;
+    /** Offset into pszReplacePattern of the significant '%' char. */
+    uint32_t                offPctReplacePattern;
+} KMKCCEXPSRPLAINVAR;
+typedef KMKCCEXPSRPLAINVAR *PKMKCCEXPSRPLAINVAR;
+
+/**
+ * Instruction format parts common to both kKmkCcExpInstr_PlainFunction and
+ * kKmkCcExpInstr_DynamicFunction.
+ */
+typedef struct kmk_cc_exp_function_core
+{
+    /** The core instruction. */
+    KMKCCEXPCORE            Core;
+    /** Number of arguments. */
+    uint32_t                cArgs;
+    /** Set if the function could be modifying the input arguments. */
+    uint8_t                 fDirty;
+    /** Where to continue after this instruction.  (This is necessary since the
+     * instructions are of variable size and may be followed by string data.) */
+    PKMKCCEXPCORE           pNext;
+    /**
+     * Pointer to the function table entry.
+     *
+     * @returns New variable buffer position.
+     * @param   pchDst      Current variable buffer position.
+     * @param   papszArgs   Pointer to a NULL terminated array of argument strings.
+     * @param   pszFuncName The name of the function being called.
+     */
+    char *                (*pfnFunction)(char *pchDst, char **papszArgs, const char *pszFuncName);
+    /** Pointer to the function name in the variable string cache. */
+    const char             *pszFuncName;
+} KMKCCEXPFUNCCORE;
+typedef KMKCCEXPFUNCCORE *PKMKCCEXPFUNCCORE;
+
+/**
+ * Instruction format for kKmkCcExpInstr_PlainFunction.
+ */
+typedef struct kmk_cc_exp_plain_function
+{
+    /** The bits comment to both plain and dynamic functions. */
+    KMKCCEXPFUNCCORE        Core;
+    /** Variable sized argument list (cArgs + 1 in length, last entry is NULL).
+     * The string pointers are to memory following this instruction, to memory in
+     * the next block or to memory in the variable / makefile we're working on
+     * (if zero terminated appropriately). */
+    const char             *apszArgs[1];
+} KMKCCEXPPLAINFUNC;
+typedef KMKCCEXPPLAINFUNC *PKMKCCEXPPLAINFUNC;
+/** Calculates the size of an KMKCCEXPPLAINFUNC with a_cArgs. */
+#define KMKCCEXPPLAINFUNC_SIZE(a_cArgs)  (sizeof(KMKCCEXPFUNCCORE) + (a_cArgs + 1) * sizeof(const char *))
+
+/**
+ * Instruction format for kKmkCcExpInstr_DynamicFunction.
+ */
+typedef struct kmk_cc_exp_dyn_function
+{
+    /** The bits comment to both plain and dynamic functions. */
+    KMKCCEXPFUNCCORE        Core;
+    /** Variable sized argument list (cArgs + 1 in length, last entry is NULL).
+     * The string pointers are to memory following this instruction, to memory in
+     * the next block or to memory in the variable / makefile we're working on
+     * (if zero terminated appropriately). */
+    struct
+    {
+        /** Set if plain string argument, clear if sub program. */
+        uint8_t             fPlain;
+        union
+        {
+            /** Sub program for expanding this argument. */
+            KMKCCEXPSUBPROG     SubProg;
+            struct
+            {
+                /** Pointer to the plain argument string.
+                 * This is allocated in the same manner as the
+                 * string pointed to by KMKCCEXPPLAINFUNC::apszArgs. */
+                const char      *pszArg;
+            } Plain;
+        } u;
+    }                       aArgs[1];
+} KMKCCEXPDYNFUNC;
+typedef KMKCCEXPDYNFUNC *PKMKCCEXPDYNFUNC;
+/** Calculates the size of an KMKCCEXPPLAINFUNC with a_cArgs. */
+#define KMKCCEXPDYNFUNC_SIZE(a_cArgs)  (  sizeof(KMKCCEXPFUNCCORE) \
+                                        + (a_cArgs) * sizeof(((PKMKCCEXPDYNFUNC)(uintptr_t)42)->aArgs[0]) )
+
+/**
+ * Instruction format for kKmkCcExpInstr_Jump.
+ */
+typedef struct kmk_cc_exp_jump
+{
+    /** The core instruction. */
+    KMKCCEXPCORE            Core;
+    /** Where to jump to (new instruction block, typically). */
+    PKMKCCEXPCORE           pNext;
+} KMKCCEXPJUMP;
+typedef KMKCCEXPJUMP *PKMKCCEXPJUMP;
+
+/**
+ * String expansion program.
+ */
+typedef struct kmk_cc_expandprog
+{
+    /** Pointer to the first instruction for this program. */
+    PKMKCCEXPCORE           pFirstInstr;
+    /** List of blocks for this program (LIFO). */
+    PKMKCCBLOCK             pBlockTail;
+    /** Statistics. */
+    KMKCCEXPSTATS           Stats;
+#ifdef KMK_CC_STRICT
+    /** The hash of the input string.  Used to check that we get all the change
+     * notifications we require. */
+    uint32_t                uInputHash;
+#endif
+    /** Reference count. */
+    uint32_t volatile       cRefs;
+} KMKCCEXPPROG;
+/** Pointer to a string expansion program. */
+typedef KMKCCEXPPROG *PKMKCCEXPPROG;
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+static uint32_t g_cVarForExpandCompilations = 0;
+static uint32_t g_cVarForExpandExecs = 0;
+#ifdef KMK_CC_WITH_STATS
+static uint32_t g_cBlockAllocated = 0;
+static uint32_t g_cbAllocated = 0;
+static uint32_t g_cBlocksAllocatedExpProgs = 0;
+static uint32_t g_cbAllocatedExpProgs = 0;
+static uint32_t g_cSingleBlockExpProgs = 0;
+static uint32_t g_cTwoBlockExpProgs = 0;
+static uint32_t g_cMultiBlockExpProgs = 0;
+static uint32_t g_cbUnusedMemExpProgs = 0;
+#endif
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSubProg);
+static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSubProg, uint32_t *pcch);
+
+
+/**
+ * Initializes global variables for the 'compiler'.
+ */
+void kmk_cc_init(void)
+{
+}
+
+
+/**
+ * Prints stats (for kmk -p).
+ */
+void kmk_cc_print_stats(void)
+{
+    puts(_("\n# The kmk 'compiler' and kmk 'program executor':\n"));
+
+    printf(_("# Variables compiled for string expansion: %6u\n"), g_cVarForExpandCompilations);
+    printf(_("# Variables string expansion runs:         %6u\n"), g_cVarForExpandExecs);
+    printf(_("# String expansion runs per compile:       %6u\n"), g_cVarForExpandExecs / g_cVarForExpandExecs);
+#ifdef KMK_CC_WITH_STATS
+    printf(_("#          Single alloc block exp progs:   %6u (%u%%)\n"
+             "#             Two alloc block exp progs:   %6u (%u%%)\n"
+             "#   Three or more alloc block exp progs:   %6u (%u%%)\n"
+             ),
+           g_cSingleBlockExpProgs, (uint32_t)((uint64_t)g_cSingleBlockExpProgs * 100 / g_cVarForExpandCompilations),
+           g_cTwoBlockExpProgs,    (uint32_t)((uint64_t)g_cTwoBlockExpProgs    * 100 / g_cVarForExpandCompilations),
+           g_cMultiBlockExpProgs,  (uint32_t)((uint64_t)g_cMultiBlockExpProgs  * 100 / g_cVarForExpandCompilations));
+    printf(_("#  Total amount of memory for exp progs: %8u bytes\n"
+             "#                                    in:   %6u blocks\n"
+             "#                        avg block size:   %6u bytes\n"
+             "#                         unused memory: %8u bytes (%u%%)\n"
+             "#           avg unused memory per block:   %6u bytes\n"
+             "\n"),
+           g_cbAllocatedExpProgs, g_cBlocksAllocatedExpProgs, g_cbAllocatedExpProgs / g_cBlocksAllocatedExpProgs,
+           g_cbUnusedMemExpProgs, (uint32_t)((uint64_t)g_cbUnusedMemExpProgs * 100 / g_cbAllocatedExpProgs),
+           g_cbUnusedMemExpProgs / g_cBlocksAllocatedExpProgs);
+
+    printf(_("#   Total amount of block mem allocated: %8u bytes\n"), g_cbAllocated);
+    printf(_("#       Total number of block allocated: %8u\n"), g_cBlockAllocated);
+    printf(_("#                    Average block size: %8u byte\n"), g_cbAllocated / g_cBlockAllocated);
+#endif
+
+    puts("");
+}
+
+
+/*
+ *
+ * Various utility functions.
+ * Various utility functions.
+ * Various utility functions.
+ *
+ */
+
+/**
+ * Counts the number of dollar chars in the string.
+ *
+ * @returns Number of dollar chars.
+ * @param   pchStr      The string to search (does not need to be zero
+ *                      terminated).
+ * @param   cchStr      The length of the string.
+ */
+static uint32_t kmk_cc_count_dollars(const char *pchStr, uint32_t cchStr)
+{
+    uint32_t cDollars = 0;
+    const char *pch;
+    while ((pch = memchr(pchStr, '$', cchStr)) != NULL)
+    {
+        cDollars++;
+        cchStr -= pch - pchStr + 1;
+        pchStr  = pch + 1;
+    }
+    return cDollars;
+}
+
+#ifdef KMK_CC_STRICT
+/**
+ * Used to check that function arguments are left alone.
+ * @returns Updated hash.
+ * @param   uHash       The current hash value.
+ * @param   psz         The string to hash.
+ */
+static uint32_t kmk_cc_debug_string_hash(uint32_t uHash, const char *psz)
+{
+    unsigned char ch;
+    while ((ch = *(unsigned char const *)psz++) != '\0')
+        uHash = (uHash << 6) + (uHash << 16) - uHash + (unsigned char)ch;
+    return uHash;
+}
+
+/**
+ * Used to check that function arguments are left alone.
+ * @returns Updated hash.
+ * @param   uHash       The current hash value.
+ * @param   pch         The string to hash, not terminated.
+ * @param   cch         The number of chars to hash.
+ */
+static uint32_t kmk_cc_debug_string_hash_n(uint32_t uHash, const char *pch, uint32_t cch)
+{
+    while (cch-- > 0)
+    {
+        unsigned char ch = *(unsigned char const *)pch++;
+        uHash = (uHash << 6) + (uHash << 16) - uHash + (unsigned char)ch;
+    }
+    return uHash;
+}
+
+#endif
+
+
+
+/*
+ *
+ * The allocator.
+ * The allocator.
+ * The allocator.
+ *
+ */
+
+
+/**
+ * For the first allocation using the block allocator.
+ *
+ * @returns Pointer to the first allocation (@a cbFirst in size).
+ * @param   ppBlockTail         Where to return the pointer to the first block.
+ * @param   cbFirst             The size of the first allocation.
+ * @param   cbHint              Hint about how much memory we might be needing.
+ */
+static void *kmk_cc_block_alloc_first(PKMKCCBLOCK *ppBlockTail, size_t cbFirst, size_t cbHint)
+{
+    uint32_t        cbBlock;
+    PKMKCCBLOCK     pNewBlock;
+
+    KMK_CC_ASSERT_ALIGNED(cbFirst, sizeof(void *));
+
+    /*
+     * Turn the hint into a block size.
+     */
+    if (cbHint <= 512)
+    {
+        if (cbHint <= 256)
+            cbBlock = 128;
+        else
+            cbBlock = 256;
+    }
+    else if (cbHint < 2048)
+        cbBlock = 1024;
+    else if (cbHint < 3072)
+        cbBlock = 2048;
+    else
+        cbBlock = 4096;
+
+    /*
+     * Allocate and initialize the first block.
+     */
+    pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
+    pNewBlock->cbBlock = cbBlock;
+    pNewBlock->offNext = sizeof(*pNewBlock) + cbFirst;
+    pNewBlock->pNext   = NULL;
+    *ppBlockTail = pNewBlock;
+
+#ifdef KMK_CC_WITH_STATS
+    g_cBlockAllocated++;
+    g_cbAllocated += cbBlock;
+#endif
+
+    return pNewBlock + 1;
+}
+
+
+/**
+ * Used for getting the address of the next instruction.
+ *
+ * @returns Pointer to the next allocation.
+ * @param   pBlockTail          The allocator tail pointer.
+ */
+static void *kmk_cc_block_get_next_ptr(PKMKCCBLOCK pBlockTail)
+{
+    return (char *)pBlockTail + pBlockTail->offNext;
+}
+
+
+/**
+ * Realigns the allocator after doing byte or string allocations.
+ *
+ * @param   ppBlockTail         Pointer to the allocator tail pointer.
+ */
+static void kmk_cc_block_realign(PKMKCCBLOCK *ppBlockTail)
+{
+    PKMKCCBLOCK pBlockTail = *ppBlockTail;
+    if (pBlockTail->offNext & (sizeof(void *) - 1))
+    {
+        pBlockTail->offNext = (pBlockTail->offNext + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
+        KMK_CC_ASSERT(pBlockTail->cbBlock - pBlockTail->offNext >= sizeof(KMKCCEXPJUMP));
+    }
+}
+
+
+/**
+ * Grows the allocation with another block, byte allocator case.
+ *
+ * @returns Pointer to the byte allocation.
+ * @param   ppBlockTail         Pointer to the allocator tail pointer.
+ * @param   cb                  The number of bytes to allocate.
+ */
+static void *kmk_cc_block_byte_alloc_grow(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
+{
+    PKMKCCBLOCK     pOldBlock  = *ppBlockTail;
+    PKMKCCBLOCK     pPrevBlock = pOldBlock->pNext;
+    PKMKCCBLOCK     pNewBlock;
+    uint32_t        cbBlock;
+
+    /*
+     * Check if there accidentally is some space left in the previous block first.
+     */
+    if (   pPrevBlock
+        && pPrevBlock->cbBlock - pPrevBlock->offNext >= cb)
+    {
+        void *pvRet = (char *)pPrevBlock + pPrevBlock->offNext;
+        pPrevBlock->offNext += cb;
+        return pvRet;
+    }
+
+    /*
+     * Allocate a new block.
+     */
+
+    /* Figure the block size. */
+    cbBlock = pOldBlock->cbBlock;
+    while (cbBlock - sizeof(KMKCCEXPJUMP) - sizeof(*pNewBlock) < cb)
+        cbBlock *= 2;
+
+    /* Allocate and initialize the block it with the new instruction already accounted for. */
+    pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
+    pNewBlock->cbBlock = cbBlock;
+    pNewBlock->offNext = sizeof(*pNewBlock) + cb;
+    pNewBlock->pNext   = pOldBlock;
+    *ppBlockTail = pNewBlock;
+
+#ifdef KMK_CC_WITH_STATS
+    g_cBlockAllocated++;
+    g_cbAllocated += cbBlock;
+#endif
+
+    return pNewBlock + 1;
+}
+
+
+/**
+ * Make a byte allocation.
+ *
+ * Must call kmk_cc_block_realign() when done doing byte and string allocations.
+ *
+ * @returns Pointer to the byte allocation (byte aligned).
+ * @param   ppBlockTail         Pointer to the allocator tail pointer.
+ * @param   cb                  The number of bytes to allocate.
+ */
+static void *kmk_cc_block_byte_alloc(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
+{
+    PKMKCCBLOCK pBlockTail = *ppBlockTail;
+    uint32_t    cbLeft = pBlockTail->cbBlock - pBlockTail->offNext;
+
+    KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEXPJUMP));
+    if (cbLeft >= cb + sizeof(KMKCCEXPJUMP))
+    {
+        void *pvRet = (char *)pBlockTail + pBlockTail->offNext;
+        pBlockTail->offNext += cb;
+        return pvRet;
+    }
+    return kmk_cc_block_byte_alloc_grow(ppBlockTail, cb);
+}
+
+
+/**
+ * Duplicates the given string in a byte allocation.
+ *
+ * Must call kmk_cc_block_realign() when done doing byte and string allocations.
+ *
+ * @returns Pointer to the byte allocation (byte aligned).
+ * @param   ppBlockTail         Pointer to the allocator tail pointer.
+ * @param   cb                  The number of bytes to allocate.
+ */
+static const char *kmk_cc_block_strdup(PKMKCCBLOCK *ppBlockTail, const char *pachStr, uint32_t cchStr)
+{
+    char *pszCopy;
+    if (cchStr)
+    {
+        pszCopy = kmk_cc_block_byte_alloc(ppBlockTail, cchStr + 1);
+        memcpy(pszCopy, pachStr, cchStr);
+        pszCopy[cchStr] = '\0';
+        return pszCopy;
+    }
+    return "";
+}
+
+
+/**
+ * Grows the allocation with another block, string expansion program case.
+ *
+ * @returns Pointer to a string expansion instruction core.
+ * @param   ppBlockTail         Pointer to the allocator tail pointer.
+ * @param   cb                  The number of bytes to allocate.
+ */
+static PKMKCCEXPCORE kmk_cc_block_alloc_exp_grow(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
+{
+    PKMKCCBLOCK     pOldBlock = *ppBlockTail;
+    PKMKCCBLOCK     pNewBlock;
+    PKMKCCEXPCORE   pRet;
+    PKMKCCEXPJUMP   pJump;
+
+    /* Figure the block size. */
+    uint32_t cbBlock = !pOldBlock->pNext ? 128 : pOldBlock->cbBlock;
+    while (cbBlock - sizeof(KMKCCEXPJUMP) - sizeof(*pNewBlock) < cb)
+        cbBlock *= 2;
+
+    /* Allocate and initialize the block it with the new instruction already accounted for. */
+    pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
+    pNewBlock->cbBlock = cbBlock;
+    pNewBlock->offNext = sizeof(*pNewBlock) + cb;
+    pNewBlock->pNext   = pOldBlock;
+    *ppBlockTail = pNewBlock;
+
+#ifdef KMK_CC_WITH_STATS
+    g_cBlockAllocated++;
+    g_cbAllocated += cbBlock;
+#endif
+
+    pRet = (PKMKCCEXPCORE)(pNewBlock + 1);
+
+    /* Emit jump. */
+    pJump = (PKMKCCEXPJUMP)((char *)pOldBlock + pOldBlock->offNext);
+    pJump->Core.enmOpCode = kKmkCcExpInstr_Jump;
+    pJump->pNext = pRet;
+    pOldBlock->offNext += sizeof(*pJump);
+    KMK_CC_ASSERT(pOldBlock->offNext <= pOldBlock->cbBlock);
+
+    return pRet;
+}
+
+
+/**
+ * Allocates a string expansion instruction of size @a cb.
+ *
+ * @returns Pointer to a string expansion instruction core.
+ * @param   ppBlockTail         Pointer to the allocator tail pointer.
+ * @param   cb                  The number of bytes to allocate.
+ */
+static PKMKCCEXPCORE kmk_cc_block_alloc_exp(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
+{
+    PKMKCCBLOCK pBlockTail = *ppBlockTail;
+    uint32_t    cbLeft = pBlockTail->cbBlock - pBlockTail->offNext;
+
+    KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEXPJUMP));
+    KMK_CC_ASSERT( (cb & (sizeof(void *) - 1)) == 0 || cb == sizeof(KMKCCEXPCORE) /* final */ );
+
+    if (cbLeft >= cb + sizeof(KMKCCEXPJUMP))
+    {
+        PKMKCCEXPCORE pRet = (PKMKCCEXPCORE)((char *)pBlockTail + pBlockTail->offNext);
+        pBlockTail->offNext += cb;
+        return pRet;
+    }
+    return kmk_cc_block_alloc_exp_grow(ppBlockTail, cb);
+}
+
+
+/**
+ * Frees all memory used by an allocator.
+ *
+ * @param   ppBlockTail         The allocator tail pointer.
+ */
+static void kmk_cc_block_free_list(PKMKCCBLOCK pBlockTail)
+{
+    while (pBlockTail)
+    {
+        PKMKCCBLOCK pThis = pBlockTail;
+        pBlockTail = pBlockTail->pNext;
+        free(pThis);
+    }
+}
+
+
+/*
+ *
+ * The string expansion compiler.
+ * The string expansion compiler.
+ * The string expansion compiler.
+ *
+ */
+
+
+/**
+ * Emits a kKmkCcExpInstr_Return.
+ *
+ * @param   ppBlockTail         Pointer to the allocator tail pointer.
+ */
+static void kmk_cc_exp_emit_return(PKMKCCBLOCK *ppBlockTail)
+{
+    PKMKCCEXPCORE pCore = kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pCore));
+    pCore->enmOpCode = kKmkCcExpInstr_Return;
+}
+
+
+/**
+ * Checks if a function is known to mess up the arguments its given.
+ *
+ * When executing calls to "dirty" functions, all arguments must be duplicated
+ * on the heap.
+ *
+ * @returns 1 if dirty, 0 if clean.
+ * @param   pszFunction         The function name.
+ */
+static uint8_t kmk_cc_is_dirty_function(const char *pszFunction)
+{
+    switch (pszFunction[0])
+    {
+        default:
+            return 0;
+
+        case 'e':
+            if (!strcmp(pszFunction, "eval"))
+                return 1;
+            if (!strcmp(pszFunction, "evalctx"))
+                return 1;
+            return 0;
+
+        case 'f':
+            if (!strcmp(pszFunction, "filter"))
+                return 1;
+            if (!strcmp(pszFunction, "filter-out"))
+                return 1;
+            if (!strcmp(pszFunction, "for"))
+                return 1;
+            return 0;
+
+        case 's':
+            if (!strcmp(pszFunction, "sort"))
+                return 1;
+            return 0;
+    }
+}
+
+
+/**
+ * Emits a function call instruction taking arguments that needs expanding.
+ *
+ * @returns 0 on success, non-zero on failure.
+ * @param   ppBlockTail     Pointer to the allocator tail pointer.
+ * @param   pszFunction     The function name (const string from function.c).
+ * @param   pchArgs         Pointer to the arguments expression string, leading
+ *                          any blanks has been stripped.
+ * @param   cchArgs         The length of the arguments expression string.
+ * @param   cArgs           Number of arguments found.
+ * @param   chOpen          The char used to open the function call.
+ * @param   chClose         The char used to close the function call.
+ * @param   pfnFunction     The function implementation.
+ * @param   cMaxArgs        Maximum number of arguments the function takes.
+ */
+static int kmk_cc_exp_emit_dyn_function(PKMKCCBLOCK *ppBlockTail, const char *pszFunction,
+                                        const char *pchArgs, uint32_t cchArgs, uint32_t cArgs, char chOpen, char chClose,
+                                        make_function_ptr_t pfnFunction, unsigned char cMaxArgs)
+{
+    uint32_t iArg;
+
+    /*
+     * The function instruction has variable size.  The maximum argument count
+     * isn't quite like the minium one.  Zero means no limit.  While a non-zero
+     * value means that any commas beyond the max will be taken to be part of
+     * the final argument.
+     */
+    uint32_t            cActualArgs = cArgs <= cMaxArgs || !cMaxArgs ? cArgs : cMaxArgs;
+    PKMKCCEXPDYNFUNC    pInstr  = (PKMKCCEXPDYNFUNC)kmk_cc_block_alloc_exp(ppBlockTail, KMKCCEXPDYNFUNC_SIZE(cActualArgs));
+    pInstr->Core.Core.enmOpCode = kKmkCcExpInstr_DynamicFunction;
+    pInstr->Core.cArgs          = cActualArgs;
+    pInstr->Core.pfnFunction    = pfnFunction;
+    pInstr->Core.pszFuncName    = pszFunction;
+    pInstr->Core.fDirty         = kmk_cc_is_dirty_function(pszFunction);
+
+    /*
+     * Parse the arguments.  Plain arguments gets duplicated in the program
+     * memory so that they are terminated and no extra processing is necessary
+     * later on.  ASSUMES that the function implementations do NOT change
+     * argument memory.  Other arguments the compiled into their own expansion
+     * sub programs.
+     */
+    iArg = 0;
+    for (;;)
+    {
+        /* Find the end of the argument. Check for $. */
+        char     ch         = '\0';
+        uint8_t  fDollar    = 0;
+        int32_t  cDepth     = 0;
+        uint32_t cchThisArg = 0;
+        while (cchThisArg < cchArgs)
+        {
+            ch = pchArgs[cchThisArg];
+            if (ch == chClose)
+            {
+                KMK_CC_ASSERT(cDepth > 0);
+                if (cDepth > 0)
+                    cDepth--;
+            }
+            else if (ch == chOpen)
+                cDepth++;
+            else if (ch == ',' && cDepth == 0 && iArg + 1 < cActualArgs)
+                break;
+            else if (ch == '$')
+                fDollar = 1;
+            cchThisArg++;
+        }
+
+        pInstr->aArgs[iArg].fPlain = !fDollar;
+        if (fDollar)
+        {
+            /* Compile it. */
+            int rc;
+            kmk_cc_block_realign(ppBlockTail);
+            rc = kmk_cc_exp_compile_subprog(ppBlockTail, pchArgs, cchThisArg, &pInstr->aArgs[iArg].u.SubProg);
+            if (rc != 0)
+                return rc;
+        }
+        else
+        {
+            /* Duplicate it. */
+            pInstr->aArgs[iArg].u.Plain.pszArg = kmk_cc_block_strdup(ppBlockTail, pchArgs, cchThisArg);
+        }
+        iArg++;
+        if (ch != ',')
+            break;
+        pchArgs += cchThisArg + 1;
+        cchArgs -= cchThisArg + 1;
+    }
+    KMK_CC_ASSERT(iArg == cActualArgs);
+
+    /*
+     * Realign the allocator and take down the address of the next instruction.
+     */
+    kmk_cc_block_realign(ppBlockTail);
+    pInstr->Core.pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
+    return 0;
+}
+
+
+/**
+ * Emits a function call instruction taking plain arguments.
+ *
+ * @returns 0 on success, non-zero on failure.
+ * @param   ppBlockTail     Pointer to the allocator tail pointer.
+ * @param   pszFunction     The function name (const string from function.c).
+ * @param   pchArgs         Pointer to the arguments string, leading any blanks
+ *                          has been stripped.
+ * @param   cchArgs         The length of the arguments string.
+ * @param   cArgs           Number of arguments found.
+ * @param   chOpen          The char used to open the function call.
+ * @param   chClose         The char used to close the function call.
+ * @param   pfnFunction     The function implementation.
+ * @param   cMaxArgs        Maximum number of arguments the function takes.
+ */
+static void kmk_cc_exp_emit_plain_function(PKMKCCBLOCK *ppBlockTail, const char *pszFunction,
+                                           const char *pchArgs, uint32_t cchArgs, uint32_t cArgs, char chOpen, char chClose,
+                                           make_function_ptr_t pfnFunction, unsigned char cMaxArgs)
+{
+    uint32_t iArg;
+
+    /*
+     * The function instruction has variable size.  The maximum argument count
+     * isn't quite like the minium one.  Zero means no limit.  While a non-zero
+     * value means that any commas beyond the max will be taken to be part of
+     * the final argument.
+     */
+    uint32_t            cActualArgs = cArgs <= cMaxArgs || !cMaxArgs ? cArgs : cMaxArgs;
+    PKMKCCEXPPLAINFUNC  pInstr  = (PKMKCCEXPPLAINFUNC)kmk_cc_block_alloc_exp(ppBlockTail, KMKCCEXPPLAINFUNC_SIZE(cActualArgs));
+    pInstr->Core.Core.enmOpCode = kKmkCcExpInstr_PlainFunction;
+    pInstr->Core.cArgs          = cActualArgs;
+    pInstr->Core.pfnFunction    = pfnFunction;
+    pInstr->Core.pszFuncName    = pszFunction;
+    pInstr->Core.fDirty         = kmk_cc_is_dirty_function(pszFunction);
+
+    /*
+     * Parse the arguments.  Plain arguments gets duplicated in the program
+     * memory so that they are terminated and no extra processing is necessary
+     * later on.  ASSUMES that the function implementations do NOT change
+     * argument memory.
+     */
+    iArg = 0;
+    for (;;)
+    {
+        /* Find the end of the argument. */
+        char     ch         = '\0';
+        int32_t  cDepth     = 0;
+        uint32_t cchThisArg = 0;
+        while (cchThisArg < cchArgs)
+        {
+            ch = pchArgs[cchThisArg];
+            if (ch == chClose)
+            {
+                KMK_CC_ASSERT(cDepth > 0);
+                if (cDepth > 0)
+                    cDepth--;
+            }
+            else if (ch == chOpen)
+                cDepth++;
+            else if (ch == ',' && cDepth == 0 && iArg + 1 < cActualArgs)
+                break;
+            cchThisArg++;
+        }
+
+        /* Duplicate it. */
+        pInstr->apszArgs[iArg++] = kmk_cc_block_strdup(ppBlockTail, pchArgs, cchThisArg);
+        if (ch != ',')
+            break;
+        pchArgs += cchThisArg + 1;
+        cchArgs -= cchThisArg + 1;
+    }
+
+    KMK_CC_ASSERT(iArg == cActualArgs);
+    pInstr->apszArgs[iArg] = NULL;
+
+    /*
+     * Realign the allocator and take down the address of the next instruction.
+     */
+    kmk_cc_block_realign(ppBlockTail);
+    pInstr->Core.pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
+}
+
+
+/**
+ * Emits a kKmkCcExpInstr_DynamicVariable.
+ *
+ * @returns 0 on success, non-zero on failure.
+ * @param   ppBlockTail         Pointer to the allocator tail pointer.
+ * @param   pchNameExpr         The name of the variable (ASSUMED presistent
+ *                              thru-out the program life time).
+ * @param   cchNameExpr         The length of the variable name. If zero,
+ *                              nothing will be emitted.
+ */
+static int kmk_cc_exp_emit_dyn_variable(PKMKCCBLOCK *ppBlockTail, const char *pchNameExpr, uint32_t cchNameExpr)
+{
+    PKMKCCEXPDYNVAR pInstr;
+    int rc;
+    KMK_CC_ASSERT(cchNameExpr > 0);
+
+    pInstr = (PKMKCCEXPDYNVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
+    pInstr->Core.enmOpCode = kKmkCcExpInstr_DynamicVariable;
+
+    rc = kmk_cc_exp_compile_subprog(ppBlockTail, pchNameExpr, cchNameExpr, &pInstr->SubProg);
+
+    pInstr->pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
+    return rc;
+}
+
+
+/**
+ * Emits either a kKmkCcExpInstr_PlainVariable or
+ * kKmkCcExpInstr_SearchAndReplacePlainVariable instruction.
+ *
+ * @param   ppBlockTail         Pointer to the allocator tail pointer.
+ * @param   pchName             The name of the variable.  (Does not need to be
+ *                              valid beyond the call.)
+ * @param   cchName             The length of the variable name. If zero,
+ *                              nothing will be emitted.
+ */
+static void kmk_cc_exp_emit_plain_variable_maybe_sr(PKMKCCBLOCK *ppBlockTail, const char *pchName, uint32_t cchName)
+{
+    if (cchName > 0)
+    {
+        /*
+         * Hopefully, we're not expected to do any search and replace on the
+         * expanded variable string later...  Requires both ':' and '='.
+         */
+        const char *pchEqual;
+        const char *pchColon = (const char *)memchr(pchName, ':', cchName);
+        if (   pchColon == NULL
+            || (pchEqual = (const char *)memchr(pchColon + 1, ':', cchName - (pchColon - pchName - 1))) == NULL
+            || pchEqual == pchEqual + 1)
+        {
+            PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
+            pInstr->Core.enmOpCode = kKmkCcExpInstr_PlainVariable;
+            pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName);
+        }
+        else if (pchColon != pchName)
+        {
+            /*
+             * Okay, we need to do search and replace the variable value.
+             * This is performed by patsubst_expand_pat using '%' patterns.
+             */
+            uint32_t            cchName2   = (uint32_t)(pchColon - pchName);
+            uint32_t            cchSearch  = (uint32_t)(pchEqual - pchColon - 1);
+            uint32_t            cchReplace = cchName - cchName2 - cchSearch - 2;
+            const char         *pchPct;
+            char               *psz;
+            PKMKCCEXPSRPLAINVAR pInstr;
+
+            pInstr = (PKMKCCEXPSRPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
+            pInstr->Core.enmOpCode = kKmkCcExpInstr_SearchAndReplacePlainVariable;
+            pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName2);
+
+            /* Figure out the search pattern, unquoting percent chars.. */
+            psz = (char *)kmk_cc_block_byte_alloc(ppBlockTail, cchSearch + 2);
+            psz[0] = '%';
+            memcpy(psz + 1, pchColon + 1, cchSearch);
+            psz[1 + cchSearch] = '\0';
+            pchPct = find_percent(psz + 1); /* also performs unquoting */
+            if (pchPct)
+            {
+                pInstr->pszSearchPattern    = psz + 1;
+                pInstr->offPctSearchPattern = (uint32_t)(pchPct - psz - 1);
+            }
+            else
+            {
+                pInstr->pszSearchPattern    = psz;
+                pInstr->offPctSearchPattern = 0;
+            }
+
+            /* Figure out the replacement pattern, unquoting percent chars.. */
+            if (cchReplace == 0)
+            {
+                pInstr->pszReplacePattern    = "%";
+                pInstr->offPctReplacePattern = 0;
+            }
+            else
+            {
+                psz = (char *)kmk_cc_block_byte_alloc(ppBlockTail, cchReplace + 2);
+                psz[0] = '%';
+                memcpy(psz + 1, pchEqual + 1, cchReplace);
+                psz[1 + cchReplace] = '\0';
+                pchPct = find_percent(psz + 1); /* also performs unquoting */
+                if (pchPct)
+                {
+                    pInstr->pszReplacePattern    = psz + 1;
+                    pInstr->offPctReplacePattern = (uint32_t)(pchPct - psz - 1);
+                }
+                else
+                {
+                    pInstr->pszReplacePattern    = psz;
+                    pInstr->offPctReplacePattern = 0;
+                }
+            }
+
+            /* Note down where the next instruction is after realigning the allocator. */
+            kmk_cc_block_realign(ppBlockTail);
+            pInstr->pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
+        }
+    }
+}
+
+
+/**
+ * Emits a kKmkCcExpInstr_CopyString.
+ *
+ * @param   ppBlockTail         Pointer to the allocator tail pointer.
+ * @param   pchStr              The string to emit (ASSUMED presistent thru-out
+ *                              the program life time).
+ * @param   cchStr              The number of chars to copy. If zero, nothing
+ *                              will be emitted.
+ */
+static void kmk_cc_exp_emit_copy_string(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr)
+{
+    if (cchStr > 0)
+    {
+        PKMKCCEXPCOPYSTRING pInstr = (PKMKCCEXPCOPYSTRING)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
+        pInstr->Core.enmOpCode = kKmkCcExpInstr_CopyString;
+        pInstr->cchCopy = cchStr;
+        pInstr->pachSrc = pchStr;
+    }
+}
+
+
+/**
+ * String expansion compilation function common to both normal and sub programs.
+ *
+ * @returns 0 on success, non-zero on failure.
+ * @param   ppBlockTail         Pointer to the allocator tail pointer.
+ * @param   pchStr              The expression to compile.
+ * @param   cchStr              The length of the expression to compile.
+ */
+static int kmk_cc_exp_compile_common(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr)
+{
+    /*
+     * Process the string.
+     */
+    while (cchStr > 0)
+    {
+        /* Look for dollar sign, marks variable expansion or dollar-escape. */
+        int         rc;
+        const char *pchDollar = memchr(pchStr, '$', cchStr);
+        if (pchDollar)
+        {
+            /*
+             * Check for multiple dollar chars.
+             */
+            uint32_t offDollar = (uint32_t)(pchDollar - pchStr);
+            uint32_t cDollars  = 1;
+            while (   offDollar + cDollars < cchStr
+                   && pchStr[offDollar + cDollars] == '$')
+                cDollars++;
+
+            /*
+             * Emit a string copy for any preceeding stuff, including half of
+             * the dollars we found (dollar escape: $$ -> $).
+             * (kmk_cc_exp_emit_copy_string ignore zero length strings).
+             */
+            kmk_cc_exp_emit_copy_string(ppBlockTail, pchStr, offDollar + cDollars / 2);
+            pchStr += offDollar + cDollars;
+            cchStr -= offDollar + cDollars;
+
+            /*
+             * Odd number of dollar chars means there is a variable to expand
+             * or function to call.
+             */
+            if (cDollars & 1)
+            {
+                if (cchStr > 0)
+                {
+                    char const chOpen = *pchStr;
+                    if (chOpen == '(' || chOpen == '{')
+                    {
+                        /* There are several alternative ways of finding the ending
+                           parenthesis / braces.
+
+                           GNU make does one thing for functions and variable containing
+                           any '$' chars before the first closing char.  While for
+                           variables where a closing char comes before any '$' char, a
+                           simplified approach is taken.  This means that for example:
+
+                                Given VAR=var, the expressions "$(var())" and
+                                "$($(VAR)())" would be expanded differently.
+                                In the first case the variable "var(" would be
+                                used and in the second "var()".
+
+                           This code will not duplicate this weird behavior, but work
+                           the same regardless of whether there is a '$' char before
+                           the first closing char. */
+                        make_function_ptr_t pfnFunction;
+                        const char         *pszFunction;
+                        unsigned char       cMaxArgs;
+                        unsigned char       cMinArgs;
+                        char                fExpandArgs;
+                        char const          chClose   = chOpen == '(' ? ')' : '}';
+                        char                ch        = 0;
+                        uint32_t            cchName   = 0;
+                        uint32_t            cDepth    = 1;
+                        uint32_t            cMaxDepth = 1;
+                        cDollars = 0;
+
+                        pchStr++;
+                        cchStr--;
+
+                        /* First loop: Identify potential function calls and dynamic expansion. */
+                        KMK_CC_ASSERT(!func_char_map[chOpen]);
+                        KMK_CC_ASSERT(!func_char_map[chClose]);
+                        KMK_CC_ASSERT(!func_char_map['$']);
+                        while (cchName < cchStr)
+                        {
+                            ch = pchStr[cchName];
+                            if (!func_char_map[(int)ch])
+                                break;
+                            cchName++;
+                        }
+
+                        if (   cchName >= MIN_FUNCTION_LENGTH
+                            && cchName <= MAX_FUNCTION_LENGTH
+                            && (isblank(ch) || ch == chClose || cchName == cchStr)
+                            && (pfnFunction = lookup_function_for_compiler(pchStr, cchName, &cMinArgs, &cMaxArgs,
+                                                                           &fExpandArgs, &pszFunction)) != NULL)
+                        {
+                            /*
+                             * It's a function invocation, we should count parameters while
+                             * looking for the end.
+                             * Note! We use cchName for the length of the argument list.
+                             */
+                            uint32_t cArgs = 1;
+                            if (ch != chClose)
+                            {
+                                /* Skip leading spaces before the first arg. */
+                                cchName++;
+                                while (cchName < cchStr && isblank((unsigned char)pchStr[cchName]))
+                                    cchName++;
+
+                                pchStr += cchName;
+                                cchStr -= cchName;
+                                cchName = 0;
+
+                                while (cchName < cchStr)
+                                {
+                                    ch = pchStr[cchName];
+                                    if (ch == ',')
+                                    {
+                                        if (cDepth == 1)
+                                            cArgs++;
+                                    }
+                                    else if (ch == chClose)
+                                    {
+                                        if (!--cDepth)
+                                            break;
+                                    }
+                                    else if (ch == chOpen)
+                                    {
+                                        if (++cDepth > cMaxDepth)
+                                            cMaxDepth = cDepth;
+                                    }
+                                    else if (ch == '$')
+                                        cDollars++;
+                                    cchName++;
+                                }
+                            }
+                            else
+                            {
+                                pchStr += cchName;
+                                cchStr -= cchName;
+                                cchName = 0;
+                            }
+                            if (cArgs < cMinArgs)
+                            {
+                                fatal(NULL, _("Function '%.*s' takes a minimum of %d arguments: %d given"),
+                                      pszFunction, (int)cMinArgs, (int)cArgs);
+                                return -1; /* not reached */
+                            }
+                            if (cDepth != 0)
+                            {
+                                fatal(NULL, chOpen == '('
+                                      ? _("Missing closing parenthesis calling '%s'") : _("Missing closing braces calling '%s'"),
+                                      pszFunction);
+                                return -1; /* not reached */
+                            }
+                            if (cMaxDepth > 16 && fExpandArgs)
+                            {
+                                fatal(NULL, _("Too many levels of nested function arguments expansions: %s"), pszFunction);
+                                return -1; /* not reached */
+                            }
+                            if (!fExpandArgs || cDollars == 0)
+                                kmk_cc_exp_emit_plain_function(ppBlockTail, pszFunction, pchStr, cchName,
+                                                               cArgs, chOpen, chClose, pfnFunction, cMaxArgs);
+                            else
+                            {
+                                rc = kmk_cc_exp_emit_dyn_function(ppBlockTail, pszFunction, pchStr, cchName,
+                                                                  cArgs, chOpen, chClose, pfnFunction, cMaxArgs);
+                                if (rc != 0)
+                                    return rc;
+                            }
+                        }
+                        else
+                        {
+                            /*
+                             * Variable, find the end while checking whether anything needs expanding.
+                             */
+                            if (ch == chClose)
+                                cDepth = 0;
+                            else if (cchName < cchStr)
+                            {
+                                if (ch != '$')
+                                {
+                                    /* Second loop: Look for things that needs expanding. */
+                                    while (cchName < cchStr)
+                                    {
+                                        ch = pchStr[cchName];
+                                        if (ch == chClose)
+                                        {
+                                            if (!--cDepth)
+                                                break;
+                                        }
+                                        else if (ch == chOpen)
+                                        {
+                                            if (++cDepth > cMaxDepth)
+                                                cMaxDepth = cDepth;
+                                        }
+                                        else if (ch == '$')
+                                            break;
+                                        cchName++;
+                                    }
+                                }
+                                if (ch == '$')
+                                {
+                                    /* Third loop: Something needs expanding, just find the end. */
+                                    cDollars = 1;
+                                    cchName++;
+                                    while (cchName < cchStr)
+                                    {
+                                        ch = pchStr[cchName];
+                                        if (ch == chClose)
+                                        {
+                                            if (!--cDepth)
+                                                break;
+                                        }
+                                        else if (ch == chOpen)
+                                        {
+                                            if (++cDepth > cMaxDepth)
+                                                cMaxDepth = cDepth;
+                                        }
+                                        cchName++;
+                                    }
+                                }
+                            }
+                            if (cDepth > 0) /* After warning, we just assume they're all there. */
+                                error(NULL, chOpen == '(' ? _("Missing closing parenthesis ") : _("Missing closing braces"));
+                            if (cMaxDepth >= 16)
+                            {
+                                fatal(NULL, _("Too many levels of nested variable expansions: '%.*s'"), (int)cchName + 2, pchStr - 1);
+                                return -1; /* not reached */
+                            }
+                            if (cDollars == 0)
+                                kmk_cc_exp_emit_plain_variable_maybe_sr(ppBlockTail, pchStr, cchName);
+                            else
+                            {
+                                rc = kmk_cc_exp_emit_dyn_variable(ppBlockTail, pchStr, cchName);
+                                if (rc != 0)
+                                    return rc;
+                            }
+                        }
+                        pchStr += cchName + 1;
+                        cchStr -= cchName + (cDepth == 0);
+                    }
+                    else
+                    {
+                        /* Single character variable name. */
+                        kmk_cc_exp_emit_plain_variable_maybe_sr(ppBlockTail, pchStr, 1);
+                        pchStr++;
+                        cchStr--;
+                    }
+                }
+                else
+                {
+                    error(NULL, _("Unexpected end of string after $"));
+                    break;
+                }
+            }
+        }
+        else
+        {
+            /*
+             * Nothing more to expand, the remainder is a simple string copy.
+             */
+            kmk_cc_exp_emit_copy_string(ppBlockTail, pchStr, cchStr);
+            break;
+        }
+    }
+
+    /*
+     * Emit final instruction.
+     */
+    kmk_cc_exp_emit_return(ppBlockTail);
+    return 0;
+}
+
+
+/**
+ * Initializes string expansion program statistics.
+ * @param   pStats              Pointer to the statistics structure to init.
+ */
+static void kmk_cc_exp_stats_init(PKMKCCEXPSTATS pStats)
+{
+    pStats->cchAvg = 0;
+}
+
+
+/**
+ * Compiles a string expansion sub program.
+ *
+ * The caller typically make a call to kmk_cc_block_get_next_ptr after this
+ * function returns to figure out where to continue executing.
+ *
+ * @returns 0 on success, non-zero on failure.
+ * @param   ppBlockTail         Pointer to the allocator tail pointer.
+ * @param   pchStr              Pointer to the string to compile an expansion
+ *                              program for (ASSUMED to be valid for the
+ *                              lifetime of the program).
+ * @param   cchStr              The length of the string to compile. Expected to
+ *                              be at least on char long.
+ * @param   pSubProg            The sub program structure to initialize.
+ */
+static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSubProg)
+{
+    KMK_CC_ASSERT(cchStr > 0);
+    pSubProg->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
+    kmk_cc_exp_stats_init(&pSubProg->Stats);
+    return kmk_cc_exp_compile_common(ppBlockTail, pchStr, cchStr);
+}
+
+
+/**
+ * Compiles a string expansion program.
+ *
+ * @returns Pointer to the program on success, NULL on failure.
+ * @param   pchStr              Pointer to the string to compile an expansion
+ *                              program for (ASSUMED to be valid for the
+ *                              lifetime of the program).
+ * @param   cchStr              The length of the string to compile. Expected to
+ *                              be at least on char long.
+ */
+static PKMKCCEXPPROG kmk_cc_exp_compile(const char *pchStr, uint32_t cchStr)
+{
+    /*
+     * Estimate block size, allocate one and initialize it.
+     */
+    PKMKCCEXPPROG   pProg;
+    PKMKCCBLOCK     pBlock;
+    pProg = kmk_cc_block_alloc_first(&pBlock, sizeof(*pProg),
+                                     (kmk_cc_count_dollars(pchStr, cchStr) + 4)  * 8);
+    if (pProg)
+    {
+        int rc = 0;
+
+        pProg->pBlockTail   = pBlock;
+        pProg->pFirstInstr  = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(pBlock);
+        kmk_cc_exp_stats_init(&pProg->Stats);
+        pProg->cRefs        = 1;
+#ifdef KMK_CC_STRICT
+        pProg->uInputHash   = kmk_cc_debug_string_hash_n(0, pchStr, cchStr);
+#endif
+
+        /*
+         * Join forces with the sub program compilation code.
+         */
+        if (kmk_cc_exp_compile_common(&pProg->pBlockTail, pchStr, cchStr) == 0)
+        {
+#ifdef KMK_CC_WITH_STATS
+            pBlock = pProg->pBlockTail;
+            if (!pBlock->pNext)
+                g_cSingleBlockExpProgs++;
+            else if (!pBlock->pNext->pNext)
+                g_cTwoBlockExpProgs++;
+            else
+                g_cMultiBlockExpProgs++;
+            for (; pBlock; pBlock = pBlock->pNext)
+            {
+                g_cBlocksAllocatedExpProgs++;
+                g_cbAllocatedExpProgs += pBlock->cbBlock;
+                g_cbUnusedMemExpProgs += pBlock->cbBlock - pBlock->offNext;
+            }
+#endif
+            return pProg;
+        }
+        kmk_cc_block_free_list(pProg->pBlockTail);
+    }
+    return NULL;
+}
+
+
+/**
+ * Compiles a variable direct evaluation as is, setting v->evalprog on success.
+ *
+ * @returns Pointer to the program on success, NULL if no program was created.
+ * @param   pVar        Pointer to the variable.
+ */
+struct kmk_cc_evalprog   *kmk_cc_compile_variable_for_eval(struct variable *pVar)
+{
+    return NULL;
+}
+
+
+/**
+ * Updates the recursive_without_dollar member of a variable structure.
+ *
+ * This avoid compiling string expansion programs without only a CopyString
+ * instruction.  By setting recursive_without_dollar to 1, code calling
+ * kmk_cc_compile_variable_for_expand and kmk_exec_expand_to_var_buf will
+ * instead treat start treating it as a simple variable, which is faster.
+ *
+ * @returns The updated recursive_without_dollar value.
+ * @param   pVar        Pointer to the variable.
+ */
+static int kmk_cc_update_variable_recursive_without_dollar(struct variable *pVar)
+{
+    int fValue;
+    KMK_CC_ASSERT(pVar->recursive_without_dollar == 0);
+
+    if (memchr(pVar->value, '$', pVar->value_length))
+        fValue = -1;
+    else
+        fValue = 1;
+    pVar->recursive_without_dollar = fValue;
+
+    return fValue;
+}
+
+
+/**
+ * Compiles a variable for string expansion.
+ *
+ * @returns Pointer to the string expansion program on success, NULL if no
+ *          program was created.
+ * @param   pVar        Pointer to the variable.
+ */
+struct kmk_cc_expandprog *kmk_cc_compile_variable_for_expand(struct variable *pVar)
+{
+    KMK_CC_ASSERT(strlen(pVar->value) == pVar->value_length);
+    KMK_CC_ASSERT(!pVar->expandprog);
+    KMK_CC_ASSERT(pVar->recursive_without_dollar <= 0);
+
+    if (   !pVar->expandprog
+        && pVar->recursive)
+    {
+        if (   pVar->recursive_without_dollar < 0
+            || (   pVar->recursive_without_dollar == 0
+                && kmk_cc_update_variable_recursive_without_dollar(pVar) < 0) )
+        {
+            pVar->expandprog = kmk_cc_exp_compile(pVar->value, pVar->value_length);
+            g_cVarForExpandCompilations++;
+        }
+    }
+    return pVar->expandprog;
+}
+
+
+/**
+ * String expansion execution worker for outputting a variable.
+ *
+ * @returns The new variable buffer position.
+ * @param   pVar        The variable to reference.
+ * @param   pchDst      The current variable buffer position.
+ */
+static char *kmk_exec_expand_worker_reference_variable(struct variable *pVar, char *pchDst)
+{
+    if (pVar->value_length > 0)
+    {
+        if (!pVar->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar))
+            pchDst = variable_buffer_output(pchDst, pVar->value, pVar->value_length);
+        else
+            pchDst = reference_recursive_variable(pchDst, pVar);
+    }
+    else if (pVar->append)
+        pchDst = reference_recursive_variable(pchDst, pVar);
+    return pchDst;
+}
+
+
+/**
+ * Executes a stream string expansion instructions, outputting to the current
+ * varaible buffer.
+ *
+ * @returns The new variable buffer position.
+ * @param   pInstrCore      The instruction to start executing at.
+ * @param   pchDst          The current variable buffer position.
+ */
+static char *kmk_exec_expand_instruction_stream_to_var_buf(PKMKCCEXPCORE pInstrCore, char *pchDst)
+{
+    for (;;)
+    {
+        switch (pInstrCore->enmOpCode)
+        {
+            case kKmkCcExpInstr_CopyString:
+            {
+                PKMKCCEXPCOPYSTRING pInstr = (PKMKCCEXPCOPYSTRING)pInstrCore;
+                pchDst = variable_buffer_output(pchDst, pInstr->pachSrc, pInstr->cchCopy);
+
+                pInstrCore = &(pInstr + 1)->Core;
+                break;
+            }
+
+            case kKmkCcExpInstr_PlainVariable:
+            {
+                PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)pInstrCore;
+                struct variable  *pVar = lookup_variable_strcached(pInstr->pszName);
+                if (pVar)
+                    pchDst = kmk_exec_expand_worker_reference_variable(pVar, pchDst);
+                else
+                    warn_undefined(pInstr->pszName, strcache2_get_len(&variable_strcache, pInstr->pszName));
+
+                pInstrCore = &(pInstr + 1)->Core;
+                break;
+            }
+
+            case kKmkCcExpInstr_DynamicVariable:
+            {
+                PKMKCCEXPDYNVAR  pInstr = (PKMKCCEXPDYNVAR)pInstrCore;
+                struct variable *pVar;
+                uint32_t         cchName;
+                char            *pszName = kmk_exec_expand_subprog_to_tmp(&pInstr->SubProg, &cchName);
+                char            *pszColon = (char *)memchr(pszName, ':', cchName);
+                char            *pszEqual;
+                if (   pszColon == NULL
+                    || (pszEqual = (char *)memchr(pszColon + 1, '=', &pszName[cchName] - pszColon - 1)) == NULL
+                    || pszEqual == pszColon + 1)
+                {
+                    pVar = lookup_variable(pszName, cchName);
+                    if (pVar)
+                        pchDst = kmk_exec_expand_worker_reference_variable(pVar, pchDst);
+                    else
+                        warn_undefined(pszName, cchName);
+                }
+                else if (pszColon != pszName)
+                {
+                    /*
+                     * Oh, we have to do search and replace. How tedious.
+                     * Since the variable name is a temporary buffer, we can transform
+                     * the strings into proper search and replacement patterns directly.
+                     */
+                    pVar = lookup_variable(pszName, pszColon - pszName);
+                    if (pVar)
+                    {
+                        char const *pszExpandedVarValue = pVar->recursive ? recursively_expand(pVar) : pVar->value;
+                        char       *pszSearchPat  = pszColon + 1;
+                        char       *pszReplacePat = pszEqual + 1;
+                        const char *pchPctSearchPat;
+                        const char *pchPctReplacePat;
+
+                        *pszEqual = '\0';
+                        pchPctSearchPat = find_percent(pszSearchPat);
+                        pchPctReplacePat = find_percent(pszReplacePat);
+
+                        if (!pchPctReplacePat)
+                        {
+                            if (pszReplacePat[-2] != '\0') /* On the offchance that a pct was unquoted by find_percent. */
+                            {
+                                memmove(pszName + 1, pszSearchPat, pszReplacePat - pszSearchPat);
+                                if (pchPctSearchPat)
+                                    pchPctSearchPat -= pszSearchPat - &pszName[1];
+                                pszSearchPat = &pszName[1];
+                            }
+                            pchPctReplacePat = --pszReplacePat;
+                            *pszReplacePat = '%';
+                        }
+
+                        if (!pchPctSearchPat)
+                        {
+                            pchPctSearchPat = --pszSearchPat;
+                            *pszSearchPat = '%';
+                        }
+
+                        pchDst = patsubst_expand_pat(pchDst, pszExpandedVarValue,
+                                                     pszSearchPat, pszReplacePat,
+                                                     pchPctSearchPat, pchPctReplacePat);
+
+                        if (pVar->recursive)
+                            free((void *)pszExpandedVarValue);
+                    }
+                    else
+                        warn_undefined(pszName, pszColon - pszName);
+                }
+                free(pszName);
+
+                pInstrCore = pInstr->pNext;
+                break;
+            }
+
+
+            case kKmkCcExpInstr_SearchAndReplacePlainVariable:
+            {
+                PKMKCCEXPSRPLAINVAR pInstr = (PKMKCCEXPSRPLAINVAR)pInstrCore;
+                struct variable    *pVar = lookup_variable_strcached(pInstr->pszName);
+                if (pVar)
+                {
+                    char const *pszExpandedVarValue = pVar->recursive ? recursively_expand(pVar) : pVar->value;
+                    pchDst = patsubst_expand_pat(pchDst,
+                                                 pszExpandedVarValue,
+                                                 pInstr->pszSearchPattern,
+                                                 pInstr->pszReplacePattern,
+                                                 &pInstr->pszSearchPattern[pInstr->offPctSearchPattern],
+                                                 &pInstr->pszReplacePattern[pInstr->offPctReplacePattern]);
+                    if (pVar->recursive)
+                        free((void *)pszExpandedVarValue);
+                }
+                else
+                    warn_undefined(pInstr->pszName, strcache2_get_len(&variable_strcache, pInstr->pszName));
+
+                pInstrCore = pInstr->pNext;
+                break;
+            }
+
+            case kKmkCcExpInstr_PlainFunction:
+            {
+                PKMKCCEXPPLAINFUNC pInstr = (PKMKCCEXPPLAINFUNC)pInstrCore;
+                uint32_t iArg;
+                if (!pInstr->Core.fDirty)
+                {
+#ifdef KMK_CC_STRICT
+                    uint32_t uCrcBefore = 0;
+                    uint32_t uCrcAfter = 0;
+                    iArg = pInstr->Core.cArgs;
+                    while (iArg-- > 0)
+                        uCrcBefore = kmk_cc_debug_string_hash(uCrcBefore, pInstr->apszArgs[iArg]);
+#endif
+
+                    pchDst = pInstr->Core.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->Core.pszFuncName);
+
+#ifdef KMK_CC_STRICT
+                    iArg = pInstr->Core.cArgs;
+                    while (iArg-- > 0)
+                        uCrcAfter = kmk_cc_debug_string_hash(uCrcAfter, pInstr->apszArgs[iArg]);
+                    KMK_CC_ASSERT(uCrcBefore == uCrcAfter);
+#endif
+                }
+                else
+                {
+                    char **papszShadowArgs = xmalloc((pInstr->Core.cArgs * 2 + 1) * sizeof(papszShadowArgs[0]));
+                    char **papszArgs = &papszShadowArgs[pInstr->Core.cArgs];
+
+                    iArg = pInstr->Core.cArgs;
+                    papszArgs[iArg] = NULL;
+                    while (iArg-- > 0)
+                        papszArgs[iArg] = papszShadowArgs[iArg] = xstrdup(pInstr->apszArgs[iArg]);
+
+                    pchDst = pInstr->Core.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->Core.pszFuncName);
+
+                    iArg = pInstr->Core.cArgs;
+                    while (iArg-- > 0)
+                        free(papszShadowArgs[iArg]);
+                    free(papszShadowArgs);
+                }
+
+                pInstrCore = pInstr->Core.pNext;
+                break;
+            }
+
+            case kKmkCcExpInstr_DynamicFunction:
+            {
+                PKMKCCEXPDYNFUNC pInstr = (PKMKCCEXPDYNFUNC)pInstrCore;
+                char           **papszArgsShadow = xmalloc( (pInstr->Core.cArgs * 2 + 1) * sizeof(char *));
+                char           **papszArgs = &papszArgsShadow[pInstr->Core.cArgs];
+                uint32_t         iArg;
+
+                if (!pInstr->Core.fDirty)
+                {
+#ifdef KMK_CC_STRICT
+                    uint32_t    uCrcBefore = 0;
+                    uint32_t    uCrcAfter = 0;
+#endif
+                    iArg = pInstr->Core.cArgs;
+                    papszArgs[iArg] = NULL;
+                    while (iArg-- > 0)
+                    {
+                        char *pszArg;
+                        if (!pInstr->aArgs[iArg].fPlain)
+                            pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.SubProg, NULL);
+                        else
+                            pszArg = (char *)pInstr->aArgs[iArg].u.Plain.pszArg;
+                        papszArgsShadow[iArg] = pszArg;
+                        papszArgs[iArg]       = pszArg;
+#ifdef KMK_CC_STRICT
+                        uCrcBefore = kmk_cc_debug_string_hash(uCrcBefore, pszArg);
+#endif
+                    }
+                    pchDst = pInstr->Core.pfnFunction(pchDst, papszArgs, pInstr->Core.pszFuncName);
+
+                    iArg = pInstr->Core.cArgs;
+                    while (iArg-- > 0)
+                    {
+#ifdef KMK_CC_STRICT
+                        KMK_CC_ASSERT(papszArgsShadow[iArg] == papszArgs[iArg]);
+                        uCrcAfter = kmk_cc_debug_string_hash(uCrcAfter, papszArgsShadow[iArg]);
+#endif
+                        if (!pInstr->aArgs[iArg].fPlain)
+                            free(papszArgsShadow[iArg]);
+                    }
+                    KMK_CC_ASSERT(uCrcBefore == uCrcAfter);
+                }
+                else
+                {
+                    iArg = pInstr->Core.cArgs;
+                    papszArgs[iArg] = NULL;
+                    while (iArg-- > 0)
+                    {
+                        char *pszArg;
+                        if (!pInstr->aArgs[iArg].fPlain)
+                            pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.SubProg, NULL);
+                        else
+                            pszArg = xstrdup(pInstr->aArgs[iArg].u.Plain.pszArg);
+                        papszArgsShadow[iArg] = pszArg;
+                        papszArgs[iArg]       = pszArg;
+                    }
+
+                    pchDst = pInstr->Core.pfnFunction(pchDst, papszArgs, pInstr->Core.pszFuncName);
+
+                    iArg = pInstr->Core.cArgs;
+                    while (iArg-- > 0)
+                        free(papszArgsShadow[iArg]);
+                }
+                free(papszArgsShadow);
+
+                pInstrCore = pInstr->Core.pNext;
+                break;
+            }
+
+            case kKmkCcExpInstr_Jump:
+            {
+                PKMKCCEXPJUMP pInstr = (PKMKCCEXPJUMP)pInstrCore;
+                pInstrCore = pInstr->pNext;
+                break;
+            }
+
+            case kKmkCcExpInstr_Return:
+                return pchDst;
+
+            default:
+                fatal(NULL, _("Unknown string expansion opcode: %d (%#x)"),
+                      (int)pInstrCore->enmOpCode, (int)pInstrCore->enmOpCode);
+                return NULL;
+        }
+    }
+}
+
+
+/**
+ * Updates the string expansion statistics.
+ *
+ * @param   pStats              The statistics structure to update.
+ * @param   cchResult           The result lenght.
+ */
+void kmk_cc_exp_stats_update(PKMKCCEXPSTATS pStats, uint32_t cchResult)
+{
+    /*
+     * The average is simplified and not an exact average for every
+     * expansion that has taken place.
+     */
+    pStats->cchAvg = (pStats->cchAvg * 7 + cchResult) / 8;
+}
+
+
+/**
+ * Execute a string expansion sub-program, outputting to a new heap buffer.
+ *
+ * @returns Pointer to the output buffer (hand to free when done).
+ * @param   pSubProg          The sub-program to execute.
+ * @param   pcchResult        Where to return the size of the result. Optional.
+ */
+static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSubProg, uint32_t *pcchResult)
+{
+    char           *pchOldVarBuf;
+    unsigned int    cbOldVarBuf;
+    char           *pchDst;
+    char           *pszResult;
+    uint32_t        cchResult;
+
+    /*
+     * Temporarily replace the variable buffer while executing the instruction
+     * stream for this sub program.
+     */
+    pchDst = install_variable_buffer_with_hint(&pchOldVarBuf, &cbOldVarBuf,
+                                               pSubProg->Stats.cchAvg ? pSubProg->Stats.cchAvg + 32 : 256);
+
+    pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pSubProg->pFirstInstr, pchDst);
+
+    /* Ensure that it's terminated. */
+    pchDst = variable_buffer_output(pchDst, "\0", 1) - 1;
+
+    /* Grab the result buffer before restoring the previous one. */
+    pszResult = variable_buffer;
+    cchResult = (uint32_t)(pchDst - pszResult);
+    if (pcchResult)
+        *pcchResult = cchResult;
+    kmk_cc_exp_stats_update(&pSubProg->Stats, cchResult);
+
+    variable_buffer = pchOldVarBuf;
+    variable_buffer_length = cbOldVarBuf;
+
+    return pszResult;
+}
+
+
+/**
+ * Execute a string expansion program, outputting to the current variable
+ * buffer.
+ *
+ * @returns New variable buffer position.
+ * @param   pProg               The program to execute.
+ * @param   pchDst              The current varaible buffer position.
+ */
+static char *kmk_exec_expand_prog_to_var_buf(PKMKCCEXPPROG pProg, char *pchDst)
+{
+    uint32_t cchResult;
+    uint32_t offStart = (uint32_t)(pchDst - variable_buffer);
+
+    if (pProg->Stats.cchAvg >= variable_buffer_length - offStart)
+        pchDst = ensure_variable_buffer_space(pchDst, offStart + pProg->Stats.cchAvg + 32);
+
+    KMK_CC_ASSERT(pProg->cRefs > 0);
+    pProg->cRefs++;
+
+    pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pProg->pFirstInstr, pchDst);
+
+    pProg->cRefs--;
+    KMK_CC_ASSERT(pProg->cRefs > 0);
+
+    cchResult = (uint32_t)(pchDst - variable_buffer);
+    KMK_CC_ASSERT(cchResult >= offStart);
+    cchResult -= offStart;
+    kmk_cc_exp_stats_update(&pProg->Stats, cchResult);
+    g_cVarForExpandExecs++;
+
+    return pchDst;
+}
+
+
+/**
+ * Equivalent of eval_buffer, only it's using the evalprog of the variable.
+ *
+ * @param   pVar        Pointer to the variable. Must have a program.
+ */
+void kmk_exec_evalval(struct variable *pVar)
+{
+    KMK_CC_ASSERT(pVar->evalprog);
+    assert(0);
+}
+
+
+/**
+ * Expands a variable into a variable buffer using its expandprog.
+ *
+ * @returns The new variable buffer position.
+ * @param   pVar        Pointer to the variable.  Must have a program.
+ * @param   pchDst      Pointer to the current variable buffer position.
+ */
+char *kmk_exec_expand_to_var_buf(struct variable *pVar, char *pchDst)
+{
+    KMK_CC_ASSERT(pVar->expandprog);
+    KMK_CC_ASSERT(pVar->expandprog->uInputHash == kmk_cc_debug_string_hash(0, pVar->value));
+    return kmk_exec_expand_prog_to_var_buf(pVar->expandprog, pchDst);
+}
+
+
+/**
+ * Called when a variable with expandprog or/and evalprog changes.
+ *
+ * @param   pVar        Pointer to the variable.
+ */
+void  kmk_cc_variable_changed(struct variable *pVar)
+{
+    PKMKCCEXPPROG pProg = pVar->expandprog;
+
+    KMK_CC_ASSERT(pVar->evalprog || pProg);
+
+#if 0
+    if (pVar->evalprog)
+    {
+        kmk_cc_block_free_list(pVar->evalprog->pBlockTail);
+        pVar->evalprog = NULL;
+    }
+#endif
+
+    if (pProg)
+    {
+        if (pProg->cRefs == 1)
+            kmk_cc_block_free_list(pProg->pBlockTail);
+        else
+            fatal(NULL, _("Modifying a variable (%s) while its expansion program is running is not supported"), pVar->name);
+        pVar->expandprog = NULL;
+    }
+}
+
+
+/**
+ * Called when a variable with expandprog or/and evalprog is deleted.
+ *
+ * @param   pVar        Pointer to the variable.
+ */
+void  kmk_cc_variable_deleted(struct variable *pVar)
+{
+    PKMKCCEXPPROG pProg = pVar->expandprog;
+
+    KMK_CC_ASSERT(pVar->evalprog || pProg);
+
+#if 0
+    if (pVar->evalprog)
+    {
+        kmk_cc_block_free_list(pVar->evalprog->pBlockTail);
+        pVar->evalprog = NULL;
+    }
+#endif
+
+    if (pProg)
+    {
+        if (pProg->cRefs == 1)
+            kmk_cc_block_free_list(pProg->pBlockTail);
+        else
+            fatal(NULL, _("Deleting a variable (%s) while its expansion program is running is not supported"), pVar->name);
+        pVar->expandprog = NULL;
+    }
+}
+
+
+#endif /* CONFIG_WITH_COMPILER */
+
diff --git a/src/kmk/kmk_cc_exec.h b/src/kmk/kmk_cc_exec.h
new file mode 100644
index 0000000..846d90f
--- /dev/null
+++ b/src/kmk/kmk_cc_exec.h
@@ -0,0 +1,45 @@
+/* $Id: kmk_cc_exec.h 2773 2015-02-03 12:59:54Z bird $ */
+/** @file
+ * kmk_cc - Make "Compiler".
+ */
+
+/*
+ * Copyright (c) 2015 knut st. osmundsen <bird-kBuild-spamx at anduin.net>
+ *
+ * This file is part of kBuild.
+ *
+ * kBuild is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * kBuild is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef ___kmk_cc_and_exech
+#define ___kmk_cc_and_exech
+#ifdef CONFIG_WITH_COMPILER
+
+
+
+void  kmk_cc_init(void);
+void  kmk_cc_print_stats(void);
+
+struct variable;
+extern struct kmk_cc_evalprog   *kmk_cc_compile_variable_for_eval(struct variable *pVar);
+extern struct kmk_cc_expandprog *kmk_cc_compile_variable_for_expand(struct variable *pVar);
+extern char *kmk_exec_expand_to_var_buf(struct variable *pVar, char *pchDst);
+extern void kmk_exec_evalval(struct variable *pVar);
+extern void kmk_cc_variable_changed(struct variable *pVar);
+extern void kmk_cc_variable_deleted(struct variable *pVar);
+
+
+#endif /* CONFIG_WITH_COMPILER */
+#endif
diff --git a/src/kmk/kmkbuiltin/append.c b/src/kmk/kmkbuiltin/append.c
index aac2e5b..d88c92f 100644
--- a/src/kmk/kmkbuiltin/append.c
+++ b/src/kmk/kmkbuiltin/append.c
@@ -1,4 +1,4 @@
-/* $Id: append.c 2466 2011-07-12 09:52:39Z bird $ */
+/* $Id: append.c 2771 2015-02-01 20:48:36Z bird $ */
 /** @file
  * kMk Builtin command - append text to file.
  */
@@ -217,15 +217,15 @@ int kmk_builtin_append(int argc, char **argv, char **envp)
             struct variable *pVar = lookup_variable(psz, cch);
             if (!pVar)
                 continue;
-            if (    pVar->recursive
-                &&  memchr(pVar->value, '$', pVar->value_length))
+            if (   !pVar->recursive
+                || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar))
+                fwrite(pVar->value, 1, pVar->value_length, pFile);
+            else
             {
                 char *pszExpanded = allocated_variable_expand(pVar->value);
                 fwrite(pszExpanded, 1, strlen(pszExpanded), pFile);
                 free(pszExpanded);
             }
-            else
-                fwrite(pVar->value, 1, pVar->value_length, pFile);
         }
         else
 #endif
diff --git a/src/kmk/kmkbuiltin/echo.c b/src/kmk/kmkbuiltin/echo.c
index 77591fe..dff8cb2 100644
--- a/src/kmk/kmkbuiltin/echo.c
+++ b/src/kmk/kmkbuiltin/echo.c
@@ -72,11 +72,19 @@ static void
 errexit(const char *prog, const char *reason)
 {
 	char *errstr = strerror(errno);
+#ifdef _MSC_VER
+	int doserrno = _doserrno;
+       char szDosErr[48];
+       sprintf(szDosErr, " (doserrno=%d)", doserrno);
+#endif
 	write(STDERR_FILENO, prog, strlen(prog));
 	write(STDERR_FILENO, ": ", 2);
 	write(STDERR_FILENO, reason, strlen(reason));
 	write(STDERR_FILENO, ": ", 2);
 	write(STDERR_FILENO, errstr, strlen(errstr));
+#ifdef _MSC_VER
+	write(STDERR_FILENO, szDosErr, strlen(szDosErr));
+#endif
 	write(STDERR_FILENO, "\n", 1);
 }
 
diff --git a/src/kmk/kmkbuiltin/kDepObj.c b/src/kmk/kmkbuiltin/kDepObj.c
index 649d9e7..7b42a59 100644
--- a/src/kmk/kmkbuiltin/kDepObj.c
+++ b/src/kmk/kmkbuiltin/kDepObj.c
@@ -1,4 +1,4 @@
-/* $Id: kDepObj.c 2591 2012-06-17 20:45:31Z bird $ */
+/* $Id: kDepObj.c 2759 2015-01-28 16:14:00Z bird $ */
 /** @file
  * kDepObj - Extract dependency information from an object file.
  */
@@ -26,6 +26,7 @@
 /*******************************************************************************
 *   Header Files                                                               *
 *******************************************************************************/
+#define MSCFAKES_NO_WINDOWS_H
 #include "config.h"
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/src/kmk/kmkbuiltin/mscfakes.c b/src/kmk/kmkbuiltin/mscfakes.c
index 444943e..b8e33c7 100644
--- a/src/kmk/kmkbuiltin/mscfakes.c
+++ b/src/kmk/kmkbuiltin/mscfakes.c
@@ -1,10 +1,10 @@
-/* $Id: mscfakes.c 2733 2014-10-16 18:29:41Z bird $ */
+/* $Id: mscfakes.c 2759 2015-01-28 16:14:00Z bird $ */
 /** @file
  * Fake Unix stuff for MSC.
  */
 
 /*
- * Copyright (c) 2005-2010 knut st. osmundsen <bird-kBuild-spamx at anduin.net>
+ * Copyright (c) 2005-2015 knut st. osmundsen <bird-kBuild-spamx at anduin.net>
  *
  * This file is part of kBuild.
  *
@@ -27,6 +27,7 @@
 *   Header Files                                                               *
 *******************************************************************************/
 #include "config.h"
+#include <assert.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -42,6 +43,11 @@
 #include <Windows.h>
 #undef timeval
 
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static BOOL isPipeFd(int fd);
+
 
 /**
  * Makes corrections to a directory path that ends with a trailing slash.
@@ -460,15 +466,125 @@ int utimes(const char *pszPath, const struct timeval *paTimes)
 }
 
 
-int writev(int fd, const struct iovec *vector, int count)
+/* We override the libc write function (in our modules only, unfortunately) so
+   we can kludge our way around a ENOSPC problem observed on build servers
+   capturing STDOUT and STDERR via pipes.  Apparently this may happen when the
+   pipe buffer is full, even with the mscfake_init hack in place.
+
+   XXX: Probably need to hook into fwrite as well. */
+ssize_t msc_write(int fd, const void *pvSrc, size_t cbSrc)
+{
+    ssize_t cbRet;
+    if (cbSrc < UINT_MAX / 4)
+    {
+#ifndef MSC_WRITE_TEST
+        cbRet = _write(fd, pvSrc, (unsigned int)cbSrc);
+#else
+        cbRet = -1; errno = ENOSPC;
+#endif
+        if (cbRet < 0)
+        {
+            /* ENOSPC on pipe kludge. */
+            int cbLimit;
+            int cSinceLastSuccess;
+
+            if (cbSrc == 0)
+                return 0;
+            if (errno != ENOSPC)
+                return -1;
+#ifndef MSC_WRITE_TEST
+            if (!isPipeFd(fd))
+            {
+                errno = ENOSPC;
+                return -1;
+            }
+#endif
+
+            /* Likely a full pipe buffer, try write smaller amounts and do some
+               sleeping inbetween each unsuccessful one. */
+            cbLimit = cbSrc / 4;
+            if (cbLimit < 4)
+                cbLimit = 4;
+            else if (cbLimit > 512)
+                cbLimit = 512;
+            cSinceLastSuccess = 0;
+            cbRet = 0;
+#ifdef MSC_WRITE_TEST
+            cbLimit = 4;
+#endif
+
+            while (cbSrc > 0)
+            {
+                unsigned int cbAttempt = cbSrc > cbLimit ? (int)cbLimit : (int)cbSrc;
+                ssize_t cbActual = _write(fd, pvSrc, cbAttempt);
+                if (cbActual > 0)
+                {
+                    assert(cbActual <= (ssize_t)cbAttempt);
+                    pvSrc  = (char *)pvSrc + cbActual;
+                    cbSrc -= cbActual;
+                    cbRet += cbActual;
+#ifndef MSC_WRITE_TEST
+                    if (cbLimit < 32)
+                        cbLimit = 32;
+#endif
+                    cSinceLastSuccess = 0;
+                }
+                else if (errno != ENOSPC)
+                    return -1;
+                else
+                {
+                    /* Delay for about 30 seconds, then just give up. */
+                    cSinceLastSuccess++;
+                    if (cSinceLastSuccess > 1860)
+                        return -1;
+                    if (cSinceLastSuccess <= 2)
+                        Sleep(0);
+                    else if (cSinceLastSuccess <= 66)
+                    {
+                        if (cbLimit >= 8)
+                            cbLimit /= 2; /* Just in case the pipe buffer is very very small. */
+                        Sleep(1);
+                    }
+                    else
+                        Sleep(16);
+                }
+            }
+        }
+    }
+    else
+    {
+        /*
+         * Type limit exceeded. Split the job up.
+         */
+        cbRet = 0;
+        while (cbSrc > 0)
+        {
+            size_t  cbToWrite = cbSrc > UINT_MAX / 4 ? UINT_MAX / 4 : cbSrc;
+            ssize_t cbWritten = msc_write(fd, pvSrc, cbToWrite);
+            if (cbWritten > 0)
+            {
+                pvSrc  = (char *)pvSrc + (size_t)cbWritten;
+                cbSrc -= (size_t)cbWritten;
+                cbRet += (size_t)cbWritten;
+            }
+            else if (cbWritten == 0 || cbRet > 0)
+                break;
+            else
+                return -1;
+        }
+    }
+    return cbRet;
+}
+
+ssize_t writev(int fd, const struct iovec *vector, int count)
 {
     int size = 0;
     int i;
     for (i = 0; i < count; i++)
     {
-        int cb = (int)write(fd, vector[i].iov_base, (int)vector[i].iov_len);
+        int cb = msc_write(fd, vector[i].iov_base, (int)vector[i].iov_len);
         if (cb < 0)
-            return -1;
+            return cb;
         size += cb;
     }
     return size;
@@ -535,13 +651,12 @@ int vasprintf(char **strp, const char *fmt, va_list va)
 
 
 /**
- * This is a kludge to make pipe handles blocking.
+ * Checks if the given file descriptor is a pipe or not.
  *
- * @returns TRUE if it's now blocking, FALSE if not a pipe or we failed to fix
- *          the blocking mode.
+ * @returns TRUE if pipe, FALSE if not.
  * @param   fd                  The libc file descriptor number.
  */
-static BOOL makePipeBlocking(int fd)
+static BOOL isPipeFd(int fd)
 {
     /* Is pipe? */
     HANDLE hFile = (HANDLE)_get_osfhandle(fd);
@@ -550,16 +665,32 @@ static BOOL makePipeBlocking(int fd)
         DWORD fType = GetFileType(hFile);
         fType &= ~FILE_TYPE_REMOTE;
         if (fType == FILE_TYPE_PIPE)
+            return TRUE;
+    }
+    return FALSE;
+}
+
+
+/**
+ * This is a kludge to make pipe handles blocking.
+ *
+ * @returns TRUE if it's now blocking, FALSE if not a pipe or we failed to fix
+ *          the blocking mode.
+ * @param   fd                  The libc file descriptor number.
+ */
+static BOOL makePipeBlocking(int fd)
+{
+    if (isPipeFd(fd))
+    {
+        /* Try fix it. */
+        HANDLE hFile = (HANDLE)_get_osfhandle(fd);
+        DWORD fState = 0;
+        if (GetNamedPipeHandleState(hFile, &fState, NULL, NULL, NULL, NULL,  0))
         {
-            /* Try fix it. */
-            DWORD fState = 0;
-            if (GetNamedPipeHandleState(hFile, &fState, NULL, NULL, NULL, NULL,  0))
-            {
-                fState &= ~PIPE_NOWAIT;
-                fState |= PIPE_WAIT;
-                if (SetNamedPipeHandleState(hFile, &fState, NULL, NULL))
-                    return TRUE;
-            }
+            fState &= ~PIPE_NOWAIT;
+            fState |= PIPE_WAIT;
+            if (SetNamedPipeHandleState(hFile, &fState, NULL, NULL))
+                return TRUE;
         }
     }
     return FALSE;
diff --git a/src/kmk/kmkbuiltin/mscfakes.h b/src/kmk/kmkbuiltin/mscfakes.h
index e5a2e99..379875a 100644
--- a/src/kmk/kmkbuiltin/mscfakes.h
+++ b/src/kmk/kmkbuiltin/mscfakes.h
@@ -1,4 +1,4 @@
-/* $Id: mscfakes.h 2713 2013-11-21 21:11:00Z bird $ */
+/* $Id: mscfakes.h 2766 2015-01-30 03:32:38Z bird $ */
 /** @file
  * Unix fakes for MSC.
  */
@@ -27,14 +27,19 @@
 #define ___mscfakes_h
 #ifdef _MSC_VER
 
+/* Include the config file (kmk's) so we don't need to duplicate stuff from it here. */
+#include "config.h"
+
 #include <io.h>
 #include <direct.h>
 #include <time.h>
 #include <stdarg.h>
 #include <malloc.h>
 #include "getopt.h"
+#ifndef MSCFAKES_NO_WINDOWS_H
+# include <Windows.h>
+#endif
 
-/* Note: Duplicated it config.h.win */
 #include <sys/stat.h>
 #include <io.h>
 #include <direct.h>
@@ -78,12 +83,27 @@ typedef unsigned short nlink_t;
 typedef unsigned short uid_t;
 typedef unsigned short gid_t;
 #endif
+#if defined(_M_AMD64) || defined(_M_X64) || defined(_M_IA64) || defined(_WIN64)
+typedef __int64 ssize_t;
+#else
 typedef long ssize_t;
+#endif
 typedef unsigned long u_long;
 typedef unsigned int u_int;
 typedef unsigned short u_short;
 
-#ifndef timerisset
+#if _MSC_VER >= 1600
+# include <stdint.h>
+#else
+typedef unsigned char  uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int   uint32_t;
+typedef signed char    int8_t;
+typedef signed short   int16_t;
+typedef signed int     int32_t;
+#endif
+
+#if !defined(timerisset) && defined(MSCFAKES_NO_WINDOWS_H)
 struct timeval
 {
     long tv_sec;
@@ -137,9 +157,12 @@ int snprintf(char *buf, size_t size, const char *fmt, ...);
 #endif
 int symlink(const char *pszDst, const char *pszLink);
 int utimes(const char *pszPath, const struct timeval *paTimes);
-int writev(int fd, const struct iovec *vector, int count);
-
+ssize_t writev(int fd, const struct iovec *vector, int count);
 
+/* bird write ENOSPC hacks. */
+#undef write
+#define write msc_write
+ssize_t msc_write(int fd, const void *pvSrc, size_t cbSrc);
 
 /*
  * MSC fake internals / helpers.
diff --git a/src/kmk/kmkbuiltin/redirect.c b/src/kmk/kmkbuiltin/redirect.c
index cbcbb18..b928215 100644
--- a/src/kmk/kmkbuiltin/redirect.c
+++ b/src/kmk/kmkbuiltin/redirect.c
@@ -1,4 +1,4 @@
-/* $Id: redirect.c 2728 2014-03-05 13:09:47Z bird $ */
+/* $Id: redirect.c 2779 2015-02-24 03:50:12Z bird $ */
 /** @file
  * kmk_redirect - Do simple program <-> file redirection (++).
  */
@@ -59,10 +59,13 @@
  * For details on how MSC parses the command line, see "Parsing C Command-Line
  * Arguments": http://msdn.microsoft.com/en-us/library/a1y7w461.aspx
  *
- * @param   argc        The argument count.
- * @param   argv        The argument vector.
+ * @param   argc                The argument count.
+ * @param   argv                The argument vector.
+ * @param   fWatcomBrainDamage  Set if we're catering for wcc, wcc386 or similar
+ *                              OpenWatcom tools.  They seem to follow some
+ *                              ancient or home made quoting convention.
  */
-static void quoteArguments(int argc, char **argv)
+static void quoteArguments(int argc, char **argv, int fWatcomBrainDamage)
 {
     int i;
     for (i = 0; i < argc; i++)
@@ -70,19 +73,21 @@ static void quoteArguments(int argc, char **argv)
         const char *pszOrg    = argv[i];
         size_t      cchOrg    = strlen(pszOrg);
         const char *pszQuotes = (const char *)memchr(pszOrg, '"', cchOrg);
+        const char *pszProblem = NULL;
         if (   pszQuotes
             || cchOrg == 0
-            || memchr(pszOrg, ' ', cchOrg)
-            || memchr(pszOrg, '\t', cchOrg)
-            || memchr(pszOrg, '\n', cchOrg)
-            || memchr(pszOrg, '\r', cchOrg)
-            || memchr(pszOrg, '&', cchOrg)
-            || memchr(pszOrg, '>', cchOrg)
-            || memchr(pszOrg, '<', cchOrg)
-            || memchr(pszOrg, '|', cchOrg)
-            || memchr(pszOrg, '%', cchOrg)
-            || memchr(pszOrg, '\'', cchOrg)
-            || memchr(pszOrg, '=', cchOrg)
+            || (pszProblem = (const char *)memchr(pszOrg, ' ',  cchOrg)) != NULL
+            || (pszProblem = (const char *)memchr(pszOrg, '\t', cchOrg)) != NULL
+            || (pszProblem = (const char *)memchr(pszOrg, '\n', cchOrg)) != NULL
+            || (pszProblem = (const char *)memchr(pszOrg, '\r', cchOrg)) != NULL
+            || (pszProblem = (const char *)memchr(pszOrg, '&',  cchOrg)) != NULL
+            || (pszProblem = (const char *)memchr(pszOrg, '>',  cchOrg)) != NULL
+            || (pszProblem = (const char *)memchr(pszOrg, '<',  cchOrg)) != NULL
+            || (pszProblem = (const char *)memchr(pszOrg, '|',  cchOrg)) != NULL
+            || (pszProblem = (const char *)memchr(pszOrg, '%',  cchOrg)) != NULL
+            || (pszProblem = (const char *)memchr(pszOrg, '\'', cchOrg)) != NULL
+            || (   !fWatcomBrainDamage
+                && (pszProblem = (const char *)memchr(pszOrg, '=',  cchOrg)) != NULL)
             )
         {
             char   ch;
@@ -92,6 +97,32 @@ static void quoteArguments(int argc, char **argv)
 
             argv[i] = pszNew;
 
+            /* Watcom does not grok "-i=c:\program files\watcom\h", it thing
+               it's a source specification. The quote must follow the equal. */
+            if (fWatcomBrainDamage)
+            {
+                size_t cchUnquoted  = 0;
+                if (pszOrg[0] == '@') /* Response file quoting: @"file name.rsp" */
+                    cchUnquoted = 1;
+                else if (pszOrg[0] == '-' || pszOrg[0] == '/') /* Switch quoting. */
+                {
+                    const char *pszNeedQuoting = (const char *)memchr(pszOrg, '=', cchOrg);
+                    if (   pszNeedQuoting == NULL
+                        || (uintptr_t)pszNeedQuoting > (uintptr_t)(pszProblem ? pszProblem : pszQuotes))
+                        pszNeedQuoting = pszProblem ? pszProblem : pszQuotes;
+                    else
+                        pszNeedQuoting++;
+                    cchUnquoted = pszNeedQuoting - pszOrg;
+                }
+                if (cchUnquoted)
+                {
+                    memcpy(pszNew, pszOrg, cchUnquoted);
+                    pszNew += cchUnquoted;
+                    pszOrg += cchUnquoted;
+                    cchOrg -= cchUnquoted;
+                }
+            }
+
             *pszNew++ = '"';
             if (fComplicated)
             {
@@ -187,7 +218,7 @@ static const char *name(const char *pszName)
 static int usage(FILE *pOut,  const char *argv0)
 {
     fprintf(pOut,
-            "usage: %s [-[rwa+tb]<fd> <file>] [-c<fd>] [-Z] [-E <var=val>] [-C <dir>] -- <program> [args]\n"
+            "usage: %s [-[rwa+tb]<fd> <file>] [-c<fd>] [-Z] [-E <var=val>] [-C <dir>] [--wcc-brain-damage] -- <program> [args]\n"
             "   or: %s --help\n"
             "   or: %s --version\n"
             "\n"
@@ -207,6 +238,9 @@ static int usage(FILE *pOut,  const char *argv0)
             "The -C switch is for changing the current directory. This takes immediate\n"
             "effect, so be careful where you put it.\n"
             "\n"
+            "The --wcc-brain-damage switch is to work around wcc and wcc386 (Open Watcom)\n"
+            "not following normal quoting conventions on Windows, OS/2, and DOS.\n"
+            "\n"
             "This command was originally just a quick hack to avoid invoking the shell\n"
             "on Windows (cygwin) where forking is very expensive and has exhibited\n"
             "stability issues on SMP machines.  It has since grown into something like\n"
@@ -225,6 +259,7 @@ int main(int argc, char **argv, char **envp)
 #endif
     FILE *pStdErr = stderr;
     FILE *pStdOut = stdout;
+    int fWatcomBrainDamage = 0;
 
     /*
      * Parse arguments.
@@ -261,6 +296,11 @@ int main(int argc, char **argv, char **envp)
                     psz = "Z";
                 else if (!strcmp(psz, "-close"))
                     psz = "c";
+                else if (!strcmp(psz, "-wcc-brain-damage"))
+                {
+                    fWatcomBrainDamage = 1;
+                    continue;
+                }
             }
 
             /*
@@ -709,7 +749,7 @@ int main(int argc, char **argv, char **envp)
     }
 
     /* MSC is a PITA since it refuses to quote the arguments... */
-    quoteArguments(argc - i, &argv[i]);
+    quoteArguments(argc - i, &argv[i], fWatcomBrainDamage);
     rc = _spawnvp(_P_WAIT, argv[i], &argv[i]);
     if (rc == -1 && pStdErr)
     {
diff --git a/src/kmk/main.c b/src/kmk/main.c
index 06a6cc0..a748da4 100644
--- a/src/kmk/main.c
+++ b/src/kmk/main.c
@@ -46,6 +46,9 @@ this program.  If not, see <http://www.gnu.org/licenses/>.  */
 #ifdef HAVE_FCNTL_H
 # include <fcntl.h>
 #endif
+#ifdef CONFIG_WITH_COMPILER
+# include "kmk_cc_exec.h"
+#endif
 
 #ifdef KMK /* for get_online_cpu_count */
 # if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
@@ -1160,6 +1163,7 @@ static BOOL WINAPI ctrl_event(DWORD CtrlType)
     HANDLE hThread;
     CONTEXT Ctx;
 
+    /*fprintf(stderr, "dbg: ctrl_event sig=%d\n", sig);*/
 #ifndef _M_IX86
     /* only once. */
     if (InterlockedExchange(&g_lTriggered, 1))
@@ -1192,9 +1196,10 @@ static BOOL WINAPI ctrl_event(DWORD CtrlType)
         Ctx.Eip = (uintptr_t)&dispatch_stub;
 #else
         g_Ctx = Ctx;
-        Ctx.Rsp -= 0x20;
+        Ctx.Rsp -= 0x80;
         Ctx.Rsp &= ~(uintptr_t)0xf;
-        Ctx.Rip = (uintptr_t)&dispatch_stub;
+        Ctx.Rsp += 8;   /* (Stack aligned before call instruction, not after.) */
+        Ctx.Rip  = (uintptr_t)&dispatch_stub;
 #endif
 
         SetThreadContext(hThread, &Ctx);
@@ -1363,6 +1368,9 @@ main (int argc, char **argv, char **envp)
   struct dep *read_makefiles;
   PATH_VAR (current_directory);
   unsigned int restarts = 0;
+#ifdef CONFIG_WITH_MAKE_STATS
+  unsigned long long uStartTick = CURRENT_CLOCK_TICK();
+#endif
 #ifdef WINDOWS32
   char *unix_path = NULL;
   char *windows32_path = NULL;
@@ -1575,6 +1583,9 @@ main (int argc, char **argv, char **envp)
   /* Set up to access user data (files).  */
   user_access ();
 
+# ifdef CONFIG_WITH_COMPILER
+  kmk_cc_init ();
+# endif
 #ifdef CONFIG_WITH_ALLOC_CACHES
   initialize_global_alloc_caches ();
 #endif
@@ -2917,6 +2928,7 @@ main (int argc, char **argv, char **envp)
       error (NILF,
              _("warning:  Clock skew detected.  Your build may be incomplete."));
 
+    MAKE_STATS_2(if (uStartTick) printf("main ticks elapsed: %ull\n", (unsigned long long)(CURRENT_CLOCK_TICK() - uStartTick)) );
     /* Exit.  */
     die (status);
   }
@@ -3812,6 +3824,9 @@ print_data_base ()
 #ifdef CONFIG_WITH_ALLOC_CACHES
   alloccache_print_all ();
 #endif
+#ifdef CONFIG_WITH_COMPILER
+  kmk_cc_print_stats ();
+#endif
 
   when = time ((time_t *) 0);
   printf (_("\n# Finished Make data base on %s\n"), ctime (&when));
diff --git a/src/kmk/make.h b/src/kmk/make.h
index 14c5ceb..60e1e54 100644
--- a/src/kmk/make.h
+++ b/src/kmk/make.h
@@ -237,6 +237,13 @@ extern unsigned long make_stats_ht_collisions;
 #endif
 
 /* bird - start */
+#ifdef _MSC_VER
+# include <intrin.h>
+# define CURRENT_CLOCK_TICK() __rdtsc()
+#else
+# define CURRENT_CLOCK_TICK() 0
+#endif
+
 #define COMMA ,
 #ifdef CONFIG_WITH_VALUE_LENGTH
 # define IF_WITH_VALUE_LENGTH(a_Expr)           a_Expr
diff --git a/src/kmk/read.c b/src/kmk/read.c
index 413df56..86a3544 100644
--- a/src/kmk/read.c
+++ b/src/kmk/read.c
@@ -2287,10 +2287,19 @@ record_target_var (struct nameseq *filenames, char *defn,
           assert (v != 0);
 
           v->origin = origin;
+#ifndef CONFIG_WITH_VALUE_LENGTH
           if (v->flavor == f_simple)
             v->value = allocated_variable_expand (v->value);
           else
             v->value = xstrdup (v->value);
+#else
+          v->value_length = strlen (v->value);
+          if (v->flavor == f_simple)
+            v->value = allocated_variable_expand_2 (v->value, v->value_length, &v->value_length);
+          else
+            v->value = (char *)memcpy (xmalloc (v->value_length + 1), v->value, v->value_length + 1);
+          v->value_alloc_len = v->value_length + 1;
+#endif
 
           fname = p->target;
         }
@@ -2361,6 +2370,7 @@ record_target_var (struct nameseq *filenames, char *defn,
               v->origin = gv->origin;
               v->recursive = gv->recursive;
               v->append = 0;
+              VARIABLE_CHANGED (v);
             }
         }
     }
diff --git a/src/kmk/remake.c b/src/kmk/remake.c
index f42cfa4..bc14311 100644
--- a/src/kmk/remake.c
+++ b/src/kmk/remake.c
@@ -1322,6 +1322,13 @@ notice_finished_file (struct file *file)
        So mark it now as "succeeded".  */
     file->update_status = 0;
 #endif
+
+#ifdef CONFIG_WITH_MEMORY_OPTIMIZATIONS
+    /* We're done with this command, so free the memory held by the chopped
+       command lines. Saves heap for the compilers & linkers. */
+    if (file->cmds && file->cmds->command_lines)
+      free_chopped_commands (file->cmds);
+#endif
 }
 

 /* Check whether another file (whose mtime is THIS_MTIME) needs updating on
diff --git a/src/kmk/variable.c b/src/kmk/variable.c
index 247556e..16e6a0f 100644
--- a/src/kmk/variable.c
+++ b/src/kmk/variable.c
@@ -41,6 +41,9 @@ this program.  If not, see <http://www.gnu.org/licenses/>.  */
 #ifdef CONFIG_WITH_STRCACHE2
 # include <stddef.h>
 #endif
+#ifdef CONFIG_WITH_COMPILER
+# include "kmk_cc_exec.h"
+#endif
 
 #ifdef KMK
 /** Gets the real variable if alias.  For use when looking up variables. */
@@ -380,7 +383,7 @@ define_variable_in_set (const char *name, unsigned int length,
             v->fileinfo.filenm = 0;
 	  v->origin = origin;
 	  v->recursive = recursive;
-          MAKE_STATS_2(v->changes++);
+         VARIABLE_CHANGED (v);
 	}
       return v;
     }
@@ -442,8 +445,20 @@ define_variable_in_set (const char *name, unsigned int length,
   v->aliased = 0;
 #endif
   v->export = v_default;
+#ifdef CONFIG_WITH_COMPILER
+  v->recursive_without_dollar = 0;
+  v->evalprog = 0;
+  v->expandprog = 0;
+  v->evalval_count = 0;
+  v->expand_count = 0;
+#else
+  MAKE_STATS_2(v->expand_count = 0);
+  MAKE_STATS_2(v->evalval_count = 0);
+#endif
   MAKE_STATS_2(v->changes = 0);
   MAKE_STATS_2(v->reallocs = 0);
+  MAKE_STATS_2(v->references = 0);
+  MAKE_STATS_2(v->cTicksEvalVal = 0);
 
   v->exportable = 1;
   if (*name != '_' && (*name < 'A' || *name > 'Z')
@@ -581,7 +596,7 @@ define_variable_alias_in_set (const char *name, unsigned int length,
 
       if (v->value != 0 && !v->rdonly_val)
           free (v->value);
-      MAKE_STATS_2(v->changes++);
+      VARIABLE_CHANGED (v);
     }
   else
     {
@@ -598,8 +613,20 @@ define_variable_alias_in_set (const char *name, unsigned int length,
       v->private_var = 0;
       v->aliased = 0;
       v->export = v_default;
+#ifdef CONFIG_WITH_COMPILER
+      v->recursive_without_dollar = 0;
+      v->evalprog = 0;
+      v->expandprog = 0;
+      v->evalval_count = 0;
+      v->expand_count = 0;
+#else
+      MAKE_STATS_2(v->expand_count = 0);
+      MAKE_STATS_2(v->evalval_count = 0);
+#endif
       MAKE_STATS_2(v->changes = 0);
       MAKE_STATS_2(v->reallocs = 0);
+      MAKE_STATS_2(v->references = 0);
+      MAKE_STATS_2(v->cTicksEvalVal = 0);
       v->exportable = 1;
       if (*name != '_' && (*name < 'A' || *name > 'Z')
           && (*name < 'a' || *name > 'z'))
@@ -727,6 +754,7 @@ lookup_special_var (struct variable *var)
       var->value_length = p - var->value - 1;
       var->value_alloc_len = max;
 #endif
+      VARIABLE_CHANGED (var);
 
       /* Remember how many variables are in our current count.  Since we never
          remove variables from the list, this is a reliable way to know whether
@@ -887,7 +915,10 @@ lookup_variable (const char *name, unsigned int length)
     {
       struct variable *v = lookup_kbuild_object_variable_accessor(name, length);
       if (v != VAR_NOT_KBUILD_ACCESSOR)
-        return v;
+        {
+          MAKE_STATS_2 (v->references++);
+          return v;
+        }
     }
 # endif
 
@@ -920,7 +951,8 @@ lookup_variable (const char *name, unsigned int length)
 # ifdef KMK
           RESOLVE_ALIAS_VARIABLE(v);
 # endif
-	  return v->special ? lookup_special_var (v) : v;
+          MAKE_STATS_2 (v->references++);
+	   return v->special ? lookup_special_var (v) : v;
         }
 
       is_parent |= setlist->next_is_parent;
@@ -993,6 +1025,76 @@ lookup_variable (const char *name, unsigned int length)
 
   return 0;
 }
+
+#ifdef CONFIG_WITH_STRCACHE2
+/* Alternative version of lookup_variable that takes a name that's already in
+   the variable string cache. */
+struct variable *
+lookup_variable_strcached (const char *name)
+{
+  struct variable *v;
+#if 1 /*FIX THIS - ndef KMK*/
+  const struct variable_set_list *setlist;
+  struct variable var_key;
+#endif /* KMK */
+  int is_parent = 0;
+
+#ifndef NDEBUG
+  strcache2_verify_entry (&variable_strcache, name);
+#endif
+
+#ifdef KMK
+  /* Check for kBuild-define- local variable accesses and handle these first. */
+  if (strcache2_get_len(&variable_strcache, name) > 3 && name[0] == '[')
+    {
+      v = lookup_kbuild_object_variable_accessor(name, strcache2_get_len(&variable_strcache, name));
+      if (v != VAR_NOT_KBUILD_ACCESSOR)
+        {
+          MAKE_STATS_2 (v->references++);
+          return v;
+        }
+    }
+#endif
+
+#if 1  /*FIX THIS - ndef KMK */
+
+  var_key.name = (char *) name;
+  var_key.length = strcache2_get_len(&variable_strcache, name);
+
+  for (setlist = current_variable_set_list;
+       setlist != 0; setlist = setlist->next)
+    {
+      const struct variable_set *set = setlist->set;
+
+      v = (struct variable *) hash_find_item_strcached ((struct hash_table *) &set->table, &var_key);
+      if (v && (!is_parent || !v->private_var))
+        {
+# ifdef KMK
+          RESOLVE_ALIAS_VARIABLE(v);
+# endif
+          MAKE_STATS_2 (v->references++);
+	   return v->special ? lookup_special_var (v) : v;
+        }
+
+      is_parent |= setlist->next_is_parent;
+    }
+
+#else  /* KMK - need for speed */
+
+  v = lookup_cached_variable (name);
+  assert (lookup_variable_for_assert(name, length) == v);
+#ifdef VMS
+  if (v)
+#endif
+    return v;
+#endif /* KMK - need for speed */
+#ifdef VMS
+# error "Port me (split out the relevant code from lookup_varaible and call it)"
+#endif
+  return 0;
+}
+#endif
+
 

 /* Lookup a variable whose name is a string starting at NAME
    and with LENGTH chars in set SET.  NAME need not be null-terminated.
@@ -1004,7 +1106,6 @@ lookup_variable_in_set (const char *name, unsigned int length,
                         const struct variable_set *set)
 {
   struct variable var_key;
-  struct variable *v;
 #ifndef CONFIG_WITH_STRCACHE2
   var_key.name = (char *) name;
   var_key.length = length;
@@ -1012,6 +1113,7 @@ lookup_variable_in_set (const char *name, unsigned int length,
   return (struct variable *) hash_find_item ((struct hash_table *) &set->table, &var_key);
 #else  /* CONFIG_WITH_STRCACHE2 */
   const char *cached_name;
+  struct variable *v;
 
 # ifdef KMK
   /* Check for kBuild-define- local variable accesses and handle these first. */
@@ -1021,6 +1123,7 @@ lookup_variable_in_set (const char *name, unsigned int length,
       if (v != VAR_NOT_KBUILD_ACCESSOR)
         {
           RESOLVE_ALIAS_VARIABLE(v);
+          MAKE_STATS_2 (v->references++);
           return v;
         }
     }
@@ -1048,6 +1151,7 @@ lookup_variable_in_set (const char *name, unsigned int length,
 # ifdef KMK
   RESOLVE_ALIAS_VARIABLE(v);
 # endif
+  MAKE_STATS_2 (if (v) v->references++);
   return v;
 #endif /* CONFIG_WITH_STRCACHE2 */
 }
@@ -1223,6 +1327,10 @@ free_variable_name_and_value (const void *item)
 #ifndef CONFIG_WITH_STRCACHE2
   free (v->name);
 #endif
+#ifdef CONFIG_WITH_COMPILER
+  if (v->evalprog || v->expandprog)
+    kmk_cc_variable_deleted (v);
+#endif
 #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
   if (!v->rdonly_val)
 #endif
@@ -1342,6 +1450,10 @@ merge_variable_sets (struct variable_set *to_set,
             if (from_var->alias)
               fatal(NULL, ("Attempting to delete variable aliased '%s'"), from_var->name);
 #endif
+#ifdef CONFIG_WITH_COMPILER
+            if (from_var->evalprog || from_var->expandprog)
+              kmk_cc_variable_deleted (from_var);
+#endif
 #ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
             if (!from_var->rdonly_val)
 #endif
@@ -2095,6 +2207,7 @@ void append_string_to_variable (struct variable *v, const char *value, unsigned
   else
     memcpy (v->value, value, value_len + 1);
   v->value_length = new_value_len;
+  VARIABLE_CHANGED (v);
 }
 
 struct variable *
@@ -2307,7 +2420,6 @@ do_variable_definition_2 (const struct floc *flocp,
 # endif
             if (free_value)
                free (free_value);
-            MAKE_STATS_2(v->changes++);
             return v;
 #else /* !CONFIG_WITH_VALUE_LENGTH */
 
@@ -2734,9 +2846,17 @@ try_variable_definition (const struct floc *flocp, char *line
   return vp;
 }
 

+#if defined (CONFIG_WITH_COMPILER) || defined (CONFIG_WITH_MAKE_STATS)
+static unsigned long var_stats_evalvals, var_stats_evalvaled;
+static unsigned long var_stats_expands, var_stats_expanded;
+#endif
+#ifdef CONFIG_WITH_COMPILER
+static unsigned long var_stats_expandprogs, var_stats_evalprogs;
+#endif
 #ifdef CONFIG_WITH_MAKE_STATS
 static unsigned long var_stats_changes, var_stats_changed;
 static unsigned long var_stats_reallocs, var_stats_realloced;
+static unsigned long var_stats_references, var_stats_referenced;
 static unsigned long var_stats_val_len, var_stats_val_alloc_len;
 static unsigned long var_stats_val_rdonly_len;
 #endif
@@ -2804,15 +2924,61 @@ print_variable (const void *item, void *arg)
     printf (_(", alias for '%s'"), v->name);
 #endif /* KMK */
 
+#if defined (CONFIG_WITH_COMPILER) || defined (CONFIG_WITH_MAKE_STATS)
+  if (v->evalval_count != 0)
+    {
+# ifdef CONFIG_WITH_MAKE_STATS
+      printf (_(", %u evalvals (%llu ticks)"), v->evalval_count, v->cTicksEvalVal);
+# else
+      printf (_(", %u evalvals"), v->evalval_count);
+# endif
+      var_stats_evalvaled++;
+    }
+  var_stats_evalvals += v->evalval_count;
+
+  if (v->expand_count != 0)
+    {
+      printf (_(", %u expands"), v->expand_count);
+      var_stats_expanded++;
+    }
+  var_stats_expands += v->expand_count;
+
+# ifdef CONFIG_WITH_COMPILER
+  if (v->evalprog != 0)
+    {
+      printf (_(", evalprog"));
+      var_stats_evalprogs++;
+    }
+  if (v->expandprog != 0)
+    {
+      printf (_(", expandprog"));
+      var_stats_expandprogs++;
+    }
+# endif
+#endif
+
 #ifdef CONFIG_WITH_MAKE_STATS
   if (v->changes != 0)
+    {
       printf (_(", %u changes"), v->changes);
+      var_stats_changed++;
+    }
   var_stats_changes += v->changes;
-  var_stats_changed += (v->changes != 0);
+
   if (v->reallocs != 0)
+    {
       printf (_(", %u reallocs"), v->reallocs);
+      var_stats_realloced++;
+    }
   var_stats_reallocs += v->reallocs;
-  var_stats_realloced += (v->reallocs != 0);
+
+  if (v->references != 0)
+    {
+      printf (_(", %u references"), v->references);
+      var_stats_referenced++;
+    }
+  var_stats_references += v->references;
+
   var_stats_val_len += v->value_length;
   if (v->value_alloc_len)
     var_stats_val_alloc_len += v->value_alloc_len;
@@ -2867,15 +3033,25 @@ print_variable (const void *item, void *arg)
 void
 print_variable_set (struct variable_set *set, char *prefix)
 {
+#if defined (CONFIG_WITH_COMPILER) || defined (CONFIG_WITH_MAKE_STATS)
+  var_stats_expands = var_stats_expanded = var_stats_evalvals
+    = var_stats_evalvaled = 0;
+#endif
+#ifdef CONFIG_WITH_COMPILER
+  var_stats_expandprogs = var_stats_evalprogs = 0;
+#endif
 #ifdef CONFIG_WITH_MAKE_STATS
   var_stats_changes = var_stats_changed = var_stats_reallocs
-      = var_stats_realloced = var_stats_val_len = var_stats_val_alloc_len
-      = var_stats_val_rdonly_len = 0;
+    = var_stats_realloced = var_stats_references = var_stats_referenced
+    = var_stats_val_len = var_stats_val_alloc_len
+    = var_stats_val_rdonly_len = 0;
+#endif
 
   hash_map_arg (&set->table, print_variable, prefix);
 
   if (set->table.ht_fill)
     {
+#ifdef CONFIG_WITH_MAKE_STATS
       unsigned long fragmentation;
 
       fragmentation = var_stats_val_alloc_len - (var_stats_val_len - var_stats_val_rdonly_len);
@@ -2899,10 +3075,34 @@ print_variable_set (struct variable_set *set, char *prefix)
                var_stats_realloced,
                (unsigned int)((100.0 * var_stats_realloced) / set->table.ht_fill),
                var_stats_reallocs);
-      }
-#else
-  hash_map_arg (&set->table, print_variable, prefix);
+
+      if (var_stats_referenced)
+        printf(_("#  referenced %5lu (%2u%%),       references %6lu\n"),
+               var_stats_referenced,
+               (unsigned int)((100.0 * var_stats_referenced) / set->table.ht_fill),
+               var_stats_references);
+#endif
+#if defined (CONFIG_WITH_COMPILER) || defined (CONFIG_WITH_MAKE_STATS)
+      if (var_stats_evalvals)
+        printf(_("#   evalvaled %5lu (%2u%%),    evalval calls %6lu\n"),
+               var_stats_evalvaled,
+               (unsigned int)((100.0 * var_stats_evalvaled) / set->table.ht_fill),
+               var_stats_evalvals);
+      if (var_stats_expands)
+        printf(_("#    expanded %5lu (%2u%%),          expands %6lu\n"),
+               var_stats_expanded,
+               (unsigned int)((100.0 * var_stats_expanded) / set->table.ht_fill),
+               var_stats_expands);
+#endif
+#ifdef CONFIG_WITH_COMPILER
+      if (var_stats_expandprogs || var_stats_evalprogs)
+        printf(_("#  eval progs %5lu (%2u%%),     expand progs %6lu (%2u%%)\n"),
+               var_stats_evalprogs,
+               (unsigned int)((100.0 * var_stats_evalprogs) / set->table.ht_fill),
+               var_stats_expandprogs,
+               (unsigned int)((100.0 * var_stats_expandprogs) / set->table.ht_fill));
 #endif
+      }
 
   fputs (_("# variable set hash-table stats:\n"), stdout);
   fputs ("# ", stdout);
diff --git a/src/kmk/variable.h b/src/kmk/variable.h
index 6c922dd..3238108 100644
--- a/src/kmk/variable.h
+++ b/src/kmk/variable.h
@@ -17,6 +17,9 @@ You should have received a copy of the GNU General Public License along with
 this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "hash.h"
+#ifdef CONFIG_WITH_COMPILER
+# include "kmk_cc_exec.h"
+#endif
 
 /* Codes in a variable definition saying where the definition came from.
    Increasing numeric values signify less-overridable definitions.  */
@@ -108,12 +111,49 @@ struct variable
 	v_ifset,		/* Export it if it has a non-default value.  */
 	v_default		/* Decide in target_environment.  */
       } export ENUM_BITFIELD (2);
+#ifdef CONFIG_WITH_COMPILER
+    int recursive_without_dollar : 2; /* 0 if undetermined, 1 if value has no '$' chars, -1 if it has. */
+#endif
 #ifdef CONFIG_WITH_MAKE_STATS
-    unsigned int changes;
-    unsigned int reallocs;
+    unsigned int changes;      /* Variable modification count.  */
+    unsigned int reallocs;     /* Realloc on value count.  */
+    unsigned int references;   /* Lookup count.  */
+    unsigned long long cTicksEvalVal; /* Number of ticks spend in cEvalVal. */
+#endif
+#if defined (CONFIG_WITH_COMPILER) || defined (CONFIG_WITH_MAKE_STATS)
+    unsigned int evalval_count; /* Times used with $(evalval ) or $(evalctx ) since last change. */
+    unsigned int expand_count;  /* Times expanded since last change (not to be confused with exp_count). */
+#endif
+#ifdef CONFIG_WITH_COMPILER
+    struct kmk_cc_evalprog *evalprog;     /* Pointer to evalval/evalctx "program". */
+    struct kmk_cc_expandprog *expandprog; /* Pointer to variable expand "program". */
 #endif
   };
 
+/* Update statistics and invalidates optimizations when a variable changes. */
+#ifdef CONFIG_WITH_COMPILER
+# define VARIABLE_CHANGED(v) \
+  do { \
+      MAKE_STATS_2((v)->changes++); \
+      if ((v)->evalprog || (v)->expandprog) kmk_cc_variable_changed(v); \
+      (v)->expand_count = 0; \
+      (v)->evalval_count = 0; \
+      (v)->recursive_without_dollar = 0; \
+    } while (0)
+#else
+# define VARIABLE_CHANGED(v) MAKE_STATS_2((v)->changes++)
+#endif
+
+/* Macro that avoids a lot of CONFIG_WITH_COMPILER checks when
+   accessing recursive_without_dollar. */
+#ifdef CONFIG_WITH_COMPILER
+# define IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(v) ((v)->recursive_without_dollar > 0)
+#else
+# define IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(v) 0
+#endif
+
+
+
 /* Structure that represents a variable set.  */
 
 struct variable_set
@@ -233,7 +273,9 @@ variable_expand_string (char *line, const char *string, long length)
 }
 #endif /* CONFIG_WITH_VALUE_LENGTH */
 void install_variable_buffer (char **bufp, unsigned int *lenp);
+char *install_variable_buffer_with_hint (char **bufp, unsigned int *lenp, unsigned int size_hint);
 void restore_variable_buffer (char *buf, unsigned int len);
+char *ensure_variable_buffer_space(char *ptr, unsigned int size);
 #ifdef CONFIG_WITH_VALUE_LENGTH
 void append_expanded_string_to_variable (struct variable *v, const char *value,
                                          unsigned int value_len, int append);
@@ -245,6 +287,12 @@ int handle_function (char **op, const char **stringp);
 #else
 int handle_function (char **op, const char **stringp, const char *nameend, const char *eol);
 #endif
+#ifdef CONFIG_WITH_COMPILER
+typedef char *(*make_function_ptr_t) (char *, char **, const char *);
+make_function_ptr_t lookup_function_for_compiler (const char *name, unsigned int len,
+                                                  unsigned char *minargsp, unsigned char *maxargsp,
+                                                  char *expargsp, const char **funcnamep);
+#endif
 int pattern_matches (const char *pattern, const char *percent, const char *str);
 char *subst_expand (char *o, const char *text, const char *subst,
                     const char *replace, unsigned int slen, unsigned int rlen,
@@ -309,6 +357,9 @@ char *recursively_expand_for_file (struct variable *v, struct file *file,
                                    unsigned int *value_lenp);
 #define recursively_expand(v)   recursively_expand_for_file (v, NULL, NULL)
 #endif
+#ifdef CONFIG_WITH_COMPILER
+char *reference_recursive_variable (char *o, struct variable *v);
+#endif
 
 /* variable.c */
 struct variable_set_list *create_new_variable_set (void);
@@ -352,6 +403,9 @@ void hash_init_function_table (void);
 struct variable *lookup_variable (const char *name, unsigned int length);
 struct variable *lookup_variable_in_set (const char *name, unsigned int length,
                                          const struct variable_set *set);
+#ifdef CONFIG_WITH_STRCACHE2
+struct variable *lookup_variable_strcached (const char *name);
+#endif
 
 #ifdef CONFIG_WITH_VALUE_LENGTH
 void append_string_to_variable (struct variable *v, const char *value,

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-virtualbox/kbuild.git



More information about the Pkg-virtualbox-commits mailing list