Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3473 lines
115 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1989 - 1994.
  5. //
  6. // File: buildmak.c
  7. //
  8. // Contents: This is the Make module for the NT Build Tool (BUILD.EXE)
  9. //
  10. // The Make module scans directories for file names and edits the
  11. // data base appropriately.
  12. //
  13. // Functions:
  14. //
  15. // History: 16-May-89 SteveWo Created
  16. // ... See SLM log
  17. // 26-Jul-94 LyleC Cleanup/Add Pass0 support
  18. //
  19. //----------------------------------------------------------------------------
  20. #include "build.h"
  21. #define SCANFLAGS_CHICAGO 0x00000002
  22. #define SCANFLAGS_OS2 0x00000004
  23. #define SCANFLAGS_POSIX 0x00000008
  24. #define SCANFLAGS_CRT 0x00000010
  25. ULONG ScanFlagsLast;
  26. ULONG ScanFlagsCurrent;
  27. USHORT GlobalSequence;
  28. USHORT LocalSequence;
  29. ULONG idFileToCompile = 1;
  30. BOOL fLineCleared = TRUE;
  31. char szRecurse[] = " . . . . . . . . .";
  32. char szAsterisks[] = " ********************";
  33. char *pszSdkLibDest;
  34. char *pszDdkLibDest;
  35. char *pszIncOak;
  36. char *pszIncDdk;
  37. char *pszIncWdm;
  38. char *pszIncSdk;
  39. char *pszIncCrt;
  40. char *pszIncMfc;
  41. char *pszIncOs2;
  42. char *pszIncPosix;
  43. char *pszIncChicago;
  44. char szCheckedAltDir[] = " CHECKED_ALT_DIR=1";
  45. #ifndef ARRAY_SIZE
  46. #define ARRAY_SIZE(array, type) (sizeof(array)/sizeof(type))
  47. #endif
  48. //
  49. // The following definitions are for the ObjectDirFlag entry in the TARGETDATA
  50. // struct.
  51. //
  52. //
  53. // TD_OBJECTDIR maps to ObjectDirectory[iObjectDir]\foobar.tar
  54. // TD_PASS0HDRDIR maps to $(PASS0_HEADERDIR)\foobar.tar
  55. // TD_PASS0DIR1 maps to $(PASS0_SOURCEDIR)\foobar.tar or $(PASS0_CLIENTDIR)\foobar.tar
  56. // TD_PASS0DIR2 maps to $(MIDL_UUIDDIR)\foobar.tar or $(PASS0_SERVERDIR)\foobar.tar
  57. //
  58. // where .tar is the given target extension, ObjectDirectory[iObjectDir] is the
  59. // appropriate object directory for that platform, and the macros are expanded
  60. // to the values given in the sources file.
  61. //
  62. #define TD_OBJECTDIR 1
  63. #define TD_PASS0HDRDIR 2
  64. #define TD_PASS0DIR1 3
  65. #define TD_PASS0DIR2 4
  66. #define TD_MCSOURCEDIR 5
  67. typedef struct _tagTARGETDATA
  68. {
  69. UCHAR ObjectDirFlag; // Indicates what object dir should be used.
  70. LPSTR pszTargetExt; // Extension of target. (Including '.')
  71. } TARGETDATA, *LPTARGETDATA;
  72. typedef struct _tagOBJECTTARGETINFO
  73. {
  74. LPSTR pszSourceExt; // Extension of source file (including '.').
  75. UCHAR NumData; // Number of entries in [Data].
  76. LPTARGETDATA Data; // Pointer to array of TARGETDATAs.
  77. } OBJECTTARGETINFO, *LPOBJECTTARGETINFO;
  78. typedef struct _tagOBJECTTARGETARRAY
  79. {
  80. int cTargetInfo;
  81. OBJECTTARGETINFO **aTargetInfo;
  82. } OBJECTTARGETARRAY;
  83. //
  84. // TARGETDATA information is used by both BuildCompileTarget() and
  85. // WriteObjectsDefinition() via the GetTargetData() function. Do not put
  86. // extensions in this table whose TARGETDATA consists entirely of
  87. // { TD_OBJECTDIR, ".obj" } because that is the default. Instead you must
  88. // modify the switch statement in WriteObjectsDefinition.
  89. //
  90. // The first target in each TARGETDATA array is considered the 'rule target'
  91. // because that is the target for which the inference rule in makefile.def is
  92. // written. The 'rule target' will always be deleted in addition to the
  93. // out-of-date target if *any* of the targets are out of date.
  94. //
  95. //
  96. // The following data defines the *PASS0* mappings of source extensions
  97. // to target files:
  98. //
  99. // .idl -> $(PASS0_HEADERDIR)\.h,
  100. // $(PASS0_SOURCEDIR)\_p.c,
  101. // $(MIDL_UUIDDIR)\_i.c
  102. // .asn -> $(PASS0_HEADERDIR)\.h,
  103. // $(PASS0_HEADERDIR)\.c
  104. // .mc -> $(PASS0_HEADERDIR)\.h, $(PASS0_SOURCEDIR)\.rc
  105. // .odl -> obj\*\.tlb
  106. // .tdl -> obj\*\.tlb
  107. //
  108. // .mc -> $(PASS0_HEADERDIR)\.h, $(PASS0_HEADERDIR)\.rc
  109. TARGETDATA MCData0[] = {
  110. { TD_PASS0HDRDIR, ".h" },
  111. { TD_MCSOURCEDIR, ".rc" }
  112. };
  113. OBJECTTARGETINFO MCInfo0 = { ".mc", ARRAY_SIZE(MCData0, TARGETDATA), MCData0 };
  114. // .asn -> $(PASS0_HEADERDIR)\.h, $(PASS0_SOURCEDIR)\.c
  115. TARGETDATA AsnData0[] = {
  116. { TD_PASS0HDRDIR, ".h" },
  117. { TD_PASS0DIR1, ".c" },
  118. };
  119. OBJECTTARGETINFO AsnInfo0 =
  120. { ".asn", ARRAY_SIZE(AsnData0, TARGETDATA), AsnData0 };
  121. // .odl/.tdl -> obj\*\.tlb
  122. TARGETDATA TLBData0 = { TD_OBJECTDIR, ".tlb" };
  123. OBJECTTARGETINFO TLBInfo0 =
  124. { ".tdl", ARRAY_SIZE(TLBData0, TARGETDATA), &TLBData0 };
  125. OBJECTTARGETINFO TLB2Info0 =
  126. { ".odl", ARRAY_SIZE(TLBData0, TARGETDATA), &TLBData0 };
  127. // .thk -> obj\*\.asm
  128. TARGETDATA THKData0 = { TD_OBJECTDIR, ".asm" };
  129. OBJECTTARGETINFO THKInfo0 =
  130. { ".thk", ARRAY_SIZE(THKData0, TARGETDATA), &THKData0 };
  131. // .mof -> obj\*\.mof, obj\*\.bmf
  132. TARGETDATA MOFData0[] = {
  133. {TD_OBJECTDIR, ".mof" },
  134. {TD_OBJECTDIR, ".bmf" }
  135. };
  136. OBJECTTARGETINFO MOFInfo0 = { ".mof", ARRAY_SIZE(MOFData0, TARGETDATA),
  137. MOFData0 };
  138. // ------
  139. LPOBJECTTARGETINFO aTargetInfo0[] = {
  140. &MCInfo0,
  141. &AsnInfo0,
  142. &TLBInfo0,
  143. &TLB2Info0,
  144. &THKInfo0,
  145. &MOFInfo0,
  146. };
  147. #define CTARGETINFO0 ARRAY_SIZE(aTargetInfo0, LPOBJECTTARGETINFO)
  148. //
  149. // The following data defines the *PASS1* mappings of source extensions
  150. // to target files:
  151. //
  152. // .rc -> obj\*\.res
  153. // .asn -> obj\*\.obj
  154. // .thk -> obj\*\.asm,
  155. // .java -> obj\*\.class,
  156. // obj\*\.obj,
  157. //
  158. // .rc -> obj\*\.res
  159. TARGETDATA RCData1 = { TD_OBJECTDIR, ".res" };
  160. OBJECTTARGETINFO RCInfo1 = { ".rc", ARRAY_SIZE(RCData1, TARGETDATA), &RCData1 };
  161. // .thk -> .asm -> .obj
  162. TARGETDATA THKData1[] = {
  163. {TD_OBJECTDIR, ".obj" }
  164. };
  165. OBJECTTARGETINFO THKInfo1 =
  166. { ".thk", ARRAY_SIZE(THKData1, TARGETDATA), THKData1 };
  167. // .java -> .class
  168. TARGETDATA JAVAData1[] = {
  169. {TD_OBJECTDIR, ".class" }
  170. };
  171. OBJECTTARGETINFO JAVAInfo1 =
  172. { ".java", ARRAY_SIZE(JAVAData1, TARGETDATA), JAVAData1 };
  173. // ------
  174. LPOBJECTTARGETINFO aTargetInfo1[] = {
  175. &RCInfo1,
  176. &THKInfo1,
  177. &JAVAInfo1,
  178. };
  179. #define CTARGETINFO1 ARRAY_SIZE(aTargetInfo1, LPOBJECTTARGETINFO)
  180. OBJECTTARGETARRAY aTargetArray[] = {
  181. { CTARGETINFO0, aTargetInfo0 },
  182. { CTARGETINFO1, aTargetInfo1 },
  183. };
  184. // ------
  185. // MIDL stuff -- IDL files have two potential sets of targets, depending
  186. // on if the IDL_TYPE flag was set to 'ole' in the sources file or not.
  187. //
  188. // IDL_TYPE = ole
  189. // .idl -> $(PASS0_HEADERDIR)\.h,
  190. // $(PASS0_SOURCEDIR)\_p.c,
  191. // $(MIDL_UUIDDIR)\_i.c
  192. TARGETDATA IDLDataOle0[] = {
  193. { TD_PASS0HDRDIR, ".h" }, // Header File
  194. // { TD_PASS0DIR1, "_p.c" }, // Proxy Stub File
  195. // { TD_PASS0DIR2, "_i.c" }, // UUID file
  196. };
  197. OBJECTTARGETINFO IDLInfoOle0 =
  198. { ".idl", ARRAY_SIZE(IDLDataOle0, TARGETDATA), IDLDataOle0 };
  199. // IDL_TYPE = rpc
  200. // .idl -> $(PASS0_HEADERDIR)\.h,
  201. // $(PASS0_CLIENTDIR)\_c.c,
  202. // $(PASS0_SERVERDIR)\_s.c,
  203. TARGETDATA IDLDataRpc0[] = {
  204. { TD_PASS0HDRDIR, ".h" }, // Header File
  205. // { TD_PASS0DIR1, "_c.c" }, // Client Stub File
  206. // { TD_PASS0DIR2, "_s.c" }, // Server Stub File
  207. };
  208. OBJECTTARGETINFO IDLInfoRpc0 =
  209. { ".idl", ARRAY_SIZE(IDLDataRpc0, TARGETDATA), IDLDataRpc0 };
  210. // ------
  211. LPOBJECTTARGETINFO aMidlTargetInfo0[] = {
  212. &IDLInfoOle0,
  213. &IDLInfoRpc0,
  214. };
  215. UCHAR cMidlTargetInfo0 = ARRAY_SIZE(aMidlTargetInfo0, LPOBJECTTARGETINFO);
  216. // ------
  217. //
  218. // Any extension not given in the above table is assumed to have a target in
  219. // the ObjectDirectory[iObjectDir] (obj\*) & have a target extension of .obj.
  220. //
  221. TARGETDATA DefaultData = { TD_OBJECTDIR, ".obj" };
  222. //*******
  223. TARGET *
  224. BuildCompileTarget(
  225. FILEREC *pfr,
  226. LPSTR pszfile,
  227. USHORT TargetIndex,
  228. LPSTR pszConditionalIncludes,
  229. DIRREC *pdrBuild,
  230. DIRSUP *pdsBuild,
  231. LONG iPass,
  232. LPSTR *ppszObjectDir,
  233. LPSTR pszSourceDir);
  234. //+---------------------------------------------------------------------------
  235. //
  236. // Function: ExpandObjAsterisk
  237. //
  238. // Synopsis: Expand an asterisk in a filename to a platform name
  239. //
  240. // Arguments: [pbuf] -- Output buffer for new filename
  241. // [pszpath] -- Input filename w/ asterisk
  242. // [ppszObjectDirectory] -- String[2] to replace asterisk with
  243. //
  244. //----------------------------------------------------------------------------
  245. VOID
  246. ExpandObjAsterisk(
  247. LPSTR pbuf,
  248. LPSTR pszpath,
  249. LPSTR *ppszObjectDirectory)
  250. {
  251. SplitToken(pbuf, '*', &pszpath);
  252. if (*pszpath == '*') {
  253. assert(strncmp(
  254. pszObjDirSlash,
  255. ppszObjectDirectory[iObjectDir],
  256. strlen(pszObjDirSlash)) == 0);
  257. strcat(pbuf, ppszObjectDirectory[iObjectDir] + strlen(pszObjDirSlash));
  258. strcat(pbuf, pszpath + 1);
  259. }
  260. }
  261. //+---------------------------------------------------------------------------
  262. //
  263. // Function: CountSourceLines
  264. //
  265. // Synopsis: Counts the source lines in a given file, including headers if
  266. // the '-S' option was given.
  267. //
  268. // Arguments: [idScan] -- Used to catch multiple inclusions
  269. // [pfr] -- File to scan
  270. //
  271. // Returns: Number of lines
  272. //
  273. //----------------------------------------------------------------------------
  274. LONG
  275. CountSourceLines(USHORT idScan, FILEREC *pfr)
  276. {
  277. INCLUDEREC *pir;
  278. AssertFile(pfr);
  279. // if we have already seen this file before, then assume
  280. // that #if guards prevent it's inclusion
  281. if (pfr->idScan == idScan) {
  282. return(0L);
  283. }
  284. pfr->idScan = idScan;
  285. // Start off with the file itself
  286. pfr->TotalSourceLines = pfr->SourceLines;
  287. if (fStatusTree) {
  288. //
  289. // If the user asked for include file line counts, then walk include
  290. // tree, accruing nested include file line counts .
  291. //
  292. for (pir = pfr->IncludeFilesTree; pir != NULL; pir = pir->NextTree) {
  293. AssertInclude(pir);
  294. if (pir->pfrInclude != NULL) {
  295. AssertFile(pir->pfrInclude);
  296. pfr->TotalSourceLines +=
  297. CountSourceLines(idScan, pir->pfrInclude);
  298. }
  299. }
  300. }
  301. return(pfr->TotalSourceLines);
  302. }
  303. //+---------------------------------------------------------------------------
  304. //
  305. // Function: CleanNTTargetFile0
  306. //
  307. // Synopsis: Parses pzFiles and deletes all files listed.
  308. // pzFile must have been allocated by MakeMacroString.
  309. // No asterisk expansion performed.
  310. //
  311. // This is used when fClean is TRUE and SOURCES_OPTIONS
  312. // includes -c0. See ReadSourcesFile. Note that
  313. // SOURCES_OPTIONS must be defined before NTTARGETFILE0.
  314. // This is a mechanism to delete target files not
  315. // included in _objects.mac.
  316. //
  317. // Arguments: [pzFiles] -- List of files
  318. //
  319. //----------------------------------------------------------------------------
  320. VOID
  321. CleanNTTargetFile0 (char * pzFiles)
  322. {
  323. BOOL fRestoreSep;
  324. char * pzDelete;
  325. while (*pzFiles != '\0') {
  326. pzDelete = pzFiles;
  327. // Find end of the next file name and NULL terminate it (if needed)
  328. fRestoreSep = FALSE;
  329. while (*pzFiles != '\0') {
  330. if (*pzFiles == ' ') {
  331. fRestoreSep = TRUE;
  332. *pzFiles = '\0';
  333. break;
  334. } else {
  335. pzFiles++;
  336. }
  337. }
  338. DeleteSingleFile (NULL, pzDelete, FALSE);
  339. if (fRestoreSep) {
  340. *pzFiles++ = ' ';
  341. }
  342. }
  343. }
  344. //+---------------------------------------------------------------------------
  345. //
  346. // Function: ProcessSourceDependencies
  347. //
  348. // Synopsis: Scan all source files in a given directory tree to determine
  349. // which files are out of date and need to be compiled and/or
  350. // linked.
  351. //
  352. // Arguments: [DirDB] -- Directory to process
  353. // [pds] -- Supplementary directory information
  354. // [DateTimeSources] -- Timestamp of 'sources' file
  355. //
  356. //----------------------------------------------------------------------------
  357. VOID
  358. ProcessSourceDependencies(DIRREC *DirDB, DIRSUP *pds, ULONG DateTimeSources)
  359. {
  360. TARGET *Target;
  361. ULONG DateTimePch = 0; // Actual timestamp of pch preserved here.
  362. UINT i;
  363. SOURCEREC *apsr[3];
  364. SOURCEREC **ppsr;
  365. char path[DB_MAX_PATH_LENGTH];
  366. static USHORT idScan = 0;
  367. AssertDir(DirDB);
  368. apsr[0] = pds->psrSourcesList[0];
  369. apsr[2] = NULL;
  370. //
  371. // For a clean build, just delete all targets
  372. //
  373. if (fFirstScan && fClean && !fKeep) {
  374. DeleteMultipleFiles("obj", "*.*"); // _objects.mac
  375. for (i = 0; i < CountTargetMachines; i++) {
  376. assert(strncmp(
  377. pszObjDirSlash,
  378. TargetMachines[i]->ObjectDirectory[iObjectDir],
  379. strlen(pszObjDirSlash)) == 0);
  380. DeleteMultipleFiles(TargetMachines[i]->ObjectDirectory[iObjectDir], "*.*");
  381. apsr[1] = pds->psrSourcesList[TargetToPossibleTarget[i] + 1];
  382. //
  383. // Delete the pch file if we have one.
  384. //
  385. if (pds->PchTarget != NULL)
  386. {
  387. char TargetDir[DB_MAX_PATH_LENGTH];
  388. ExpandObjAsterisk(TargetDir,
  389. pds->PchTargetDir,
  390. TargetMachines[i]->ObjectDirectory);
  391. //
  392. // Kind of a cludgy way to do this, but we must ensure that
  393. // we don't delete a pch file that was built earlier on during
  394. // this same build. We do this by comparing the timestamp of
  395. // the pch file against the time we started the build.
  396. //
  397. if ((*pDateTimeFile)(TargetDir, pds->PchTarget) <= BuildStartTime)
  398. {
  399. DeleteSingleFile(TargetDir, pds->PchTarget, FALSE);
  400. if (DirDB->PchObj != NULL) {
  401. ExpandObjAsterisk(path,
  402. DirDB->PchObj,
  403. TargetMachines[i]->ObjectDirectory);
  404. DeleteSingleFile(NULL, path, FALSE);
  405. } else {
  406. char *p;
  407. strcpy(path, pds->PchTarget);
  408. p = strrchr(path, '.');
  409. if (p != NULL && strcmp(p, ".pch") == 0) {
  410. strcpy(p, ".obj");
  411. DeleteSingleFile(TargetDir, path, FALSE);
  412. }
  413. }
  414. }
  415. }
  416. if (DirDB->DirFlags & DIRDB_PASS0) {
  417. for (ppsr = apsr; *ppsr != NULL; ppsr++) {
  418. SOURCEREC *psr;
  419. for (psr = *ppsr; psr != NULL; psr = psr->psrNext) {
  420. FILEREC *pfr;
  421. AssertSource(psr);
  422. pfr = psr->pfrSource;
  423. //
  424. // Pass Zero files have different target directories.
  425. //
  426. if (pfr->FileFlags & FILEDB_PASS0)
  427. {
  428. USHORT j;
  429. //
  430. // If the file has multiple targets, (e.g. .mc,
  431. // .idl or .asn), then loop through all targets.
  432. //
  433. j = 0;
  434. while (Target = BuildCompileTarget(
  435. pfr,
  436. pfr->Name,
  437. j,
  438. pds->ConditionalIncludes,
  439. DirDB,
  440. pds,
  441. 0, // pass 0
  442. TargetMachines[i]->ObjectDirectory,
  443. TargetMachines[i]->SourceDirectory)) {
  444. DeleteSingleFile(NULL, Target->Name, FALSE);
  445. FreeMem(&Target, MT_TARGET);
  446. j++;
  447. }
  448. }
  449. }
  450. }
  451. }
  452. if ((DirDB->DirFlags & DIRDB_TARGETFILE0) && (DirDB->NTTargetFile0 != NULL)) {
  453. CleanNTTargetFile0 (DirDB->NTTargetFile0);
  454. }
  455. }
  456. }
  457. if (fFirstScan && (DirDB->DirFlags & DIRDB_TARGETFILE0)) {
  458. DirDB->DirFlags |= DIRDB_PASS0NEEDED;
  459. }
  460. if (!fQuickZero || !fFirstScan || !RecurseLevel)
  461. {
  462. GenerateObjectsDotMac(DirDB, pds, DateTimeSources);
  463. }
  464. else if (fFirstScan)
  465. {
  466. SOURCEREC *psr;
  467. USHORT i;
  468. USHORT j;
  469. BOOL fNeedCompile = FALSE;
  470. if ( !(DirDB->DirFlags & DIRDB_PASS0NEEDED)) {
  471. for (i = 0; i < CountTargetMachines; i++) {
  472. for (psr = pds->psrSourcesList[0]; psr != NULL; psr = psr->psrNext) {
  473. FILEREC *pfr;
  474. AssertSource(psr);
  475. pfr = psr->pfrSource;
  476. AssertFile(pfr);
  477. if (pfr->FileFlags & FILEDB_PASS0)
  478. {
  479. for (j = 0;
  480. Target = BuildCompileTarget(
  481. pfr,
  482. pfr->Name,
  483. j,
  484. pds->ConditionalIncludes,
  485. DirDB,
  486. pds,
  487. 0,
  488. TargetMachines[i]->ObjectDirectory,
  489. TargetMachines[i]->SourceDirectory);
  490. j++) {
  491. if ((psr->SrcFlags & SOURCEDB_FILE_MISSING) ||
  492. (Target->DateTime == 0) ||
  493. ((pfr->FileFlags & FILEDB_C) && Target->DateTime < DateTimePch))
  494. {
  495. fNeedCompile = TRUE;
  496. }
  497. FreeMem(&Target, MT_TARGET);
  498. }
  499. if (fNeedCompile)
  500. {
  501. DirDB->DirFlags |= DIRDB_PASS0NEEDED;
  502. }
  503. }
  504. }
  505. }
  506. }
  507. if (DirDB->DirFlags & DIRDB_PASS0NEEDED)
  508. {
  509. GenerateObjectsDotMac(DirDB, pds, DateTimeSources);
  510. }
  511. }
  512. if ((DirDB->TargetExt != NULL) &&
  513. (DirDB->TargetName != NULL) &&
  514. (DirDB->TargetPath != NULL) &&
  515. (fClean && !fKeep))
  516. {
  517. // If we haven't already deleted the final target, do so now.
  518. if (_memicmp(DirDB->TargetPath, pszObjDirSlash, strlen(pszObjDirSlash) -1)) {
  519. for (i = 0; i < CountTargetMachines; i++) {
  520. FormatLinkTarget(
  521. path,
  522. TargetMachines[i]->ObjectDirectory,
  523. DirDB->TargetPath,
  524. DirDB->TargetName,
  525. DirDB->TargetExt);
  526. DeleteSingleFile(NULL, path, FALSE);
  527. FormatLinkTarget(
  528. path,
  529. TargetMachines[i]->ObjectDirectory,
  530. DirDB->TargetPath,
  531. DirDB->TargetName,
  532. ".pdb");
  533. DeleteSingleFile(NULL, path, FALSE);
  534. }
  535. }
  536. }
  537. if (pds->fNoTarget) {
  538. if (apsr[0] || !(DirDB->DirFlags & DIRDB_PASS0NEEDED) || fSemiQuicky) {
  539. // If there's sources to compile, mark as such then get out.
  540. DirDB->DirFlags |= DIRDB_COMPILENEEDED;
  541. }
  542. return;
  543. }
  544. if (fQuicky) {
  545. if (fSemiQuicky)
  546. DirDB->DirFlags |= DIRDB_COMPILENEEDED;
  547. else
  548. DirDB->DirFlags |= DIRDB_PASS0NEEDED;
  549. return;
  550. }
  551. //
  552. // For a DLL or LIB target, ensure that it will be rebuilt
  553. //
  554. if (DirDB->TargetPath != NULL &&
  555. DirDB->TargetName != NULL &&
  556. ((DirDB->DirFlags & DIRDB_DLLTARGET) ||
  557. (DirDB->TargetExt != NULL && strcmp(DirDB->TargetExt, ".lib") == 0))) {
  558. for (i = 0; i < CountTargetMachines; i++) {
  559. FormatLinkTarget(
  560. path,
  561. TargetMachines[i]->ObjectDirectory,
  562. DirDB->TargetPath,
  563. DirDB->TargetName,
  564. ".lib");
  565. if (ProbeFile(NULL, path) == -1) {
  566. DirDB->DirFlags |= DIRDB_COMPILENEEDED;
  567. }
  568. else
  569. if (fFirstScan && (fCleanLibs || (fClean && !fKeep))) {
  570. DeleteSingleFile(NULL, path, FALSE);
  571. DirDB->DirFlags |= DIRDB_COMPILENEEDED;
  572. }
  573. }
  574. }
  575. //
  576. // If the scan flags have changed (or haven't been set), then indicate
  577. // that we should look for the actual location of global included files
  578. // instead of assuming it's in the same location as we last knew. This is
  579. // because different directories my include the same file from different
  580. // places.
  581. //
  582. if (GlobalSequence == 0 ||
  583. ScanFlagsLast == 0 ||
  584. ScanFlagsLast != ScanFlagsCurrent) {
  585. GlobalSequence++; // don't reuse snapped global includes
  586. if (GlobalSequence == 0) {
  587. GlobalSequence++;
  588. }
  589. ScanFlagsLast = ScanFlagsCurrent;
  590. }
  591. //
  592. // Do the same as above for locally included files.
  593. //
  594. LocalSequence++; // don't reuse snapped local includes
  595. if (LocalSequence == 0) {
  596. LocalSequence++;
  597. }
  598. for (i = 0; i < CountTargetMachines; i++) {
  599. //
  600. // Ensure that precompiled headers are rebuilt as necessary.
  601. //
  602. if (!fPassZero && (pds->PchInclude != NULL || pds->PchTarget != NULL)) {
  603. LPSTR p;
  604. ExpandObjAsterisk(
  605. path,
  606. pds->PchTargetDir != NULL?
  607. pds->PchTargetDir : pszObjDirSlashStar,
  608. TargetMachines[i]->ObjectDirectory);
  609. if (!CanonicalizePathName(path, CANONICALIZE_DIR, path)) {
  610. DateTimePch = ULONG_MAX; // always out of date
  611. goto ProcessSourceList;
  612. }
  613. strcat(path, "\\");
  614. //
  615. // If they gave a target directory for the pch file, then use it,
  616. // otherwise assume it's in the same directory as the .h file.
  617. //
  618. if (pds->PchTarget != NULL) {
  619. strcat(path, pds->PchTarget);
  620. }
  621. else {
  622. assert(pds->PchInclude != NULL);
  623. p = path + strlen(path);
  624. if ( DirDB->Pch ) {
  625. strcpy(p, DirDB->Pch);
  626. } else {
  627. strcpy(p, pds->PchInclude);
  628. if ((p = strrchr(p, '.')) != NULL) {
  629. *p = '\0';
  630. }
  631. strcat(path, ".pch");
  632. }
  633. }
  634. //
  635. // 'path' now contains the (possibly relative) path name of
  636. // the PCH target: "..\path\foobar.pch"
  637. //
  638. Target = BuildCompileTarget(
  639. NULL,
  640. path,
  641. 0,
  642. pds->ConditionalIncludes,
  643. DirDB,
  644. NULL,
  645. 1, // pass 1
  646. TargetMachines[i]->ObjectDirectory,
  647. TargetMachines[i]->SourceDirectory);
  648. DateTimePch = Target->DateTime;
  649. if (DateTimePch == 0) { // Target doesn't exist
  650. DateTimePch = ULONG_MAX; // Always out of date
  651. }
  652. if (fClean && !fKeep && fFirstScan) {
  653. // Target will be deleted later if it exists.
  654. }
  655. else if (pds->PchInclude == NULL) {
  656. //
  657. // The SOURCES file didn't indicate where the source file
  658. // for the .pch is, so assume the .pch binary is up to date
  659. // with respect to the source includes and with respect to
  660. // the pch source file itself.
  661. //
  662. // char szFullPath[DB_MAX_PATH_LENGTH];
  663. // CanonicalizePathName(DirDB->Name, CANONICALIZE_DIR, szFullPath);
  664. //BuildMsg("SOURCES file in %s gives PRECOMPILED_TARGET but not "
  665. // "PRECOMPILED_INCLUDE.\n", szFullPath);
  666. Target->DateTime = 0; // Don't delete pch target
  667. }
  668. else {
  669. FILEREC *pfrPch = NULL;
  670. path[0] = '\0';
  671. if (pds->PchIncludeDir != NULL) {
  672. strcpy(path, pds->PchIncludeDir);
  673. strcat(path, "\\");
  674. }
  675. strcat(path, pds->PchInclude);
  676. if ((pds->PchIncludeDir != NULL) &&
  677. (IsFullPath(pds->PchIncludeDir))) {
  678. DIRREC *DirDBPch;
  679. DirDBPch = FindSourceDirDB(pds->PchIncludeDir,
  680. pds->PchInclude, TRUE);
  681. if (DirDBPch) {
  682. pfrPch = FindSourceFileDB(DirDBPch,
  683. pds->PchInclude,
  684. NULL);
  685. }
  686. }
  687. else {
  688. pfrPch = FindSourceFileDB(DirDB, path, NULL);
  689. }
  690. if (pfrPch != NULL) {
  691. FILEREC *pfrRoot;
  692. SOURCEREC *psr = NULL;
  693. BOOL fCase1;
  694. BOOL fCase2;
  695. BOOL fCase3;
  696. BOOL fNeedCompile;
  697. BOOL fCheckDepends;
  698. // Remote directory PCH files can't be found here
  699. if (pfrPch->Dir == DirDB) {
  700. psr = FindSourceDB(pds->psrSourcesList[0], pfrPch);
  701. assert(psr != NULL);
  702. psr->SrcFlags |= SOURCEDB_PCH;
  703. }
  704. Target->pfrCompiland = pfrPch;
  705. assert((pfrRoot = NULL) == NULL); // assign NULL
  706. fNeedCompile = FALSE;
  707. fCheckDepends = FALSE;
  708. switch(0) {
  709. default:
  710. fCase1 = (fStatusTree && (fCheckDepends=TRUE) && CheckDependencies(Target, pfrPch, TRUE, &pfrRoot));
  711. if ( fCase1 ) {
  712. fNeedCompile = TRUE;
  713. break;
  714. }
  715. fCase2 = (Target->DateTime == 0);
  716. if ( fCase2 ) {
  717. fNeedCompile = TRUE;
  718. break;
  719. }
  720. fCase3 = (!fStatusTree && (fCheckDepends=TRUE) && CheckDependencies(Target, pfrPch, TRUE, &pfrRoot));
  721. if ( fCase3 ) {
  722. fNeedCompile = TRUE;
  723. break;
  724. }
  725. break;
  726. }
  727. if (( fCheckIncludePaths ) && ( ! fCheckDepends )) {
  728. CheckDependencies(Target, pfrPch, TRUE, &pfrRoot);
  729. }
  730. if (fNeedCompile) {
  731. if (psr != NULL) {
  732. if (fWhyBuild) {
  733. BuildMsgRaw("\n");
  734. if (fCase1) {
  735. BuildMsgRaw("Compiling %s because (Case 1) *1\n", psr->pfrSource->Name);
  736. } else
  737. if (fCase2) {
  738. BuildMsgRaw("Compiling %s because Target date == 0 (Target->Compiland=%s) *1\n", psr->pfrSource->Name, Target->pfrCompiland->Name);
  739. } else
  740. if (fCase3) {
  741. BuildMsgRaw("Compiling %s because (Case 3) *1\n", psr->pfrSource->Name);
  742. }
  743. }
  744. psr->SrcFlags |= SOURCEDB_COMPILE_NEEDED;
  745. } else {
  746. if (fWhyBuild) {
  747. BuildMsgRaw("\n");
  748. BuildMsgRaw("Compiling %s because Target date == 0 (Target->Compiland=%s) *1\n", Target->Name, Target->pfrCompiland->Name);
  749. }
  750. }
  751. pfrPch->Dir->DirFlags |= DIRDB_COMPILENEEDED;
  752. DateTimePch = ULONG_MAX; // always out of date
  753. if (fKeep) {
  754. Target->DateTime = 0; // don't delete pch target
  755. }
  756. }
  757. else { // else it exists and is up to date...
  758. Target->DateTime = 0; // don't delete pch target
  759. }
  760. // No cycle possible at the root of the tree.
  761. assert(pfrRoot == NULL);
  762. }
  763. else if (DEBUG_1) {
  764. BuildError("Cannot locate precompiled header file: %s.\n",
  765. path);
  766. }
  767. }
  768. //
  769. // Target->DateTime will be zero if the file is up to date (or we
  770. // don't want to delete it). If Target->DateTime is non-zero,
  771. // delete the .pch and corresponding .obj file so they will be
  772. // rebuilt.
  773. //
  774. if (Target->DateTime != 0) {
  775. DeleteSingleFile(NULL, Target->Name, FALSE);
  776. if (DirDB->PchObj != NULL) {
  777. ExpandObjAsterisk(
  778. path,
  779. DirDB->PchObj,
  780. TargetMachines[i]->ObjectDirectory);
  781. DeleteSingleFile(NULL, path, FALSE);
  782. } else {
  783. p = strrchr(Target->Name, '.');
  784. if (p != NULL && strcmp(p, ".pch") == 0) {
  785. strcpy(p, ".obj");
  786. DeleteSingleFile(NULL, Target->Name, FALSE);
  787. }
  788. }
  789. }
  790. FreeMem(&Target, MT_TARGET);
  791. }
  792. //
  793. // Check to see which files given in the SOURCES macro need to be
  794. // rebuilt, and delete their targets (.obj) if they're out of date.
  795. //
  796. ProcessSourceList:
  797. apsr[1] = pds->psrSourcesList[TargetToPossibleTarget[i] + 1];
  798. for (ppsr = apsr; ppsr < apsr + (sizeof(apsr)/sizeof(*apsr)); ppsr++) {
  799. SOURCEREC *psr;
  800. if (*ppsr == NULL) {
  801. continue;
  802. }
  803. for (psr = *ppsr; psr != NULL; psr = psr->psrNext) {
  804. FILEREC *pfr, *pfrRoot;
  805. AssertSource(psr);
  806. pfr = psr->pfrSource;
  807. AssertFile(pfr);
  808. if ((psr->SrcFlags & SOURCEDB_PCH) == 0) {
  809. USHORT j;
  810. LONG iPass, iPassEnd;
  811. iPass = 1;
  812. iPassEnd = 0;
  813. if (pfr->FileFlags & FILEDB_PASS0)
  814. iPass = 0;
  815. if ((pfr->FileFlags & FILEDB_MULTIPLEPASS) ||
  816. !(pfr->FileFlags & FILEDB_PASS0))
  817. iPassEnd = 1;
  818. assert(iPass <= iPassEnd);
  819. //
  820. // If we're doing a pass zero scan and the file is
  821. // not a pass zero file, then continue because we
  822. // don't care about it right now.
  823. //
  824. if (fFirstScan && fPassZero && iPass == 1) {
  825. continue;
  826. }
  827. //
  828. // Don't check dependencies of pass zero files on the
  829. // second scan, because they're all supposed to be built
  830. // by now.
  831. //
  832. if (!fFirstScan && iPassEnd == 0) {
  833. continue;
  834. }
  835. //
  836. // If the file was created during pass zero, then make sure
  837. // we don't think it's still missing.
  838. //
  839. if (!fFirstScan &&
  840. (psr->SrcFlags & SOURCEDB_FILE_MISSING) &&
  841. !(pfr->FileFlags & FILEDB_FILE_MISSING))
  842. {
  843. psr->SrcFlags &= ~SOURCEDB_FILE_MISSING;
  844. }
  845. // If the file is a multiple pass file (e.g. .asn), loop
  846. // through both passes.
  847. for ( ; iPass <= iPassEnd; iPass++) {
  848. //
  849. // If the file has multiple targets (e.g. .mc, .idl or
  850. // .asn), then loop through all the targets.
  851. //
  852. for (j = 0;
  853. Target = BuildCompileTarget(
  854. pfr,
  855. pfr->Name,
  856. j,
  857. pds->ConditionalIncludes,
  858. DirDB,
  859. pds,
  860. iPass,
  861. TargetMachines[i]->ObjectDirectory,
  862. TargetMachines[i]->SourceDirectory);
  863. j++)
  864. {
  865. BOOL fCase1;
  866. BOOL fCase2;
  867. BOOL fCase3;
  868. BOOL fCase4;
  869. BOOL fCase5;
  870. BOOL fNeedCompile;
  871. BOOL fCheckDepends;
  872. if (DEBUG_4) {
  873. BuildMsgRaw(szNewLine);
  874. }
  875. assert((pfrRoot = NULL) == NULL); // assign NULL
  876. // Decide whether the target needs to be compiled.
  877. // Forcibly examine dependencies to get line count.
  878. fNeedCompile = FALSE;
  879. fCheckDepends = FALSE;
  880. switch(0) {
  881. default:
  882. fCase1 = (psr->SrcFlags & SOURCEDB_FILE_MISSING);
  883. if ( fCase1 ) {
  884. fNeedCompile = TRUE;
  885. break;
  886. }
  887. fCase2 = (fStatusTree && (fCheckDepends=TRUE) && CheckDependencies(Target, pfr, TRUE, &pfrRoot));
  888. if ( fCase2 ) {
  889. fNeedCompile = TRUE;
  890. break;
  891. }
  892. fCase3 = (Target->DateTime == 0);
  893. if ( fCase3 ) {
  894. fNeedCompile = TRUE;
  895. break;
  896. }
  897. fCase4 = ((pfr->FileFlags & FILEDB_C) && Target->DateTime < DateTimePch);
  898. if ( fCase4 ) {
  899. fNeedCompile = TRUE;
  900. break;
  901. }
  902. fCase5 = (!fStatusTree && (fCheckDepends=TRUE) && CheckDependencies(Target, pfr, TRUE, &pfrRoot));
  903. if ( fCase5 ) {
  904. fNeedCompile = TRUE;
  905. break;
  906. }
  907. break;
  908. }
  909. if (( fCheckIncludePaths ) && ( ! fCheckDepends )) {
  910. CheckDependencies(Target, pfr, TRUE, &pfrRoot);
  911. }
  912. if ( fNeedCompile )
  913. {
  914. if (fWhyBuild) {
  915. BuildMsgRaw("\n");
  916. if (fCase1) {
  917. BuildMsgRaw("Compiling %s because filename is missing from build database *2\n", psr->pfrSource->Name);
  918. } else
  919. if (fCase2) {
  920. BuildMsgRaw("Compiling %s because (Case 2) *2\n", psr->pfrSource->Name);
  921. } else
  922. if (fCase3) {
  923. BuildMsgRaw("Compiling %s because Target date == 0 *2\n", psr->pfrSource->Name);
  924. } else
  925. if (fCase4) {
  926. BuildMsgRaw("Compiling %s because C file is later earlier than pch *2\n", psr->pfrSource->Name);
  927. } else
  928. if (fCase5) {
  929. BuildMsgRaw("Compiling %s because (Case 5) *2\n", psr->pfrSource->Name);
  930. }
  931. }
  932. psr->SrcFlags |= SOURCEDB_COMPILE_NEEDED;
  933. if (pfr->FileFlags & FILEDB_PASS0) {
  934. DirDB->DirFlags |= DIRDB_PASS0NEEDED;
  935. }
  936. else
  937. DirDB->DirFlags |= DIRDB_COMPILENEEDED;
  938. if (Target->DateTime != 0 && !fKeep)
  939. {
  940. DeleteSingleFile(NULL, Target->Name, FALSE);
  941. }
  942. FreeMem(&Target, MT_TARGET);
  943. if (j != 0) {
  944. //
  945. // Delete the 'rule target' so nmake
  946. // doesn't complain about "don't know how
  947. // to make ..."
  948. //
  949. Target = BuildCompileTarget(
  950. pfr,
  951. pfr->Name,
  952. 0,
  953. pds->ConditionalIncludes,
  954. DirDB,
  955. pds,
  956. iPass,
  957. TargetMachines[i]->ObjectDirectory,
  958. TargetMachines[i]->SourceDirectory);
  959. if (Target) {
  960. DeleteSingleFile(
  961. NULL,
  962. Target->Name,
  963. FALSE);
  964. FreeMem(&Target, MT_TARGET);
  965. }
  966. }
  967. // No need to check other targets,
  968. // we know they all will be rebuilt.
  969. break;
  970. }
  971. // No cycle possible at the root of the tree.
  972. assert(pfrRoot == NULL);
  973. FreeMem(&Target, MT_TARGET);
  974. }
  975. }
  976. }
  977. if (fClean || (psr->SrcFlags & SOURCEDB_COMPILE_NEEDED)) {
  978. ULONG cline;
  979. if (++idScan == 0) {
  980. ++idScan; // skip zero
  981. }
  982. if (fFirstScan && (pfr->FileFlags & FILEDB_PASS0))
  983. {
  984. cline = CountSourceLines(idScan, pfr);
  985. DirDB->PassZeroLines += cline;
  986. DirDB->CountOfPassZeroFiles++;
  987. }
  988. // For a multiple pass file, we really need to count the
  989. // lines in the file compiled duing pass1 (and generated
  990. // during pass 0). Instead, we just count the pass 0
  991. // source file all over again. It's cheap, but the line
  992. // count is inaccurate.
  993. if (!fPassZero &&
  994. ((pfr->FileFlags & FILEDB_MULTIPLEPASS) ||
  995. !(pfr->FileFlags & FILEDB_PASS0)))
  996. {
  997. cline = CountSourceLines(idScan, pfr);
  998. DirDB->SourceLinesToCompile += cline;
  999. DirDB->CountOfFilesToCompile++;
  1000. }
  1001. }
  1002. }
  1003. }
  1004. }
  1005. }
  1006. //+---------------------------------------------------------------------------
  1007. //
  1008. // Function: ScanSourceDirectories
  1009. //
  1010. // Synopsis: Scan a source directory to determine what files it
  1011. // contains, whether it should be compiled or linked, and
  1012. // whether it has subdirectories that we should process.
  1013. //
  1014. // Arguments: [DirName] -- Directory to scan
  1015. //
  1016. //----------------------------------------------------------------------------
  1017. VOID
  1018. ScanSourceDirectories(LPSTR DirName)
  1019. {
  1020. char path[DB_MAX_PATH_LENGTH];
  1021. PDIRREC DirDB;
  1022. DIRSUP *pds = NULL;
  1023. LPSTR SavedCurrentDirectory;
  1024. BOOL DirsPresent;
  1025. ULONG DateTimeSources = 0;
  1026. UINT i;
  1027. if (DEBUG_4) {
  1028. BuildMsgRaw(
  1029. "ScanSourceDirectories(%s) level = %d\n",
  1030. DirName,
  1031. RecurseLevel);
  1032. }
  1033. // Change to the given directory
  1034. SavedCurrentDirectory = PushCurrentDirectory(DirName);
  1035. // Process all the files in this directory
  1036. DirDB = ScanDirectory(DirName);
  1037. AssertOptionalDir(DirDB);
  1038. if (fCleanRestart && DirDB != NULL && !strcmp(DirDB->Name, RestartDir)) {
  1039. fCleanRestart = FALSE;
  1040. fClean = fRestartClean;
  1041. fCleanLibs = fRestartCleanLibs;
  1042. }
  1043. if (!DirDB || !(DirDB->DirFlags & (DIRDB_DIRS | DIRDB_SOURCES))) {
  1044. PopCurrentDirectory(SavedCurrentDirectory);
  1045. return;
  1046. }
  1047. if (fShowTree && !(DirDB->DirFlags & DIRDB_SHOWN)) {
  1048. AddShowDir(DirDB);
  1049. }
  1050. if (DirDB->DirFlags & DIRDB_SOURCES) {
  1051. BOOL fSourcesRead = TRUE;
  1052. SetObjDir((DirDB->DirFlags & DIRDB_CHECKED_ALT_DIR) != 0);
  1053. //
  1054. // This directory contains a SOURCES file
  1055. //
  1056. if (fFirstScan)
  1057. {
  1058. AllocMem(sizeof(DIRSUP), &pds, MT_DIRSUP);
  1059. memset(pds, 0, sizeof(*pds));
  1060. fSourcesRead = ReadSourcesFile(DirDB, pds, &DateTimeSources);
  1061. DirDB->pds = pds;
  1062. }
  1063. else
  1064. {
  1065. pds = DirDB->pds;
  1066. assert(pds);
  1067. DateTimeSources = pds->DateTimeSources;
  1068. //
  1069. // We need to rebuild the sources list because
  1070. // the previous scan was probably not complete.
  1071. //
  1072. if (pds)
  1073. PostProcessSources(DirDB, pds);
  1074. }
  1075. assert(pds);
  1076. if (DEBUG_4) {
  1077. BuildMsgRaw("ScanSourceDirectories(%s) SOURCES\n", DirName);
  1078. }
  1079. ScanFlagsCurrent = 0;
  1080. CountIncludeDirs = CountSystemIncludeDirs;
  1081. // Scan the include environments in the order that MAKEFILE.DEF
  1082. // processes them. This order is:
  1083. //
  1084. // 1) Sources variable INCLUDE
  1085. // 2) Cairo/Chicago directories
  1086. // 3) System includes
  1087. // 4) UMTYPE-derived includes
  1088. //
  1089. // The subtlety is that we must do this in the reverse order
  1090. // since each of the processing routines pushes search directories
  1091. // onto the HEAD of the include search list.
  1092. //
  1093. // Note: we come in here with the system includes already set.
  1094. // There's no way to stick the UMTYPE-derived ones ahead of the
  1095. // system includes
  1096. // 4) UMTYPE-derived includes
  1097. if (pds->TestType != NULL && !strcmp(pds->TestType, "os2")) {
  1098. ScanGlobalIncludeDirectory(pszIncCrt);
  1099. ScanGlobalIncludeDirectory(pszIncOs2);
  1100. ScanFlagsCurrent |= SCANFLAGS_OS2;
  1101. }
  1102. else
  1103. if (pds->TestType != NULL && !strcmp(pds->TestType, "posix")) {
  1104. ScanGlobalIncludeDirectory(pszIncPosix);
  1105. ScanFlagsCurrent |= SCANFLAGS_POSIX;
  1106. }
  1107. else {
  1108. ScanGlobalIncludeDirectory(pszIncCrt);
  1109. ScanFlagsCurrent |= SCANFLAGS_CRT;
  1110. }
  1111. if (DirDB->DirFlags & DIRDB_CHICAGO_INCLUDES) {
  1112. ScanGlobalIncludeDirectory(pszIncChicago);
  1113. ScanFlagsCurrent |= SCANFLAGS_CHICAGO;
  1114. }
  1115. // 1) Sources variable INCLUDE
  1116. if (pds->LocalIncludePath) {
  1117. ScanIncludeEnv(pds->LocalIncludePath);
  1118. }
  1119. DirsPresent = FALSE;
  1120. }
  1121. else
  1122. if (DirDB->DirFlags & DIRDB_DIRS) {
  1123. //
  1124. // This directory contains a DIRS or MYDIRS file
  1125. //
  1126. DirsPresent = ReadDirsFile(DirDB);
  1127. if (DEBUG_4) {
  1128. BuildMsgRaw("ScanSourceDirectories(%s) DIRS\n", DirName);
  1129. }
  1130. }
  1131. if (!fQuicky || (fQuickZero && fFirstScan)) {
  1132. if (!RecurseLevel) {
  1133. BuildError(
  1134. "Examining %s directory%s for %s.%s\n",
  1135. DirDB->Name,
  1136. DirsPresent? " tree" : "",
  1137. fLinkOnly? "targets to link" : "files to compile",
  1138. fFirstScan ? "" : " (2nd Pass)"
  1139. );
  1140. }
  1141. ClearLine();
  1142. BuildMsgRaw(" %s ", DirDB->Name);
  1143. fLineCleared = FALSE;
  1144. if (fDebug || !(BOOL) _isatty(_fileno(stderr))) {
  1145. BuildMsgRaw(szNewLine);
  1146. fLineCleared = TRUE;
  1147. }
  1148. }
  1149. if (!fLinkOnly) {
  1150. if (DirDB->DirFlags & DIRDB_SOURCESREAD) {
  1151. //
  1152. // Determine what files need to be compiled
  1153. //
  1154. ProcessSourceDependencies(DirDB, pds, DateTimeSources);
  1155. }
  1156. else
  1157. if (fFirstScan && DirsPresent && (DirDB->DirFlags & DIRDB_MAKEFIL0)) {
  1158. DirDB->DirFlags |= ((fSemiQuicky && (!fQuickZero || !fFirstScan)) ? DIRDB_COMPILENEEDED :
  1159. DIRDB_PASS0NEEDED);
  1160. }
  1161. else
  1162. if (DirsPresent && (DirDB->DirFlags & DIRDB_MAKEFIL1)) {
  1163. DirDB->DirFlags |= DIRDB_COMPILENEEDED;
  1164. }
  1165. if (fFirstScan && (DirDB->DirFlags & DIRDB_PASS0NEEDED))
  1166. {
  1167. if (CountPassZeroDirs >= MAX_BUILD_DIRECTORIES) {
  1168. BuildError(
  1169. "%s: Ignoring PassZero Directory table overflow, %u "
  1170. "entries allowed\n",
  1171. DirDB->Name,
  1172. MAX_BUILD_DIRECTORIES);
  1173. }
  1174. else {
  1175. //
  1176. // This directory needs to be compiled in pass zero. Add it
  1177. // to the list.
  1178. //
  1179. PassZeroDirs[CountPassZeroDirs++] = DirDB;
  1180. }
  1181. if (fQuicky && !fQuickZero) {
  1182. if (!(fSemiQuicky && (DirDB->DirFlags & DIRDB_COMPILENEEDED))) {
  1183. // For -Z with compile needed anyway, CompileSourceDirectories do it.
  1184. CompilePassZeroDirectories();
  1185. }
  1186. CountPassZeroDirs = 0;
  1187. }
  1188. else {
  1189. if (fFirstScan) {
  1190. fPassZero = TRUE; // Limits scanning during pass zero.
  1191. }
  1192. if (DirDB->CountOfPassZeroFiles) {
  1193. if (fLineCleared) {
  1194. BuildMsgRaw(" %s ", DirDB->Name);
  1195. }
  1196. BuildMsgRaw(
  1197. "- %d Pass Zero files (%s lines)\n",
  1198. DirDB->CountOfPassZeroFiles,
  1199. FormatNumber(DirDB->PassZeroLines));
  1200. }
  1201. }
  1202. }
  1203. if ((DirDB->DirFlags & DIRDB_COMPILENEEDED) &&
  1204. (!fFirstScan || !fPassZero)) {
  1205. if (CountCompileDirs >= MAX_BUILD_DIRECTORIES) {
  1206. BuildError(
  1207. "%s: Ignoring Compile Directory table overflow, %u "
  1208. "entries allowed\n",
  1209. DirDB->Name,
  1210. MAX_BUILD_DIRECTORIES);
  1211. }
  1212. else {
  1213. //
  1214. // This directory needs to be compiled. Add it to the list.
  1215. //
  1216. CompileDirs[CountCompileDirs++] = DirDB;
  1217. }
  1218. if (fQuicky && (!fQuickZero || !fFirstScan)) {
  1219. CompileSourceDirectories();
  1220. CountCompileDirs = 0;
  1221. }
  1222. else
  1223. if (DirDB->CountOfFilesToCompile) {
  1224. if (fLineCleared) {
  1225. BuildMsgRaw(" %s ", DirDB->Name);
  1226. }
  1227. BuildMsgRaw(
  1228. "- %d source files (%s lines)\n",
  1229. DirDB->CountOfFilesToCompile,
  1230. FormatNumber(DirDB->SourceLinesToCompile));
  1231. }
  1232. }
  1233. }
  1234. if (DirsPresent && (DirDB->DirFlags & DIRDB_MAKEFILE)) {
  1235. DirDB->DirFlags |= DIRDB_LINKNEEDED | DIRDB_FORCELINK;
  1236. }
  1237. else
  1238. if (DirDB->DirFlags & DIRDB_TARGETFILES) {
  1239. DirDB->DirFlags |= DIRDB_LINKNEEDED | DIRDB_FORCELINK;
  1240. }
  1241. if ((DirDB->DirFlags & DIRDB_LINKNEEDED) && (!fQuicky || fSemiQuicky)) {
  1242. if (CountLinkDirs >= MAX_BUILD_DIRECTORIES) {
  1243. BuildError(
  1244. "%s: Ignoring Link Directory table overflow, %u entries allowed\n",
  1245. DirDB->Name,
  1246. MAX_BUILD_DIRECTORIES);
  1247. }
  1248. else {
  1249. LinkDirs[CountLinkDirs++] = DirDB;
  1250. }
  1251. }
  1252. if ((DirDB->DirFlags & DIRDB_SOURCESREAD) && !fFirstScan) {
  1253. FreeDirSupData(pds); // free data that are no longer needed
  1254. FreeMem(&pds, MT_DIRSUP);
  1255. DirDB->pds = NULL;
  1256. }
  1257. //
  1258. // Recurse into subdirectories
  1259. //
  1260. if (DirsPresent) {
  1261. for (i = 1; i <= DirDB->CountSubDirs; i++) {
  1262. FILEREC *FileDB, **FileDBNext;
  1263. FileDBNext = &DirDB->Files;
  1264. while (FileDB = *FileDBNext) {
  1265. if (FileDB->SubDirIndex == (USHORT) i) {
  1266. GetCurrentDirectory(DB_MAX_PATH_LENGTH, path);
  1267. strcat(path, "\\");
  1268. strcat(path, FileDB->Name);
  1269. DirDB->RecurseLevel = (USHORT) ++RecurseLevel;
  1270. ScanSourceDirectories(path);
  1271. RecurseLevel--;
  1272. break;
  1273. }
  1274. FileDBNext = &FileDB->Next;
  1275. }
  1276. }
  1277. }
  1278. if (((fQuickZero && fFirstScan) || (!fQuicky)) && !RecurseLevel) {
  1279. ClearLine();
  1280. }
  1281. PopCurrentDirectory(SavedCurrentDirectory);
  1282. }
  1283. //+---------------------------------------------------------------------------
  1284. //
  1285. // Function: CompilePassZeroDirectories
  1286. //
  1287. // Synopsis: Spawns the compiler on the directories in the PassZeroDirs
  1288. // array.
  1289. //
  1290. // Arguments: (none)
  1291. //
  1292. //----------------------------------------------------------------------------
  1293. VOID
  1294. CompilePassZeroDirectories(
  1295. VOID
  1296. )
  1297. {
  1298. PDIRREC DirDB;
  1299. LPSTR SavedCurrentDirectory;
  1300. UINT i;
  1301. PCHAR s;
  1302. StartElapsedTime();
  1303. for (i = 0; i < CountPassZeroDirs; i++) {
  1304. DirDB = PassZeroDirs[ i ];
  1305. AssertDir(DirDB);
  1306. if (fQuicky && !fSemiQuicky)
  1307. s = "Compiling and linking";
  1308. else
  1309. s = "Building generated files in";
  1310. BuildMsg("%s %s\n", s, DirDB->Name);
  1311. LogMsg("%s %s%s\n", s, DirDB->Name, szAsterisks);
  1312. if ((fQuickZero && fFirstScan) || !fQuicky) {
  1313. SavedCurrentDirectory = PushCurrentDirectory( DirDB->Name );
  1314. }
  1315. if (DirDB->DirFlags & DIRDB_DIRS) {
  1316. if (DirDB->DirFlags & DIRDB_MAKEFIL0) {
  1317. strcpy( MakeParametersTail, " -f makefil0." );
  1318. strcat( MakeParametersTail, " NOLINK=1" );
  1319. if (fClean) {
  1320. strcat( MakeParametersTail, " clean" );
  1321. }
  1322. if (fQuery) {
  1323. BuildErrorRaw("'%s %s'\n", MakeProgram, MakeParameters);
  1324. }
  1325. else {
  1326. if (DEBUG_1) {
  1327. BuildMsg(
  1328. "Executing: %s %s\n",
  1329. MakeProgram,
  1330. MakeParameters);
  1331. }
  1332. CurrentCompileDirDB = NULL;
  1333. RecurseLevel = DirDB->RecurseLevel;
  1334. ExecuteProgram(MakeProgram, MakeParameters, MakeTargets, TRUE);
  1335. }
  1336. }
  1337. }
  1338. else {
  1339. strcpy(MakeParametersTail, " NTTEST=");
  1340. if (DirDB->KernelTest) {
  1341. strcat(MakeParametersTail, DirDB->KernelTest);
  1342. }
  1343. strcat(MakeParametersTail, " UMTEST=");
  1344. if (DirDB->UserTests) {
  1345. strcat(MakeParametersTail, DirDB->UserTests);
  1346. }
  1347. if (DirDB->DirFlags & DIRDB_CHECKED_ALT_DIR) {
  1348. strcat(MakeParametersTail, szCheckedAltDir);
  1349. }
  1350. if (fQuicky && !fSemiQuicky) {
  1351. if (DirDB->DirFlags & DIRDB_DLLTARGET) {
  1352. strcat(MakeParametersTail, " MAKEDLL=1");
  1353. }
  1354. ProcessLinkTargets(DirDB, NULL);
  1355. }
  1356. else {
  1357. strcat( MakeParametersTail, " NOLINK=1 PASS0ONLY=1");
  1358. }
  1359. if (fQuery) {
  1360. BuildErrorRaw(
  1361. "'%s %s%s'\n",
  1362. MakeProgram,
  1363. MakeParameters,
  1364. MakeTargets);
  1365. }
  1366. else {
  1367. if ((DirDB->DirFlags & DIRDB_SYNCHRONIZE_DRAIN) &&
  1368. (fParallel)) {
  1369. //
  1370. // Wait for all threads to complete before
  1371. // trying to compile this directory.
  1372. //
  1373. WaitForParallelThreads();
  1374. }
  1375. if (DEBUG_1) {
  1376. BuildMsg("Executing: %s %s%s\n",
  1377. MakeProgram,
  1378. MakeParameters,
  1379. MakeTargets);
  1380. }
  1381. CurrentCompileDirDB = DirDB;
  1382. RecurseLevel = DirDB->RecurseLevel;
  1383. ExecuteProgram(
  1384. MakeProgram,
  1385. MakeParameters,
  1386. MakeTargets,
  1387. (DirDB->DirFlags & DIRDB_SYNCHRONIZE_BLOCK) != 0);
  1388. }
  1389. }
  1390. PrintElapsedTime();
  1391. if ((fQuickZero && fFirstScan) || !fQuicky) {
  1392. PopCurrentDirectory(SavedCurrentDirectory);
  1393. }
  1394. DirDB->DirFlags &= ~DIRDB_PASS0NEEDED;
  1395. DirDB->CountOfPassZeroFiles = 0;
  1396. DirDB->PassZeroLines = 0;
  1397. }
  1398. }
  1399. //+---------------------------------------------------------------------------
  1400. //
  1401. // Function: CompileSourceDirectories
  1402. //
  1403. // Synopsis: Spawns the compiler on the directories in the CompileDirs
  1404. // array.
  1405. //
  1406. // Arguments: (none)
  1407. //
  1408. //----------------------------------------------------------------------------
  1409. VOID
  1410. CompileSourceDirectories(
  1411. VOID
  1412. )
  1413. {
  1414. PDIRREC DirDB;
  1415. LPSTR SavedCurrentDirectory;
  1416. UINT i,j;
  1417. PCHAR s;
  1418. char path[DB_MAX_PATH_LENGTH];
  1419. StartElapsedTime();
  1420. for (i = 0; i < CountCompileDirs; i++) {
  1421. DirDB = CompileDirs[ i ];
  1422. AssertDir(DirDB);
  1423. if (fQuicky && !fSemiQuicky) {
  1424. s = "Compiling and linking";
  1425. }
  1426. else {
  1427. s = "Compiling";
  1428. }
  1429. BuildMsg("%s %s directory\n", s, DirDB->Name);
  1430. LogMsg("%s %s directory%s\n", s, DirDB->Name, szAsterisks);
  1431. if (!fQuicky || (fQuickZero && (!fFirstScan || !RecurseLevel))) {
  1432. SavedCurrentDirectory = PushCurrentDirectory( DirDB->Name );
  1433. if (fQuickZero && !RecurseLevel && fFirstScan)
  1434. {
  1435. GenerateObjectsDotMac(DirDB, DirDB->pds, DirDB->pds->DateTimeSources);
  1436. }
  1437. }
  1438. if (DirDB->DirFlags & DIRDB_DIRS) {
  1439. if ((DirDB->DirFlags & DIRDB_SYNCHRONIZE_DRAIN) &&
  1440. (fParallel)) {
  1441. //
  1442. // Wait for all threads to complete before
  1443. // trying to compile this directory.
  1444. //
  1445. WaitForParallelThreads();
  1446. }
  1447. if (fSemiQuicky && (DirDB->DirFlags & DIRDB_MAKEFIL0)) {
  1448. strcpy( MakeParametersTail, " -f makefil0." );
  1449. strcat( MakeParametersTail, " NOLINK=1" );
  1450. if (fClean) {
  1451. strcat( MakeParametersTail, " clean" );
  1452. }
  1453. if (fQuery) {
  1454. BuildErrorRaw("'%s %s'\n", MakeProgram, MakeParameters);
  1455. }
  1456. else {
  1457. if (DEBUG_1) {
  1458. BuildMsg(
  1459. "Executing: %s %s\n",
  1460. MakeProgram,
  1461. MakeParameters);
  1462. }
  1463. CurrentCompileDirDB = NULL;
  1464. RecurseLevel = DirDB->RecurseLevel;
  1465. ExecuteProgram(MakeProgram, MakeParameters, MakeTargets, TRUE);
  1466. }
  1467. }
  1468. if (DirDB->DirFlags & DIRDB_MAKEFIL1) {
  1469. strcpy( MakeParametersTail, " -f makefil1." );
  1470. strcat( MakeParametersTail, " NOLINK=1 NOPASS0=1" );
  1471. if (fClean) {
  1472. strcat( MakeParametersTail, " clean" );
  1473. }
  1474. if (fQuery) {
  1475. BuildErrorRaw("'%s %s'\n", MakeProgram, MakeParameters);
  1476. }
  1477. else {
  1478. if (DEBUG_1) {
  1479. BuildMsg(
  1480. "Executing: %s %s\n",
  1481. MakeProgram,
  1482. MakeParameters);
  1483. }
  1484. CurrentCompileDirDB = NULL;
  1485. RecurseLevel = DirDB->RecurseLevel;
  1486. ExecuteProgram(MakeProgram, MakeParameters, MakeTargets, TRUE);
  1487. }
  1488. }
  1489. }
  1490. else {
  1491. strcpy(MakeParametersTail, " NTTEST=");
  1492. if (DirDB->KernelTest) {
  1493. strcat(MakeParametersTail, DirDB->KernelTest);
  1494. }
  1495. strcat(MakeParametersTail, " UMTEST=");
  1496. if (DirDB->UserTests) {
  1497. strcat(MakeParametersTail, DirDB->UserTests);
  1498. }
  1499. if (fQuicky && DirDB->PchObj) {
  1500. for (j = 0; j < CountTargetMachines; j++) {
  1501. FormatLinkTarget(
  1502. path,
  1503. TargetMachines[j]->ObjectDirectory,
  1504. DirDB->TargetPath,
  1505. DirDB->PchObj,
  1506. "");
  1507. if (ProbeFile( NULL, path ) != -1) {
  1508. //
  1509. // the pch.obj file is present so we therefore
  1510. // must do this incremental build without pch
  1511. //
  1512. strcat( MakeParametersTail, " NTNOPCH=yes" );
  1513. break;
  1514. }
  1515. }
  1516. }
  1517. if (DirDB->DirFlags & DIRDB_CHECKED_ALT_DIR) {
  1518. strcat(MakeParametersTail, szCheckedAltDir);
  1519. }
  1520. if (fQuicky && !fSemiQuicky) {
  1521. if (DirDB->DirFlags & DIRDB_DLLTARGET) {
  1522. strcat(MakeParametersTail, " MAKEDLL=1");
  1523. }
  1524. ProcessLinkTargets(DirDB, NULL);
  1525. }
  1526. else
  1527. if (fQuicky && fSemiQuicky) {
  1528. strcat(MakeParametersTail, " NOLINK=1");
  1529. }
  1530. else {
  1531. strcat(MakeParametersTail, " NOLINK=1 NOPASS0=1");
  1532. }
  1533. if (fQuery) {
  1534. BuildErrorRaw(
  1535. "'%s %s%s'\n",
  1536. MakeProgram,
  1537. MakeParameters,
  1538. MakeTargets);
  1539. }
  1540. else {
  1541. if ((DirDB->DirFlags & DIRDB_SYNCHRONIZE_DRAIN) &&
  1542. (fParallel)) {
  1543. //
  1544. // Wait for all threads to complete before
  1545. // trying to compile this directory.
  1546. //
  1547. WaitForParallelThreads();
  1548. }
  1549. if (DEBUG_1) {
  1550. BuildMsg("Executing: %s %s%s\n",
  1551. MakeProgram,
  1552. MakeParameters,
  1553. MakeTargets);
  1554. }
  1555. CurrentCompileDirDB = DirDB;
  1556. RecurseLevel = DirDB->RecurseLevel;
  1557. ExecuteProgram(
  1558. MakeProgram,
  1559. MakeParameters,
  1560. MakeTargets,
  1561. (DirDB->DirFlags & DIRDB_SYNCHRONIZE_BLOCK) != 0);
  1562. }
  1563. }
  1564. PrintElapsedTime();
  1565. if (!fQuicky || (fQuickZero && (!fFirstScan || !RecurseLevel))) {
  1566. PopCurrentDirectory(SavedCurrentDirectory);
  1567. }
  1568. }
  1569. }
  1570. static CountLinkTargets;
  1571. //+---------------------------------------------------------------------------
  1572. //
  1573. // Function: LinkSourceDirectories
  1574. //
  1575. // Synopsis: Link the directories given in the LinkDirs array. This is
  1576. // done by passing LINKONLY=1 to nmake.
  1577. //
  1578. // Arguments: (none)
  1579. //
  1580. //----------------------------------------------------------------------------
  1581. VOID
  1582. LinkSourceDirectories(VOID)
  1583. {
  1584. PDIRREC DirDB;
  1585. LPSTR SavedCurrentDirectory;
  1586. UINT i;
  1587. CountLinkTargets = 0;
  1588. StartElapsedTime();
  1589. for (i = 0; i < CountLinkDirs; i++) {
  1590. DirDB = LinkDirs[ i ];
  1591. AssertDir(DirDB);
  1592. SavedCurrentDirectory = PushCurrentDirectory(DirDB->Name);
  1593. //
  1594. // Deletes link targets as necessary
  1595. //
  1596. ProcessLinkTargets(DirDB, SavedCurrentDirectory);
  1597. PopCurrentDirectory(SavedCurrentDirectory);
  1598. }
  1599. if (fPause && !fMTScriptSync) {
  1600. BuildMsg("Press enter to continue with linking (or 'q' to quit)...");
  1601. if (getchar() == 'q') {
  1602. return;
  1603. }
  1604. }
  1605. for (i = 0; i < CountLinkDirs; i++) {
  1606. DirDB = LinkDirs[i];
  1607. if (!fMTScriptSync &&
  1608. (DirDB->DirFlags & DIRDB_COMPILEERRORS) &&
  1609. (DirDB->DirFlags & DIRDB_FORCELINK) == 0) {
  1610. BuildMsg("Compile errors: not linking %s directory\n", DirDB->Name);
  1611. LogMsg(
  1612. "Compile errors: not linking %s directory%s\n",
  1613. DirDB->Name,
  1614. szAsterisks);
  1615. continue;
  1616. }
  1617. SavedCurrentDirectory = PushCurrentDirectory(DirDB->Name);
  1618. BuildMsg("Linking %s directory\n", DirDB->Name);
  1619. LogMsg ("Linking %s directory%s\n", DirDB->Name, szAsterisks);
  1620. strcpy(MakeParametersTail, " LINKONLY=1 NOPASS0=1");
  1621. strcat(MakeParametersTail, " NTTEST=");
  1622. if (DirDB->KernelTest) {
  1623. strcat(MakeParametersTail, DirDB->KernelTest);
  1624. }
  1625. strcat(MakeParametersTail, " UMTEST=");
  1626. if (DirDB->UserTests) {
  1627. strcat(MakeParametersTail, DirDB->UserTests);
  1628. }
  1629. if (DirDB->DirFlags & DIRDB_CHECKED_ALT_DIR) {
  1630. strcat(MakeParametersTail, szCheckedAltDir);
  1631. }
  1632. if (DirDB->DirFlags & DIRDB_DLLTARGET) {
  1633. strcat(MakeParametersTail, " MAKEDLL=1");
  1634. }
  1635. if ((DirDB->DirFlags & DIRDB_DIRS) &&
  1636. (DirDB->DirFlags & DIRDB_MAKEFILE) &&
  1637. fClean) {
  1638. strcat(MakeParametersTail, " clean");
  1639. }
  1640. if (fQuery) {
  1641. BuildErrorRaw(
  1642. "'%s %s%s'\n",
  1643. MakeProgram,
  1644. MakeParameters,
  1645. MakeTargets);
  1646. }
  1647. else {
  1648. if ((DirDB->DirFlags & DIRDB_SYNCHRONIZE_DRAIN) &&
  1649. (fParallel) && (fSyncLink)) {
  1650. //
  1651. // Wait for all threads to complete before
  1652. // trying to compile this directory.
  1653. //
  1654. WaitForParallelThreads();
  1655. }
  1656. if (DEBUG_1) {
  1657. BuildMsg("Executing: %s %s%s\n",
  1658. MakeProgram,
  1659. MakeParameters,
  1660. MakeTargets);
  1661. }
  1662. CurrentCompileDirDB = NULL;
  1663. RecurseLevel = DirDB->RecurseLevel;
  1664. ExecuteProgram(MakeProgram,
  1665. MakeParameters,
  1666. MakeTargets,
  1667. (fSyncLink) && (DirDB->DirFlags & DIRDB_SYNCHRONIZE_BLOCK) != 0);
  1668. }
  1669. PopCurrentDirectory(SavedCurrentDirectory);
  1670. PrintElapsedTime();
  1671. }
  1672. }
  1673. //+---------------------------------------------------------------------------
  1674. //
  1675. // Function: GetTargetData
  1676. //
  1677. // Synopsis: Searches aTargetInfo for an entry corresponding to the given
  1678. // extension.
  1679. //
  1680. // Arguments: [ext] -- Extension to look up (including '.').
  1681. // [iPass] -- 0 for pass zero; 1 for pass 1
  1682. // [index] -- Index used to differentiate multiple targets
  1683. // [usMidlFlag] -- Indicates which set of MIDL targets should
  1684. // be used for MIDL source files.
  1685. //
  1686. // Returns: A TARGETDATA for the given extension and index. NULL if
  1687. // Index is invalid.
  1688. //
  1689. // History: 29-Jul-94 LyleC Created
  1690. //
  1691. // Notes: If ext is not found in the aTargetInfo array, then a default
  1692. // TARGETINFO is used which maps the extension to obj\*\.obj.
  1693. //
  1694. //----------------------------------------------------------------------------
  1695. LPTARGETDATA
  1696. GetTargetData(LPSTR ext, LONG iPass, USHORT index, ULONG usMidlIndex)
  1697. {
  1698. int i;
  1699. OBJECTTARGETINFO **aTargetInfo;
  1700. int cTargetInfo;
  1701. if (!ext || (ext[0] == '\0') || (ext[1] == '\0'))
  1702. return &DefaultData;
  1703. if ((ext[1] == aMidlTargetInfo0[usMidlIndex]->pszSourceExt[1]) &&
  1704. (strcmp(ext, aMidlTargetInfo0[usMidlIndex]->pszSourceExt) == 0))
  1705. {
  1706. if (index >= aMidlTargetInfo0[usMidlIndex]->NumData)
  1707. return NULL;
  1708. return &(aMidlTargetInfo0[usMidlIndex]->Data[index]);
  1709. }
  1710. assert(iPass == 0 || iPass == 1);
  1711. cTargetInfo = aTargetArray[iPass].cTargetInfo;
  1712. aTargetInfo = aTargetArray[iPass].aTargetInfo;
  1713. for (i = 0; i < cTargetInfo; i++)
  1714. {
  1715. if ((ext[1] == aTargetInfo[i]->pszSourceExt[1]) &&
  1716. (strcmp(ext, aTargetInfo[i]->pszSourceExt) == 0))
  1717. {
  1718. if (index >= aTargetInfo[i]->NumData)
  1719. return NULL;
  1720. return(&aTargetInfo[i]->Data[index]);
  1721. }
  1722. }
  1723. if (index)
  1724. return NULL;
  1725. return &DefaultData;
  1726. }
  1727. //+---------------------------------------------------------------------------
  1728. //
  1729. // Function: BuildCompileTarget
  1730. //
  1731. // Synopsis: Fills a TARGET struct with data about the target of a given
  1732. // source file.
  1733. //
  1734. // Arguments: [pfr] -- FileRec of source file
  1735. // [pszfile] -- Path of source file (compiland)
  1736. // [TargetIndex] -- Which target for a source file
  1737. // with multiple targets.
  1738. // [pszConditionalIncludes] -- List of conditional includes
  1739. // [pdrBuild] -- Build directory (with source file)
  1740. // [iPass] -- 0 for pass zero; 1 for pass 1
  1741. // [ppszObjectDir] -- Names of target object directories
  1742. // [pszSourceDir] -- Name of machine specific source dir
  1743. //
  1744. // Returns: A filled TARGET struct. NULL if TargetIndex is an invalid
  1745. // value for the given file type.
  1746. //
  1747. // Notes: If [pfr] is NULL, then [pszfile] is not modified and is
  1748. // used as the full pathname of the target file.
  1749. // [pszObjectDir] is ignored in this case. if [pfr] is not
  1750. // NULL, the filename component of [pszfile] is taken, its
  1751. // extension is modified, and it is appended to [pszObjectDir]
  1752. // to obtain the pathname of the target. The other data is
  1753. // used to fill in the rest of the TARGET struct in all cases.
  1754. //
  1755. // For source files with multiple targets, use the TargetIndex
  1756. // parameter to indicate which target you want the path of. For
  1757. // instance, .idl files have two targets, so a TargetIndex of 0
  1758. // will return the .h target and TargetIndex=1 will return the
  1759. // .c target. A TargetIndex of 2 or above in this case will
  1760. // return NULL. TargetIndex is ignored if [pfr] is NULL.
  1761. //
  1762. //----------------------------------------------------------------------------
  1763. TARGET *
  1764. BuildCompileTarget(
  1765. FILEREC *pfr,
  1766. LPSTR pszfile,
  1767. USHORT TargetIndex,
  1768. LPSTR pszConditionalIncludes,
  1769. DIRREC *pdrBuild,
  1770. DIRSUP *pdsBuild,
  1771. LONG iPass,
  1772. LPSTR *ppszObjectDir,
  1773. LPSTR pszSourceDir)
  1774. {
  1775. LPSTR p, p1;
  1776. PTARGET Target;
  1777. char path[DB_MAX_PATH_LENGTH];
  1778. LPTARGETDATA pData;
  1779. p = pszfile;
  1780. if (pfr != NULL) {
  1781. p1 = p;
  1782. while (*p) {
  1783. if (*p++ == '\\') {
  1784. p1 = p; // point to last component of pathname
  1785. }
  1786. }
  1787. sprintf(path, "%s", p1);
  1788. p = strrchr(path, '.');
  1789. pData = GetTargetData(p, iPass, TargetIndex, pdsBuild->IdlType);
  1790. if (!pData) {
  1791. if (DEBUG_1) {
  1792. BuildMsg(
  1793. "BuildCompileTarget(\"%s\"[%u][%u], \"%s\") -> NULL\n",
  1794. pszfile,
  1795. iPass,
  1796. TargetIndex,
  1797. ppszObjectDir[iObjectDir]);
  1798. }
  1799. return NULL;
  1800. }
  1801. assert(pdsBuild);
  1802. switch (pData->ObjectDirFlag)
  1803. {
  1804. case TD_OBJECTDIR:
  1805. p = ppszObjectDir[iObjectDir];
  1806. break;
  1807. case TD_PASS0HDRDIR:
  1808. p = pdsBuild->PassZeroHdrDir;
  1809. break;
  1810. p = pdsBuild->PassZeroSrcDir1;
  1811. break;
  1812. case TD_MCSOURCEDIR:
  1813. case TD_PASS0DIR1:
  1814. p = pdsBuild->PassZeroSrcDir1;
  1815. break;
  1816. case TD_PASS0DIR2:
  1817. p = pdsBuild->PassZeroSrcDir2;
  1818. break;
  1819. default:
  1820. assert(0 && "Invalid ObjectDirFlag");
  1821. break;
  1822. }
  1823. if (!p) {
  1824. // Make sure path ends in a period
  1825. sprintf(path, "%s.", p1);
  1826. } else
  1827. if (p[0] == '.' && p[1] == '\0') {
  1828. strcpy(path, p1);
  1829. }
  1830. else {
  1831. sprintf(path, "%s\\%s", p, p1);
  1832. }
  1833. p = strrchr(path, '.');
  1834. if (p) {
  1835. strcpy(p, pData->pszTargetExt);
  1836. }
  1837. p = path;
  1838. }
  1839. AllocMem(sizeof(TARGET) + strlen(p), &Target, MT_TARGET);
  1840. strcpy(Target->Name, p);
  1841. Target->pdrBuild = pdrBuild;
  1842. Target->DateTime = (*pDateTimeFile)(NULL, p);
  1843. Target->pfrCompiland = pfr;
  1844. Target->pszSourceDirectory = pszSourceDir;
  1845. Target->ConditionalIncludes = pszConditionalIncludes;
  1846. Target->DirFlags = pdrBuild->DirFlags;
  1847. if (DEBUG_1) {
  1848. BuildMsg(
  1849. "BuildCompileTarget(\"%s\"[%u][%u], \"%s\") -> \"%s\"\n",
  1850. pszfile,
  1851. iPass,
  1852. TargetIndex,
  1853. ppszObjectDir[iObjectDir],
  1854. Target->Name);
  1855. }
  1856. if (Target->DateTime == 0) {
  1857. if (fShowOutOfDateFiles) {
  1858. BuildError("%s target is missing.\n", Target->Name);
  1859. }
  1860. }
  1861. return(Target);
  1862. }
  1863. //+---------------------------------------------------------------------------
  1864. //
  1865. // Function: FormatLinkTarget
  1866. //
  1867. // Synopsis: Builds a link target path name.
  1868. //
  1869. // Arguments: [path] -- Place to put constructed name
  1870. // [ObjectDirectory] -- e.g. "obj\i386"
  1871. // [TargetPath] -- Path (w/o platfrom spec. name) for target
  1872. // [TargetName] -- Base name of target
  1873. // [TargetExt] -- Extension of target
  1874. //
  1875. // Notes: Sample input: (path, "obj\i386", "..\obj", "foobar", ".dll")
  1876. //
  1877. // output: path = "..\obj\i386\foobar.dll"
  1878. //
  1879. //----------------------------------------------------------------------------
  1880. VOID
  1881. FormatLinkTarget(
  1882. LPSTR path,
  1883. LPSTR *ObjectDirectory,
  1884. LPSTR TargetPath,
  1885. LPSTR TargetName,
  1886. LPSTR TargetExt)
  1887. {
  1888. LPSTR p, p1;
  1889. p = ObjectDirectory[iObjectDir];
  1890. assert(strncmp(pszObjDirSlash, p, strlen(pszObjDirSlash)) == 0);
  1891. p1 = p + strlen(p);
  1892. while (p1 > p) {
  1893. if (*--p1 == '\\') {
  1894. p1++;
  1895. break;
  1896. }
  1897. }
  1898. sprintf(path, "%s\\%s\\%s%s", TargetPath, p1, TargetName, TargetExt);
  1899. }
  1900. //+---------------------------------------------------------------------------
  1901. //
  1902. // Function: ProcessLinkTargets
  1903. //
  1904. // Synopsis: Deletes link targets for the given directory (.lib & .dll)
  1905. //
  1906. // Arguments: [DirDB] -- Directory to process
  1907. // [CurrentDirectory] -- Current directory
  1908. //
  1909. //----------------------------------------------------------------------------
  1910. VOID
  1911. ProcessLinkTargets(PDIRREC DirDB, LPSTR CurrentDirectory)
  1912. {
  1913. UINT i;
  1914. char path[DB_MAX_PATH_LENGTH];
  1915. AssertDir(DirDB);
  1916. for (i = 0; i < CountTargetMachines; i++) {
  1917. //
  1918. // Delete 'special' link targets
  1919. //
  1920. if (DirDB->KernelTest) {
  1921. FormatLinkTarget(
  1922. path,
  1923. TargetMachines[i]->ObjectDirectory,
  1924. pszObjDir,
  1925. DirDB->KernelTest,
  1926. ".exe");
  1927. if (fClean && !fKeep && fFirstScan) {
  1928. DeleteSingleFile(NULL, path, FALSE);
  1929. }
  1930. }
  1931. else {
  1932. UINT j;
  1933. for (j = 0; j < 2; j++) {
  1934. LPSTR pNextName;
  1935. pNextName = j == 0? DirDB->UserAppls : DirDB->UserTests;
  1936. if (pNextName != NULL) {
  1937. char name[256];
  1938. while (SplitToken(name, '*', &pNextName)) {
  1939. FormatLinkTarget(
  1940. path,
  1941. TargetMachines[i]->ObjectDirectory,
  1942. pszObjDir,
  1943. name,
  1944. ".exe");
  1945. if (fClean && !fKeep && fFirstScan) {
  1946. DeleteSingleFile(NULL, path, FALSE);
  1947. }
  1948. }
  1949. }
  1950. }
  1951. }
  1952. if (DirDB->TargetPath != NULL &&
  1953. DirDB->TargetName != NULL &&
  1954. DirDB->TargetExt != NULL &&
  1955. strcmp(DirDB->TargetExt, ".lib")) {
  1956. FormatLinkTarget(
  1957. path,
  1958. TargetMachines[i]->ObjectDirectory,
  1959. DirDB->TargetPath,
  1960. DirDB->TargetName,
  1961. DirDB->TargetExt);
  1962. if (fClean && !fKeep && fFirstScan) {
  1963. DeleteSingleFile(NULL, path, FALSE);
  1964. }
  1965. }
  1966. if (DirDB->DirFlags & DIRDB_DIRS) {
  1967. if (fDebug && (DirDB->DirFlags & DIRDB_MAKEFILE)) {
  1968. BuildError(
  1969. "%s\\makefile. unexpected in directory with DIRS file\n",
  1970. DirDB->Name);
  1971. }
  1972. if ((DirDB->DirFlags & DIRDB_SOURCES)) {
  1973. BuildError(
  1974. "%s\\sources. unexpected in directory with DIRS file\n",
  1975. DirDB->Name);
  1976. BuildError("Ignoring %s\\sources.\n", DirDB->Name);
  1977. DirDB->DirFlags &= ~DIRDB_SOURCES;
  1978. }
  1979. }
  1980. }
  1981. }
  1982. //+---------------------------------------------------------------------------
  1983. //
  1984. // Function: IncludeError
  1985. //
  1986. // Synopsis: Print out the name of an include file and an error message
  1987. // to the screen.
  1988. //
  1989. // Arguments: [pt] -- Target of the file which includes the include
  1990. // file or [pfr].
  1991. // [pfr] -- File which includes the include file
  1992. // [pir] -- Include file at issue
  1993. // [pszError] -- Error string
  1994. //
  1995. // Notes: If [pt]->pfrCompiland and [pfr] are different, then the names
  1996. // of both are printed.
  1997. //
  1998. //----------------------------------------------------------------------------
  1999. VOID
  2000. IncludeError(TARGET *pt, FILEREC *pfr, INCLUDEREC *pir, LPSTR pszError)
  2001. {
  2002. char c1, c2;
  2003. AssertFile(pfr);
  2004. AssertInclude(pir);
  2005. if (pir->IncFlags & INCLUDEDB_LOCAL) {
  2006. c1 = c2 = '"';
  2007. }
  2008. else {
  2009. c1 = '<';
  2010. c2 = '>';
  2011. }
  2012. BuildError("%s\\%s: ", pt->pfrCompiland->Dir->Name, pt->pfrCompiland->Name);
  2013. if (pt->pfrCompiland != pfr) {
  2014. if (pt->pfrCompiland->Dir != pfr->Dir) {
  2015. BuildErrorRaw("%s\\", pfr->Dir->Name);
  2016. }
  2017. BuildErrorRaw("%s: ", pfr->Name);
  2018. }
  2019. BuildErrorRaw("%s %c%s%c\n", pszError, c1, pir->Name, c2);
  2020. }
  2021. //+---------------------------------------------------------------------------
  2022. //
  2023. // Function: IsConditionalInc
  2024. //
  2025. // Synopsis: Returns TRUE if the given filename is a conditional include
  2026. // for this directory. (As given by the CONDITIONAL_INCLUDES
  2027. // macro).
  2028. //
  2029. // Arguments: [pszFile] -- Name of file to check
  2030. // [pt] -- Target struct giving list of conditional includes
  2031. //
  2032. // Returns: TRUE if it's a conditional include
  2033. //
  2034. //----------------------------------------------------------------------------
  2035. BOOL
  2036. IsConditionalInc(LPSTR pszFile, TARGET *pt)
  2037. {
  2038. AssertPathString(pszFile);
  2039. if (pt->ConditionalIncludes != NULL) {
  2040. LPSTR p;
  2041. char name[DB_MAX_PATH_LENGTH];
  2042. p = pt->ConditionalIncludes;
  2043. while (SplitToken(name, ' ', &p)) {
  2044. if (strcmp(name, pszFile) == 0) {
  2045. return(TRUE);
  2046. }
  2047. }
  2048. }
  2049. return(FALSE);
  2050. }
  2051. //+---------------------------------------------------------------------------
  2052. //
  2053. // Function: IsExcludedInc
  2054. //
  2055. // Synopsis: Returns TRUE if the given file is listed in the ExcludeIncs
  2056. // array.
  2057. //
  2058. // Arguments: [pszFile] -- File to check
  2059. //
  2060. //----------------------------------------------------------------------------
  2061. BOOL
  2062. IsExcludedInc(LPSTR pszFile)
  2063. {
  2064. ULONG i;
  2065. AssertPathString(pszFile);
  2066. for (i = 0; i < CountExcludeIncs; i++) {
  2067. if (!strcmp(pszFile, ExcludeIncs[i])) {
  2068. return(TRUE);
  2069. }
  2070. }
  2071. return(FALSE);
  2072. }
  2073. //+---------------------------------------------------------------------------
  2074. //
  2075. // Function: CheckDependencies
  2076. //
  2077. // Synopsis: Process dependencies to see if a target is out of date
  2078. //
  2079. // Arguments: [Target] -- Target to check date on
  2080. // [FileDB] -- File which makes [Target]
  2081. // [CheckDate] -- If FALSE, then the date check is bypassed.
  2082. // [ppfrRoot] -- Returns a cycle root if a cycle is encountered.
  2083. // Used only during recursion.
  2084. //
  2085. // Returns: TRUE if [Target] is out of date w/r/t [FileDB]
  2086. //
  2087. //----------------------------------------------------------------------------
  2088. BOOL
  2089. CheckDependencies(
  2090. PTARGET Target,
  2091. FILEREC *FileDB,
  2092. BOOL CheckDate,
  2093. FILEREC **ppfrRoot)
  2094. {
  2095. BOOL fOutOfDate;
  2096. BOOL CheckVersion;
  2097. static ULONG ChkRecursLevel = 0;
  2098. *ppfrRoot = NULL;
  2099. ChkRecursLevel++;
  2100. assert(FileDB != NULL); // NULL FileDB should never happen.
  2101. AssertFile(FileDB);
  2102. if (FileDB->fDependActive) {
  2103. // We have detected a loop in the graph of include files.
  2104. // Just return, to terminate the recursion.
  2105. if (DEBUG_1) {
  2106. BuildMsgRaw(
  2107. "ChkDepend(%s, %s, %u) %s\n",
  2108. Target->Name,
  2109. FileDB->Name,
  2110. CheckDate,
  2111. "Target Match, *** ASSUME UP TO DATE ***");
  2112. }
  2113. if (DEBUG_4) {
  2114. BuildMsgRaw(
  2115. "%lu-%hu/%hu: ChkDepend(%s %x, %4s%.*s%s, %u) %x %s\n",
  2116. ChkRecursLevel,
  2117. LocalSequence,
  2118. GlobalSequence,
  2119. Target->Name,
  2120. Target->DateTime,
  2121. "",
  2122. ChkRecursLevel,
  2123. szRecurse,
  2124. FileDB->Name,
  2125. CheckDate,
  2126. FileDB->DateTime,
  2127. "Target Match");
  2128. }
  2129. *ppfrRoot = FileDB;
  2130. ChkRecursLevel--;
  2131. return(FALSE);
  2132. }
  2133. if (DEBUG_4) {
  2134. BuildMsgRaw(
  2135. "%lu-%hu/%hu: ChkDepend(%s %x, %4s%.*s%s, %u) %x\n",
  2136. ChkRecursLevel,
  2137. LocalSequence,
  2138. GlobalSequence,
  2139. Target->Name,
  2140. Target->DateTime,
  2141. "++",
  2142. ChkRecursLevel,
  2143. szRecurse,
  2144. FileDB->Name,
  2145. CheckDate,
  2146. FileDB->DateTime);
  2147. }
  2148. // We've decided to process this file:
  2149. FileDB->fDependActive = TRUE;
  2150. CheckVersion = fEnableVersionCheck;
  2151. fOutOfDate = FALSE;
  2152. if (FileDB->GlobalSequence != GlobalSequence ||
  2153. FileDB->LocalSequence != LocalSequence) {
  2154. if (FileDB->GlobalSequence != 0 || FileDB->LocalSequence != 0) {
  2155. if (DEBUG_1) {
  2156. BuildError(
  2157. "Include Sequence %hu/%hu -> %hu/%hu\n",
  2158. FileDB->LocalSequence,
  2159. FileDB->GlobalSequence,
  2160. LocalSequence,
  2161. GlobalSequence);
  2162. }
  2163. if (fDebug & 16) {
  2164. PrintFileDB(stderr, FileDB, 0);
  2165. }
  2166. UnsnapIncludeFiles(
  2167. FileDB,
  2168. (FileDB->Dir->DirFlags & DIRDB_GLOBAL_INCLUDES) == 0 ||
  2169. FileDB->GlobalSequence != GlobalSequence);
  2170. }
  2171. FileDB->GlobalSequence = GlobalSequence;
  2172. FileDB->LocalSequence = LocalSequence;
  2173. FileDB->DateTimeTree = 0;
  2174. }
  2175. if (DEBUG_1) {
  2176. BuildMsgRaw(
  2177. "ChkDepend(%s, %s, %u)\n",
  2178. Target->Name,
  2179. FileDB->Name,
  2180. CheckDate);
  2181. }
  2182. if (CheckDate &&
  2183. (FileDB->FileFlags & FILEDB_HEADER) &&
  2184. FileDB->DateTimeTree == 0 &&
  2185. IsExcludedInc(FileDB->Name)) {
  2186. if (DEBUG_1) {
  2187. BuildMsg("Skipping date check for %s\n", FileDB->Name);
  2188. }
  2189. CheckVersion = FALSE;
  2190. FileDB->DateTimeTree = 1; // never out of date
  2191. }
  2192. if (FileDB->IncludeFiles == NULL && FileDB->DateTimeTree == 0) {
  2193. FileDB->DateTimeTree = FileDB->DateTime;
  2194. if (DEBUG_4) {
  2195. BuildMsgRaw(
  2196. "%lu-%hu/%hu: ChkDepend(%s %x, %4s%.*s%s, %u) %x\n",
  2197. ChkRecursLevel,
  2198. LocalSequence,
  2199. GlobalSequence,
  2200. Target->Name,
  2201. Target->DateTime,
  2202. "t<-f",
  2203. ChkRecursLevel,
  2204. szRecurse,
  2205. FileDB->Name,
  2206. CheckDate,
  2207. FileDB->DateTime);
  2208. }
  2209. }
  2210. if (CheckDate &&
  2211. (Target->DateTime < FileDB->DateTime ||
  2212. Target->DateTime < FileDB->DateTimeTree)) {
  2213. if (Target->DateTime != 0) {
  2214. if (DEBUG_1 || fShowOutOfDateFiles) {
  2215. BuildMsg("%s is out of date with respect to %s\\%s.\n",
  2216. Target->Name,
  2217. FileDB->NewestDependency->Dir->Name,
  2218. FileDB->NewestDependency->Name);
  2219. }
  2220. }
  2221. fOutOfDate = TRUE;
  2222. }
  2223. //
  2224. // If FileDB->DateTimeTree is non-zero, then the field is equal to the
  2225. // newest DateTime of this file or any of its dependants, so we don't
  2226. // need to go through the dependency tree again.
  2227. //
  2228. if (FileDB->DateTimeTree == 0) {
  2229. INCLUDEREC *IncludeDB, **IncludeDBNext, **ppirTree;
  2230. //
  2231. // Find the file records for all include files so that after cycles are
  2232. // collapsed, we won't attempt to lookup an include file relative to
  2233. // the wrong directory.
  2234. //
  2235. ppirTree = &FileDB->IncludeFilesTree;
  2236. for (IncludeDBNext = &FileDB->IncludeFiles;
  2237. (IncludeDB = *IncludeDBNext) != NULL;
  2238. IncludeDBNext = &IncludeDB->Next) {
  2239. AssertInclude(IncludeDB);
  2240. AssertCleanTree(IncludeDB, FileDB);
  2241. IncludeDB->IncFlags |= INCLUDEDB_SNAPPED;
  2242. if (IncludeDB->pfrInclude == NULL) {
  2243. IncludeDB->pfrInclude =
  2244. FindIncludeFileDB(
  2245. FileDB,
  2246. Target->pfrCompiland,
  2247. Target->pdrBuild,
  2248. Target->pszSourceDirectory,
  2249. IncludeDB);
  2250. AssertOptionalFile(IncludeDB->pfrInclude);
  2251. if (IncludeDB->pfrInclude != NULL &&
  2252. (IncludeDB->pfrInclude->Dir->DirFlags & DIRDB_GLOBAL_INCLUDES))
  2253. {
  2254. IncludeDB->IncFlags |= INCLUDEDB_GLOBAL;
  2255. }
  2256. }
  2257. if (IncludeDB->pfrInclude == NULL) {
  2258. if (!IsConditionalInc(IncludeDB->Name, Target)) {
  2259. if (DEBUG_1 || !(IncludeDB->IncFlags & INCLUDEDB_MISSING)) {
  2260. IncludeError(
  2261. Target,
  2262. FileDB,
  2263. IncludeDB,
  2264. "cannot find include file");
  2265. IncludeDB->IncFlags |= INCLUDEDB_MISSING;
  2266. }
  2267. } else
  2268. if (DEBUG_1) {
  2269. IncludeError(
  2270. Target,
  2271. FileDB,
  2272. IncludeDB,
  2273. "Skipping missing conditional include file");
  2274. }
  2275. continue;
  2276. }
  2277. *ppirTree = IncludeDB;
  2278. ppirTree = &IncludeDB->NextTree;
  2279. }
  2280. *ppirTree = NULL; // truncate any links from previous sequence
  2281. FileDB->DateTimeTree = FileDB->DateTime;
  2282. //
  2283. // Walk through the dynamic list.
  2284. //
  2285. rescan:
  2286. for (IncludeDBNext = &FileDB->IncludeFilesTree;
  2287. (IncludeDB = *IncludeDBNext) != NULL;
  2288. IncludeDBNext = &IncludeDB->NextTree) {
  2289. AssertInclude(IncludeDB);
  2290. if (DEBUG_2) {
  2291. BuildMsgRaw(
  2292. "%lu-%hu/%hu %s %*s%-10s %*s%s\n",
  2293. ChkRecursLevel,
  2294. LocalSequence,
  2295. GlobalSequence,
  2296. Target->pfrCompiland->Name,
  2297. (ChkRecursLevel - 1) * 2,
  2298. "",
  2299. IncludeDB->Name,
  2300. max(0, 12 - ((int)ChkRecursLevel - 1) * 2),
  2301. "",
  2302. IncludeDB->pfrInclude != NULL?
  2303. IncludeDB->pfrInclude->Dir->Name : "not found");
  2304. }
  2305. //
  2306. // tommcg 5/21/98
  2307. //
  2308. // If included file is not in "sanctioned" path, warn about it.
  2309. // Sanctioned paths are set in an environment variable named
  2310. // BUILD_ACCEPTABLE_INCLUDES which can contain wildcards and look
  2311. // something like this:
  2312. //
  2313. // *\nt\public\*;*\nt\private\inc\*;*\..\inc\*;*\..\include\*
  2314. //
  2315. if (( fCheckIncludePaths ) && ( IncludeDB->pfrInclude != NULL )) {
  2316. CheckIncludeForWarning(
  2317. Target->pfrCompiland->Dir->Name,
  2318. Target->pfrCompiland->Name,
  2319. FileDB->Dir->Name,
  2320. FileDB->Name,
  2321. IncludeDB->pfrInclude->Dir->Name,
  2322. IncludeDB->pfrInclude->Name
  2323. );
  2324. }
  2325. assert(IncludeDB->IncFlags & INCLUDEDB_SNAPPED);
  2326. if (IncludeDB->pfrInclude != NULL) {
  2327. if (fEnableVersionCheck) {
  2328. CheckDate = (IncludeDB->pfrInclude->Version == 0);
  2329. }
  2330. if (IncludeDB->Version != IncludeDB->pfrInclude->Version) {
  2331. if (CheckVersion) {
  2332. if (DEBUG_1 || fShowOutOfDateFiles) {
  2333. BuildError(
  2334. "%s (v%d) is out of date with "
  2335. "respect to %s\\%s (v%d).\n",
  2336. FileDB->Name,
  2337. IncludeDB->Version,
  2338. IncludeDB->pfrInclude->Dir->Name,
  2339. IncludeDB->pfrInclude->Name,
  2340. IncludeDB->pfrInclude->Version);
  2341. }
  2342. FileDB->DateTimeTree = ULONG_MAX; // always out of date
  2343. fOutOfDate = TRUE;
  2344. }
  2345. else
  2346. if (!fClean && fEnableVersionCheck && !fSilent) {
  2347. BuildError(
  2348. "%s - #include %s (v%d updated to v%d)\n",
  2349. FileDB->Name,
  2350. IncludeDB->pfrInclude->Name,
  2351. IncludeDB->Version,
  2352. IncludeDB->pfrInclude->Version);
  2353. }
  2354. IncludeDB->Version = IncludeDB->pfrInclude->Version;
  2355. AllDirsModified = TRUE;
  2356. }
  2357. if (CheckDependencies(Target,
  2358. IncludeDB->pfrInclude,
  2359. CheckDate,
  2360. ppfrRoot)) {
  2361. fOutOfDate = TRUE;
  2362. // No cycle possible if recursive call returned TRUE.
  2363. assert(*ppfrRoot == NULL);
  2364. }
  2365. // if the include file is involved in a cycle, unwind the
  2366. // recursion up to the root of the cycle while collpasing
  2367. // the cycle, then process the tree again from cycle root.
  2368. else if (*ppfrRoot != NULL) {
  2369. AssertFile(*ppfrRoot);
  2370. // Don't say the file is out of date, yet.
  2371. fOutOfDate = FALSE;
  2372. // Remove the current include file record from the list,
  2373. // because it participates in the cycle.
  2374. *IncludeDBNext = IncludeDB->NextTree;
  2375. if (IncludeDB->IncFlags & INCLUDEDB_CYCLEROOT) {
  2376. RemoveFromCycleRoot(IncludeDB, FileDB);
  2377. }
  2378. IncludeDB->NextTree = NULL;
  2379. IncludeDB->IncFlags |= INCLUDEDB_CYCLEORPHAN;
  2380. // If the included file is not the cycle root, add the
  2381. // cycle root to the included file's include file list.
  2382. if (*ppfrRoot != IncludeDB->pfrInclude) {
  2383. LinkToCycleRoot(IncludeDB, *ppfrRoot);
  2384. }
  2385. if (*ppfrRoot == FileDB) {
  2386. // We're at the cycle root; clear the root pointer.
  2387. // Then go rescan the list.
  2388. *ppfrRoot = NULL;
  2389. if (DEBUG_4) {
  2390. BuildMsgRaw(
  2391. "%lu-%hu/%hu: ChkDepend(%s %x, %4s%.*s%s, %u) %x %s\n",
  2392. ChkRecursLevel,
  2393. LocalSequence,
  2394. GlobalSequence,
  2395. Target->Name,
  2396. Target->DateTime,
  2397. "^^",
  2398. ChkRecursLevel,
  2399. szRecurse,
  2400. FileDB->Name,
  2401. CheckDate,
  2402. FileDB->DateTime,
  2403. "ReScan");
  2404. BuildMsgRaw("^^\n");
  2405. }
  2406. goto rescan;
  2407. }
  2408. // Merge the list for the file involved in the
  2409. // cycle into the root file's include list.
  2410. MergeIncludeFiles(
  2411. *ppfrRoot,
  2412. FileDB->IncludeFilesTree,
  2413. FileDB);
  2414. FileDB->IncludeFilesTree = NULL;
  2415. // Return immediately and reprocess the flattened
  2416. // tree, which now excludes the include files
  2417. // directly involved in the cycle. First, make
  2418. // sure the files removed from the cycle have their file
  2419. // (not tree) time stamps reflected in the cycle root.
  2420. if ((*ppfrRoot)->DateTimeTree < FileDB->DateTime) {
  2421. (*ppfrRoot)->DateTimeTree = FileDB->DateTime;
  2422. (*ppfrRoot)->NewestDependency = FileDB;
  2423. if (DEBUG_4) {
  2424. BuildMsgRaw(
  2425. "%lu-%hu/%hu: ChkDepend(%s %x, %4s%.*s%s, %u) %x\n",
  2426. ChkRecursLevel,
  2427. LocalSequence,
  2428. GlobalSequence,
  2429. Target->Name,
  2430. Target->DateTime,
  2431. "t<-c",
  2432. ChkRecursLevel,
  2433. szRecurse,
  2434. (*ppfrRoot)->Name,
  2435. CheckDate,
  2436. (*ppfrRoot)->DateTimeTree);
  2437. }
  2438. }
  2439. break;
  2440. }
  2441. //
  2442. // Propagate newest time up through the dependency tree.
  2443. // This way, each parent will have the date of its newest
  2444. // dependent, so we don't have to check through the whole
  2445. // dependency tree for each file more than once.
  2446. //
  2447. // Note that similar behavior has not been enabled for
  2448. // version checking.
  2449. //
  2450. if (FileDB->DateTimeTree < IncludeDB->pfrInclude->DateTimeTree)
  2451. {
  2452. FileDB->DateTimeTree = IncludeDB->pfrInclude->DateTimeTree;
  2453. FileDB->NewestDependency =
  2454. IncludeDB->pfrInclude->NewestDependency;
  2455. if (DEBUG_4) {
  2456. BuildMsgRaw(
  2457. "%lu-%hu/%hu: ChkDepend(%s %x, %4s%.*s%s, %u) %x\n",
  2458. ChkRecursLevel,
  2459. LocalSequence,
  2460. GlobalSequence,
  2461. Target->Name,
  2462. Target->DateTime,
  2463. "t<-s",
  2464. ChkRecursLevel,
  2465. szRecurse,
  2466. FileDB->Name,
  2467. CheckDate,
  2468. FileDB->DateTimeTree);
  2469. }
  2470. }
  2471. }
  2472. else
  2473. {
  2474. //
  2475. // Couldn't find the FILEDB for the include file, but this
  2476. // could be because the file is 'rcinclude'd, or 'importlib'd
  2477. // and isn't considered a source file. In this case, just get
  2478. // the timestamp on the file if possible.
  2479. //
  2480. // Time will be zero if the file is not found.
  2481. //
  2482. ULONG Time = (*pDateTimeFile)(NULL, IncludeDB->Name);
  2483. if (FileDB->DateTimeTree < Time)
  2484. {
  2485. FileDB->DateTimeTree = Time;
  2486. //
  2487. // Since we don't have a FILEDB for this dependency, just
  2488. // set the pointer to itself and print a message.
  2489. //
  2490. FileDB->NewestDependency = FileDB;
  2491. if (DEBUG_1 || fShowOutOfDateFiles) {
  2492. BuildError(
  2493. "%s (v%d) is out of date with respect to %s.\n",
  2494. FileDB->Name,
  2495. IncludeDB->Version,
  2496. IncludeDB->Name);
  2497. }
  2498. if (DEBUG_4) {
  2499. BuildMsgRaw(
  2500. "%lu-%hu/%hu: ChkDepend(%s %x, %4s%.*s%s, %u) %x\n",
  2501. ChkRecursLevel,
  2502. LocalSequence,
  2503. GlobalSequence,
  2504. Target->Name,
  2505. Target->DateTime,
  2506. "t<-s",
  2507. ChkRecursLevel,
  2508. szRecurse,
  2509. FileDB->Name,
  2510. CheckDate,
  2511. FileDB->DateTimeTree);
  2512. }
  2513. }
  2514. }
  2515. }
  2516. }
  2517. if (DEBUG_4) {
  2518. BuildMsgRaw(
  2519. "%lu-%hu/%hu: ChkDepend(%s %x, %4s%.*s%s, %u) %x %s\n",
  2520. ChkRecursLevel,
  2521. LocalSequence,
  2522. GlobalSequence,
  2523. Target->Name,
  2524. Target->DateTime,
  2525. "--",
  2526. ChkRecursLevel,
  2527. szRecurse,
  2528. FileDB->Name,
  2529. CheckDate,
  2530. FileDB->DateTimeTree,
  2531. *ppfrRoot != NULL? "Collapse Cycle" :
  2532. fOutOfDate? "OUT OF DATE" : "up-to-date");
  2533. }
  2534. assert(FileDB->fDependActive);
  2535. FileDB->fDependActive = FALSE;
  2536. ChkRecursLevel--;
  2537. return(fOutOfDate);
  2538. }
  2539. //+---------------------------------------------------------------------------
  2540. //
  2541. // Function: PickFirst
  2542. //
  2543. // Synopsis: When called iteratively, the set of returned values is
  2544. // effectively a merge sort of the two source lists.
  2545. //
  2546. // Effects: The pointers given in [ppsr1] and [ppsr2] are modified to point
  2547. // to the next appropriate item in the list.
  2548. //
  2549. // Arguments: [ppsr1] -- First SOURCEREC list
  2550. // [ppsr2] -- Second SOURCEREC list
  2551. //
  2552. // Returns: The appropriate next item from either [ppsr1] or [ppsr2]
  2553. //
  2554. // Notes: [ppsr1] and [ppsr2] should each be appropriately sorted.
  2555. //
  2556. // InsertSourceDB maintains a sort order for PickFirst() based first on the
  2557. // filename extension, then on the subdirectory mask. Two exceptions to the
  2558. // alphabetic sort are:
  2559. // - No extension sorts last.
  2560. // - .rc extension sorts first.
  2561. //
  2562. //----------------------------------------------------------------------------
  2563. #define PF_FIRST -1
  2564. #define PF_SECOND 1
  2565. SOURCEREC *
  2566. PickFirst(SOURCEREC **ppsr1, SOURCEREC **ppsr2)
  2567. {
  2568. SOURCEREC **ppsr;
  2569. SOURCEREC *psr;
  2570. int r = 0;
  2571. AssertOptionalSource(*ppsr1);
  2572. AssertOptionalSource(*ppsr2);
  2573. if (*ppsr1 == NULL) {
  2574. if (*ppsr2 == NULL) {
  2575. return(NULL); // both lists NULL -- no more
  2576. }
  2577. r = PF_SECOND; // 1st is NULL -- return 2nd
  2578. }
  2579. else if (*ppsr2 == NULL) {
  2580. r = PF_FIRST; // 2nd is NULL -- return 1st
  2581. }
  2582. else {
  2583. LPSTR pszext1, pszext2;
  2584. pszext1 = strrchr((*ppsr1)->pfrSource->Name, '.');
  2585. pszext2 = strrchr((*ppsr2)->pfrSource->Name, '.');
  2586. if (pszext1 == NULL) {
  2587. r = PF_SECOND; // 1st has no extension -- return 2nd
  2588. }
  2589. else if (pszext2 == NULL) {
  2590. r = PF_FIRST; // 2nd has no extension -- return 1st
  2591. }
  2592. else if (strcmp(pszext1, ".rc") == 0) {
  2593. r = PF_FIRST; // 1st is .rc -- return 1st
  2594. }
  2595. else if (strcmp(pszext2, ".rc") == 0) {
  2596. r = PF_SECOND; // 2nd is .rc -- return 2nd
  2597. }
  2598. else {
  2599. r = strcmp(pszext1, pszext2);
  2600. if (r == 0 &&
  2601. (*ppsr1)->SourceSubDirMask != (*ppsr2)->SourceSubDirMask) {
  2602. if ((*ppsr1)->SourceSubDirMask > (*ppsr2)->SourceSubDirMask) {
  2603. r = PF_FIRST; // 2nd subdir after 1st -- return 1st
  2604. } else {
  2605. r = PF_SECOND; // 1st subdir after 2nd -- return 2nd
  2606. }
  2607. }
  2608. }
  2609. }
  2610. if (r <= 0) {
  2611. ppsr = ppsr1;
  2612. } else {
  2613. ppsr = ppsr2;
  2614. }
  2615. psr = *ppsr;
  2616. *ppsr = psr->psrNext;
  2617. return(psr);
  2618. }
  2619. //+---------------------------------------------------------------------------
  2620. //
  2621. // Function: WriteObjectsDefinition
  2622. //
  2623. // Synopsis: Writes out a single platform-specific section of the
  2624. // _objects.mac file.
  2625. //
  2626. // Arguments: [OutFileHandle] -- File handle to write to
  2627. // [psrCommon] -- List of common source files
  2628. // [psrMachine] -- List of machine-specific source files
  2629. // [DirDB] -- directory record
  2630. // [ObjectVariable] -- e.g. 386_SOURCES
  2631. // [ObjectDirectory] -- name of machine obj dir (e.g. obj\i386)
  2632. //
  2633. // Returns:
  2634. //
  2635. // History: 26-Jul-94 LyleC Created
  2636. //
  2637. // Notes:
  2638. //
  2639. //----------------------------------------------------------------------------
  2640. VOID
  2641. WriteObjectsDefinition(
  2642. FILE *OutFileHandle,
  2643. SOURCEREC *psrMachine,
  2644. DIRSUP *pds,
  2645. LPSTR ObjectVariable,
  2646. LPSTR ObjectDirectory,
  2647. LPSTR DirName
  2648. )
  2649. {
  2650. LPSTR pbuf;
  2651. LPSTR pszextsrc;
  2652. LPSTR pszextdir;
  2653. LPTARGETDATA pData;
  2654. SOURCEREC *psrComCopy;
  2655. SOURCEREC *psrMachCopy;
  2656. SOURCEREC *psrCommon = pds->psrSourcesList[0];
  2657. SOURCEREC *psr;
  2658. USHORT i;
  2659. LONG iPass;
  2660. //
  2661. // We loop twice - the first time writing out the non-pass-zero files
  2662. // to the ObjectVariable, the second time writing out pass zero
  2663. // files to the PASS0_ObjectVariable.
  2664. //
  2665. for (iPass = 1; iPass >= 0; iPass--)
  2666. {
  2667. pbuf = BigBuf;
  2668. pbuf[0] = '\0';
  2669. if (iPass == 0) {
  2670. strcpy(pbuf, "PASS0_");
  2671. }
  2672. strcat(pbuf, ObjectVariable);
  2673. strcat(pbuf, "=");
  2674. pbuf += strlen(pbuf);
  2675. psrComCopy = psrCommon;
  2676. psrMachCopy = psrMachine;
  2677. while ((psr = PickFirst(&psrComCopy, &psrMachCopy)) != NULL) {
  2678. AssertSource(psr);
  2679. if ((psr->SrcFlags & SOURCEDB_SOURCES_LIST) == 0) {
  2680. continue;
  2681. }
  2682. // if pass 0 macro and not a pass 0 file, skip it.
  2683. if (iPass == 0 && !(psr->pfrSource->FileFlags & FILEDB_PASS0))
  2684. continue;
  2685. // if pass 1 macro and not a pass 1 file, skip it.
  2686. if (iPass == 1 &&
  2687. (psr->pfrSource->FileFlags & FILEDB_PASS0) &&
  2688. !(psr->pfrSource->FileFlags & FILEDB_MULTIPLEPASS))
  2689. continue;
  2690. pszextsrc = strrchr(psr->pfrSource->Name, '.');
  2691. if (!pszextsrc) {
  2692. BuildError("Bad sources extension: %s\n", psr->pfrSource->Name);
  2693. continue;
  2694. }
  2695. i = 0;
  2696. while (pData = GetTargetData(pszextsrc, iPass, i, pds->IdlType))
  2697. {
  2698. if (pData == &DefaultData)
  2699. {
  2700. //
  2701. // Check for implicitly 'known' extensions...
  2702. //
  2703. switch (pszextsrc[1]) {
  2704. case 'f': // Fortran
  2705. case 'h': // Header file ?
  2706. case 'p': // Pascal
  2707. BuildError(
  2708. "%s: Interesting sources extension: %s\n",
  2709. DirName,
  2710. psr->pfrSource->Name);
  2711. // FALL THROUGH
  2712. case 'a': // Assembly file (.asm)
  2713. case 'c': // C file (.c or .cxx)
  2714. case 's': // Assembly file (.s)
  2715. break;
  2716. default:
  2717. BuildError("Bad sources extension: %s\n",
  2718. psr->pfrSource->Name);
  2719. }
  2720. }
  2721. switch (pData->ObjectDirFlag)
  2722. {
  2723. case TD_OBJECTDIR:
  2724. pszextdir = ObjectDirectory;
  2725. break;
  2726. case TD_PASS0HDRDIR:
  2727. pszextdir = "$(PASS0_HEADERDIR)";
  2728. break;
  2729. case TD_MCSOURCEDIR:
  2730. pszextdir = "$(MC_SOURCEDIR)";
  2731. break;
  2732. case TD_PASS0DIR1:
  2733. pszextdir = pds->PassZeroSrcDir1;
  2734. break;
  2735. case TD_PASS0DIR2:
  2736. pszextdir = pds->PassZeroSrcDir2;
  2737. break;
  2738. default:
  2739. assert(0 && "Invalid ObjectDirFlag");
  2740. break;
  2741. }
  2742. assert(pszextdir);
  2743. assert(pData->pszTargetExt);
  2744. sprintf(
  2745. pbuf,
  2746. " \\\r\n %s\\%.*s%s",
  2747. pszextdir,
  2748. pszextsrc - psr->pfrSource->Name,
  2749. psr->pfrSource->Name,
  2750. pData->pszTargetExt);
  2751. pbuf += strlen(pbuf);
  2752. i++;
  2753. }
  2754. }
  2755. strcpy(pbuf, "\r\n\r\n");
  2756. pbuf += 4;
  2757. fwrite(BigBuf, 1, (UINT) (pbuf - BigBuf), OutFileHandle);
  2758. }
  2759. }
  2760. DWORD
  2761. CreateDirectoriesOnPath(
  2762. LPTSTR pszPath,
  2763. LPSECURITY_ATTRIBUTES psa)
  2764. {
  2765. DWORD dwErr = ERROR_SUCCESS;
  2766. if (pszPath && *pszPath)
  2767. {
  2768. LPTSTR pch = pszPath;
  2769. // If the path is a UNC path, we need to skip the \\server\share
  2770. // portion.
  2771. //
  2772. if ((TEXT('\\') == *pch) && (TEXT('\\') == *(pch+1)))
  2773. {
  2774. // pch now pointing at the server name. Skip to the backslash
  2775. // before the share name.
  2776. //
  2777. pch += 2;
  2778. while (*pch && (TEXT('\\') != *pch))
  2779. {
  2780. pch++;
  2781. }
  2782. if (!*pch)
  2783. {
  2784. // Just the \\server was specified. This is bogus.
  2785. //
  2786. return ERROR_INVALID_PARAMETER;
  2787. }
  2788. // pch now pointing at the backslash before the share name.
  2789. // Skip to the backslash that should come after the share name.
  2790. //
  2791. pch++;
  2792. while (*pch && (TEXT('\\') != *pch))
  2793. {
  2794. pch++;
  2795. }
  2796. if (!*pch)
  2797. {
  2798. // Just the \\server\share was specified. No subdirectories
  2799. // to create.
  2800. //
  2801. return ERROR_SUCCESS;
  2802. }
  2803. }
  2804. // Loop through the path.
  2805. //
  2806. for (; *pch; pch++)
  2807. {
  2808. // Stop at each backslash and make sure the path
  2809. // is created to that point. Do this by changing the
  2810. // backslash to a null-terminator, calling CreateDirecotry,
  2811. // and changing it back.
  2812. //
  2813. if (TEXT('\\') == *pch)
  2814. {
  2815. BOOL fOk;
  2816. *pch = 0;
  2817. fOk = CreateDirectory (pszPath, psa);
  2818. *pch = TEXT('\\');
  2819. // Any errors other than path alredy exists and we should
  2820. // bail out. We also get access denied when trying to
  2821. // create a root drive (i.e. c:) so check for this too.
  2822. //
  2823. if (!fOk)
  2824. {
  2825. dwErr = GetLastError ();
  2826. if (ERROR_ALREADY_EXISTS == dwErr)
  2827. {
  2828. dwErr = ERROR_SUCCESS;
  2829. }
  2830. else if ((ERROR_ACCESS_DENIED == dwErr) &&
  2831. (pch - 1 > pszPath) && (TEXT(':') == *(pch - 1)))
  2832. {
  2833. dwErr = ERROR_SUCCESS;
  2834. }
  2835. else
  2836. {
  2837. break;
  2838. }
  2839. }
  2840. }
  2841. }
  2842. if (ERROR_ALREADY_EXISTS == dwErr)
  2843. {
  2844. dwErr = ERROR_SUCCESS;
  2845. }
  2846. if (ERROR_SUCCESS == dwErr)
  2847. {
  2848. // All dirs up to the last are created. Make the last one also.
  2849. if (CreateDirectory(pszPath, psa))
  2850. {
  2851. dwErr = GetLastError ();
  2852. if (ERROR_ALREADY_EXISTS == dwErr)
  2853. {
  2854. dwErr = ERROR_SUCCESS;
  2855. }
  2856. }
  2857. }
  2858. }
  2859. return dwErr;
  2860. }
  2861. //+---------------------------------------------------------------------------
  2862. //
  2863. // Function: CreateBuildDirectory
  2864. //
  2865. // Synopsis: Creates a directory to hold generate object files. SET the
  2866. // FILE_ATTRIBUTE_ARCHIVE bit for the directory, since there is nothing
  2867. // to backup. We use SET since the default setting for a new directory
  2868. // is clear. Go figure. DOS was such a well planned product.
  2869. //
  2870. // Arguments: [Name] -- Directory to create
  2871. //
  2872. // Returns: TRUE if directory already exists or was created successfully.
  2873. // FALSE otherwise.
  2874. //----------------------------------------------------------------------------
  2875. BOOL
  2876. CreateBuildDirectory(LPSTR Name)
  2877. {
  2878. DWORD Attributes;
  2879. Attributes = GetFileAttributes(Name);
  2880. if (Attributes == -1) {
  2881. CreateDirectoriesOnPath(Name, NULL);
  2882. Attributes = GetFileAttributes(Name);
  2883. }
  2884. if (Attributes != -1 && ((Attributes & FILE_ATTRIBUTE_ARCHIVE) == 0)) {
  2885. SetFileAttributes(Name, Attributes | FILE_ATTRIBUTE_ARCHIVE);
  2886. }
  2887. return((BOOL)(Attributes != -1));
  2888. }
  2889. //+---------------------------------------------------------------------------
  2890. //
  2891. // Function: CreatedBuildFile
  2892. //
  2893. // Synopsis: Called whenever BUILD creates a file. Clears the FILE_ATTRIBUTE_ARCHIVE
  2894. // bit for the file, since there is nothing to backup with a generated file.
  2895. //
  2896. // Arguments: [DirName] -- DIRDB for directory
  2897. // [FileName] -- file name path relative to DirName
  2898. //
  2899. //----------------------------------------------------------------------------
  2900. VOID
  2901. CreatedBuildFile(LPSTR DirName, LPSTR FileName)
  2902. {
  2903. char Name[ DB_MAX_PATH_LENGTH * 2 + 1]; // ensure we have enough space for "DirName" + "\\" + "FileName"
  2904. DWORD Attributes;
  2905. strcpy(Name, DirName);
  2906. if (Name[0] != '\0') {
  2907. strcat(Name, "\\");
  2908. }
  2909. strcat(Name, FileName);
  2910. Attributes = GetFileAttributes(Name);
  2911. if (Attributes != -1 && (Attributes & FILE_ATTRIBUTE_ARCHIVE)) {
  2912. SetFileAttributes(Name, Attributes & ~FILE_ATTRIBUTE_ARCHIVE);
  2913. }
  2914. return;
  2915. }
  2916. //+---------------------------------------------------------------------------
  2917. //
  2918. // Function: GenerateObjectsDotMac
  2919. //
  2920. // Synopsis: Creates the _objects.mac file containing info for all platforms
  2921. //
  2922. // Arguments: [DirDB] -- Directory to create file for
  2923. // [pds] -- Supplementary information on [DirDB]
  2924. // [DateTimeSources] -- Timestamp of the SOURCES file
  2925. //
  2926. //----------------------------------------------------------------------------
  2927. VOID
  2928. GenerateObjectsDotMac(DIRREC *DirDB, DIRSUP *pds, ULONG DateTimeSources)
  2929. {
  2930. FILE *OutFileHandle;
  2931. UINT i;
  2932. ULONG ObjectsDateTime;
  2933. CreateBuildDirectory("obj");
  2934. if (strcmp(pszObjDir, "obj") != 0) {
  2935. if (ProbeFile(".", pszObjDir) == -1) {
  2936. CreateDirectory(pszObjDir, NULL);
  2937. }
  2938. }
  2939. for (i = 0; i < CountTargetMachines; i++) {
  2940. assert(strncmp(
  2941. pszObjDirSlash,
  2942. TargetMachines[i]->ObjectDirectory[iObjectDir],
  2943. strlen(pszObjDirSlash)) == 0);
  2944. CreateBuildDirectory(TargetMachines[i]->ObjectDirectory[iObjectDir]);
  2945. }
  2946. if (ObjectsDateTime = (*pDateTimeFile)(DirDB->Name, "obj\\_objects.mac")) {
  2947. if (DateTimeSources == 0) {
  2948. BuildError("%s: no sources timestamp\n", DirDB->Name);
  2949. }
  2950. if (ObjectsDateTime >= DateTimeSources) {
  2951. if (!fForce) {
  2952. return;
  2953. }
  2954. }
  2955. }
  2956. if (!MyOpenFile(DirDB->Name, "obj\\_objects.mac", "wb", &OutFileHandle, TRUE)) {
  2957. return;
  2958. }
  2959. if ((DirDB->DirFlags & DIRDB_SOURCES_SET) == 0) {
  2960. BuildError("Missing SOURCES= definition in %s\n", DirDB->Name);
  2961. } else {
  2962. for (i = 0; i < MAX_TARGET_MACHINES; i++) {
  2963. WriteObjectsDefinition(
  2964. OutFileHandle,
  2965. pds->psrSourcesList[i + 1],
  2966. pds,
  2967. PossibleTargetMachines[i]->ObjectVariable,
  2968. PossibleTargetMachines[i]->ObjectMacro,
  2969. DirDB->Name);
  2970. }
  2971. }
  2972. fclose(OutFileHandle);
  2973. CreatedBuildFile(DirDB->Name, "obj\\_objects.mac");
  2974. //
  2975. // If the _objects.mac file was generated during the first pass, then we
  2976. // want to regenerate it during the second scan because the first scan
  2977. // wasn't complete and _objects.mac may not be correct for non-pass-zero
  2978. // files. We do this by setting the timestamp back to the old time.
  2979. //
  2980. if (fFirstScan && fPassZero)
  2981. {
  2982. HANDLE hf;
  2983. FILETIME ft;
  2984. hf = CreateFile("obj\\_objects.mac", GENERIC_WRITE, 0,
  2985. (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING,
  2986. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING,
  2987. (HANDLE)NULL);
  2988. if (hf != INVALID_HANDLE_VALUE) {
  2989. ULONG time;
  2990. if (ObjectsDateTime) {
  2991. time = ObjectsDateTime;
  2992. }
  2993. else if (DateTimeSources) {
  2994. //
  2995. // All we care about is that time time stamp on _objects.mac
  2996. // is less than that of the sources file so it will get
  2997. // regenerated during the second scan.
  2998. //
  2999. time = DateTimeSources;
  3000. if (LOWORD(time) != 0)
  3001. time &= 0xFFFF0000; // 00:00:00 on the same date
  3002. else
  3003. time = 0x1421A000; // 12:00:00 1/1/1990
  3004. }
  3005. else {
  3006. time = 0x1421A000; // 12:00:00 1/1/1990
  3007. }
  3008. DosDateTimeToFileTime(HIWORD(time), LOWORD(time), &ft);
  3009. SetFileTime(hf, (LPFILETIME)NULL, (LPFILETIME)NULL, &ft);
  3010. CloseHandle(hf);
  3011. }
  3012. }
  3013. }