summaryrefslogtreecommitdiff
path: root/src/kObjCache/kObjCache.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kObjCache/kObjCache.c')
-rw-r--r--src/kObjCache/kObjCache.c1503
1 files changed, 1304 insertions, 199 deletions
diff --git a/src/kObjCache/kObjCache.c b/src/kObjCache/kObjCache.c
index 0713b1a..d6badb7 100644
--- a/src/kObjCache/kObjCache.c
+++ b/src/kObjCache/kObjCache.c
@@ -1,10 +1,10 @@
-/* $Id: kObjCache.c 2568 2012-03-18 17:59:32Z bird $ */
+/* $Id: kObjCache.c 2627 2012-08-09 14:12:12Z bird $ */
/** @file
* kObjCache - Object Cache.
*/
/*
- * 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.
*
@@ -29,6 +29,7 @@
#if 0
# define ELECTRIC_HEAP
# include "../kmk/electric.h"
+# include "../kmk/electric.c"
#endif
#include <string.h>
#include <stdlib.h>
@@ -79,6 +80,7 @@
#include "crc32.h"
#include "md5.h"
+#include "kDep.h"
/*******************************************************************************
@@ -109,6 +111,12 @@
# define STDERR_FILENO 2
#endif
+#define MY_IS_BLANK(a_ch) ((a_ch) == ' ' || (a_ch) == '\t')
+
+#define KOC_BUF_MIN KOC_BUF_ALIGNMENT
+#define KOC_BUF_INCR KOC_BUF_ALIGNMENT
+#define KOC_BUF_ALIGNMENT (4U*1024U*1024U)
+
/*******************************************************************************
* Global Variables *
@@ -121,6 +129,11 @@ static char g_szErrorPrefix[128];
/** Read buffer shared by the cache components. */
static char g_szLine[KOBJCACHE_MAX_LINE_LEN + 16];
+/** How many times we've moved memory around. */
+static size_t g_cMemMoves = 0;
+/** How much memory we've moved. */
+static size_t g_cbMemMoved = 0;
+
/*******************************************************************************
* Internal Functions *
@@ -128,9 +141,9 @@ static char g_szLine[KOBJCACHE_MAX_LINE_LEN + 16];
static char *MakePathFromDirAndFile(const char *pszName, const char *pszDir);
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);
@@ -756,13 +769,992 @@ static void AppendArgs(int *pcArgs, char ***ppapszArgs, const char *pszCmdLine,
}
+/**
+ * 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;
+}
+
+
+static void kOCDepEnter(PKOCDEP pDepState, const char *pszUnescFilename, size_t cchFilename)
+{
+ if (cchFilename + 1 >= pDepState->cbFilenameAlloced)
+ {
+ pDepState->cbFilenameAlloced = (cchFilename + 1 + 15) & ~15;
+ pDepState->pszFilename = (char *)xrealloc(pDepState->pszFilename, pDepState->cbFilenameAlloced);
+ }
+
+ memcpy(pDepState->pszFilename, pszUnescFilename, cchFilename);
+ pDepState->pszFilename[cchFilename] = '\0';
+ cchFilename = kOCDepUnescape(pDepState->pszFilename);
+
+ if ( !pDepState->pCurDep
+ || cchFilename != pDepState->pCurDep->cchFilename
+ || strcmp(pDepState->pszFilename, pDepState->pCurDep->szFilename))
+ pDepState->pCurDep = depAdd(pDepState->pszFilename, cchFilename);
+}
+
+
+/**
+ * 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;
+ char *psz;
+ FILE *pFile = fopen(pszFilename, "w");
+ if (!pFile)
+ FatalMsg("Failed to open dependency file '%s': %s\n", pszFilename, strerror(errno));
+
+ depOptimize(fFixCase, fQuiet);
+
+ /* Make object file name with unix slashes. */
+ pszObjFileAbs = MakePathFromDirAndFile(pszObjFile, pszObjDir);
+ psz = pszObjFileAbs;
+ while ((psz = strchr(psz, '\\')) != NULL)
+ *psz++ = '/';
+
+ 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));
+}
+
+
+/**
+ * Preprocessor output reader state.
+ */
+typedef struct KOCCPPRD
+{
+ /** Pointer to the preprocessor output. */
+ char *pszBuf;
+ /** Allocated buffer size. */
+ size_t cbBufAlloc;
+ /** Amount preprocessor output that we've completed optimizations for. */
+ size_t cchDstOptimized;
+ /** Offset to the start of the unoptimized source. */
+ size_t offSrcUnoptimized;
+ /** The offset of the next bits to process. */
+ size_t offSrcCur;
+ /** The offset where to put more raw preprocessor output. */
+ size_t offSrcRead;
+ /** The line number corresponding to offOptimized. */
+ uint32_t uOptLineNo;
+ /** The current line number. */
+ uint32_t uCurLineNo;
+ /** Set if we're done, clear if we're expecting more preprocessor output. */
+ int fDone;
+ /** The saved character at cchOptimized. */
+ char chSaved;
+ /** Whether the optimizations are enabled. */
+ int fOptimize;
+
+ /** Buffer holding the current file name (unescaped). */
+ char *pszFileNmBuf;
+ /** The size of the file name buffer. */
+ size_t cbFileNmBuf;
+ /** The length of the current file string. */
+ size_t cchCurFileNm;
+
+ /** Line directive / new line sequence buffer. */
+ char *pszLineBuf;
+ /** The size of the buffer pointed to by pszLineBuf. */
+ size_t cbLineBuf;
+
+ /** Set if we should work the dependency generator as well. */
+ PKOCDEP pDepState;
+} KOCCPPRD;
+/** Pointer to a preprocessor reader state. */
+typedef KOCCPPRD *PKOCCPPRD;
+
+
+/**
+ * Allocate the initial C preprocessor output buffer.
+ *
+ * @param pCppRd The C preprocessor reader instance.
+ * @param cbOldCpp The size of the output the last time. This is 0 if
+ * there was not previous run.
+ * @param fOptimize Whether optimizations are enabled.
+ * @param pDepState Pointer to the dependency generator. Must only be set
+ * if @a fOptimize is also set.
+ */
+static void kOCCppRdInit(PKOCCPPRD pCppRd, size_t cbOldCpp, int fOptimize, PKOCDEP pDepState)
+{
+ assert(!pDepState || fOptimize);
+
+ pCppRd->cbBufAlloc = cbOldCpp ? (cbOldCpp + KOC_BUF_INCR) & ~(KOC_BUF_ALIGNMENT - 1) : KOC_BUF_MIN;
+ pCppRd->pszBuf = xmalloc(pCppRd->cbBufAlloc);
+ pCppRd->cchCurFileNm = 0;
+ pCppRd->cchDstOptimized = 0;
+ pCppRd->offSrcUnoptimized = 0;
+ pCppRd->offSrcCur = 0;
+ pCppRd->offSrcRead = 0;
+ pCppRd->uOptLineNo = 1;
+ pCppRd->uCurLineNo = 1;
+ pCppRd->fDone = 0;
+ pCppRd->chSaved = 0;
+ pCppRd->fOptimize = fOptimize;
+
+ pCppRd->pszFileNmBuf = NULL;
+ pCppRd->cbFileNmBuf = 0;
+ pCppRd->cchCurFileNm = 0;
+
+ pCppRd->pszLineBuf = NULL;
+ pCppRd->cbLineBuf = 0;
+
+ pCppRd->pDepState = pDepState;
+}
+
+
+static void kOCCppRdDelete(PKOCCPPRD pCppRd)
+{
+ free(pCppRd->pszBuf);
+ pCppRd->pszBuf = NULL;
+
+ free(pCppRd->pszFileNmBuf);
+ pCppRd->pszFileNmBuf = NULL;
+
+ free(pCppRd->pszLineBuf);
+ pCppRd->pszLineBuf = NULL;
+}
+
+
+/**
+ * Allocate more buffer space for the C preprocessor output.
+ *
+ * @param pCppRd The C preprocessor reader instance.
+ */
+static size_t kOCCppRdGrowBuffer(PKOCCPPRD pCppRd)
+{
+ pCppRd->cbBufAlloc += KOC_BUF_INCR;
+ pCppRd->pszBuf = xrealloc(pCppRd->pszBuf, pCppRd->cbBufAlloc);
+
+ return pCppRd->cbBufAlloc - pCppRd->offSrcRead;
+}
+
+
+static size_t kOCCppRdOptInsert(PKOCCPPRD pCppRd, size_t cchSrcReplaced, const char *pchInsert, size_t cchInsert)
+{
+ size_t offDelta = 0;
+ size_t cchAvail;
+
+ pCppRd->offSrcUnoptimized += cchSrcReplaced;
+ assert(pCppRd->offSrcUnoptimized <= pCppRd->offSrcCur);
+ cchAvail = pCppRd->offSrcUnoptimized - pCppRd->cchDstOptimized;
+ if (cchAvail < cchInsert)
+ {
+ size_t const cbToMove = pCppRd->offSrcRead - pCppRd->offSrcUnoptimized;
+ assert(cbToMove <= pCppRd->offSrcRead);
+ offDelta = cchInsert - cchAvail;
+
+ while (pCppRd->offSrcRead + offDelta >= pCppRd->cbBufAlloc)
+ kOCCppRdGrowBuffer(pCppRd);
+
+ g_cMemMoves++;
+ g_cbMemMoved += cbToMove + 1;
+ memmove(pCppRd->pszBuf + pCppRd->offSrcUnoptimized + offDelta,
+ pCppRd->pszBuf + pCppRd->offSrcUnoptimized,
+ cbToMove + 1);
+
+ pCppRd->offSrcRead += offDelta;
+ pCppRd->offSrcUnoptimized += offDelta;
+ pCppRd->offSrcCur += offDelta;
+ assert(pCppRd->offSrcRead < 1 || pCppRd->pszBuf[pCppRd->offSrcRead - 1] != '\0');
+ }
+
+ memcpy(pCppRd->pszBuf + pCppRd->cchDstOptimized, pchInsert, cchInsert);
+ pCppRd->cchDstOptimized += cchInsert;
+
+ return offDelta;
+}
+
+
+static void kOCCppRdOptCommit(PKOCCPPRD pCppRd)
+{
+ size_t cchToCommit = pCppRd->offSrcCur - pCppRd->offSrcUnoptimized;
+ assert(pCppRd->offSrcUnoptimized <= pCppRd->offSrcCur);
+
+ if (cchToCommit)
+ {
+ memmove(pCppRd->pszBuf + pCppRd->cchDstOptimized, pCppRd->pszBuf + pCppRd->offSrcUnoptimized, cchToCommit);
+ pCppRd->cchDstOptimized += cchToCommit;
+ pCppRd->offSrcUnoptimized = pCppRd->offSrcCur;
+ }
+
+ pCppRd->uOptLineNo = pCppRd->uCurLineNo;
+}
+
+
+
+static char *kOCCppRdOptGetEol(PKOCCPPRD pCppRd, char *pszCur, size_t cbLeft)
+{
+ char *pszEol = memchr(pszCur, '\n', cbLeft);
+ if (pszEol)
+ {
+ if (pszCur != pszEol && pszEol[-1] == '\r')
+ pszEol--;
+ }
+ else if (pCppRd->fDone && cbLeft)
+ pszEol = pszCur + cbLeft;
+ return pszEol;
+}
+
+static void kOCCppRdOptSetFile(PKOCCPPRD pCppRd, const char *pchFile, size_t cchFile)
+{
+ if (cchFile >= pCppRd->cbFileNmBuf)
+ {
+ pCppRd->cbFileNmBuf = (cchFile + 15 + 1) & ~(size_t)15;
+ pCppRd->pszFileNmBuf = xrealloc(pCppRd->pszFileNmBuf, pCppRd->cbFileNmBuf);
+ }
+ memcpy(pCppRd->pszFileNmBuf, pchFile, cchFile);
+ pCppRd->pszFileNmBuf[cchFile] = '\0';
+ pCppRd->cchCurFileNm = cchFile;
+}
+
+
+static size_t kOCCppRdOptFmtLine(PKOCCPPRD pCppRd, uint32_t uLine, const char *pchFile, size_t cchFile)
+{
+ size_t cchUsed;
+ size_t cbNeeded;
+
+ /* Make sure we've got enough buffer space. */
+ cbNeeded = sizeof("#line 4888222111 \"\"\n") + cchFile;
+ if (cbNeeded > pCppRd->cbLineBuf)
+ {
+ pCppRd->cbLineBuf = (cbNeeded + 32 + 15) & ~(size_t)15;
+ pCppRd->pszLineBuf = xrealloc(pCppRd->pszLineBuf, pCppRd->cbLineBuf);
+ }
+
+ /* Do the formatting. */
+ cchUsed = sprintf(pCppRd->pszLineBuf, "#line %lu", (unsigned long)uLine);
+ if (cchFile)
+ {
+ pCppRd->pszLineBuf[cchUsed++] = ' ';
+ pCppRd->pszLineBuf[cchUsed++] = '"';
+ memcpy(&pCppRd->pszLineBuf[cchUsed], pchFile, cchFile);
+ cchUsed += cchFile;
+ pCppRd->pszLineBuf[cchUsed++] = '"';
+ }
+ pCppRd->pszLineBuf[cchUsed++] = '\n';
+ pCppRd->pszLineBuf[cchUsed] = '\0';
+
+ return cchUsed;
+}
+
+
+static size_t kOCCppRdOptFmtNewLines(PKOCCPPRD pCppRd, uint32_t cNewLines)
+{
+ if (cNewLines + 1 > pCppRd->cbLineBuf)
+ {
+ pCppRd->cbLineBuf = (cNewLines + 1 + 32 + 15) & ~(size_t)15;
+ pCppRd->pszLineBuf = xrealloc(pCppRd->pszLineBuf, pCppRd->cbLineBuf);
+ }
+
+ memset(pCppRd->pszLineBuf, '\n', cNewLines);
+ pCppRd->pszLineBuf[cNewLines] = '\0';
+ return cNewLines;
+}
+
+
+static size_t kOCCppRdOptFlush(PKOCCPPRD pCppRd, size_t offSrcCur, int fLineDirNext)
+{
+ size_t offDelta = 0;
+ size_t const offSrcUnoptimized = pCppRd->offSrcUnoptimized;
+ assert(offSrcUnoptimized <= offSrcCur);
+
+ if (offSrcCur > offSrcUnoptimized)
+ {
+ /*
+ * We've got unflushed whitelines.
+ */
+ size_t const cchSrcInQuestion = offSrcCur - offSrcUnoptimized;
+ uint32_t const cLinesInQuestion = pCppRd->uCurLineNo - pCppRd->uOptLineNo;
+ size_t cchLineDir;
+
+ if ( cLinesInQuestion <= 7
+ || (cchLineDir = kOCCppRdOptFmtLine(pCppRd, pCppRd->uCurLineNo, NULL, 0)) >= cLinesInQuestion)
+ cchLineDir = kOCCppRdOptFmtNewLines(pCppRd, cLinesInQuestion);
+
+ offDelta = kOCCppRdOptInsert(pCppRd, cchSrcInQuestion, pCppRd->pszLineBuf, cchLineDir);
+ }
+
+ (void)fLineDirNext; /* Use later if required. */
+ return offDelta;
+}
+
+
+static int kOCCppRdOptParseLine(PKOCCPPRD pCppRd, char *pszCur, char *pszEol,
+ uint32_t *puNewLineNo, char **ppszNewFile, size_t *pcchNewFile)
+{
+ char *psz = pszCur;
+ uint32_t uNewLineNo;
+ int fIsShort;
+
+ /*
+ * Check if it's a #line directive of some kind and parse it.
+ */
+ if (*psz != '#')
+ return 0;
+ psz++;
+
+ fIsShort = MY_IS_BLANK(*psz);
+ while (MY_IS_BLANK(*psz))
+ psz++;
+
+ if ( psz[0] == 'l'
+ && psz[1] == 'i'
+ && psz[2] == 'n'
+ && psz[3] == 'e'
+ && MY_IS_BLANK(psz[4]) )
+ {
+ fIsShort = 0;
+ psz += 5;
+ while (MY_IS_BLANK(*psz))
+ psz++;
+ }
+ else if (fIsShort && isdigit(*psz))
+ fIsShort = 1;
+ else
+ return 0;
+
+ /* Parse the line number. */
+ if (!isdigit(*psz))
+ return 0;
+
+ uNewLineNo = *psz++ - '0';
+ while (isdigit(*psz))
+ {
+ uNewLineNo *= 10;
+ uNewLineNo += *psz++ - '0';
+ }
+ if ( psz != pszEol
+ && !MY_IS_BLANK(*psz))
+ return 0;
+
+ /*
+ * The file name part is optional.
+ */
+ while (MY_IS_BLANK(*psz))
+ psz++;
+
+ if ( psz != pszEol
+ && *psz == '"')
+ {
+ *ppszNewFile = ++psz;
+ while ( psz != pszEol
+ && ( *psz != '"'
+ || ( psz[-1] == '\\'
+ && kOCDepIsEscaped(psz, psz - *ppszNewFile)) )
+ )
+ psz++;
+ if (psz == pszEol)
+ {
+ /** @todo complain? */
+ return 0;
+ }
+ *pcchNewFile = psz - *ppszNewFile;
+
+ do
+ psz++;
+ while (psz != pszEol && MY_IS_BLANK(*psz));
+ }
+ else
+ {
+ /* No file given => Same as the current. */
+ *ppszNewFile = pCppRd->cchCurFileNm ? pCppRd->pszFileNmBuf : NULL;
+ *pcchNewFile = pCppRd->cchCurFileNm;
+ }
+ if (psz != pszEol)
+ {
+ /** @todo complain? */
+ return 0;
+ }
+
+ *puNewLineNo = uNewLineNo;
+ return 1;
+}
+
+
+static char *kOCCppRdOptHandleLine(PKOCCPPRD pCppRd, char *pszCur, size_t *pcbLeft, int *pfEmptyLine, char *pszEol)
+{
+ size_t const offSrcLine = pCppRd->offSrcCur;
+ size_t const cchSrcLine = pszEol - pCppRd->pszBuf - (pCppRd->fOptimize & 2 ? pCppRd->offSrcUnoptimized : pCppRd->offSrcCur);
+ size_t const cbLeftAssert = *pcbLeft;
+ char *pszNewFile;
+ size_t cchNewFile;
+ uint32_t uNewLineNo;
+ assert(*pszEol == '\r' || *pszEol == '\n' || *pszEol == '\0');
+
+ /* Advance to the end of the line before we do anything. This can be a
+ little confusing but it saves effort and avoid trouble in the end. */
+ pCppRd->offSrcCur = pszEol - pCppRd->pszBuf;
+ *pcbLeft -= pszEol - pszCur;
+ assert(*pcbLeft <= cbLeftAssert); (void)cbLeftAssert;
+
+ /*
+ * Try parse the directive a '#line' one....
+ */
+ if (!kOCCppRdOptParseLine(pCppRd, pszCur, pszEol, &uNewLineNo, &pszNewFile, &cchNewFile))
+ {
+ /*
+ * No line directive. Flush pending optimizations and indicate that
+ * the line isn't empty and needs to be commited at EOL.
+ */
+ kOCCppRdOptFlush(pCppRd, offSrcLine, 0);
+ *pfEmptyLine = 0;
+ }
+ else
+ {
+ char *pszCurFile = pCppRd->cchCurFileNm ? pCppRd->pszFileNmBuf : NULL;
+ if ( pszNewFile == pszCurFile
+ || ( cchNewFile == pCppRd->cchCurFileNm
+ && !memcmp(pszNewFile, pszCurFile, cchNewFile)) )
+ {
+ /*
+ * A #line directive specifying the same file.
+ */
+ if (uNewLineNo >= pCppRd->uCurLineNo)
+ *pfEmptyLine = 1;
+ else
+ {
+ /*
+ * It went backwards, so we need to flush the old section of
+ * the file and emit another directive for starting the new one.
+ */
+ size_t cchLineDir;
+ if (!(pCppRd->fOptimize & 2))
+ kOCCppRdOptFlush(pCppRd, offSrcLine, 1);
+
+ cchLineDir = kOCCppRdOptFmtLine(pCppRd, uNewLineNo, NULL, 0) - 1; /* sans \n */
+ kOCCppRdOptInsert(pCppRd, cchSrcLine, pCppRd->pszLineBuf, cchLineDir);
+
+ *pfEmptyLine = 0;
+ }
+ }
+ else
+ {
+ /*
+ * The #line directive changed the file.
+ */
+ size_t cchLineDir;
+
+ kOCCppRdOptSetFile(pCppRd, pszNewFile, cchNewFile); /* save to do this early */
+ if (!(pCppRd->fOptimize & 2))
+ kOCCppRdOptFlush(pCppRd, offSrcLine, 1);
+
+ cchLineDir = kOCCppRdOptFmtLine(pCppRd, uNewLineNo, pCppRd->pszFileNmBuf, cchNewFile) - 1; /* sans \n */
+ kOCCppRdOptInsert(pCppRd, cchSrcLine, pCppRd->pszLineBuf, cchLineDir);
+
+ if (pCppRd->pDepState)
+ kOCDepEnter(pCppRd->pDepState, pCppRd->pszFileNmBuf, cchNewFile);
+
+ *pfEmptyLine = 0;
+ }
+
+ pCppRd->uCurLineNo = uNewLineNo - 1;
+ }
+
+ return pCppRd->pszBuf + pCppRd->offSrcCur;
+}
+
+
+static void kOCCppRdOpt(PKOCCPPRD pCppRd)
+{
+ size_t cch;
+ char *pszEol;
+ char *pszCur = pCppRd->pszBuf + pCppRd->offSrcCur;
+ size_t cbTodo = pCppRd->offSrcRead - pCppRd->offSrcCur;
+ int fEmptyLine = 1;
+
+ while (cbTodo > 0)
+ {
+ switch (*pszCur)
+ {
+ case ' ':
+ case '\t':
+ break;
+
+ case '\n':
+ pCppRd->offSrcCur = pszCur - pCppRd->pszBuf + 1;
+ pCppRd->uCurLineNo++;
+ if (!fEmptyLine)
+ kOCCppRdOptCommit(pCppRd);
+ fEmptyLine = 1;
+ break;
+
+ case '\r': /* "\r\n" -> "\n" */
+ if (cbTodo <= 1 && !pCppRd->fDone)
+ return;
+ if (pszCur[1] == '\n' && !fEmptyLine)
+ {
+ /* Commit the part up to the '\r' first, replace '\r\n' with '\n'. */
+ pCppRd->offSrcCur = pszCur - pCppRd->pszBuf;
+ kOCCppRdOptCommit(pCppRd);
+
+ pCppRd->offSrcCur += 2;
+ kOCCppRdOptInsert(pCppRd, 2, "\n", 1);
+
+ assert(cbTodo >= 2);
+ cbTodo -= 2;
+ pszCur += 2;
+
+ fEmptyLine = 1;
+ continue;
+ }
+ break;
+
+ case '#':
+ pszEol = kOCCppRdOptGetEol(pCppRd, pszCur + 1, cbTodo - 1);
+ if (!pszEol)
+ return;
+ pszCur = kOCCppRdOptHandleLine(pCppRd, pszCur, &cbTodo, &fEmptyLine, pszEol);
+ continue;
+
+ default:
+ /*
+ * Some non-white stuff encountered, flush pending white
+ * line optimizations and skip to the end of the line.
+ */
+ fEmptyLine = 0;
+ pszEol = kOCCppRdOptGetEol(pCppRd, pszCur + 1, cbTodo - 1);
+ if (!pszEol)
+ return;
+ cch = pszEol - pszCur;
+
+ pszCur += kOCCppRdOptFlush(pCppRd, pCppRd->offSrcCur, 0);
+
+ assert(cch <= cbTodo);
+ cbTodo -= cch;
+ pszCur += cch;
+ continue;
+ }
+
+ cbTodo--;
+ pszCur++;
+ }
+}
+
+
+static void kOCCppRdOptFinalize(PKOCCPPRD pCppRd)
+{
+ pCppRd->fDone = 1;
+ assert(pCppRd->offSrcRead < 1 || pCppRd->pszBuf[pCppRd->offSrcRead - 1] != '\0');
+ pCppRd->pszBuf[pCppRd->offSrcRead] = '\0';
+ kOCCppRdOpt(pCppRd);
+
+ assert(pCppRd->offSrcCur == pCppRd->offSrcRead);
+ kOCCppRdOptFlush(pCppRd, pCppRd->offSrcCur, 0);
+}
+
+
+
+/**
+ * Read C preprocessor output from the given file descriptor, optionally
+ * optimzing it.
+ *
+ * @returns Number of bytes read. 0 indicates end of file.
+ *
+ * @param pCppRd The C preprocessor reader instance.
+ * @param fdIn The file descriptor to read the raw preprocessor output
+ * from.
+ * @param ppszRet Where to return the pointer to the output.
+ *
+ * @remarks Won't return on error, calls FatalDie on those occasions.
+ */
+static long kOCCppRdRead(PKOCCPPRD pCppRd, int fdIn, const char **ppszRet)
+{
+ size_t cbLeft;
+ long cbRead;
+
+ if (pCppRd->fOptimize)
+ {
+ /*
+ * Optimize the C preprocessor output on the way thru.
+ */
+ size_t const cchOldOptimized = pCppRd->cchDstOptimized;
+ if (pCppRd->chSaved)
+ pCppRd->pszBuf[pCppRd->cchDstOptimized] = pCppRd->chSaved;
+
+ do
+ {
+ /* Read more raw C preprocessor output. */
+ cbLeft = pCppRd->cbBufAlloc - pCppRd->offSrcRead;
+ if (cbLeft <= 1)
+ cbLeft = kOCCppRdGrowBuffer(pCppRd);
+
+ do
+ cbRead = read(fdIn, pCppRd->pszBuf + pCppRd->offSrcRead, (long)(cbLeft - 1));
+ while (cbRead < 0 && errno == EINTR);
+ if (cbRead < 0)
+ FatalDie("kOCCppRdRead - read(%d,,%ld) failed: %s\n",
+ fdIn, (long)(cbLeft - 1), strerror(errno));
+ pCppRd->offSrcRead += cbRead;
+
+ /* Optimize it. */
+ if (!cbRead)
+ {
+ kOCCppRdOptFinalize(pCppRd);
+ break;
+ }
+ kOCCppRdOpt(pCppRd);
+ } while (pCppRd->cchDstOptimized == cchOldOptimized);
+
+ *ppszRet = &pCppRd->pszBuf[cchOldOptimized];
+ pCppRd->chSaved = pCppRd->pszBuf[pCppRd->cchDstOptimized];
+ pCppRd->pszBuf[pCppRd->cchDstOptimized] = '\0';
+ cbRead = (long)(pCppRd->cchDstOptimized - cchOldOptimized);
+ }
+ else
+ {
+ /*
+ * Pass thru.
+ */
+ char *pszBuf;
+ cbLeft = pCppRd->cbBufAlloc - pCppRd->offSrcRead;
+ if (cbLeft <= 1)
+ cbLeft = kOCCppRdGrowBuffer(pCppRd);
+ pszBuf = pCppRd->pszBuf + pCppRd->offSrcRead;
+
+ do
+ cbRead = read(fdIn, pszBuf, (long)(cbLeft - 1));
+ while (cbRead < 0 && errno == EINTR);
+ if (cbRead < 0)
+ FatalDie("kOCCppRdRead - read(%d,,%ld) failed: %s\n",
+ fdIn, (long)(cbLeft - 1), strerror(errno));
+
+ *ppszRet = pszBuf;
+ pCppRd->offSrcRead += cbRead;
+ pszBuf[cbRead] = '\0';
+ }
+
+ return cbRead;
+}
+
+
+/**
+ * Grabs the output buffer from the C preprocessor reader.
+ *
+ * @param pCppRd The C preprocessor reader instance.
+ * @param ppszRet Where to return the pointer to the output.
+ * @param pcbRet Where to return the size of the output.
+ */
+static void kOCCppRdGrabOutput(PKOCCPPRD pCppRd, char **ppszRet, size_t *pcbRet)
+{
+ assert(pCppRd->offSrcRead < 1 || pCppRd->pszBuf[pCppRd->offSrcRead - 1] != '\0');
+ *ppszRet = pCppRd->pszBuf;
+ *pcbRet = pCppRd->fOptimize ? pCppRd->cchDstOptimized : pCppRd->offSrcRead;
+ pCppRd->pszBuf = NULL;
+ pCppRd->offSrcRead = 0;
+}
+
+
+
/** 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
{
@@ -782,8 +1774,7 @@ typedef const KOCSUM *PCKOCSUM;
/**
- * 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
{
@@ -1079,28 +2070,41 @@ typedef struct KOCENTRY
char *pszAbsPath;
/** 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;
+ /** Whether the optimizations are enabled. */
+ int fOptimizeCpp;
/** Cache entry key that's used for some quick digest validation. */
uint32_t uKey;
/** The file data. */
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. */
uint32_t cMsCpp;
@@ -1116,6 +2120,7 @@ typedef struct KOCENTRY
/** The number of milliseconds spent compiling. */
uint32_t cMsCompile;
/** @todo need a list of additional output files for MSC. */
+ /** @todo need compiler output (warnings). */
/** The target os/arch identifier. */
char *pszTarget;
@@ -1147,6 +2152,8 @@ static PKOCENTRY kOCEntryCreate(const char *pszFilename)
*/
pEntry = xmallocz(sizeof(*pEntry));
+ kOCDepInit(&pEntry->DepState);
+
kOCSumInit(&pEntry->New.SumHead);
kOCSumInit(&pEntry->Old.SumHead);
@@ -1180,6 +2187,9 @@ static void kOCEntryDestroy(PKOCENTRY pEntry)
free(pEntry->pszDir);
free(pEntry->pszAbsPath);
free(pEntry->pszNmPipeCompile);
+ free(pEntry->pszMakeDepFilename);
+
+ kOCDepDelete(&pEntry->DepState);
kOCSumDeleteChain(&pEntry->New.SumHead);
kOCSumDeleteChain(&pEntry->Old.SumHead);
@@ -1217,14 +2227,19 @@ static void kOCEntryDestroy(PKOCENTRY pEntry)
* @param pEntry The cache entry.
* @param papszArgv The argument vector.
* @param cArgc The number of entries in the vector.
- * @param pszIgnorePath Path to ignore when encountered at the end of arguments.
- * (Not quite safe for simple file names, but what the heck.)
+ * @param pszIgnorePath1 Path to ignore when encountered at the end of
+ * arguments. (Not quite safe for simple file names,
+ * but what the heck.)
+ * @param pszIgnorePath2 Path to ignore when encountered at the end of
+ * arguments. (Not quite safe for simple file names,
+ * but what the heck.)
* @param pSum Where to store the check sum.
*/
static void kOCEntryCalcArgvSum(PKOCENTRY pEntry, const char * const *papszArgv, unsigned cArgc,
- const char *pszIgnorePath, PKOCSUM pSum)
+ const char *pszIgnorePath1, const char *pszIgnorePath2, PKOCSUM pSum)
{
- size_t cchIgnorePath = strlen(pszIgnorePath);
+ size_t cchIgnorePath1 = strlen(pszIgnorePath1);
+ size_t cchIgnorePath2 = pszIgnorePath2 ? strlen(pszIgnorePath2) : ~(size_t)0;
KOCSUMCTX Ctx;
unsigned i;
@@ -1232,8 +2247,10 @@ static void kOCEntryCalcArgvSum(PKOCENTRY pEntry, const char * const *papszArgv,
for (i = 0; i < cArgc; i++)
{
size_t cch = strlen(papszArgv[i]);
- if ( cch < cchIgnorePath
- || !ArePathsIdenticalN(papszArgv[i] + cch - cchIgnorePath, pszIgnorePath, cch))
+ if ( ( cch < cchIgnorePath1
+ || !ArePathsIdenticalN(papszArgv[i] + cch - cchIgnorePath1, pszIgnorePath1, cch))
+ && ( cch < cchIgnorePath2
+ || !ArePathsIdenticalN(papszArgv[i] + cch - cchIgnorePath2, pszIgnorePath2, cch)) )
kOCSumUpdate(pSum, &Ctx, papszArgv[i], cch + 1);
}
kOCSumFinalize(pSum, &Ctx);
@@ -1410,7 +2427,8 @@ static void kOCEntryRead(PKOCENTRY pEntry)
{
KOCSUM Sum;
kOCEntryCalcArgvSum(pEntry, (const char * const *)pEntry->Old.papszArgvCompile,
- pEntry->Old.cArgvCompile, pEntry->Old.pszObjName, &Sum);
+ pEntry->Old.cArgvCompile, pEntry->Old.pszObjName, pEntry->Old.pszCppName,
+ &Sum);
fBad = !kOCSumIsEqual(&pEntry->Old.SumCompArgv, &Sum);
}
if (fBad)
@@ -1597,7 +2615,8 @@ static void kOCEntrySetCompileArgv(PKOCENTRY pEntry, const char * const *papszAr
pEntry->New.papszArgvCompile[i] = xstrdup(papszArgvCompile[i]);
pEntry->New.papszArgvCompile[i] = NULL; /* for exev/spawnv */
- kOCEntryCalcArgvSum(pEntry, papszArgvCompile, cArgvCompile, pEntry->New.pszObjName, &pEntry->New.SumCompArgv);
+ kOCEntryCalcArgvSum(pEntry, papszArgvCompile, cArgvCompile, pEntry->New.pszObjName, pEntry->New.pszCppName,
+ &pEntry->New.SumCompArgv);
kOCSumInfo(&pEntry->New.SumCompArgv, 4, "comp-argv");
/*
@@ -1634,11 +2653,11 @@ static void kOCEntrySetTarget(PKOCENTRY pEntry, const char *pszTarget)
/**
- * 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)
{
@@ -1648,10 +2667,10 @@ static void kOCEntrySetCppName(PKOCENTRY pEntry, const char *pszCppName)
/**
- * 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
* the microsoft compiler.
@@ -1666,6 +2685,37 @@ static void kOCEntrySetPipedMode(PKOCENTRY pEntry, int fRedirPreCompStdOut, int
/**
+ * 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;
+}
+
+
+/**
+ * Configures the preprocessor output optimizations.
+ *
+ * @param pEntry The cache entry.
+ * @param fOptimizeCpp The one and only flag, so far.
+ */
+static void kOCEntrySetOptimizations(PKOCENTRY pEntry, int fOptimizeCpp)
+{
+ pEntry->fOptimizeCpp = fOptimizeCpp;
+}
+
+
+/**
* Spawns a child in a synchronous fashion.
* Terminating on failure.
*
@@ -1824,17 +2874,17 @@ static pid_t kOCEntrySpawnChild(PCKOCENTRY pEntry, uint32_t *pcMs, const char *
pid = _spawnvp(_P_NOWAIT, papszArgv[0], papszArgv);
# endif
if (pid == -1)
- FatalDie("precompile - _spawnvp failed: %s\n", strerror(errno));
+ FatalDie("preprocess - _spawnvp failed: %s\n", strerror(errno));
#else
pid = fork();
if (!pid)
{
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
/*
@@ -1902,13 +2952,14 @@ static void kOCEntryWaitChild(PCKOCENTRY pEntry, uint32_t *pcMs, pid_t pid, cons
* Creates a pipe for setting up redirected stdin/stdout.
*
* @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.)
+ * @param fText Whether to read text mode or binary mode.
*/
-static void kOCEntryCreatePipe(PKOCENTRY pEntry, int *pFDs, const char *pszPipeName, const char *pszMsg)
+static void kOCEntryCreatePipe(PKOCENTRY pEntry, int *paFDs, const char *pszPipeName, const char *pszMsg, int fText)
{
- pFDs[0] = pFDs[1] = -1;
+ paFDs[0] = paFDs[1] = -1;
#if defined(__WIN__)
if (pszPipeName)
{
@@ -1924,18 +2975,19 @@ static void kOCEntryCreatePipe(PKOCENTRY pEntry, int *pFDs, const char *pszPipeN
if (hPipe == INVALID_HANDLE_VALUE)
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 | (fText ? _O_TEXT : _O_BINARY)) < 0
+ && _pipe(paFDs, 0, _O_NOINHERIT | (fText ? _O_TEXT : _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
(void)pEntry;
@@ -1957,7 +3009,7 @@ static void kOCEntrySpawnProducer(PKOCENTRY pEntry, const char * const *papszArg
int fds[2];
pid_t pid;
- kOCEntryCreatePipe(pEntry, fds, NULL, pszMsg);
+ kOCEntryCreatePipe(pEntry, fds, NULL, pszMsg, pEntry->fOptimizeCpp);
pid = kOCEntrySpawnChild(pEntry, &pEntry->New.cMsCpp, papszArgv, cArgv, -1, fds[1 /* write */], pszMsg);
pfnConsumer(pEntry, fds[0 /* read */]);
@@ -1981,7 +3033,7 @@ static void kOCEntrySpawnConsumer(PKOCENTRY pEntry, const char * const *papszArg
int fds[2];
pid_t pid;
- kOCEntryCreatePipe(pEntry, fds, pEntry->pszNmPipeCompile, pszMsg);
+ kOCEntryCreatePipe(pEntry, fds, pEntry->pszNmPipeCompile, pszMsg, 0 /*fText*/);
pid = kOCEntrySpawnChild(pEntry, &pEntry->New.cMsCompile, papszArgv, cArgv, fds[0 /* read */], -1, pszMsg);
#ifdef __WIN__
if (pEntry->pszNmPipeCompile && !ConnectNamedPipe((HANDLE)_get_osfhandle(fds[1 /* write */]), NULL))
@@ -2015,14 +3067,14 @@ static void kOCEntrySpawnTee(PKOCENTRY pEntry, const char * const *papszProdArgv
/*
* The producer.
*/
- kOCEntryCreatePipe(pEntry, fds, NULL, pszMsg);
+ kOCEntryCreatePipe(pEntry, fds, NULL, pszMsg, pEntry->fOptimizeCpp);
pidConsumer = kOCEntrySpawnChild(pEntry, &pEntry->New.cMsCpp, papszProdArgv, cProdArgv, -1, fds[1 /* write */], pszMsg);
fdIn = fds[0 /* read */];
/*
* The consumer.
*/
- kOCEntryCreatePipe(pEntry, fds, pEntry->pszNmPipeCompile, pszMsg);
+ kOCEntryCreatePipe(pEntry, fds, pEntry->pszNmPipeCompile, pszMsg, 0 /*fText*/);
pidProducer = kOCEntrySpawnChild(pEntry, &pEntry->New.cMsCompile, papszConsArgv, cConsArgv, fds[0 /* read */], -1, pszMsg);
fdOut = fds[1 /* write */];
@@ -2040,7 +3092,7 @@ static void kOCEntrySpawnTee(PKOCENTRY pEntry, const char * const *papszProdArgv
/**
- * 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.
* @param pWhich Specifies what to read (old/new).
@@ -2059,14 +3111,14 @@ static int kOCEntryReadCppOutput(PKOCENTRY pEntry, struct KOCENTRYDATA *pWhich,
return -1;
}
- 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;
}
/**
- * 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.
*/
@@ -2081,62 +3133,42 @@ static void kOCEntryCalcChecksum(PKOCENTRY pEntry)
/**
- * 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;
- long cbLeft;
- long cbAlloc;
- char *psz;
+ KOCCPPRD CppRd;
kOCSumInitWithCtx(&pEntry->New.SumHead, &Ctx);
- cbAlloc = pEntry->Old.cbCpp ? ((long)pEntry->Old.cbCpp + 4*1024*1024 + 4096) & ~(4*1024*1024 - 1) : 4*1024*1024;
- cbLeft = cbAlloc;
- pEntry->New.pszCppMapping = psz = xmalloc(cbAlloc);
+ kOCCppRdInit(&CppRd, pEntry->Old.cbCpp, pEntry->fOptimizeCpp,
+ pEntry->pszMakeDepFilename ? &pEntry->DepState : NULL);
+
for (;;)
{
/*
* Read data from the pipe.
*/
- long cbRead = read(fdIn, psz, cbLeft - 1);
+ const char *psz;
+ long cbRead = kOCCppRdRead(&CppRd, fdIn, &psz);
if (!cbRead)
break;
- if (cbRead < 0)
- {
- if (errno == EINTR)
- continue;
- FatalDie("precompile - read(%d,,%ld) failed: %s\n",
- fdIn, (long)cbLeft, strerror(errno));
- }
/*
* Process the data.
*/
- psz[cbRead] = '\0';
kOCSumUpdate(&pEntry->New.SumHead, &Ctx, psz, cbRead);
-
- /*
- * Advance.
- */
- psz += cbRead;
- cbLeft -= cbRead;
- if (cbLeft <= 1)
- {
- size_t off = psz - pEntry->New.pszCppMapping;
- cbLeft += 4*1024*1024;
- cbAlloc += 4*1024*1024;
- pEntry->New.pszCppMapping = xrealloc(pEntry->New.pszCppMapping, cbAlloc);
- psz = pEntry->New.pszCppMapping + off;
- }
+ if (pEntry->pszMakeDepFilename && !pEntry->fOptimizeCpp)
+ kOCDepConsumer(&pEntry->DepState, psz, cbRead);
}
close(fdIn);
- pEntry->New.cbCpp = cbAlloc - cbLeft;
+ kOCCppRdGrabOutput(&CppRd, &pEntry->New.pszCppMapping, &pEntry->New.cbCpp);
+ kOCCppRdDelete(&CppRd);
kOCSumFinalize(&pEntry->New.SumHead, &Ctx);
kOCSumInfo(&pEntry->New.SumHead, 4, "cpp (pipe)");
}
@@ -2145,24 +3177,25 @@ static void kOCEntryPreCompileConsumer(PKOCENTRY pEntry, int fdIn)
/**
- * 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)
+static void kOCEntryPreProcess(PKOCENTRY pEntry, const char * const *papszArgvPreComp, unsigned cArgvPreComp)
{
/*
- * If we're executing the precompiler in piped mode, it's relatively simple.
+ * 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.
*/
if ( pEntry->Old.pszCppName
@@ -2183,19 +3216,25 @@ static void kOCEntryPreCompile(PKOCENTRY pEntry, const char * const *papszArgvPr
}
/*
- * Precompile it and calculate the checksum on the output.
+ * Preprocess it and calculate the checksum on the output.
*/
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);
}
/**
* Worker function for kOCEntryTeeConsumer and kOCEntryCompileIt that
- * writes the precompiler output to disk.
+ * writes the preprocessor output to disk.
*
* @param pEntry The cache entry.
* @param fFreeIt Whether we can free it after writing it or not.
@@ -2256,8 +3295,8 @@ static void kOCEntryWriteCppOutput(PKOCENTRY pEntry, int fFreeIt)
/**
- * 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.
* @param fdOut The pipe handle connected to the childs stdin.
@@ -2345,11 +3384,11 @@ static void kOCEntryCompileIt(PKOCENTRY pEntry)
/**
* 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).
*/
static void kOCEntryTeeConsumer(PKOCENTRY pEntry, int fdIn, int fdOut)
@@ -2358,41 +3397,34 @@ static void kOCEntryTeeConsumer(PKOCENTRY pEntry, int fdIn, int fdOut)
unsigned fConnectedToCompiler = fdOut == -1 || pEntry->pszNmPipeCompile == NULL;
#endif
KOCSUMCTX Ctx;
- long cbLeft;
- long cbAlloc;
- char *psz;
+ KOCCPPRD CppRd;
kOCSumInitWithCtx(&pEntry->New.SumHead, &Ctx);
- cbAlloc = pEntry->Old.cbCpp ? ((long)pEntry->Old.cbCpp + 4*1024*1024 + 4096) & ~(4*1024*1024 - 1) : 4*1024*1024;
- cbLeft = cbAlloc;
- pEntry->New.pszCppMapping = psz = xmalloc(cbAlloc);
- InfoMsg(3, "precompiler|compile - starting passhtru...\n");
+ kOCCppRdInit(&CppRd, pEntry->Old.cbCpp, pEntry->fOptimizeCpp,
+ pEntry->pszMakeDepFilename ? &pEntry->DepState : NULL);
+ InfoMsg(3, "preprocessor|compile - starting passhtru...\n");
for (;;)
{
/*
* Read data from the pipe.
*/
- long cbRead = read(fdIn, psz, cbLeft - 1);
+ const char *psz;
+ long cbRead = kOCCppRdRead(&CppRd, fdIn, &psz);
if (!cbRead)
break;
- if (cbRead < 0)
- {
- if (errno == EINTR)
- continue;
- FatalDie("precompile|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);
/*
* Process the data.
*/
- psz[cbRead] = '\0';
kOCSumUpdate(&pEntry->New.SumHead, &Ctx, psz, cbRead);
+ if (pEntry->pszMakeDepFilename && !pEntry->fOptimizeCpp)
+ 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
{
@@ -2401,35 +3433,24 @@ static void kOCEntryTeeConsumer(PKOCENTRY pEntry, int fdIn, int fdOut)
{
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;
cbRead -= cbWritten;
- cbLeft -= cbWritten;
} while (cbRead > 0);
- /*
- * Expand the buffer?
- */
- if (cbLeft <= 1)
- {
- size_t off = psz - pEntry->New.pszCppMapping;
- cbLeft = 4*1024*1024;
- cbAlloc += cbLeft;
- pEntry->New.pszCppMapping = xrealloc(pEntry->New.pszCppMapping, cbAlloc);
- psz = pEntry->New.pszCppMapping + off;
- }
}
- InfoMsg(3, "precompiler|compile - done passhtru\n");
+ InfoMsg(3, "preprocessor|compile - done passhtru\n");
close(fdIn);
close(fdOut);
- pEntry->New.cbCpp = cbAlloc - cbLeft;
+ kOCCppRdGrabOutput(&CppRd, &pEntry->New.pszCppMapping, &pEntry->New.cbCpp);
+ kOCCppRdDelete(&CppRd);
kOCSumFinalize(&pEntry->New.SumHead, &Ctx);
kOCSumInfo(&pEntry->New.SumHead, 4, "cpp (tee)");
/*
- * 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.
*/
kOCEntryWriteCppOutput(pEntry, 1 /* free it */);
@@ -2440,10 +3461,11 @@ static void kOCEntryTeeConsumer(PKOCENTRY pEntry, int fdIn, int fdOut)
* Performs pre-compile and compile in one go (typical clean build scenario).
*
* @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
&& pEntry->fPipedPreComp)
@@ -2461,15 +3483,18 @@ static void kOCEntryPreCompileAndCompile(PKOCENTRY pEntry, const char * const *p
UnlinkFileInDir(pEntry->New.pszCppName, pEntry->pszDir);
/*
- * 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);
}
}
@@ -2562,7 +3587,7 @@ static const char *kOCEntryFindFileStatement(const char *pszStart, const char *p
/**
* 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.
* @param pEntry The entry containing the names of the files to compare.
@@ -2612,7 +3637,7 @@ static int kOCEntryCompareFast(PCKOCENTRY pEntry)
* Since we might be skipping a few new empty headers, it is
* 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.
*/
const char *psz;
@@ -2778,7 +3803,7 @@ static int kOCEntryCompareFast(PCKOCENTRY pEntry)
/**
* Worker for kOCEntryCompileIfNeeded that compares the
- * precompiled output.
+ * preprocessed output.
*
* @returns 1 if matching, 0 if not matching.
* @param pEntry The entry containing the names of the files to compare.
@@ -2809,15 +3834,23 @@ static void kOCEntryCalcRecompile(PKOCENTRY pEntry)
return;
/*
- * 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))
{
- InfoMsg(2, "no checksum match - comparing output\n");
- if (!kOCEntryCompareOldAndNewOutput(pEntry))
+ if (pEntry->fOptimizeCpp & 2)
+ {
+ InfoMsg(2, "no checksum match - no need to compare output, -O2.\n");
pEntry->fNeedCompiling = 1;
+ }
else
- kOCSumAddChain(&pEntry->New.SumHead, &pEntry->Old.SumHead);
+ {
+ InfoMsg(2, "no checksum match - comparing output\n");
+ if (!kOCEntryCompareOldAndNewOutput(pEntry))
+ pEntry->fNeedCompiling = 1;
+ else
+ kOCSumAddChain(&pEntry->New.SumHead, &pEntry->Old.SumHead);
+ }
}
}
@@ -2835,6 +3868,45 @@ static int kOCEntryNeedsCompiling(PCKOCENTRY pEntry)
/**
+ * Tries to hardlink a file.
+ *
+ * @returns 1 if it succeeded, 0 if it didn't.
+ * @param pszLink The name of the hardlink.
+ * @param pszLinkTo The file to hardlinkg @a pszDst to.
+ */
+static int kOCEntryTryHardlink(const char *pszLink, const char *pszLinkTo)
+{
+#ifdef __WIN__
+ typedef BOOL (WINAPI *PFNCREATEHARDLINKA)(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES);
+ static PFNCREATEHARDLINKA s_pfnCreateHardLinkA = NULL;
+ static int s_fTried = FALSE;
+
+ /* The API was introduced in Windows 2000, so resolve it dynamically. */
+ if (!s_pfnCreateHardLinkA)
+ {
+ if (!s_fTried)
+ {
+ HMODULE hmod = LoadLibrary("KERNEL32.DLL");
+ if (hmod)
+ *(FARPROC *)&s_pfnCreateHardLinkA = GetProcAddress(hmod, "CreateHardLinkA");
+ s_fTried = TRUE;
+ }
+ if (!s_pfnCreateHardLinkA)
+ return 0;
+ }
+
+ if (!s_pfnCreateHardLinkA(pszLink, pszLinkTo, NULL))
+ return 0;
+#else
+ if (link(pszLinkTo, pszLink) != 0)
+ return 0;
+#endif
+ return 1;
+}
+
+
+
+/**
* Worker function for kOCEntryCopy.
*
* @param pEntry The entry we're coping to, which pszTo is relative to.
@@ -2844,60 +3916,63 @@ static int kOCEntryNeedsCompiling(PCKOCENTRY pEntry)
static void kOCEntryCopyFile(PCKOCENTRY pEntry, const char *pszTo, char *pszSrc)
{
char *pszDst = MakePathFromDirAndFile(pszTo, pEntry->pszDir);
- char *pszBuf = xmalloc(256 * 1024);
- char *psz;
- int fdSrc;
- int fdDst;
-
- /*
- * Open the files.
- */
- fdSrc = open(pszSrc, O_RDONLY | O_BINARY);
- if (fdSrc == -1)
- FatalDie("failed to open '%s': %s\n", pszSrc, strerror(errno));
-
unlink(pszDst);
- fdDst = open(pszDst, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
- if (fdDst == -1)
- FatalDie("failed to create '%s': %s\n", pszDst, strerror(errno));
-
- /*
- * Copy them.
- */
- for (;;)
+ if (!kOCEntryTryHardlink(pszDst, pszSrc))
{
- /* read a chunk. */
- long cbRead = read(fdSrc, pszBuf, 256*1024);
- if (cbRead < 0)
- {
- if (errno == EINTR)
- continue;
- FatalDie("read '%s' failed: %s\n", pszSrc, strerror(errno));
- }
- if (!cbRead)
- break; /* eof */
+ char *pszBuf = xmalloc(256 * 1024);
+ char *psz;
+ int fdSrc;
+ int fdDst;
- /* write the chunk. */
- psz = pszBuf;
- do
+ /*
+ * Open the files.
+ */
+ fdSrc = open(pszSrc, O_RDONLY | O_BINARY);
+ if (fdSrc == -1)
+ FatalDie("failed to open '%s': %s\n", pszSrc, strerror(errno));
+
+ fdDst = open(pszDst, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+ if (fdDst == -1)
+ FatalDie("failed to create '%s': %s\n", pszDst, strerror(errno));
+
+ /*
+ * Copy them.
+ */
+ for (;;)
{
- long cbWritten = write(fdDst, psz, cbRead);
- if (cbWritten < 0)
+ /* read a chunk. */
+ long cbRead = read(fdSrc, pszBuf, 256*1024);
+ if (cbRead < 0)
{
if (errno == EINTR)
continue;
- FatalDie("write '%s' failed: %s\n", pszSrc, strerror(errno));
+ FatalDie("read '%s' failed: %s\n", pszSrc, strerror(errno));
}
- psz += cbWritten;
- cbRead -= cbWritten;
- } while (cbRead > 0);
- }
+ if (!cbRead)
+ break; /* eof */
- /* cleanup */
- if (close(fdDst) != 0)
- FatalDie("closing '%s' failed: %s\n", pszDst, strerror(errno));
- close(fdSrc);
- free(pszBuf);
+ /* write the chunk. */
+ psz = pszBuf;
+ do
+ {
+ long cbWritten = write(fdDst, psz, cbRead);
+ if (cbWritten < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ FatalDie("write '%s' failed: %s\n", pszSrc, strerror(errno));
+ }
+ psz += cbWritten;
+ cbRead -= cbWritten;
+ } while (cbRead > 0);
+ }
+
+ /* cleanup */
+ if (close(fdDst) != 0)
+ FatalDie("closing '%s' failed: %s\n", pszDst, strerror(errno));
+ close(fdSrc);
+ free(pszBuf);
+ }
free(pszDst);
free(pszSrc);
}
@@ -2956,7 +4031,7 @@ typedef struct KOCDIGEST
uint32_t uKey;
/** 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;
/** Pointer to a file digest. */
@@ -3831,7 +4906,7 @@ static int usage(FILE *pOut)
" <-f|--file <local-cache-file>>\n"
" <-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"
);
@@ -3870,6 +4945,12 @@ int main(int argc, char **argv)
int fRedirCompileStdIn = 0;
const char *pszNmPipeCompile = NULL;
+ const char *pszMakeDepFilename = NULL;
+ int fMakeDepFixCase = 0;
+ int fMakeDepGenStubs = 0;
+ int fMakeDepQuiet = 0;
+ int fOptimizePreprocessorOutput = 0;
+
const char *pszTarget = NULL;
enum { kOC_Options, kOC_CppArgv, kOC_CcArgv, kOC_BothArgv } enmMode = kOC_Options;
@@ -3910,7 +4991,7 @@ int main(int argc, char **argv)
if (!pszObjName)
{
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];
}
}
@@ -3974,6 +5055,22 @@ int main(int argc, char **argv)
pszNmPipeCompile = argv[++i];
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], "-O1") || !strcmp(argv[i], "--optimize-1"))
+ fOptimizePreprocessorOutput = 1;
+ else if (!strcmp(argv[i], "-O2") || !strcmp(argv[i], "--optimize-2"))
+ fOptimizePreprocessorOutput = 1 | 2;
else if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--passthru"))
fRedirPreCompStdOut = fRedirCompileStdIn = 1;
else if (!strcmp(argv[i], "-r") || !strcmp(argv[i], "--redir-stdout"))
@@ -3990,8 +5087,8 @@ int main(int argc, char **argv)
}
else if (!strcmp(argv[i], "-V") || !strcmp(argv[i], "--version"))
{
- printf("kObjCache - kBuild version %d.%d.%d ($Revision: 2568 $)\n"
- "Copyright (c) 2007-2011 knut st. osmundsen\n",
+ printf("kObjCache - kBuild version %d.%d.%d ($Revision: 2627 $)\n"
+ "Copyright (c) 2007-2012 knut st. osmundsen\n",
KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH);
return 0;
}
@@ -4005,7 +5102,7 @@ int main(int argc, char **argv)
if (!cArgvCompile)
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");
/*
* Calc the cache file name.
@@ -4025,7 +5122,7 @@ int main(int argc, char **argv)
psz = strrchr(pszCacheName, '.');
if (!psz || psz <= pszCacheName)
psz = (char *)pszCacheName + cch;
- memcpy(psz, ".koc", sizeof(".koc") - 1);
+ memcpy(psz, ".koc", sizeof(".koc"));
}
pszCacheFile = MakePathFromDirAndFile(pszCacheName, pszCacheDir);
}
@@ -4042,11 +5139,13 @@ int main(int argc, char **argv)
pEntry = kOCEntryCreate(pszEntryFile);
kOCEntryRead(pEntry);
+ kOCEntrySetCppName(pEntry, pszPreCompName);
kOCEntrySetCompileObjName(pEntry, pszObjName);
kOCEntrySetCompileArgv(pEntry, papszArgvCompile, cArgvCompile);
kOCEntrySetTarget(pEntry, pszTarget);
- kOCEntrySetCppName(pEntry, pszPreCompName);
kOCEntrySetPipedMode(pEntry, fRedirPreCompStdOut, fRedirCompileStdIn, pszNmPipeCompile);
+ kOCEntrySetDepFilename(pEntry, pszMakeDepFilename, fMakeDepFixCase, fMakeDepQuiet, fMakeDepGenStubs);
+ kOCEntrySetOptimizations(pEntry, fOptimizePreprocessorOutput);
/*
* Open (& lock) the two files and do validity checks and such.
@@ -4061,16 +5160,16 @@ int main(int argc, char **argv)
*/
kObjCacheUnlock(pCache);
InfoMsg(1, "doing full compile\n");
- kOCEntryPreCompileAndCompile(pEntry, papszArgvPreComp, cArgvPreComp);
+ kOCEntryPreProcessAndCompile(pEntry, papszArgvPreComp, cArgvPreComp);
kObjCacheLock(pCache);
}
else
{
/*
- * 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);
/*
* Check if we need to recompile. If we do, try see if the is a cache entry first.
@@ -4111,6 +5210,12 @@ int main(int argc, char **argv)
kOCEntryWrite(pEntry);
kObjCacheUnlock(pCache);
kObjCacheDestroy(pCache);
+ if (fOptimizePreprocessorOutput)
+ {
+ InfoMsg(3, "g_cbMemMoved=%#x (%d)\n", g_cbMemMoved, g_cbMemMoved);
+ InfoMsg(3, "g_cMemMoves=%#x (%d)\n", g_cMemMoves, g_cMemMoves);
+ }
+
return 0;
}