Changeset 393 in kBuild
- Timestamp:
- Jan 13, 2006 12:42:10 AM (19 years ago)
- Location:
- trunk
- Files:
-
- 7 added
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/ChangeLog
r392 r393 2 2 3 3 2006-01-12: bird 4 - src/kDepIDB/kDepIDB.c: 5 o Initial coding. (This is a VC++ dependency extractor.) 6 - src/kDepPre/kDepPre.c, src/lib/kDep.h, src/lib/kDep.c, Config.kmk: 7 o Created a library for the dep*() functions. 8 o Removed the IDB hacks from kDepPre. 9 10 2006-01-11: bird 4 11 - kBuild/tools/vcc70.kmk: 5 12 o Prepared for new IDB based dependencies.s -
trunk/Config.kmk
r298 r393 45 45 TEMPLATE_BIN_INCS = \ 46 46 . \ 47 $(PATH_ROOT)/src/lib \ 47 48 $(PATH_ROOT)/src/gmake/w32/include \ 48 49 $(PATH_ROOT)/src/gmake/glob \ … … 75 76 76 77 78 79 # 80 # Template for building libraries for the tools. 81 # 82 TEMPLATE_LIB = Library for Commandline binary 83 84 TEMPLATE_LIB_TOOL = $(TEMPLATE_BIN_TOOL) 85 TEMPLATE_LIB_INST = lib/ 86 TEMPLATE_LIB_INCS = $(TEMPLATE_BIN_INCS) 87 TEMPLATE_LIB_INCS.$(BUILD_TYPE) = $(TEMPLATE_BIN_INCS.$(BUILD_TYPE)) 88 TEMPLATE_LIB_DEFS = $(TEMPLATE_BIN_DEFS) 89 TEMPLATE_LIB_DEFS.$(BUILD_TYPE) = $(TEMPLATE_BIN_DEFS.$(BUILD_TYPE)) 90 TEMPLATE_LIB_CFLAGS = $(TEMPLATE_BIN_CFLAGS) 91 TEMPLATE_LIB_CFLAGS.$(BUILD_TYPE) = $(TEMPLATE_BIN_CFLAGS.$(BUILD_TYPE)) 92 TEMPLATE_LIB_CXXFLAGS = $(TEMPLATE_BIN_CXXFLAGS) 93 TEMPLATE_LIB_CXXFLAGS.$(BUILD_TYPE) = $(TEMPLATE_BIN_CXXFLAGS.$(BUILD_TYPE)) 94 95 LIB_KDEP = $(PATH_OUT)/$(TEMPLATE_LIB_INST)$(TOOL_$(TEMPLATE_LIB_TOOL)_ARLIBPREF)kDep$$(TOOL_$(TEMPLATE_LIB_TOOL)_ARLIBSUFF) 96 -
trunk/src/kDepPre/Makefile.kmk
r304 r393 28 28 29 29 kDepPre_TEMPLATE = BIN 30 kDepPre_LIBS = $(LIB_KDEP) 30 31 kDepPre_DEFS.linux = HAVE_FGETC_UNLOCKED=1 31 32 kDepPre_DEFS.win32 = NEED_ISBLANK=1 __WIN32__=1 -
trunk/src/kDepPre/kDepPre.c
r384 r393 4 4 * kDepPre - Dependency Generator using Precompiler output. 5 5 * 6 * Copyright (c) 2005 knut st. osmundsen <[email protected]>6 * Copyright (c) 2005-2006 knut st. osmundsen <[email protected]> 7 7 * 8 8 * … … 26 26 27 27 28 /******************************************************************************* 29 * Header Files * 30 *******************************************************************************/ 28 31 #include <stdio.h> 29 #include <stdlib.h>30 32 #include <string.h> 31 #include <errno.h>32 33 #include <ctype.h> 33 #include <limits.h> 34 #include <sys/stat.h> 35 #ifdef __WIN32__ 36 # include <windows.h> 37 #endif 38 #if !defined(__WIN32__) && !defined(__OS2__) 39 # include <dirent.h> 40 #endif 41 #ifndef __WIN32__ 42 # include <unistd.h> 43 #endif 34 #include "kDep.h" 44 35 45 36 #ifdef HAVE_FGETC_UNLOCKED … … 54 45 55 46 56 57 58 /*******************************************************************************59 * Structures and Typedefs *60 *******************************************************************************/61 /** A dependency. */62 typedef struct DEP63 {64 /** Next dependency in the list. */65 struct DEP *pNext;66 /** The filename hash. */67 unsigned uHash;68 /** The length of the filename. */69 size_t cchFilename;70 /** The filename. */71 char szFilename[4];72 } DEP, *PDEP;73 74 75 /*******************************************************************************76 * Global Variables *77 *******************************************************************************/78 /** List of dependencies. */79 static PDEP g_pDeps = NULL;80 81 82 /*******************************************************************************83 * Internal Functions *84 *******************************************************************************/85 static PDEP depAdd(const char *pszFilename, size_t cchFilename);86 static void depOptimize(int fFixCase);87 static void depPrint(FILE *pOutput);88 static void depPrintStubs(FILE *pOutput);89 90 91 #ifdef __WIN32__92 /**93 * Corrects the case of a path.94 * Expects a fullpath!95 *96 * @param pszPath Pointer to the path, both input and output.97 * The buffer must be able to hold one more byte than the string length.98 */99 void fixcase(char *pszPath)100 {101 #define my_assert(expr) \102 do { \103 if (!(expr)) { \104 printf("my_assert: %s, file %s, line %d\npszPath=%s\npsz=%s\n", \105 #expr, __FILE__, __LINE__, pszPath, psz); \106 __asm { __asm int 3 } \107 exit(1); \108 } \109 } while (0)110 111 char *psz = pszPath;112 if (*psz == '/' || *psz == '\\')113 {114 if (psz[1] == '/' || psz[1] == '\\')115 {116 /* UNC */117 my_assert(psz[1] == '/' || psz[1] == '\\');118 my_assert(psz[2] != '/' && psz[2] != '\\');119 120 /* skip server name */121 psz += 2;122 while (*psz != '\\' && *psz != '/')123 {124 if (!*psz)125 return;126 *psz++ = toupper(*psz);127 }128 129 /* skip the share name */130 psz++;131 my_assert(*psz != '/' && *psz != '\\');132 while (*psz != '\\' && *psz != '/')133 {134 if (!*psz)135 return;136 *psz++ = toupper(*psz);137 }138 my_assert(*psz == '/' || *psz == '\\');139 psz++;140 }141 else142 {143 /* Unix spec */144 psz++;145 }146 }147 else148 {149 /* Drive letter */150 my_assert(psz[1] == ':');151 *psz = toupper(*psz);152 my_assert(psz[0] >= 'A' && psz[0] <= 'Z');153 my_assert(psz[2] == '/' || psz[2] == '\\');154 psz += 3;155 }156 157 /*158 * Pointing to the first char after the unc or drive specifier.159 */160 while (*psz)161 {162 WIN32_FIND_DATA FindFileData;163 HANDLE hDir;164 char chSaved0;165 char chSaved1;166 char *pszEnd;167 168 169 /* find the end of the component. */170 pszEnd = psz;171 while (*pszEnd && *pszEnd != '/' && *pszEnd != '\\')172 pszEnd++;173 174 /* replace the end with "?\0" */175 chSaved0 = pszEnd[0];176 chSaved1 = pszEnd[1];177 pszEnd[0] = '?';178 pszEnd[1] = '\0';179 180 /* find the right filename. */181 hDir = FindFirstFile(pszPath, &FindFileData);182 pszEnd[1] = chSaved1;183 if (!hDir)184 {185 pszEnd[0] = chSaved0;186 return;187 }188 pszEnd[0] = '\0';189 while (stricmp(FindFileData.cFileName, psz))190 {191 if (!FindNextFile(hDir, &FindFileData))192 {193 pszEnd[0] = chSaved0;194 return;195 }196 }197 strcpy(psz, FindFileData.cFileName);198 pszEnd[0] = chSaved0;199 200 /* advance to the next component */201 if (!chSaved0)202 return;203 psz = pszEnd + 1;204 my_assert(*psz != '/' && *psz != '\\');205 }206 #undef my_assert207 }208 209 /**210 * Corrects all slashes to unix slashes.211 *212 * @returns pszFilename.213 * @param pszFilename The filename to correct.214 */215 char *fixslash(char *pszFilename)216 {217 char *psz = pszFilename;218 while ((psz = strchr(psz, '\\')) != NULL)219 *psz++ = '/';220 return pszFilename;221 }222 223 #elif defined(__OS2__)224 225 /**226 * Corrects the case of a path.227 *228 * @param pszPath Pointer to the path, both input and output.229 * The buffer must be able to hold one more byte than the string length.230 */231 void fixcase(char *pszFilename)232 {233 return;234 }235 236 #else237 238 /**239 * Corrects the case of a path.240 *241 * @param pszPath Pointer to the path, both input and output.242 */243 void fixcase(char *pszFilename)244 {245 char *psz;246 247 /*248 * Skip the root.249 */250 psz = pszFilename;251 while (*psz == '/')252 psz++;253 254 /*255 * Iterate all the components.256 */257 while (*psz)258 {259 char chSlash;260 struct stat s;261 char *pszStart = psz;262 263 /*264 * Find the next slash (or end of string) and terminate the string there.265 */266 while (*psz != '/' && *psz)267 *psz++;268 chSlash = *psz;269 *psz = '\0';270 271 /*272 * Does this part exist?273 * If not we'll enumerate the directory and search for an case-insensitive match.274 */275 if (stat(pszFilename, &s))276 {277 struct dirent *pEntry;278 DIR *pDir;279 if (pszStart == pszFilename)280 pDir = opendir(*pszFilename ? pszFilename : ".");281 else282 {283 pszStart[-1] = '\0';284 pDir = opendir(pszFilename);285 pszStart[-1] = '/';286 }287 if (!pDir)288 {289 *psz = chSlash;290 break; /* giving up, if we fail to open the directory. */291 }292 293 while ((pEntry = readdir(pDir)) != NULL)294 {295 if (!strcasecmp(pEntry->d_name, pszStart))296 {297 strcpy(pszStart, pEntry->d_name);298 break;299 }300 }301 closedir(pDir);302 if (!pEntry)303 {304 *psz = chSlash;305 break; /* giving up if not found. */306 }307 }308 309 /* restore the slash and press on. */310 *psz = chSlash;311 while (*psz == '/')312 psz++;313 }314 315 return;316 }317 318 319 #endif320 321 322 /**323 * 'Optimizes' and corrects the dependencies.324 */325 static void depOptimize(int fFixCase)326 {327 /*328 * Walk the list correct the names and re-insert them.329 */330 PDEP pDepOrg = g_pDeps;331 PDEP pDep = g_pDeps;332 g_pDeps = NULL;333 for (; pDep; pDep = pDep->pNext)334 {335 #ifdef __WIN32__336 char szFilename[_MAX_PATH + 1];337 #else338 char szFilename[PATH_MAX + 1];339 #endif340 char *pszFilename;341 struct stat s;342 343 /*344 * Skip some fictive names like <built-in> and <command line>.345 */346 if ( pDep->szFilename[0] == '<'347 && pDep->szFilename[pDep->cchFilename - 1] == '>')348 continue;349 pszFilename = pDep->szFilename;350 351 #if !defined(__OS2__) && !defined(__WIN32__)352 /*353 * Skip any drive letters from compilers running in wine.354 */355 if (pszFilename[1] == ':')356 pszFilename += 2;357 #endif358 359 /*360 * The microsoft compilers are notoriously screwing up the casing.361 * This will screw up kmk (/ GNU Make).362 */363 if (fFixCase)364 {365 #ifdef __WIN32__366 if (_fullpath(szFilename, pszFilename, sizeof(szFilename)))367 fixslash(szFilename);368 else369 #endif370 strcpy(szFilename, pszFilename);371 fixcase(szFilename);372 pszFilename = szFilename;373 }374 375 /*376 * Check that the file exists before we start depending on it.377 */378 if (stat(pszFilename, &s))379 {380 fprintf(stderr, "kDepPre: Skipping '%s' - %s!\n", szFilename, strerror(errno));381 continue;382 }383 384 /*385 * Insert the corrected dependency.386 */387 depAdd(pszFilename, strlen(pszFilename));388 }389 390 #if 0 /* waste of time */391 /*392 * Free the old ones.393 */394 while (pDepOrg)395 {396 pDep = pDepOrg;397 pDepOrg = pDepOrg->pNext;398 free(pDep);399 }400 #endif401 }402 403 404 /**405 * Prints the dependency chain.406 *407 * @returns Pointer to the allocated dependency.408 * @param pOutput Output stream.409 */410 static void depPrint(FILE *pOutput)411 {412 PDEP pDep;413 for (pDep = g_pDeps; pDep; pDep = pDep->pNext)414 fprintf(pOutput, " \\\n\t%s", pDep->szFilename);415 fprintf(pOutput, "\n\n");416 }417 418 419 /**420 * Prints empty dependency stubs for all dependencies.421 */422 static void depPrintStubs(FILE *pOutput)423 {424 PDEP pDep;425 for (pDep = g_pDeps; pDep; pDep = pDep->pNext)426 fprintf(pOutput, "%s:\n\n", pDep->szFilename);427 }428 429 430 /* sdbm:431 This algorithm was created for sdbm (a public-domain reimplementation of432 ndbm) database library. it was found to do well in scrambling bits,433 causing better distribution of the keys and fewer splits. it also happens434 to be a good general hashing function with good distribution. the actual435 function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below436 is the faster version used in gawk. [there is even a faster, duff-device437 version] the magic constant 65599 was picked out of thin air while438 experimenting with different constants, and turns out to be a prime.439 this is one of the algorithms used in berkeley db (see sleepycat) and440 elsewhere. */441 static unsigned sdbm(const char *str)442 {443 unsigned hash = 0;444 int c;445 446 while ((c = *(unsigned const char *)str++))447 hash = c + (hash << 6) + (hash << 16) - hash;448 449 return hash;450 }451 452 453 /**454 * Adds a dependency.455 *456 * @returns Pointer to the allocated dependency.457 * @param pszFilename The filename.458 * @param cchFilename The length of the filename.459 */460 static PDEP depAdd(const char *pszFilename, size_t cchFilename)461 {462 unsigned uHash = sdbm(pszFilename);463 PDEP pDep;464 PDEP pDepPrev;465 466 /*467 * Check if we've already got this one.468 */469 pDepPrev = NULL;470 for (pDep = g_pDeps; pDep; pDepPrev = pDep, pDep = pDep->pNext)471 if ( pDep->uHash == uHash472 && pDep->cchFilename == cchFilename473 && !memcmp(pDep->szFilename, pszFilename, cchFilename))474 return pDep;475 476 /*477 * Add it.478 */479 pDep = (PDEP)malloc(sizeof(*pDep) + cchFilename);480 if (!pDep)481 {482 fprintf(stderr, "\nOut of memory! (requested %#x bytes)\n\n", sizeof(*pDep) + cchFilename);483 exit(1);484 }485 486 pDep->cchFilename = cchFilename;487 memcpy(pDep->szFilename, pszFilename, cchFilename + 1);488 pDep->uHash = uHash;489 490 if (pDepPrev)491 {492 pDep->pNext = pDepPrev->pNext;493 pDepPrev->pNext = pDep;494 }495 else496 {497 pDep->pNext = g_pDeps;498 g_pDeps = pDep;499 }500 return pDep;501 }502 47 503 48 … … 662 207 663 208 664 /**665 * Make an attempt at parsing a Visual C++ IDB file.666 */667 static int ParseVCxxIDB(FILE *pInput, const char *argv0)668 {669 char *pbFile;670 long cbFile;671 int rc = 0;672 673 /*674 * Figure out file size.675 */676 if ( fseek(pInput, 0, SEEK_END) < 0677 || (cbFile = ftell(pInput)) < 0678 || fseek(pInput, 0, SEEK_SET))679 {680 fprintf(stderr, "%s: error: Failed to determin file size of the Visual C++ IDB file.\n", argv0);681 return -1;682 }683 684 /*685 * Allocate memory and read the file.686 */687 pbFile = (char *)malloc(cbFile + 1);688 if (!pbFile)689 {690 fprintf(stderr, "%s: error: Failed to allocate %ld bytes of memory for the Visual C++ IDB file.\n", argv0, cbFile);691 return -1;692 }693 if (fread(pbFile, cbFile, 1, pInput))694 {695 const char *pszPrefix = NULL;696 int cchPrefix = 0;697 pbFile[cbFile] = '\0';698 699 /*700 * Check the header.701 */702 if (!strncmp(pbFile, "Microsoft C/C++ MSF 7.", sizeof("Microsoft C/C++ MSF 7.") - 1))703 {704 pszPrefix = "/mr/inversedeps/";705 cchPrefix = sizeof("/mr/inversedeps/") - 1;706 }707 else if (!strncmp(pbFile, "Microsoft C/C++ program database 2.", sizeof("Microsoft C/C++ program database 2.") - 1))708 {709 pszPrefix = "/ipm/header/";710 cchPrefix = sizeof("/ipm/header/") - 1;711 }712 if (pszPrefix)713 {714 /*715 * Do a brute force scan of the file until we encounter "\0/mr/inversedeps/" (which is the716 * vc70 and vc80 prefix) or "\0/ipm/header/" (which is the vc60 prefix).717 * (This is highly experimental and I've no idea about the actual format of the file.)718 */719 char *pb = pbFile;720 long cbLeft = cbFile;721 while (cbLeft > cchPrefix + 3)722 {723 /** @todo use memchr? */724 if ( *pb != *pszPrefix725 || strncmp(pb, pszPrefix, cchPrefix))726 {727 pb++;728 cbLeft--;729 }730 else731 {732 const char *psz = &pb[cchPrefix];733 size_t cch = strlen(psz);734 depAdd(psz, cch);735 //printf("dep='%s'\n", psz);736 pb += cch + cchPrefix;737 cbLeft -= cch + cchPrefix;738 }739 }740 }741 else742 {743 fprintf(stderr, "%s: error: Doesn't recognize the header of the Visual C++ IDB file.\n", argv0, cbFile);744 rc = 1;745 }746 }747 else748 {749 fprintf(stderr, "%s: error: Failed to allocate %ld bytes of memory for the Visual C++ IDB file.\n", argv0, cbFile);750 rc = 1;751 }752 753 return rc;754 }755 756 757 209 static void usage(const char *argv0) 758 210 { 759 printf("syntax: %s [-l=c] -o <output> -t <target> [-f] [-s] < - | <filename> | -e <cmdline> | -i <vc idb-file>>\n", argv0);211 printf("syntax: %s [-l=c] -o <output> -t <target> [-f] [-s] < - | <filename> | -e <cmdline> >\n", argv0); 760 212 } 761 213 … … 775 227 /* Argument parsing. */ 776 228 int fInput = 0; /* set when we've found input argument. */ 777 int fIDBMode = 0;778 229 779 230 /* … … 886 337 pInput = stdin; 887 338 fInput = 1; 888 break;889 }890 891 /*892 * IDB input.893 */894 case 'i':895 {896 if (++i >= argc)897 {898 fprintf(stderr, "%s: syntax error: The '-i' argument is missing IDB filename.\n", argv[0]);899 return 1;900 }901 pInput = fopen(argv[i], "rb");902 if (!pInput)903 {904 fprintf(stderr, "%s: error: Failed to open input file '%s'.\n", argv[0], argv[i]);905 return 1;906 }907 fInput = 1;908 fIDBMode = 1;909 339 break; 910 340 } … … 993 423 * Do the parsing. 994 424 */ 995 if (!fIDBMode) 996 i = ParseCPrecompiler(pInput); 997 else 998 i = ParseVCxxIDB(pInput, argv[0]); 425 i = ParseCPrecompiler(pInput); 999 426 1000 427 /* … … 1035 462 return i; 1036 463 } 464
Note:
See TracChangeset
for help on using the changeset viewer.