Index: /trunk/src/kObjCache/Makefile.kmk
===================================================================
--- /trunk/src/kObjCache/Makefile.kmk	(revision 2611)
+++ /trunk/src/kObjCache/Makefile.kmk	(revision 2612)
@@ -30,5 +30,7 @@
 kObjCache_TEMPLATE = BIN
 kObjCache_SOURCES = kObjCache.c
-kObjCache_LIBS = $(LIB_KUTIL)
+kObjCache_LIBS = \
+	$(LIB_KDEP) \
+	$(LIB_KUTIL)
 
 include $(KBUILD_PATH)/subfooter.kmk
Index: /trunk/src/kObjCache/kObjCache.c
===================================================================
--- /trunk/src/kObjCache/kObjCache.c	(revision 2611)
+++ /trunk/src/kObjCache/kObjCache.c	(revision 2612)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (c) 2007-2011 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+ * Copyright (c) 2007-2012 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
  *
  * This file is part of kBuild.
@@ -80,4 +80,5 @@
 #include "crc32.h"
 #include "md5.h"
+#include "kDep.h"
 
 
@@ -110,4 +111,6 @@
 #endif
 
+#define MY_IS_BLANK(a_ch)   ((a_ch) == ' ' || (a_ch) == '\t')
+
 
 /*******************************************************************************
@@ -129,7 +132,7 @@
 static char *CalcRelativeName(const char *pszPath, const char *pszDir);
 static FILE *FOpenFileInDir(const char *pszName, const char *pszDir, const char *pszMode);
-static int UnlinkFileInDir(const char *pszName, const char *pszDir);
-static int RenameFileInDir(const char *pszOldName, const char *pszNewName, const char *pszDir);
-static int DoesFileInDirExist(const char *pszName, const char *pszDir);
+static int   UnlinkFileInDir(const char *pszName, const char *pszDir);
+static int   RenameFileInDir(const char *pszOldName, const char *pszNewName, const char *pszDir);
+static int   DoesFileInDirExist(const char *pszName, const char *pszDir);
 static void *ReadFileInDir(const char *pszName, const char *pszDir, size_t *pcbFile);
 
@@ -757,11 +760,336 @@
 
 
+/**
+ * Dependency collector state.
+ */
+typedef struct KOCDEP
+{
+    /** The statemachine for processing the preprocessed code stream. */
+    enum KOCDEPSTATE
+    {
+        kOCDepState_Invalid = 0,
+        kOCDepState_NeedNewLine,
+        kOCDepState_NeedHash,
+        kOCDepState_NeedLine_l,
+        kOCDepState_NeedLine_l_HaveSpace,
+        kOCDepState_NeedLine_i,
+        kOCDepState_NeedLine_n,
+        kOCDepState_NeedLine_e,
+        kOCDepState_NeedSpaceBeforeDigit,
+        kOCDepState_NeedFirstDigit,
+        kOCDepState_NeedMoreDigits,
+        kOCDepState_NeedQuote,
+        kOCDepState_NeedEndQuote
+    }   enmState;
+    /** Current offset into the filename buffer. */
+    uint32_t offFilename;
+    /** The amount of space currently allocated for the filename buffer. */
+    uint32_t cbFilenameAlloced;
+    /** Pointer to the filename buffer. */
+    char *pszFilename;
+    /** The current dependency file. */
+    PDEP pCurDep;
+} KOCDEP;
+/** Pointer to a KOCDEP.  */
+typedef KOCDEP *PKOCDEP;
+
+
+/**
+ * Initializes the dependency collector state.
+ *
+ * @param   pDepState       The dependency collector state.
+ */
+static void kOCDepInit(PKOCDEP pDepState)
+{
+    pDepState->enmState = kOCDepState_NeedHash;
+    pDepState->offFilename = 0;
+    pDepState->cbFilenameAlloced = 0;
+    pDepState->pszFilename = NULL;
+    pDepState->pCurDep = NULL;
+}
+
+
+/**
+ * Deletes the dependency collector state, releasing all resources.
+ *
+ * @param   pDepState       The dependency collector state.
+ */
+static void kOCDepDelete(PKOCDEP pDepState)
+{
+    pDepState->enmState = kOCDepState_Invalid;
+    free(pDepState->pszFilename);
+    pDepState->pszFilename = NULL;
+    depCleanup();
+}
+
+
+/**
+ * Unescapes a string in place.
+ *
+ * @returns The new string length.
+ * @param   psz             The string to unescape (input and output).
+ */
+static size_t kOCDepUnescape(char *psz)
+{
+    char *pszSrc = psz;
+    char *pszDst = psz;
+    char ch;
+
+    while ((ch = *pszSrc++) != '\0')
+    {
+        if (ch == '\\')
+        {
+            char ch2 = *pszSrc;
+            if (ch2)
+            {
+                pszSrc++;
+                ch = ch2;
+            }
+            /* else: cannot happen / just ignore */
+        }
+        *pszDst++ = ch;
+    }
+
+    *pszDst = '\0';
+    return pszDst - psz;
+}
+
+
+/**
+ * Checks if the character at @a offChar is escaped or not.
+ *
+ * @returns 1 if escaped, 0 if not.
+ * @param   pach            The string (not terminated).
+ * @param   offChar         The offset of the character in question.
+ */
+static int kOCDepIsEscaped(char *pach, size_t offChar)
+{
+    while (offChar > 0 && pach[offChar - 1] == '\\')
+    {
+        if (   offChar == 1
+            || pach[offChar - 2] != '\\')
+            return 1;
+        offChar -= 2;
+    }
+    return 0;
+}
+
+
+/**
+ * This consumes the preprocessor output and generate dependencies from it.
+ *
+ * The trick is to look at the line directives and which files get listed there.
+ *
+ * @returns The new state. This is a convenience for saving code space and it
+ *          isn't really meant to be of any use to the caller.
+ * @param   pDepState       The dependency collector state.
+ * @param   pszInput        The input.
+ * @param   cchInput        The input length.
+ */
+static enum KOCDEPSTATE
+kOCDepConsumer(PKOCDEP pDepState, const char *pszInput, size_t cchInput)
+{
+    enum KOCDEPSTATE enmState = pDepState->enmState;
+    const char *psz;
+
+    while (cchInput > 0)
+    {
+        switch (enmState)
+        {
+            case kOCDepState_NeedNewLine:
+                psz = (const char *)memchr(pszInput, '\n', cchInput);
+                if (!psz)
+                    return enmState;
+                psz++;
+                cchInput -= psz - pszInput;
+                pszInput = psz;
+
+            case kOCDepState_NeedHash:
+                while (cchInput > 0 && MY_IS_BLANK(*pszInput))
+                    cchInput--, pszInput++;
+                if (!cchInput)
+                    return pDepState->enmState = kOCDepState_NeedHash;
+
+                if (*pszInput != '#')
+                    break;
+                pszInput++;
+                cchInput--;
+                enmState = kOCDepState_NeedLine_l;
+
+            case kOCDepState_NeedLine_l:
+            case kOCDepState_NeedLine_l_HaveSpace:
+                while (cchInput > 0 && MY_IS_BLANK(*pszInput))
+                {
+                    enmState = kOCDepState_NeedLine_l_HaveSpace;
+                    cchInput--, pszInput++;
+                }
+                if (!cchInput)
+                    return pDepState->enmState = enmState;
+
+                if (*pszInput != 'l')
+                {
+                    /* # <digit> "<file>" */
+                    if (enmState != kOCDepState_NeedLine_l_HaveSpace || !isdigit(*pszInput))
+                        break;
+                    pszInput++;
+                    cchInput--;
+                    enmState = kOCDepState_NeedMoreDigits;
+                    continue;
+                }
+                pszInput++;
+                if (!--cchInput)
+                    return pDepState->enmState = kOCDepState_NeedLine_i;
+
+            case kOCDepState_NeedLine_i:
+                if (*pszInput != 'i')
+                    break;
+                pszInput++;
+                if (!--cchInput)
+                    return pDepState->enmState = kOCDepState_NeedLine_n;
+
+            case kOCDepState_NeedLine_n:
+                if (*pszInput != 'n')
+                    break;
+                pszInput++;
+                if (!--cchInput)
+                    return pDepState->enmState = kOCDepState_NeedLine_e;
+
+            case kOCDepState_NeedLine_e:
+                if (*pszInput != 'e')
+                    break;
+                pszInput++;
+                if (!--cchInput)
+                    return pDepState->enmState = kOCDepState_NeedSpaceBeforeDigit;
+
+            case kOCDepState_NeedSpaceBeforeDigit:
+                if (!MY_IS_BLANK(*pszInput))
+                    break;
+                pszInput++;
+                cchInput--;
+
+            case kOCDepState_NeedFirstDigit:
+                while (cchInput > 0 && MY_IS_BLANK(*pszInput))
+                    cchInput--, pszInput++;
+                if (!cchInput)
+                    return pDepState->enmState = kOCDepState_NeedFirstDigit;
+
+                if (!isdigit(*pszInput))
+                    break;
+                pszInput++;
+                cchInput--;
+
+            case kOCDepState_NeedMoreDigits:
+                while (cchInput > 0 && isdigit(*pszInput))
+                    cchInput--, pszInput++;
+                if (!cchInput)
+                    return pDepState->enmState = kOCDepState_NeedMoreDigits;
+
+            case kOCDepState_NeedQuote:
+                while (cchInput > 0 && MY_IS_BLANK(*pszInput))
+                    cchInput--, pszInput++;
+                if (!cchInput)
+                    return pDepState->enmState = kOCDepState_NeedQuote;
+
+                if (*pszInput != '"')
+                    break;
+                pszInput++;
+                cchInput--;
+
+            case kOCDepState_NeedEndQuote:
+            {
+                uint32_t off = pDepState->offFilename;
+                for (;;)
+                {
+                    char ch;
+
+                    if (!cchInput)
+                    {
+                        pDepState->offFilename = off;
+                        return pDepState->enmState = kOCDepState_NeedEndQuote;
+                    }
+
+                    if (off + 1 >= pDepState->cbFilenameAlloced)
+                    {
+                        if (!pDepState->cbFilenameAlloced)
+                            pDepState->cbFilenameAlloced = 32;
+                        else
+                            pDepState->cbFilenameAlloced *= 2;
+                        pDepState->pszFilename = (char *)xrealloc(pDepState->pszFilename, pDepState->cbFilenameAlloced);
+                    }
+                    pDepState->pszFilename[off] = ch = *pszInput++;
+                    cchInput--;
+
+                    if (   ch == '"'
+                        && (   off == 0
+                            || pDepState->pszFilename[off - 1] != '\\'
+                            || !kOCDepIsEscaped(pDepState->pszFilename, off)))
+                    {
+                        /* Done, unescape and add the file. */
+                        size_t cchFilename;
+
+                        pDepState->pszFilename[off] = '\0';
+                        cchFilename = kOCDepUnescape(pDepState->pszFilename);
+
+                        if (   !pDepState->pCurDep
+                            || cchFilename != pDepState->pCurDep->cchFilename
+                            || strcmp(pDepState->pszFilename, pDepState->pCurDep->szFilename))
+                            pDepState->pCurDep = depAdd(pDepState->pszFilename, cchFilename);
+                        pDepState->offFilename = 0;
+                        break;
+                    }
+
+                    off++;
+                }
+            }
+        }
+
+        /* next newline */
+        enmState = kOCDepState_NeedNewLine;
+    }
+
+    return pDepState->enmState = enmState;
+}
+
+
+/**
+ * Writes the dependencies to the specified file.
+ *
+ * @param   pDepState       The dependency collector state.
+ * @param   pszFilename     The name of the dependency file.
+ * @param   pszObjFile      The object file name, relative to @a pszObjDir.
+ * @param   pszObjDir       The object file directory.
+ * @param   fFixCase        Whether to fix the case of dependency files.
+ * @param   fQuiet          Whether to be quiet about the dependencies.
+ * @param   fGenStubs       Whether to generate stubs.
+ */
+static void kOCDepWriteToFile(PKOCDEP pDepState, const char *pszFilename, const char *pszObjFile, const char *pszObjDir,
+                              int fFixCase, int fQuiet, int fGenStubs)
+{
+    char *pszObjFileAbs;
+    FILE *pFile = fopen(pszFilename, "w");
+    if (!pFile)
+        FatalMsg("Failed to open dependency file '%s': %s\n", pszFilename, strerror(errno));
+
+    depOptimize(fFixCase, fQuiet);
+
+    pszObjFileAbs = MakePathFromDirAndFile(pszObjFile, pszObjDir);
+    fprintf(pFile, "%s:", pszObjFileAbs);
+    free(pszObjFileAbs);
+    depPrint(pFile);
+    if (fGenStubs)
+        depPrintStubs(pFile);
+
+    if (fclose(pFile) != 0)
+        FatalMsg("Failed to write dependency file '%s': %s\n", pszFilename, strerror(errno));
+}
+
 
 
 
 /** A checksum list entry.
- * We keep a list checksums (of precompiler output) that matches, The planned
- * matching algorithm doesn't require the precompiler output to be indentical,
- * only to produce the same object files.
+ * We keep a list checksums (of preprocessor output) that matches.
+ *
+ * The matching algorithm doesn't require the preprocessor output to be
+ * indentical, only to produce the same object files.
  */
 typedef struct KOCSUM
@@ -783,6 +1111,5 @@
 
 /**
- * Temporary context record used when calculating
- * the checksum of some data.
+ * Temporary context record used when calculating the checksum of some data.
  */
 typedef struct KOCSUMCTX
@@ -1080,13 +1407,24 @@
     /** Set if the object needs to be (re)compiled. */
     unsigned fNeedCompiling;
-    /** Whether the precompiler runs in piped mode. If clear it's file
+    /** Whether the preprocessor runs in piped mode. If clear it's file
      * mode (it could be redirected stdout, but that's essentially the
      * same from our point of view). */
     unsigned fPipedPreComp;
-    /** Whether the compiler runs in piped mode (precompiler output on stdin). */
+    /** Whether the compiler runs in piped mode (preprocessor output on stdin). */
     unsigned fPipedCompile;
-    /** The name of the pipe that we're feeding the precompiled output to the
+    /** The name of the pipe that we're feeding the preprocessed output to the
      *  compiler via.  This is a Windows thing. */
     char *pszNmPipeCompile;
+    /** Name of the dependency file (generated from #line statements in the
+     * preprocessor output). */
+    char *pszMakeDepFilename;
+    /** Whether to fix the case of the make depedencies. */
+    int fMakeDepFixCase;
+    /** Whether to do the make dependencies quietly. */
+    int fMakeDepQuiet;
+    /** Whether to generate stubs for headers files. */
+    int fMakeDepGenStubs;
+    /** The dependency collector state.  */
+    KOCDEP DepState;
     /** Cache entry key that's used for some quick digest validation. */
     uint32_t uKey;
@@ -1095,11 +1433,11 @@
     struct KOCENTRYDATA
     {
-        /** The name of file containing the precompiler output. */
+        /** The name of file containing the preprocessor output. */
         char *pszCppName;
-        /** Pointer to the precompiler output. */
+        /** Pointer to the preprocessor output. */
         char *pszCppMapping;
-        /** The size of the precompiler output. 0 if not determined. */
+        /** The size of the preprocessor output. 0 if not determined. */
         size_t cbCpp;
-        /** The precompiler output checksums that will produce the cached object. */
+        /** The preprocessor output checksums that will produce the cached object. */
         KOCSUM SumHead;
         /** The number of milliseconds spent precompiling. */
@@ -1117,4 +1455,5 @@
         uint32_t cMsCompile;
         /** @todo need a list of additional output files for MSC. */
+        /** @todo need compiler output (warnings). */
 
         /** The target os/arch identifier. */
@@ -1148,4 +1487,6 @@
     pEntry = xmallocz(sizeof(*pEntry));
 
+    kOCDepInit(&pEntry->DepState);
+
     kOCSumInit(&pEntry->New.SumHead);
     kOCSumInit(&pEntry->Old.SumHead);
@@ -1181,4 +1522,7 @@
     free(pEntry->pszAbsPath);
     free(pEntry->pszNmPipeCompile);
+    free(pEntry->pszMakeDepFilename);
+
+    kOCDepDelete(&pEntry->DepState);
 
     kOCSumDeleteChain(&pEntry->New.SumHead);
@@ -1635,9 +1979,9 @@
 
 /**
- * Sets the precompiler output filename.
- * We don't generally care if this matches the old name or not.
+ * Sets the preprocessor output filename. We don't generally care if this
+ * matches the old name or not.
  *
  * @param   pEntry      The cache entry.
- * @param   pszCppName  The precompiler output filename.
+ * @param   pszCppName  The preprocessor output filename.
  */
 static void kOCEntrySetCppName(PKOCENTRY pEntry, const char *pszCppName)
@@ -1649,8 +1993,8 @@
 
 /**
- * Sets the piped mode of the precompiler and compiler.
+ * Sets the piped mode of the preprocessor and compiler.
  *
  * @param   pEntry                  The cache entry.
- * @param   fRedirPreCompStdOut     Whether the precompiler is in piped mode.
+ * @param   fRedirPreCompStdOut     Whether the preprocessor is in piped mode.
  * @param   fRedirCompileStdIn      Whether the compiler is in piped mode.
  * @param   pszNmPipeCompile        The name of the named pipe to use to feed
@@ -1663,4 +2007,23 @@
     pEntry->fPipedCompile = fRedirCompileStdIn || pszNmPipeCompile;
     pEntry->pszNmPipeCompile = xstrdup(pszNmPipeCompile);
+}
+
+
+/**
+ * Sets the dependency file.
+ *
+ * @param   pEntry                  The cache entry.
+ * @param   pszMakeDepFilename      The dependency filename.
+ * @param   fMakeDepFixCase         Whether to fix the case of dependency files.
+ * @param   fMakeDepQuiet           Whether to be quiet about the dependencies.
+ * @param   fMakeDepGenStubs        Whether to generate stubs.
+ */
+static void kOCEntrySetDepFilename(PKOCENTRY pEntry, const char *pszMakeDepFilename,
+                                   int fMakeDepFixCase, int fMakeDepQuiet, int fMakeDepGenStubs)
+{
+    pEntry->pszMakeDepFilename = xstrdup(pszMakeDepFilename);
+    pEntry->fMakeDepFixCase = fMakeDepFixCase;
+    pEntry->fMakeDepQuiet = fMakeDepQuiet;
+    pEntry->fMakeDepGenStubs = fMakeDepGenStubs;
 }
 
@@ -1825,5 +2188,5 @@
 # endif
     if (pid == -1)
-        FatalDie("precompile - _spawnvp failed: %s\n", strerror(errno));
+        FatalDie("preprocess - _spawnvp failed: %s\n", strerror(errno));
 
 #else
@@ -1832,8 +2195,8 @@
     {
         execvp(papszArgv[0], (char **)papszArgv);
-        FatalDie("precompile - execvp failed: %s\n", strerror(errno));
+        FatalDie("preprocess - execvp failed: %s\n", strerror(errno));
     }
     if (pid == -1)
-        FatalDie("precompile - fork() failed: %s\n", strerror(errno));
+        FatalDie("preprocess - fork() failed: %s\n", strerror(errno));
 #endif
 
@@ -1903,11 +2266,11 @@
  *
  * @param   pEntry          The cache entry.
- * @param   pFDs            Where to store the two file descriptors.
+ * @param   paFDs           Where to store the two file descriptors.
  * @param   pszMsg          The operation message for info/error messages.
  * @param   pszPipeName     The pipe name if it is supposed to be named. (Windows only.)
  */
-static void kOCEntryCreatePipe(PKOCENTRY pEntry, int *pFDs, const char *pszPipeName, const char *pszMsg)
-{
-    pFDs[0] = pFDs[1] = -1;
+static void kOCEntryCreatePipe(PKOCENTRY pEntry, int *paFDs, const char *pszPipeName, const char *pszMsg)
+{
+    paFDs[0] = paFDs[1] = -1;
 #if defined(__WIN__)
     if (pszPipeName)
@@ -1925,16 +2288,17 @@
             FatalDie("%s - CreateNamedPipe(%s) failed: %d\n", pszMsg, pszPipeName, GetLastError());
 
-        pFDs[1 /* write */] = _open_osfhandle((intptr_t)hPipe, _O_WRONLY | _O_TEXT | _O_NOINHERIT);
-        if (pFDs[1 /* write */] == -1)
+        paFDs[1 /* write */] = _open_osfhandle((intptr_t)hPipe, _O_WRONLY | _O_TEXT | _O_NOINHERIT);
+        if (paFDs[1 /* write */] == -1)
             FatalDie("%s - _open_osfhandle failed: %d\n", pszMsg, strerror(errno));
     }
-    else if (_pipe(pFDs, 0, _O_NOINHERIT | _O_BINARY) < 0)
+    else if (   _pipe(paFDs, 256*1024, _O_NOINHERIT | _O_BINARY) < 0
+             && _pipe(paFDs,        0, _O_NOINHERIT | _O_BINARY) < 0)
 #else
-    if (pipe(pFDs) < 0)
+    if (pipe(paFDs) < 0)
 #endif
         FatalDie("%s - pipe failed: %s\n", pszMsg, strerror(errno));
 #if !defined(__WIN__)
-    fcntl(pFDs[0], F_SETFD, FD_CLOEXEC);
-    fcntl(pFDs[1], F_SETFD, FD_CLOEXEC);
+    fcntl(paFDs[0], F_SETFD, FD_CLOEXEC);
+    fcntl(paFDs[1], F_SETFD, FD_CLOEXEC);
 #endif
 
@@ -2041,5 +2405,5 @@
 
 /**
- * Reads the output from the precompiler.
+ * Reads the output from the preprocessor.
  *
  * @param   pEntry      The cache entry. New.cbCpp and New.pszCppMapping will be updated.
@@ -2060,5 +2424,5 @@
     }
 
-    InfoMsg(3, "precompiled file is %lu bytes long\n", (unsigned long)pWhich->cbCpp);
+    InfoMsg(3, "preprocessed file is %lu bytes long\n", (unsigned long)pWhich->cbCpp);
     return 0;
 }
@@ -2066,6 +2430,6 @@
 
 /**
- * Worker for kOCEntryPreCompile and calculates the checksum of
- * the precompiler output.
+ * Worker for kOCEntryPreProcess and calculates the checksum of
+ * the preprocessor output.
  *
  * @param   pEntry      The cache entry. NewSum will be updated.
@@ -2082,11 +2446,11 @@
 
 /**
- * This consumes the precompiler output and checksums it.
+ * This consumes the preprocessor output and checksums it.
  *
  * @param   pEntry  The cache entry.
- * @param   fdIn    The precompiler output pipe.
+ * @param   fdIn    The preprocessor output pipe.
  * @param   fdOut   The compiler input pipe, -1 if no compiler.
  */
-static void kOCEntryPreCompileConsumer(PKOCENTRY pEntry, int fdIn)
+static void kOCEntryPreProcessConsumer(PKOCENTRY pEntry, int fdIn)
 {
     KOCSUMCTX Ctx;
@@ -2111,5 +2475,5 @@
             if (errno == EINTR)
                 continue;
-            FatalDie("precompile - read(%d,,%ld) failed: %s\n",
+            FatalDie("PreProcess - read(%d,,%ld) failed: %s\n",
                      fdIn, (long)cbLeft, strerror(errno));
         }
@@ -2120,4 +2484,6 @@
         psz[cbRead] = '\0';
         kOCSumUpdate(&pEntry->New.SumHead, &Ctx, psz, cbRead);
+        if (pEntry->pszMakeDepFilename)
+            kOCDepConsumer(&pEntry->DepState, psz, cbRead);
 
         /*
@@ -2146,22 +2512,23 @@
 
 /**
- * Run the precompiler and calculate the checksum of the output.
+ * Run the preprocessor and calculate the checksum of the output.
  *
  * @param   pEntry              The cache entry.
- * @param   papszArgvPreComp    The argument vector for executing precompiler. The cArgvPreComp'th argument must be NULL.
+ * @param   papszArgvPreComp    The argument vector for executing preprocessor.
+ *                              The cArgvPreComp'th argument must be NULL.
  * @param   cArgvPreComp        The number of arguments.
  */
-static void kOCEntryPreCompile(PKOCENTRY pEntry, const char * const *papszArgvPreComp, unsigned cArgvPreComp)
-{
-    /*
-     * If we're executing the precompiler in piped mode, it's relatively simple.
+static void kOCEntryPreProcess(PKOCENTRY pEntry, const char * const *papszArgvPreComp, unsigned cArgvPreComp)
+{
+    /*
+     * If we're executing the preprocessor in piped mode, it's relatively simple.
      */
     if (pEntry->fPipedPreComp)
-        kOCEntrySpawnProducer(pEntry, papszArgvPreComp, cArgvPreComp, "precompile",
-                              kOCEntryPreCompileConsumer);
+        kOCEntrySpawnProducer(pEntry, papszArgvPreComp, cArgvPreComp, "preprocess",
+                              kOCEntryPreProcessConsumer);
     else
     {
         /*
-         * Rename the old precompiled output to '-old' so the precompiler won't
+         * Rename the old preprocessed output to '-old' so the preprocessor won't
          * overwrite it when we execute it.
          */
@@ -2187,8 +2554,14 @@
          */
         InfoMsg(3, "precompiling -> '%s'...\n", pEntry->New.pszCppName);
-        kOCEntrySpawn(pEntry, &pEntry->New.cMsCpp, papszArgvPreComp, cArgvPreComp, "precompile", NULL);
+        kOCEntrySpawn(pEntry, &pEntry->New.cMsCpp, papszArgvPreComp, cArgvPreComp, "preprocess", NULL);
         kOCEntryReadCppOutput(pEntry, &pEntry->New, 0 /* fatal */);
         kOCEntryCalcChecksum(pEntry);
-    }
+        if (pEntry->pszMakeDepFilename)
+            kOCDepConsumer(&pEntry->DepState, pEntry->New.pszCppMapping, pEntry->New.cbCpp);
+    }
+
+    if (pEntry->pszMakeDepFilename)
+        kOCDepWriteToFile(&pEntry->DepState, pEntry->pszMakeDepFilename, pEntry->New.pszObjName, pEntry->pszDir,
+                          pEntry->fMakeDepFixCase, pEntry->fMakeDepQuiet, pEntry->fMakeDepGenStubs);
 }
 
@@ -2196,5 +2569,5 @@
 /**
  * Worker function for kOCEntryTeeConsumer and kOCEntryCompileIt that
- * writes the precompiler output to disk.
+ * writes the preprocessor output to disk.
  *
  * @param   pEntry      The cache entry.
@@ -2257,6 +2630,6 @@
 
 /**
- * kOCEntrySpawnConsumer callback that passes the precompiler
- * output to the compiler and writes it to the disk (latter only when necesary).
+ * kOCEntrySpawnConsumer callback that passes the preprocessor output to the
+ * compiler and writes it to the disk (latter only when necesary).
  *
  * @param   pEntry      The cache entry.
@@ -2346,9 +2719,9 @@
  * kOCEntrySpawnTee callback that works sort of like 'tee'.
  *
- * It will calculate the precompiled output checksum and
+ * It will calculate the preprocessed output checksum and
  * write it to disk while the compiler is busy compiling it.
  *
  * @param   pEntry  The cache entry.
- * @param   fdIn    The input handle (connected to the precompiler).
+ * @param   fdIn    The input handle (connected to the preprocessor).
  * @param   fdOut   The output handle (connected to the compiler).
  */
@@ -2367,5 +2740,5 @@
     cbLeft = cbAlloc;
     pEntry->New.pszCppMapping = psz = xmalloc(cbAlloc);
-    InfoMsg(3, "precompiler|compile - starting passhtru...\n");
+    InfoMsg(3, "preprocessor|compile - starting passhtru...\n");
     for (;;)
     {
@@ -2380,8 +2753,8 @@
             if (errno == EINTR)
                 continue;
-            FatalDie("precompile|compile - read(%d,,%ld) failed: %s\n",
+            FatalDie("preprocess|compile - read(%d,,%ld) failed: %s\n",
                      fdIn, (long)cbLeft, strerror(errno));
         }
-        InfoMsg(3, "precompiler|compile - read %d\n", cbRead);
+        InfoMsg(3, "preprocessor|compile - read %d\n", cbRead);
 
         /*
@@ -2390,8 +2763,11 @@
         psz[cbRead] = '\0';
         kOCSumUpdate(&pEntry->New.SumHead, &Ctx, psz, cbRead);
+        if (pEntry->pszMakeDepFilename)
+            kOCDepConsumer(&pEntry->DepState, psz, cbRead);
+
 #ifdef __WIN__
         if (   !fConnectedToCompiler
             && !(fConnectedToCompiler = ConnectNamedPipe((HANDLE)_get_osfhandle(fdOut), NULL)))
-            FatalDie("precompile|compile - ConnectNamedPipe failed: %d\n", GetLastError());
+            FatalDie("preprocess|compile - ConnectNamedPipe failed: %d\n", GetLastError());
 #endif
         do
@@ -2402,5 +2778,5 @@
                 if (errno == EINTR)
                     continue;
-                FatalDie("precompile|compile - write(%d,,%ld) failed: %s\n", fdOut, cbRead, strerror(errno));
+                FatalDie("preprocess|compile - write(%d,,%ld) failed: %s\n", fdOut, cbRead, strerror(errno));
             }
             psz += cbWritten;
@@ -2421,5 +2797,5 @@
         }
     }
-    InfoMsg(3, "precompiler|compile - done passhtru\n");
+    InfoMsg(3, "preprocessor|compile - done passhtru\n");
 
     close(fdIn);
@@ -2430,5 +2806,5 @@
 
     /*
-     * Write the precompiler output to disk and free the memory it
+     * Write the preprocessor output to disk and free the memory it
      * occupies while the compiler is busy compiling.
      */
@@ -2441,8 +2817,9 @@
  *
  * @param   pEntry              The cache entry.
- * @param   papszArgvPreComp    The argument vector for executing precompiler. The cArgvPreComp'th argument must be NULL.
+ * @param   papszArgvPreComp    The argument vector for executing preprocessor.
+ *                              The cArgvPreComp'th argument must be NULL.
  * @param   cArgvPreComp        The number of arguments.
  */
-static void kOCEntryPreCompileAndCompile(PKOCENTRY pEntry, const char * const *papszArgvPreComp, unsigned cArgvPreComp)
+static void kOCEntryPreProcessAndCompile(PKOCENTRY pEntry, const char * const *papszArgvPreComp, unsigned cArgvPreComp)
 {
     if (    pEntry->fPipedCompile
@@ -2462,13 +2839,16 @@
 
         /*
-         * Do the actual compile and write the precompiler output to disk.
+         * Do the actual compile and write the preprocessor output to disk.
          */
         kOCEntrySpawnTee(pEntry, papszArgvPreComp, cArgvPreComp,
                          (const char * const *)pEntry->New.papszArgvCompile, pEntry->New.cArgvCompile,
-                         "precompile|compile", kOCEntryTeeConsumer);
+                         "preprocess|compile", kOCEntryTeeConsumer);
+        if (pEntry->pszMakeDepFilename)
+            kOCDepWriteToFile(&pEntry->DepState, pEntry->pszMakeDepFilename,  pEntry->New.pszObjName, pEntry->pszDir,
+                              pEntry->fMakeDepFixCase, pEntry->fMakeDepQuiet, pEntry->fMakeDepGenStubs);
     }
     else
     {
-        kOCEntryPreCompile(pEntry, papszArgvPreComp, cArgvPreComp);
+        kOCEntryPreProcess(pEntry, papszArgvPreComp, cArgvPreComp);
         kOCEntryCompileIt(pEntry);
     }
@@ -2563,5 +2943,5 @@
 /**
  * Worker for kOCEntryCompareOldAndNewOutput() that compares the
- * precompiled output using a fast but not very good method.
+ * preprocessed output using a fast but not very good method.
  *
  * @returns 1 if matching, 0 if not matching.
@@ -2613,5 +2993,5 @@
              * possible that we will omit this header from the dependencies
              * when using VCC. This might not be a problem, since it seems
-             * we'll have to use the precompiler output to generate the deps
+             * we'll have to use the preprocessor output to generate the deps
              * anyway.
              */
@@ -2779,5 +3159,5 @@
 /**
  * Worker for kOCEntryCompileIfNeeded that compares the
- * precompiled output.
+ * preprocessed output.
  *
  * @returns 1 if matching, 0 if not matching.
@@ -2810,5 +3190,5 @@
 
     /*
-     * Check if the precompiler output differ in any significant way?
+     * Check if the preprocessor output differ in any significant way?
      */
     if (!kOCSumHasEqualInChain(&pEntry->Old.SumHead, &pEntry->New.SumHead))
@@ -2957,5 +3337,5 @@
     /** The checksum of the compile argument vector. */
     KOCSUM SumCompArgv;
-    /** The list of precompiler output checksums that's . */
+    /** The list of preprocessor output checksums that's . */
     KOCSUM SumHead;
 } KOCDIGEST;
@@ -3832,5 +4212,5 @@
             "            <-t|--target <target-name>>\n"
             "            [-r|--redir-stdout] [-p|--passthru] [--named-pipe-compile <pipename>]\n"
-            "            --kObjCache-cpp <filename> <precompiler + args>\n"
+            "            --kObjCache-cpp <filename> <preprocessor + args>\n"
             "            --kObjCache-cc <object> <compiler + args>\n"
             "            [--kObjCache-both [args]]\n"
@@ -3871,4 +4251,9 @@
     const char *pszNmPipeCompile = NULL;
 
+    const char *pszMakeDepFilename = NULL;
+    int fMakeDepFixCase = 0;
+    int fMakeDepGenStubs = 0;
+    int fMakeDepQuiet = 0;
+
     const char *pszTarget = NULL;
 
@@ -3911,5 +4296,5 @@
             {
                 if (++i >= argc)
-                    return SyntaxError("--kObjCache-cc requires an precompiler output filename!\n");
+                    return SyntaxError("--kObjCache-cc requires an preprocessor output filename!\n");
                 pszObjName = argv[i];
             }
@@ -3975,4 +4360,16 @@
             fRedirCompileStdIn = 0;
         }
+        else if (!strcmp(argv[i], "-m") || !strcmp(argv[i], "--make-dep-file"))
+        {
+            if (i + 1 >= argc)
+                return SyntaxError("%s requires a filename!\n", argv[i]);
+            pszMakeDepFilename = argv[++i];
+        }
+        else if (!strcmp(argv[i], "--make-dep-fix-case"))
+            fMakeDepFixCase = 1;
+        else if (!strcmp(argv[i], "--make-dep-gen-stubs"))
+            fMakeDepGenStubs = 1;
+        else if (!strcmp(argv[i], "--make-dep-quiet"))
+            fMakeDepQuiet = 1;
         else if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--passthru"))
             fRedirPreCompStdOut = fRedirCompileStdIn = 1;
@@ -3992,5 +4389,5 @@
         {
             printf("kObjCache - kBuild version %d.%d.%d ($Revision$)\n"
-                   "Copyright (c) 2007-2011 knut st. osmundsen\n",
+                   "Copyright (c) 2007-2012 knut st. osmundsen\n",
                    KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH);
             return 0;
@@ -4006,5 +4403,5 @@
         return SyntaxError("No compiler arguments (--kObjCache-cc)!\n");
     if (!cArgvPreComp)
-        return SyntaxError("No precompiler arguments (--kObjCache-cc)!\n");
+        return SyntaxError("No preprocessor arguments (--kObjCache-cc)!\n");
 
     /*
@@ -4048,4 +4445,5 @@
     kOCEntrySetCppName(pEntry, pszPreCompName);
     kOCEntrySetPipedMode(pEntry, fRedirPreCompStdOut, fRedirCompileStdIn, pszNmPipeCompile);
+    kOCEntrySetDepFilename(pEntry, pszMakeDepFilename, fMakeDepFixCase, fMakeDepQuiet, fMakeDepGenStubs);
 
     /*
@@ -4062,5 +4460,5 @@
         kObjCacheUnlock(pCache);
         InfoMsg(1, "doing full compile\n");
-        kOCEntryPreCompileAndCompile(pEntry, papszArgvPreComp, cArgvPreComp);
+        kOCEntryPreProcessAndCompile(pEntry, papszArgvPreComp, cArgvPreComp);
         kObjCacheLock(pCache);
     }
@@ -4068,8 +4466,8 @@
     {
         /*
-         * Do the precompile (don't need to lock the cache file for this).
+         * Do the preprocess (don't need to lock the cache file for this).
          */
         kObjCacheUnlock(pCache);
-        kOCEntryPreCompile(pEntry, papszArgvPreComp, cArgvPreComp);
+        kOCEntryPreProcess(pEntry, papszArgvPreComp, cArgvPreComp);
 
         /*
