Index: /trunk/src/kmk/Makefile.am
===================================================================
--- /trunk/src/kmk/Makefile.am	(revision 1931)
+++ /trunk/src/kmk/Makefile.am	(revision 1932)
@@ -139,4 +139,5 @@
 	-DCONFIG_PRETTY_COMMAND_PRINTING \
 	-DCONFIG_WITH_PRINT_STATS_SWITCH \
+	-DCONFIG_WITH_RDONLY_VARIABLE_VALUE \
 	\
 	-DKBUILD_HOST=\"$(BUILD_TARGET)\" \
Index: /trunk/src/kmk/Makefile.kmk
===================================================================
--- /trunk/src/kmk/Makefile.kmk	(revision 1931)
+++ /trunk/src/kmk/Makefile.kmk	(revision 1932)
@@ -169,4 +169,5 @@
 	CONFIG_PRETTY_COMMAND_PRINTING \
 	CONFIG_WITH_PRINT_STATS_SWITCH \
+	CONFIG_WITH_RDONLY_VARIABLE_VALUE \
 	\
 	KBUILD_HOST=\"$(KBUILD_TARGET)\" \
Index: /trunk/src/kmk/commands.c
===================================================================
--- /trunk/src/kmk/commands.c	(revision 1931)
+++ /trunk/src/kmk/commands.c	(revision 1932)
@@ -85,4 +85,10 @@
       const char *name;
       unsigned int len;
+#ifdef CONFIG_WITH_STRCACHE2
+      static const char *suffixes_strcache = 0; /* XXX: make this global */
+
+      if (!suffixes_strcache)
+        suffixes_strcache = strcache_add_len (".SUFFIXES", sizeof (".SUFFIXES") - 1);
+#endif /* CONFIG_WITH_STRCACHE2 */
 
 #ifndef	NO_ARCHIVES
@@ -103,9 +109,11 @@
 	}
 
+#ifndef CONFIG_WITH_STRCACHE2
       for (d = enter_file (strcache_add (".SUFFIXES"))->deps; d ; d = d->next)
 	{
-#ifndef CONFIG_WITH_STRCACHE2
 	  unsigned int slen = strlen (dep_name (d));
 #else
+      for (d = enter_file (suffixes_strcache)->deps; d ; d = d->next)
+        {
 	  unsigned int slen = strcache2_get_len (&file_strcache, dep_name (d));
 #endif
@@ -140,8 +148,36 @@
   /* Define the variables.  */
 
+#ifndef CONFIG_WITH_RDONLY_VARIABLE_VALUE
   DEFINE_VARIABLE ("<", 1, less);
   DEFINE_VARIABLE ("*", 1, star);
   DEFINE_VARIABLE ("@", 1, at);
   DEFINE_VARIABLE ("%", 1, percent);
+#else  /* CONFIG_WITH_RDONLY_VARIABLE_VALUE */
+# define DEFINE_VARIABLE_RO_VAL(name, len, value, value_len) \
+  define_variable_in_set((name), (len), (value), (value_len), -1, \
+        (o_automatic), 0, (file)->variables->set, NILF)
+
+  if (*less == '\0')
+    DEFINE_VARIABLE_RO_VAL ("<", 1, "", 0);
+  else if (less != at || at == file->name)
+    DEFINE_VARIABLE_RO_VAL ("<", 1, less, strcache_get_len (less));
+  else
+    DEFINE_VARIABLE ("<", 1, less);
+
+  if (*star == '\0')
+    DEFINE_VARIABLE_RO_VAL ("*", 1, "", 0);
+  else
+    DEFINE_VARIABLE_RO_VAL ("*", 1, star, strcache_get_len (star));
+
+  if (at == file->name)
+    DEFINE_VARIABLE_RO_VAL ("@", 1, at, strcache_get_len (at));
+  else
+    DEFINE_VARIABLE ("@", 1, at);
+
+  if (*percent == '\0')
+    DEFINE_VARIABLE_RO_VAL ("%", 1, "", 0);
+  else
+    DEFINE_VARIABLE ("%", 1, percent);
+#endif /* CONFIG_WITH_RDONLY_VARIABLE_VALUE */
 
   /* Compute the values for $^, $+, $?, and $|.  */
Index: /trunk/src/kmk/expand.c
===================================================================
--- /trunk/src/kmk/expand.c	(revision 1931)
+++ /trunk/src/kmk/expand.c	(revision 1932)
@@ -976,5 +976,10 @@
 
       /* Replace the variable with the variable buffer. */
-      free (v->value);
+#ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
+      if (v->rdonly_val)
+        v->rdonly_val = 0;
+      else
+#endif
+        free (v->value);
       v->value = variable_buffer;
       v->value_length = p - v->value;
Index: /trunk/src/kmk/function.c
===================================================================
--- /trunk/src/kmk/function.c	(revision 1931)
+++ /trunk/src/kmk/function.c	(revision 1932)
@@ -1041,5 +1041,10 @@
       if (len >= (unsigned int)var->value_alloc_len)
         {
-          free (var->value);
+# ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
+          if (var->rdonly_val)
+            var->rdonly_val = 0;
+          else
+# endif
+            free (var->value);
           var->value_alloc_len = (len + 32) & ~31;
           var->value = xmalloc (var->value_alloc_len);
Index: /trunk/src/kmk/kbuild.c
===================================================================
--- /trunk/src/kmk/kbuild.c	(revision 1931)
+++ /trunk/src/kmk/kbuild.c	(revision 1932)
@@ -572,5 +572,11 @@
         unsigned int value_len;
         char *pszExpanded = allocated_variable_expand_2(pVar->value, pVar->value_length, &value_len);
-        free(pVar->value);
+#ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
+        if (pVar->rdonly_val)
+            pVar->rdonly_val = 0;
+        else
+#endif
+            free(pVar->value);
+        assert (pVar->origin != o_automatic);
         pVar->value = pszExpanded;
         pVar->value_length = value_len;
@@ -643,5 +649,11 @@
     struct variable *pVar = kbuild_lookup_variable_n(pszName, cchName);
     if (pVar && pDefPath)
+    {
+        assert(pVar->origin != o_automatic);
+#ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
+        assert(!pVar->rdonly_val);
+#endif
         kbuild_apply_defpath(pDefPath, &pVar->value, (unsigned int *)&pVar->value_length, &pVar->value_alloc_len, 1);
+    }
     return pVar;
 }
@@ -661,5 +673,11 @@
     struct variable *pVar = kbuild_lookup_variable(pszName);
     if (pVar && pDefPath)
+    {
+        assert(pVar->origin != o_automatic);
+#ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
+        assert(!pVar->rdonly_val);
+#endif
         kbuild_apply_defpath(pDefPath, &pVar->value, (unsigned int *)&pVar->value_length, &pVar->value_alloc_len, 1);
+    }
     return pVar;
 }
@@ -2044,5 +2062,12 @@
      */
     if (pDefPath)
+    {
+        /** @todo assert(pSource->origin != o_automatic);  We're changing 'source'
+         *        from the foreach loop!  */
+#ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
+        assert(!pSource->rdonly_val);
+#endif
         kbuild_apply_defpath(pDefPath, &pSource->value, (unsigned int *)&pSource->value_length, &pSource->value_alloc_len, 1 /* can free */);
+    }
 
     /*
Index: /trunk/src/kmk/variable.c
===================================================================
--- /trunk/src/kmk/variable.c	(revision 1931)
+++ /trunk/src/kmk/variable.c	(revision 1932)
@@ -254,10 +254,18 @@
           else
             assert (value_len == strlen (value));
-          if (!duplicate_value)
+          if (!duplicate_value || duplicate_value == -1)
             {
+# ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
+              if (v->value != 0 && !v->rdonly_val)
+                  free (v->value);
+              v->rdonly_val = duplicate_value == -1;
+              v->value = (char *)value;
+              v->value_alloc_len = 0;
+# else
               if (v->value != 0)
                 free (v->value);
               v->value = (char *)value;
               v->value_alloc_len = value_len + 1;
+# endif
             }
           else
@@ -265,5 +273,10 @@
               if ((unsigned int)v->value_alloc_len <= value_len)
                 {
-                  free (v->value);
+# ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
+                  if (v->rdonly_val)
+                    v->rdonly_val = 0;
+                  else
+# endif
+                    free (v->value);
                   v->value_alloc_len = (value_len + 0x40) & ~0x3f;
                   v->value = xmalloc (v->value_alloc_len);
@@ -272,9 +285,9 @@
             }
           v->value_length = value_len;
-#else
+#else  /* !CONFIG_WITH_VALUE_LENGTH */
           if (v->value != 0)
             free (v->value);
 	  v->value = xstrdup (value);
-#endif
+#endif /* !CONFIG_WITH_VALUE_LENGTH */
           if (flocp != 0)
             v->fileinfo = *flocp;
@@ -307,11 +320,17 @@
     assert (value_len == strlen (value));
   v->value_length = value_len;
-  if (!duplicate_value)
-    {
-      v->value_alloc_len = value_len + 1;
+  if (!duplicate_value || duplicate_value == -1)
+    {
+# ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
+      v->rdonly_val = duplicate_value == -1;
+      v->value_alloc_len = v->rdonly_val ? 0 : value_len + 1;
+# endif
       v->value = (char *)value;
     }
   else
     {
+# ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
+      v->rdonly_val = 0;
+# endif
       v->value_alloc_len = (value_len + 32) & ~31;
       v->value = xmalloc (v->value_alloc_len);
@@ -1345,5 +1364,10 @@
   if (*v->value == '\0' || v->origin == o_env || v->origin == o_env_override)
     {
-      free (v->value);
+#ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
+      if (v->rdonly_val)
+        v->rdonly_val = 0;
+      else
+#endif
+        free (v->value);
       v->origin = o_file;
       v->value = xstrdup (default_shell);
@@ -1589,5 +1613,9 @@
       if ((unsigned)v->value_alloc_len < new_value_len + 1)
           v->value_alloc_len = (new_value_len + 1 + value_len + 0x7f) + ~0x7fU;
+# ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
+      if ((append || !v->value_length) && !v->rdonly_val)
+# else
       if (append || !v->value_length)
+# endif
         v->value = xrealloc (v->value, v->value_alloc_len);
       else
@@ -1597,5 +1625,10 @@
           memcpy (&new_buf[value_len + 1], v->value, v->value_length + 1);
           done_1st_prepend_copy = 1;
-          free (v->value);
+# ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
+          if (v->rdonly_val)
+            v->rdonly_val = 0;
+          else
+# endif
+            free (v->value);
           v->value = new_buf;
         }
@@ -2094,4 +2127,7 @@
   v->value_length = eos != NULL ? eos - p : -1;
   assert (eos == NULL || strchr (p, '\0') == eos);
+# ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
+  v->rdonly_val = 0;
+# endif
 #endif
 
Index: /trunk/src/kmk/variable.h
===================================================================
--- /trunk/src/kmk/variable.h	(revision 1931)
+++ /trunk/src/kmk/variable.h	(revision 1932)
@@ -82,4 +82,7 @@
                                 /* If >1, allow this many self-referential
                                    expansions.  */
+#ifdef CONFIG_WITH_RDONLY_VARIABLE_VALUE
+    unsigned int rdonly_val:1;  /* VALUE is read only (strcache/const). */
+#endif
     enum variable_flavor
       flavor ENUM_BITFIELD (3);	/* Variable flavor.  */
