Index: /trunk/src/kmk/Makefile.am
===================================================================
--- /trunk/src/kmk/Makefile.am	(revision 1933)
+++ /trunk/src/kmk/Makefile.am	(revision 1934)
@@ -140,4 +140,5 @@
 	-DCONFIG_WITH_PRINT_STATS_SWITCH \
 	-DCONFIG_WITH_RDONLY_VARIABLE_VALUE \
+	-DCONFIG_WITH_LAZY_DEP_LISTS \
 	\
 	-DKBUILD_HOST=\"$(BUILD_TARGET)\" \
Index: /trunk/src/kmk/Makefile.kmk
===================================================================
--- /trunk/src/kmk/Makefile.kmk	(revision 1933)
+++ /trunk/src/kmk/Makefile.kmk	(revision 1934)
@@ -170,4 +170,5 @@
 	CONFIG_WITH_PRINT_STATS_SWITCH \
 	CONFIG_WITH_RDONLY_VARIABLE_VALUE \
+	CONFIG_WITH_LAZY_DEPS_VARS \
 	\
 	KBUILD_HOST=\"$(KBUILD_TARGET)\" \
@@ -517,5 +518,9 @@
 	fi
 
-
-test_all:	test_math test_stack test_shell test_if1of test_local test_includedep test_2ndtargetexp test_30_continued_on_failure
-
+test_lazy_deps_vars:
+	$(MAKE) -C $(kmk_PATH) -f testcase-lazy-deps-vars.kmk
+
+
+test_all:	test_math test_stack test_shell test_if1of test_local test_includedep test_2ndtargetexp test_30_continued_on_failure test_lazy_deps_vars
+
+
Index: /trunk/src/kmk/commands.c
===================================================================
--- /trunk/src/kmk/commands.c	(revision 1933)
+++ /trunk/src/kmk/commands.c	(revision 1934)
@@ -26,4 +26,7 @@
 #include <windows.h>
 #include "w32err.h"
+#endif
+#ifdef CONFIG_WITH_LAZY_DEPS_VARS
+# include <assert.h>
 #endif
 
@@ -175,4 +178,5 @@
 #endif /* CONFIG_WITH_RDONLY_VARIABLE_VALUE */
 
+#ifndef CONFIG_WITH_LAZY_DEPS_VARS
   /* Compute the values for $^, $+, $?, and $|.  */
 
@@ -317,4 +321,16 @@
   }
 
+#else  /* CONFIG_WITH_LAZY_DEPS_VARS */
+
+  /* Make a copy of the current dependency chain for later use in
+     potential $(dep-pluss $@) calls.  Then drop duplicate deps.  */
+
+  /* assert (file->org_deps == NULL); - FIXME? */
+  free_dep_chain (file->org_deps);
+  file->org_deps = copy_dep_chain (file->deps);
+
+  uniquize_deps (file->deps);
+
+#endif /* CONFIG_WITH_LAZY_DEPS_VARS */
 #undef	DEFINE_VARIABLE
 }
Index: /trunk/src/kmk/filedef.h
===================================================================
--- /trunk/src/kmk/filedef.h	(revision 1933)
+++ /trunk/src/kmk/filedef.h	(revision 1934)
@@ -30,4 +30,8 @@
     const char *vpath;          /* VPATH/vpath pathname */
     struct dep *deps;		/* all dependencies, including duplicates */
+#ifdef CONFIG_WITH_LAZY_DEPS_VARS
+    struct dep *org_deps;	/* original dependencies before
+                                   duplicates were dropped. */
+#endif
     struct commands *cmds;	/* Commands to execute for this target.  */
     int command_flags;		/* Flags OR'd in for cmds; see commands.h.  */
Index: /trunk/src/kmk/function.c
===================================================================
--- /trunk/src/kmk/function.c	(revision 1933)
+++ /trunk/src/kmk/function.c	(revision 1934)
@@ -2185,4 +2185,393 @@
 
 
+#ifdef CONFIG_WITH_LAZY_DEPS_VARS
+
+/* This is also in file.c (bad).  */
+# if VMS
+#  define FILE_LIST_SEPARATOR ','
+# else
+#  define FILE_LIST_SEPARATOR ' '
+# endif
+
+/* Implements $^ and $+.
+
+   The first is somes with with FUNCNAME 'dep', the second as 'dep-all'.
+
+   If no second argument is given, or if it's empty, or if it's zero,
+   all dependencies will be returned.  If the second argument is non-zero
+   the dependency at that position will be returned.  If the argument is
+   negative a fatal error is thrown.  */
+static char *
+func_deps (char *o, char **argv, const char *funcname)
+{
+  unsigned int idx = 0;
+  struct file *file;
+
+  /* Handle the argument if present. */
+
+  if (argv[1])
+    {
+      char *p = argv[1];
+      while (isspace ((unsigned int)*p))
+        p++;
+      if (*p != '\0')
+        {
+          char *n;
+          long l = strtol (p, &n, 0);
+          while (isspace ((unsigned int)*n))
+            n++;
+          idx = l;
+          if (*n != '\0' || l < 0 || (long)idx != l)
+            fatal (NILF, _("%s: invalid index value: `%s'\n"), funcname, p);
+        }
+    }
+
+  /* Find the file and select the list corresponding to FUNCNAME. */
+
+  file = lookup_file (argv[0]);
+  if (file)
+    {
+      struct dep *deps = funcname[4] != '\0' && file->org_deps
+                       ? file->org_deps : file->deps;
+      struct dep *d;
+
+      if (idx == 0 /* all */)
+        {
+          unsigned int total_len = 0;
+
+          /* calc the result length. */
+
+          for (d = deps; d; d = d->next)
+            if (!d->ignore_mtime)
+              {
+                const char *c = dep_name (d);
+
+#ifndef	NO_ARCHIVES
+                if (ar_name (c))
+                  {
+                    c = strchr (c, '(') + 1;
+                    total_len += strlen (c);
+                  }
+                else
+#else
+                  total_len += strcache2_get_len (&file_strcache, c) + 1;
+#endif
+              }
+
+          if (total_len)
+            {
+              /* prepare the variable buffer dude wrt to the output size and
+                 pass along the strings.  */
+
+              o = variable_buffer_output (o + total_len, "", 0) - total_len; /* a hack */
+
+              for (d = deps; d; d = d->next)
+                if (!d->ignore_mtime)
+                  {
+                    unsigned int len;
+                    const char *c = dep_name (d);
+
+#ifndef	NO_ARCHIVES
+                    if (ar_name (c))
+                      {
+                        c = strchr (c, '(') + 1;
+                        len += strlen (c);
+                      }
+                    else
+#else
+                      len = strcache2_get_len (&file_strcache, c) + 1;
+#endif
+                    o = variable_buffer_output (o, c, len);
+                    o[-1] = FILE_LIST_SEPARATOR;
+                  }
+
+                --o;        /* nuke the last list separator */
+                *o = '\0';
+            }
+        }
+      else
+        {
+          /* Dependency given by index.  */
+
+          for (d = deps; d; d = d->next)
+            if (!d->ignore_mtime)
+              {
+                if (--idx == 0) /* 1 based indexing */
+                  {
+                    unsigned int len;
+                    const char *c = dep_name (d);
+
+#ifndef	NO_ARCHIVES
+                    if (ar_name (c))
+                      {
+                        c = strchr (c, '(') + 1;
+                        len += strlen (c) - ;
+                      }
+                    else
+#else
+                        len = strcache2_get_len (&file_strcache, c);
+#endif
+                    o = variable_buffer_output (o, c, len);
+                    break;
+                  }
+              }
+        }
+    }
+
+  return o;
+}
+
+/* Implements $?.
+
+   If no second argument is given, or if it's empty, or if it's zero,
+   all dependencies will be returned.  If the second argument is non-zero
+   the dependency at that position will be returned.  If the argument is
+   negative a fatal error is thrown.  */
+static char *
+func_deps_newer (char *o, char **argv, const char *funcname)
+{
+  unsigned int idx = 0;
+  struct file *file;
+
+  /* Handle the argument if present. */
+
+  if (argv[1])
+    {
+      char *p = argv[1];
+      while (isspace ((unsigned int)*p))
+        p++;
+      if (*p != '\0')
+        {
+          char *n;
+          long l = strtol (p, &n, 0);
+          while (isspace ((unsigned int)*n))
+            n++;
+          idx = l;
+          if (*n != '\0' || l < 0 || (long)idx != l)
+            fatal (NILF, _("%s: invalid index value: `%s'\n"), funcname, p);
+        }
+    }
+
+  /* Find the file. */
+
+  file = lookup_file (argv[0]);
+  if (file)
+    {
+      struct dep *deps = file->deps;
+      struct dep *d;
+
+      if (idx == 0 /* all */)
+        {
+          unsigned int total_len = 0;
+
+          /* calc the result length. */
+
+          for (d = deps; d; d = d->next)
+            if (!d->ignore_mtime && d->changed)
+              {
+                const char *c = dep_name (d);
+
+#ifndef	NO_ARCHIVES
+                if (ar_name (c))
+                  {
+                    c = strchr (c, '(') + 1;
+                    total_len += strlen (c);
+                  }
+                else
+#else
+                  total_len += strcache2_get_len (&file_strcache, c) + 1;
+#endif
+              }
+
+          if (total_len)
+            {
+              /* prepare the variable buffer dude wrt to the output size and
+                 pass along the strings.  */
+
+              o = variable_buffer_output (o + total_len, "", 0) - total_len; /* a hack */
+
+              for (d = deps; d; d = d->next)
+                if (!d->ignore_mtime && d->changed)
+                  {
+                    unsigned int len;
+                    const char *c = dep_name (d);
+
+#ifndef	NO_ARCHIVES
+                    if (ar_name (c))
+                      {
+                        c = strchr (c, '(') + 1;
+                        len += strlen (c);
+                      }
+                    else
+#else
+                      len = strcache2_get_len (&file_strcache, c) + 1;
+#endif
+                    o = variable_buffer_output (o, c, len);
+                    o[-1] = FILE_LIST_SEPARATOR;
+                  }
+
+                --o;        /* nuke the last list separator */
+                *o = '\0';
+            }
+        }
+      else
+        {
+          /* Dependency given by index.  */
+
+          for (d = deps; d; d = d->next)
+            if (!d->ignore_mtime && d->changed)
+              {
+                if (--idx == 0) /* 1 based indexing */
+                  {
+                    unsigned int len;
+                    const char *c = dep_name (d);
+
+#ifndef	NO_ARCHIVES
+                    if (ar_name (c))
+                      {
+                        c = strchr (c, '(') + 1;
+                        len += strlen (c) - ;
+                      }
+                    else
+#else
+                        len = strcache2_get_len (&file_strcache, c);
+#endif
+                    o = variable_buffer_output (o, c, len);
+                    break;
+                  }
+              }
+        }
+    }
+
+  return o;
+}
+
+/* Implements $|, the order only dependency list.
+
+   If no second argument is given, or if it's empty, or if it's zero,
+   all dependencies will be returned.  If the second argument is non-zero
+   the dependency at that position will be returned.  If the argument is
+   negative a fatal error is thrown.  */
+static char *
+func_deps_order_only (char *o, char **argv, const char *funcname)
+{
+  unsigned int idx = 0;
+  struct file *file;
+
+  /* Handle the argument if present. */
+
+  if (argv[1])
+    {
+      char *p = argv[1];
+      while (isspace ((unsigned int)*p))
+        p++;
+      if (*p != '\0')
+        {
+          char *n;
+          long l = strtol (p, &n, 0);
+          while (isspace ((unsigned int)*n))
+            n++;
+          idx = l;
+          if (*n != '\0' || l < 0 || (long)idx != l)
+            fatal (NILF, _("%s: invalid index value: `%s'\n"), funcname, p);
+        }
+    }
+
+  /* Find the file. */
+
+  file = lookup_file (argv[0]);
+  if (file)
+    {
+      struct dep *deps = file->deps;
+      struct dep *d;
+
+      if (idx == 0 /* all */)
+        {
+          unsigned int total_len = 0;
+
+          /* calc the result length. */
+
+          for (d = deps; d; d = d->next)
+            if (d->ignore_mtime)
+              {
+                const char *c = dep_name (d);
+
+#ifndef	NO_ARCHIVES
+                if (ar_name (c))
+                  {
+                    c = strchr (c, '(') + 1;
+                    total_len += strlen (c);
+                  }
+                else
+#else
+                  total_len += strcache2_get_len (&file_strcache, c) + 1;
+#endif
+              }
+
+          if (total_len)
+            {
+              /* prepare the variable buffer dude wrt to the output size and
+                 pass along the strings.  */
+
+              o = variable_buffer_output (o + total_len, "", 0) - total_len; /* a hack */
+
+              for (d = deps; d; d = d->next)
+                if (d->ignore_mtime)
+                  {
+                    unsigned int len;
+                    const char *c = dep_name (d);
+
+#ifndef	NO_ARCHIVES
+                    if (ar_name (c))
+                      {
+                        c = strchr (c, '(') + 1;
+                        len += strlen (c);
+                      }
+                    else
+#else
+                      len = strcache2_get_len (&file_strcache, c) + 1;
+#endif
+                    o = variable_buffer_output (o, c, len);
+                    o[-1] = FILE_LIST_SEPARATOR;
+                  }
+
+                --o;        /* nuke the last list separator */
+                *o = '\0';
+            }
+        }
+      else
+        {
+          /* Dependency given by index.  */
+
+          for (d = deps; d; d = d->next)
+            if (d->ignore_mtime)
+              {
+                if (--idx == 0) /* 1 based indexing */
+                  {
+                    unsigned int len;
+                    const char *c = dep_name (d);
+
+#ifndef	NO_ARCHIVES
+                    if (ar_name (c))
+                      {
+                        c = strchr (c, '(') + 1;
+                        len += strlen (c) - ;
+                      }
+                    else
+#else
+                        len = strcache2_get_len (&file_strcache, c);
+#endif
+                    o = variable_buffer_output (o, c, len);
+                    break;
+                  }
+              }
+        }
+    }
+
+  return o;
+}
+#endif /* CONFIG_WITH_LAZY_DEPS_VARS */
+
+
 
 #ifdef CONFIG_WITH_DEFINED
@@ -3844,5 +4233,5 @@
 
       initialize_file_variables (file, 1 /* reading - FIXME: we don't know? */);
-      set_file_variables (file);
+      set_file_variables (file); /* FIXME: this must *NOT* be done twice! */
       chop_commands (cmds);
 
@@ -4073,4 +4462,10 @@
   { STRING_SIZE_TUPLE("not"),           0,  1,  1,  func_not},
 #endif
+#ifdef CONFIG_WITH_LAZY_DEPS_VARS
+  { STRING_SIZE_TUPLE("deps"),          1,  2,  1,  func_deps},
+  { STRING_SIZE_TUPLE("deps-all"),      1,  2,  1,  func_deps},
+  { STRING_SIZE_TUPLE("deps-newer"),    1,  2,  1,  func_deps_newer},
+  { STRING_SIZE_TUPLE("deps-oo"),       1,  2,  1,  func_deps_order_only},
+#endif
 #ifdef CONFIG_WITH_DEFINED
   { STRING_SIZE_TUPLE("defined"),       1,  1,  1,  func_defined},
Index: /trunk/src/kmk/testcase-lazy-deps-vars.kmk
===================================================================
--- /trunk/src/kmk/testcase-lazy-deps-vars.kmk	(revision 1934)
+++ /trunk/src/kmk/testcase-lazy-deps-vars.kmk	(revision 1934)
@@ -0,0 +1,73 @@
+# $Id$
+## @file
+# kBuild - testcase for the lazy dependency lists.
+#
+
+#
+# Copyright (c) 2008 knut st. osmundsen <bird-src-spam@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 2 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#
+#
+
+DEPTH = ../..
+include $(PATH_KBUILD)/header.kmk
+
+ifneq ($(not 1),)
+ $(error The 'not' function is missing)
+endif
+ifneq ($(eq 1,1),1)
+ $(error The 'eq' function is missing)
+endif
+
+
+all: simple_1
+
+
+simple_1: variable.c variable.h variable.c variable.c variable.h function.c | variable.h read.c
+	@$(ECHO) "testcase-lazy-deps-vars.kmk::$@: TESTING..."
+	@$(ECHO) "pluss: $+"
+	$(if $(eq $+,variable.c variable.h variable.c variable.c variable.h function.c),,exit 1)
+	$(if $(eq $(deps-all $@,1),variable.c),,exit 1)
+	$(if $(eq $(deps-all $@,2),variable.h),,exit 2)
+	$(if $(eq $(deps-all $@,3),variable.c),,exit 3)
+	$(if $(eq $(deps-all $@,4),variable.c),,exit 4)
+	$(if $(eq $(deps-all $@,5),variable.h),,exit 5)
+	$(if $(eq $(deps-all $@,6),function.c),,exit 6)
+	$(if $(eq $(deps-all $@,7),),,exit 7)
+
+	@$(ECHO) "caret: $^"
+	$(if $(eq $^,variable.c variable.h function.c),,exit 1)
+	$(if $(eq $(deps $@,1),variable.c),,exit 1)
+	$(if $(eq $(deps $@,2),variable.h),,exit 2)
+	$(if $(eq $(deps $@,3),function.c),,exit 3)
+	$(if $(eq $(deps $@,4),),,exit 4)
+
+	@$(ECHO) "qmark: $?"
+	$(if $(eq $?,variable.c variable.h function.c),,exit 1)
+	$(if $(eq $(deps-newer $@,1),variable.c),,exit 1)
+	$(if $(eq $(deps-newer $@,2),variable.h),,exit 2)
+	$(if $(eq $(deps-newer $@,3),function.c),,exit 3)
+	$(if $(eq $(deps-newer $@,4),),,exit 4)
+
+	@$(ECHO) "  bar: $|"
+	$(if $(eq $|,read.c),,exit 1)
+	$(if $(eq $(deps-oo $@,1),read.c),,exit 1)
+	$(if $(eq $(deps-oo $@,2),),,exit 2)
+
+	@$(ECHO) "testcase-lazy-deps-vars.kmk::simple_1: SUCCESS"
+
Index: /trunk/src/kmk/variable.c
===================================================================
--- /trunk/src/kmk/variable.c	(revision 1933)
+++ /trunk/src/kmk/variable.c	(revision 1934)
@@ -1410,4 +1410,10 @@
   define_variable ("^F", 2, "$(notdir $^)", o_automatic, 1);
   define_variable ("+F", 2, "$(notdir $+)", o_automatic, 1);
+#ifdef CONFIG_WITH_LAZY_DEPS_VARS
+  define_variable ("^", 1, "$(deps $@)", o_automatic, 1);
+  define_variable ("+", 1, "$(deps-all $@)", o_automatic, 1);
+  define_variable ("?", 1, "$(deps-newer $@)", o_automatic, 1);
+  define_variable ("|", 1, "$(deps-oo $@)", o_automatic, 1);
+#endif /* CONFIG_WITH_LAZY_DEPS_VARS */
 }
 
