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.

1828 lines
54 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1989 - 1994.
  5. //
  6. // File: build.c
  7. //
  8. // Contents: Parameter processing and main entry point for Build.exe
  9. //
  10. // History: 16-May-89 SteveWo Created
  11. // ... See SLM log
  12. // 26-Jul-94 LyleC Cleanup/Add Pass0 support
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "build.h"
  16. #include <ntverp.h>
  17. //
  18. // Increase critical section timeout so people don't get
  19. // frightened when the CRT takes a long time to acquire
  20. // its critical section.
  21. //
  22. IMAGE_LOAD_CONFIG_DIRECTORY _load_config_used = {
  23. 0, // Reserved
  24. 0, // Reserved
  25. 0, // Reserved
  26. 0, // Reserved
  27. 0, // GlobalFlagsClear
  28. 0, // GlobalFlagsSet
  29. 1000 * 60 * 60 * 24, // CriticalSectionTimeout (milliseconds)
  30. 0, // DeCommitFreeBlockThreshold
  31. 0, // DeCommitTotalFreeThreshold
  32. 0, // LockPrefixTable
  33. 0, 0, 0, 0, 0, 0, 0 // Reserved
  34. };
  35. //
  36. // Target machine info:
  37. //
  38. // SourceSubDirMask, Description, Switch, MakeVariable,
  39. // SourceVariable, ObjectVariable, AssociateDirectory,
  40. // SourceDirectory, ObjectDirectory
  41. //
  42. TARGET_MACHINE_INFO i386TargetMachine = {
  43. TMIDIR_I386, "i386", "-386", "-x86", "386=1",
  44. "i386_SOURCES", "386_OBJECTS", "i386",
  45. "i386", "i386dirs", { "i386" },
  46. DIR_INCLUDE_X86 | DIR_INCLUDE_WIN32
  47. };
  48. TARGET_MACHINE_INFO ia64TargetMachine = {
  49. TMIDIR_IA64, "IA64", "-ia64", "-merced", "IA64=1",
  50. "IA64_SOURCES", "IA64_OBJECTS", "ia64",
  51. "ia64", "ia64dirs", { "ia64" },
  52. DIR_INCLUDE_IA64 | DIR_INCLUDE_RISC | DIR_INCLUDE_WIN64
  53. };
  54. TARGET_MACHINE_INFO Amd64TargetMachine = {
  55. TMIDIR_AMD64, "AMD64", "-amd64", "-amd64", "AMD64=1",
  56. "AMD64_SOURCES", "AMD64_OBJECTS", "amd64",
  57. "amd64", "amd64dirs", { "amd64" },
  58. DIR_INCLUDE_AMD64 | DIR_INCLUDE_RISC | DIR_INCLUDE_WIN64
  59. };
  60. TARGET_MACHINE_INFO *PossibleTargetMachines[MAX_TARGET_MACHINES] = {
  61. &i386TargetMachine,
  62. &ia64TargetMachine,
  63. &Amd64TargetMachine
  64. };
  65. UINT NumberCompileWarnings;
  66. UINT NumberCompileErrors;
  67. UINT NumberCompiles;
  68. UINT NumberLibraries;
  69. UINT NumberLibraryWarnings;
  70. UINT NumberLibraryErrors;
  71. UINT NumberLinks;
  72. UINT NumberLinkWarnings;
  73. UINT NumberLinkErrors;
  74. UINT NumberBinplaces;
  75. UINT NumberBinplaceWarnings;
  76. UINT NumberBinplaceErrors;
  77. //
  78. // Machine specific target dirs default. If one there is only one build
  79. // target and a target specific dirs file is selected, then this gets
  80. // filled with a pointer to the target specific dirs filename.
  81. //
  82. LPSTR pszTargetDirs = "";
  83. #define AltDirMaxSize 10 // Maximum size for alternate obj dir name
  84. CHAR LogDirectory[DB_MAX_PATH_LENGTH] = ".";
  85. CHAR LogFileName[DB_MAX_PATH_LENGTH] = "build";
  86. CHAR WrnFileName[DB_MAX_PATH_LENGTH] = "build";
  87. CHAR ErrFileName[DB_MAX_PATH_LENGTH] = "build";
  88. CHAR IncFileName[DB_MAX_PATH_LENGTH] = "build";
  89. CHAR szObjRoot[DB_MAX_PATH_LENGTH];
  90. CHAR *pszObjRoot;
  91. CHAR szBuildAltDir[DB_MAX_PATH_LENGTH];
  92. CHAR *pszBuildAltDir = NULL;
  93. CHAR szObjDir[DB_MAX_PATH_LENGTH];
  94. CHAR szObjDirSlash[DB_MAX_PATH_LENGTH];
  95. CHAR szObjDirSlashStar[DB_MAX_PATH_LENGTH];
  96. CHAR szObjDirD[DB_MAX_PATH_LENGTH];
  97. CHAR szObjDirSlashD[DB_MAX_PATH_LENGTH];
  98. CHAR szObjDirSlashStarD[DB_MAX_PATH_LENGTH];
  99. CHAR *pszObjDir = szObjDir;
  100. CHAR *pszObjDirSlash = szObjDirSlash;
  101. CHAR *pszObjDirSlashStar = szObjDirSlashStar;
  102. CHAR *pszObjDirD = szObjDirD;
  103. BOOL fCheckedBuild = TRUE;
  104. ULONG iObjectDir = 0;
  105. BOOL fDependencySwitchUsed;
  106. BOOL fCmdLineDependencySwitchUsed;
  107. BOOL fCmdLineQuicky;
  108. BOOL fCmdLineSemiQuicky;
  109. BOOL fCmdLineQuickZero;
  110. CHAR *BuildProduct;
  111. ULONG DefaultProcesses = 0;
  112. CHAR *szBuildTag;
  113. #define MAX_ENV_ARG 512
  114. const char szNewLine[] = "\n";
  115. const char szUsage[] =
  116. "Usage: BUILD [-?] display this message\n"
  117. "\t[-#] force _objects.mac to be regenerated\n"
  118. "\t[-0] pass 0 generation only, no compile, no link\n"
  119. "\t[-2] same as old -Z (only do a 2 pass build - no pass 0)\n"
  120. "\t[-3] same as -Z\n"
  121. "\t[-a] allows synchronized blocks and drains during link pass\n"
  122. "\t[-b] displays full error message text (doesn't truncate)\n"
  123. "\t[-c] deletes all object files\n"
  124. "\t[-C] deletes all .lib files only\n"
  125. #if DBG
  126. "\t[-d] display debug information\n"
  127. #endif
  128. "\t[-D] check dependencies before building (on by default if BUILD_PRODUCT != NT)\n"
  129. "\t[-e] generates build.log, build.wrn & build.err files\n"
  130. "\t[-E] always keep the log/wrn/err files (use with -z)\n"
  131. "\t[-f] force rescan of all source and include files\n"
  132. "\t[-F] when displaying errors/warnings to stdout, print the full path\n"
  133. "\t[-G] enables target specific dirs files iff one target\n"
  134. "\t[-i] ignore extraneous compiler warning messages\n"
  135. "\t[-I] do not display thread index if multiprocessor build\n"
  136. "\t[-k] keep (don't delete) out-of-date targets\n"
  137. "\t[-l] link only, no compiles\n"
  138. "\t[-L] compile only, no link phase\n"
  139. "\t[-m] run build in the idle priority class\n"
  140. "\t[-M [n]] Multiprocessor build (for MP machines)\n"
  141. "\t[-o] display out-of-date files\n"
  142. "\t[-O] generate obj\\_objects.mac file for current directory\n"
  143. "\t[-p] pause' before compile and link phases\n"
  144. "\t[-P] Print elapsed time after every directory\n"
  145. "\t[-q] query only, don't run NMAKE\n"
  146. "\t[-r dirPath] restarts clean build at specified directory path\n"
  147. "\t[-s] display status line at top of display\n"
  148. "\t[-S] display status line with include file line counts\n"
  149. "\t[-t] display the first level of the dependency tree\n"
  150. "\t[-T] display the complete dependency tree\n"
  151. "\t[-$] display the complete dependency tree hierarchically\n"
  152. "\t[-u] display unused BUILD_OPTIONS\n"
  153. "\t[-v] enable include file version checking\n"
  154. "\t[-w] show warnings on screen\n"
  155. "\t[-y] show files scanned\n"
  156. "\t[-z] no dependency checking or scanning of source files -\n"
  157. "\t\tone pass compile/link\n"
  158. "\t[-Z] no dependency checking or scanning of source files -\n"
  159. "\t\tthree passes\n"
  160. "\t[-why] list reasons for building targets\n"
  161. "\n"
  162. "\t[-386] build targets for 32-bit Intel\n"
  163. "\t[-x86] Same as -i386\n"
  164. "\t[-ia64] build targets for IA64\n"
  165. "\t[-amd64] build targets for AMD64\n"
  166. "\n"
  167. "\t[-x filename] exclude include file from dependency checks\n"
  168. "\t[-j filename] use 'filename' as the name for log files\n"
  169. "\t[-jpath pathname] use 'pathname' as the path for log files instead of \".\"\n"
  170. "\t[-nmake arg] argument to pass to NMAKE\n"
  171. "\t[-clean] equivalent to '-nmake clean'\n"
  172. "\tNon-switch parameters specify additional source directories\n"
  173. "\t* builds all optional source directories\n";
  174. BOOL
  175. ProcessParameters(int argc, LPSTR argv[], BOOL SkipFirst);
  176. VOID
  177. GetEnvParameters(
  178. LPSTR EnvVarName,
  179. LPSTR DefaultValue,
  180. int *pargc,
  181. int maxArgc,
  182. LPSTR argv[]);
  183. VOID
  184. FreeEnvParameters(int argc, LPSTR argv[]);
  185. VOID
  186. FreeCmdStrings(VOID);
  187. VOID
  188. MungePossibleTarget(
  189. PTARGET_MACHINE_INFO pti
  190. );
  191. VOID
  192. GetIncludePatterns(
  193. LPSTR EnvVarName,
  194. int maxArgc,
  195. LPSTR argv[]);
  196. VOID
  197. FreeIncludePatterns(
  198. int argc,
  199. LPSTR argv[]);
  200. //+---------------------------------------------------------------------------
  201. //
  202. // Function: main
  203. //
  204. //----------------------------------------------------------------------------
  205. int
  206. __cdecl main(
  207. int argc,
  208. LPSTR argv[]
  209. )
  210. {
  211. char c;
  212. PDIRREC DirDB;
  213. UINT i;
  214. int EnvArgc = 0;
  215. LPSTR EnvArgv[ MAX_ENV_ARG ] = {0};
  216. LPSTR s, s1;
  217. LPSTR PostBuildCmd;
  218. BOOL fPauseDone = FALSE;
  219. #if DBG
  220. BOOL fDebugSave;
  221. fDebug = 0;
  222. #endif
  223. if ( getenv("NTMAKEENV") == NULL ) {
  224. printf("environment variable NTMAKEENV must be defined\n");
  225. exit(1);
  226. }
  227. strcpy(szObjDir, "obj");
  228. strcpy(szObjDirSlash, "obj\\");
  229. strcpy(szObjDirSlashStar, "obj\\*");
  230. strcpy(szObjDirD, "objd");
  231. strcpy(szObjDirSlashD, "objd\\");
  232. strcpy(szObjDirSlashStarD, "objd\\*");
  233. for (i=3; i<_NFILE; i++) {
  234. _close( i );
  235. }
  236. pGetFileAttributesExA = (BOOL (WINAPI *)(LPCSTR, GET_FILEEX_INFO_LEVELS, LPVOID))
  237. GetProcAddress(GetModuleHandle("kernel32.dll"), "GetFileAttributesExA");
  238. if (pGetFileAttributesExA) {
  239. pDateTimeFile = DateTimeFile2;
  240. } else {
  241. pDateTimeFile = DateTimeFile;
  242. }
  243. InitializeCriticalSection(&TTYCriticalSection);
  244. s1 = getenv("COMSPEC");
  245. if (s1) {
  246. cmdexe = s1;
  247. } else {
  248. cmdexe = ( _osver & 0x8000 ) ? "command.com" : "cmd.exe";
  249. }
  250. {
  251. SYSTEMTIME st;
  252. FILETIME ft;
  253. GetSystemTime(&st);
  254. SystemTimeToFileTime(&st, &ft);
  255. FileTimeToDosDateTime( &ft,
  256. ((LPWORD)&BuildStartTime)+1,
  257. (LPWORD)&BuildStartTime
  258. );
  259. }
  260. BigBufSize = 0xFFF0;
  261. AllocMem(BigBufSize, &BigBuf, MT_IOBUFFER);
  262. // All env parsing should happen here (after the cmd line is processed)
  263. s = getenv("BASEDIR");
  264. if (s)
  265. {
  266. strcpy(NtRoot, s);
  267. }
  268. else
  269. {
  270. s = getenv("_NTROOT");
  271. if (!s)
  272. s = "\\nt";
  273. s1 = getenv("_NTDRIVE");
  274. if (!s1)
  275. s1 = "";
  276. sprintf(NtRoot, "%s%s", s1, s);
  277. }
  278. sprintf(DbMasterName, "%s\\%s", NtRoot, DBMASTER_NAME);
  279. s = getenv("_OBJ_ROOT");
  280. if (s) {
  281. pszObjRoot = strcpy(szObjRoot, s);
  282. }
  283. s = getenv("BUILD_ALT_DIR");
  284. if (s) {
  285. if (strlen(s) > sizeof(szObjDir) - strlen(szObjDir) - 1) {
  286. BuildError("environment variable BUILD_ALT_DIR may not be longer than %d characters.\n",
  287. sizeof(szObjDir) - strlen(szObjDir) - 1);
  288. exit(1);
  289. }
  290. strcat(szObjDir, s);
  291. strcpy(szObjDirSlash, szObjDir);
  292. strcpy(szObjDirSlashStar, szObjDir);
  293. strcat(szObjDirSlash, "\\");
  294. strcat(szObjDirSlashStar, "\\*");
  295. strcat(LogFileName, s);
  296. strcat(WrnFileName, s);
  297. strcat(ErrFileName, s);
  298. strcat(IncFileName, s);
  299. BuildMsg("Object root set to: ==> obj%s\n", s);
  300. }
  301. s = getenv("NTDEBUG");
  302. if (!s || *s == '\0' || strcmp(s, "retail") == 0 || strcmp(s, "ntsdnodbg") == 0) {
  303. fCheckedBuild = FALSE;
  304. }
  305. s = getenv("OS2_INC_PATH");
  306. if (s) {
  307. MakeString(&pszIncOs2, s, TRUE, MT_DIRSTRING);
  308. } else {
  309. MakeExpandedString(&pszIncOs2, "\\public\\sdk\\inc\\os2");
  310. }
  311. s = getenv("POSIX_INC_PATH");
  312. if (s) {
  313. MakeString(&pszIncPosix, s, TRUE, MT_DIRSTRING);
  314. } else {
  315. MakeExpandedString(&pszIncPosix, "\\public\\sdk\\inc\\posix");
  316. }
  317. s = getenv("CHICAGO_INC_PATH");
  318. if (s) {
  319. MakeString(&pszIncChicago, s, TRUE, MT_DIRSTRING);
  320. } else {
  321. MakeExpandedString(&pszIncChicago, "\\public\\sdk\\inc\\chicago");
  322. }
  323. s = getenv("CRT_INC_PATH");
  324. if (s) {
  325. MakeString(&pszIncCrt, s, TRUE, MT_DIRSTRING);
  326. } else {
  327. MakeExpandedString(&pszIncCrt, "\\public\\sdk\\inc\\crt");
  328. }
  329. s = getenv("SDK_INC_PATH");
  330. if (s) {
  331. MakeString(&pszIncSdk, s, TRUE, MT_DIRSTRING);
  332. } else {
  333. MakeExpandedString(&pszIncSdk, "\\public\\sdk\\inc");
  334. }
  335. s = getenv("OAK_INC_PATH");
  336. if (s) {
  337. MakeString(&pszIncOak, s, TRUE, MT_DIRSTRING);
  338. } else {
  339. MakeExpandedString(&pszIncOak, "\\public\\oak\\inc");
  340. }
  341. s = getenv("DDK_INC_PATH");
  342. if (s) {
  343. MakeString(&pszIncDdk, s, TRUE, MT_DIRSTRING);
  344. } else {
  345. MakeExpandedString(&pszIncDdk, "\\public\\ddk\\inc");
  346. }
  347. s = getenv("WDM_INC_PATH");
  348. if (s) {
  349. MakeString(&pszIncWdm, s, TRUE, MT_DIRSTRING);
  350. } else {
  351. MakeExpandedString(&pszIncWdm, "\\public\\ddk\\inc\\wdm");
  352. }
  353. s = getenv("PRIVATE_INC_PATH");
  354. if (s) {
  355. MakeString(&pszIncPri, s, TRUE, MT_DIRSTRING);
  356. } else {
  357. MakeExpandedString(&pszIncPri, "\\private\\inc");
  358. }
  359. s = getenv("MFC_INCLUDES");
  360. if (s) {
  361. MakeString(&pszIncMfc, s, TRUE, MT_DIRSTRING);
  362. } else {
  363. MakeExpandedString(&pszIncMfc, "\\public\\sdk\\inc\\mfc42");
  364. }
  365. s = getenv("SDK_LIB_DEST");
  366. if (s) {
  367. MakeString(&pszSdkLibDest, s, TRUE, MT_DIRSTRING);
  368. } else {
  369. MakeExpandedString(&pszSdkLibDest, "\\public\\sdk\\lib");
  370. }
  371. s = getenv("DDK_LIB_DEST");
  372. if (s) {
  373. MakeString(&pszDdkLibDest, s, TRUE, MT_DIRSTRING);
  374. } else {
  375. MakeExpandedString(&pszDdkLibDest, "\\public\\sdk\\lib");
  376. }
  377. s = getenv("PUBLIC_INTERNAL_PATH");
  378. if (s) {
  379. MakeString(&pszPublicInternalPath, s, TRUE, MT_DIRSTRING);
  380. } else {
  381. MakeExpandedString(&pszPublicInternalPath, "\\public\\internal");
  382. }
  383. szBuildTag = getenv("BUILD_TAG");
  384. strcpy( MakeParameters, "" );
  385. MakeParametersTail = AppendString( MakeParameters,
  386. "/c BUILDMSG=Stop.",
  387. FALSE);
  388. RecurseLevel = 0;
  389. #if DBG
  390. if ((s = getenv("BUILD_DEBUG_FLAG")) != NULL) {
  391. i = atoi(s);
  392. if (!isdigit(*s)) {
  393. i = 1;
  394. }
  395. BuildMsg("Debug Output Enabled: %u ==> %u\n", fDebug, fDebug | i);
  396. fDebug |= i;
  397. }
  398. #endif
  399. if (!(MakeProgram = getenv( "BUILD_MAKE_PROGRAM" ))) {
  400. MakeProgram = "NMAKE.EXE";
  401. }
  402. if (s = getenv("BUILD_PATH")) {
  403. SetEnvironmentVariable("PATH", s);
  404. }
  405. if (s = getenv("COPYCMD")) {
  406. if (!strchr(s, 'y') && !strchr(s, 'Y')) {
  407. // COPYCMD is set, but /y isn't a part of it. Add /Y.
  408. BuildMsg("Adding /Y to COPYCMD so xcopy ops won't hang.\n");
  409. s1 = malloc(strlen(s) + sizeof(" /Y") + 1);
  410. if (s1) {
  411. strcpy(s1, s);
  412. strcat(s1, " /Y");
  413. SetEnvironmentVariable("COPYCMD", s1);
  414. }
  415. }
  416. } else {
  417. // COPYCMD not set. Do so.
  418. BuildMsg("Adding /Y to COPYCMD so xcopy ops won't hang.\n");
  419. SetEnvironmentVariable("COPYCMD", "/Y");
  420. }
  421. PostBuildCmd = getenv("BUILD_POST_PROCESS");
  422. SystemIncludeEnv = getenv( "INCLUDE" );
  423. GetCurrentDirectory( sizeof( CurrentDirectory ), CurrentDirectory );
  424. for (i = 0; i < MAX_TARGET_MACHINES; i++) {
  425. TargetMachines[i] = NULL;
  426. TargetToPossibleTarget[i] = 0;
  427. MungePossibleTarget(PossibleTargetMachines[i]);
  428. }
  429. if (!(BuildProduct = getenv("BUILD_PRODUCT"))) {
  430. BuildProduct = "";
  431. }
  432. if (!ProcessParameters( argc, argv, TRUE )) {
  433. fUsage = TRUE;
  434. } else {
  435. fCmdLineDependencySwitchUsed = fDependencySwitchUsed;
  436. fCmdLineQuicky = fQuicky;
  437. fCmdLineSemiQuicky = fSemiQuicky;
  438. fCmdLineQuickZero = fQuickZero;
  439. GetEnvParameters( "BUILD_DEFAULT", NULL, &EnvArgc, MAX_ENV_ARG, EnvArgv );
  440. GetEnvParameters( "BUILD_OPTIONS", NULL, &EnvArgc, MAX_ENV_ARG, EnvArgv );
  441. if (CountTargetMachines == 0) {
  442. if ( getenv("PROCESSOR_ARCHITECTURE") == NULL ) {
  443. BuildError("environment variable PROCESSOR_ARCHITECTURE must be defined\n");
  444. exit(1);
  445. }
  446. if (!strcmp(getenv("PROCESSOR_ARCHITECTURE"), "IA64"))
  447. GetEnvParameters( "BUILD_DEFAULT_TARGETS", "-ia64", &EnvArgc, MAX_ENV_ARG, EnvArgv );
  448. else
  449. if (!strcmp(getenv("PROCESSOR_ARCHITECTURE"), "AMD64"))
  450. GetEnvParameters( "BUILD_DEFAULT_TARGETS", "-amd64", &EnvArgc, MAX_ENV_ARG, EnvArgv );
  451. else
  452. GetEnvParameters( "BUILD_DEFAULT_TARGETS", "-386", &EnvArgc, MAX_ENV_ARG, EnvArgv );
  453. }
  454. if (!ProcessParameters( EnvArgc, EnvArgv, FALSE )) {
  455. fUsage = TRUE;
  456. }
  457. }
  458. FreeEnvParameters(EnvArgc, EnvArgv);
  459. if (!fUsage && !fGenerateObjectsDotMacOnly) {
  460. if (!_stricmp(BuildProduct, "NT")) {
  461. if (fCmdLineDependencySwitchUsed) {
  462. fDependencySwitchUsed = fCmdLineDependencySwitchUsed;
  463. fQuicky = fCmdLineQuicky;
  464. fSemiQuicky = fCmdLineSemiQuicky;
  465. fQuickZero = fCmdLineQuickZero;
  466. }
  467. if (!fDependencySwitchUsed) {
  468. BuildError("(Fatal Error) One of either /D, /Z, /z, or /3 is required for NT builds\n");
  469. exit( 1 );
  470. } else {
  471. if (fDependencySwitchUsed == 1) {
  472. if (fQuicky) {
  473. BuildError("(Fatal Error) switch can not be used with /Z, /z, or /3\n");
  474. exit( 1 );
  475. }
  476. BuildMsgRaw( "BUILD: /D specified - The NT build lab will not accept build requests using this switch\n");
  477. }
  478. if (fDependencySwitchUsed == 2){
  479. if (fStopAfterPassZero) {
  480. BuildError("(Fatal Error) switch /0 can not be used with /z\n");
  481. exit( 1 );
  482. }
  483. }
  484. }
  485. }
  486. }
  487. GetIncludePatterns( "BUILD_ACCEPTABLE_INCLUDES", MAX_INCLUDE_PATTERNS, AcceptableIncludePatternList );
  488. GetIncludePatterns( "BUILD_UNACCEPTABLE_INCLUDES", MAX_INCLUDE_PATTERNS, UnacceptableIncludePatternList );
  489. if (( fCheckIncludePaths ) &&
  490. ( AcceptableIncludePatternList[ 0 ] == NULL ) &&
  491. ( UnacceptableIncludePatternList[ 0 ] == NULL )) {
  492. BuildMsgRaw( "WARNING: -# specified without BUILD_[UN]ACCEPTABLE_INCLUDES set\n" );
  493. }
  494. if (fCleanRestart) {
  495. if (fClean) {
  496. fClean = FALSE;
  497. fRestartClean = TRUE;
  498. }
  499. else
  500. if (fCleanLibs) {
  501. fCleanLibs = FALSE;
  502. fRestartCleanLibs = TRUE;
  503. }
  504. else {
  505. BuildError("/R switch only valid with /c or /C switch.\n");
  506. fUsage = TRUE;
  507. }
  508. }
  509. NumberProcesses = 1;
  510. if (fParallel || getenv("BUILD_MULTIPROCESSOR")) {
  511. SYSTEM_INFO SystemInfo;
  512. if (DefaultProcesses == 0) {
  513. GetSystemInfo(&SystemInfo);
  514. NumberProcesses = SystemInfo.dwNumberOfProcessors;
  515. } else {
  516. NumberProcesses = DefaultProcesses;
  517. }
  518. if (NumberProcesses == 1) {
  519. fParallel = FALSE;
  520. } else {
  521. if (NumberProcesses > 32) {
  522. BuildError("(Fatal Error) Number of Processes: %d exceeds max (32)\n", NumberProcesses);
  523. exit(1);
  524. }
  525. fParallel = TRUE;
  526. BuildMsg("Using %d child processes\n", NumberProcesses);
  527. }
  528. }
  529. if (fUsage) {
  530. BuildMsgRaw(
  531. "\nBUILD: Version %x.%02x.%04d\n\n",
  532. BUILD_VERSION >> 8,
  533. BUILD_VERSION & 0xFF,
  534. VER_PRODUCTBUILD);
  535. BuildMsgRaw(szUsage);
  536. }
  537. else
  538. if (CountTargetMachines != 0) {
  539. BuildError(
  540. "%s for ",
  541. fLinkOnly? "Link" : (fCompileOnly? "Compile" : "Compile and Link"));
  542. for (i = 0; i < CountTargetMachines; i++) {
  543. BuildErrorRaw(i==0? "%s" : ", %s", TargetMachines[i]->Description);
  544. AppendString(
  545. MakeTargets,
  546. TargetMachines[i]->MakeVariable,
  547. TRUE);
  548. }
  549. BuildErrorRaw(szNewLine);
  550. //
  551. // If there is one and only one build target and target dirs has
  552. // been enabled, then fill in the appropriate target dirs name.
  553. //
  554. if (CountTargetMachines == 1) {
  555. if (fTargetDirs == TRUE) {
  556. pszTargetDirs = TargetMachines[0]->TargetDirs;
  557. FileDesc[0].pszPattern = TargetMachines[0]->TargetDirs;
  558. }
  559. }
  560. if (DEBUG_1) {
  561. if (CountExcludeIncs) {
  562. BuildError("Include files that will be excluded:");
  563. for (i = 0; i < CountExcludeIncs; i++) {
  564. BuildErrorRaw(i == 0? " %s" : ", %s", ExcludeIncs[i]);
  565. }
  566. BuildErrorRaw(szNewLine);
  567. }
  568. if (CountOptionalDirs) {
  569. BuildError("Optional Directories that will be built:");
  570. for (i = 0; i < CountOptionalDirs; i++) {
  571. BuildErrorRaw(i == 0? " %s" : ", %s", OptionalDirs[i]);
  572. }
  573. BuildErrorRaw(szNewLine);
  574. }
  575. if (CountExcludeDirs) {
  576. BuildError("Directories that will be NOT be built:");
  577. for (i = 0; i < CountExcludeDirs; i++) {
  578. BuildErrorRaw(i == 0? " %s" : ", %s", ExcludeDirs[i]);
  579. }
  580. BuildErrorRaw(szNewLine);
  581. }
  582. BuildMsg("MakeParameters == %s\n", MakeParameters);
  583. BuildMsg("MakeTargets == %s\n", MakeTargets);
  584. }
  585. #if DBG
  586. fDebugSave = fDebug;
  587. // fDebug = 0;
  588. #endif
  589. //
  590. // Generate the _objects.mac file if requested
  591. //
  592. if (fGenerateObjectsDotMacOnly) {
  593. DIRSUP DirSup;
  594. ULONG DateTimeSources;
  595. DirDB = ScanDirectory( CurrentDirectory );
  596. if (DirDB && (DirDB->DirFlags & (DIRDB_DIRS | DIRDB_SOURCES))) {
  597. if (!ReadSourcesFile(DirDB, &DirSup, &DateTimeSources)) {
  598. BuildError("Current directory not a SOURCES directory.\n");
  599. return( 1 );
  600. }
  601. GenerateObjectsDotMac(DirDB, &DirSup, DateTimeSources);
  602. FreeDirSupData(&DirSup);
  603. ReportDirsUsage();
  604. FreeCmdStrings();
  605. ReportMemoryUsage();
  606. return(0);
  607. }
  608. }
  609. if (!fQuery && fErrorLog) {
  610. strcat(LogFileName, ".log");
  611. if (!MyOpenFile(LogDirectory, LogFileName, "wb", &LogFile, TRUE)) {
  612. BuildError("(Fatal Error) Unable to open log file\n");
  613. exit( 1 );
  614. }
  615. CreatedBuildFile(LogDirectory, LogFileName);
  616. strcat(WrnFileName, ".wrn");
  617. if (!MyOpenFile(LogDirectory, WrnFileName, "wb", &WrnFile, FALSE)) {
  618. BuildError("(Fatal Error) Unable to open warning file\n");
  619. exit( 1 );
  620. }
  621. CreatedBuildFile(LogDirectory, WrnFileName);
  622. strcat(ErrFileName, ".err");
  623. if (!MyOpenFile(LogDirectory, ErrFileName, "wb", &ErrFile, FALSE)) {
  624. BuildError("(Fatal Error) Unable to open error file\n");
  625. exit( 1 );
  626. }
  627. CreatedBuildFile(LogDirectory, ErrFileName);
  628. if ( fCheckIncludePaths ) {
  629. strcat( IncFileName, ".inc");
  630. if (!MyOpenFile( LogDirectory, IncFileName, "wb", &IncFile, FALSE ) ) {
  631. BuildError( "(Fatal Error) Unable to open include log file\n");
  632. exit( 1 );
  633. }
  634. CreatedBuildFile( LogDirectory, IncFileName );
  635. }
  636. }
  637. else {
  638. LogFile = NULL;
  639. WrnFile = NULL;
  640. ErrFile = NULL;
  641. IncFile = NULL;
  642. }
  643. s = getenv("__MTSCRIPT_ENV_ID");
  644. if (s) {
  645. if (fDependencySwitchUsed == 2 && fPause)
  646. {
  647. BuildError("Cannot combine -z (or -2) and -p switches under MTScript");
  648. exit(1);
  649. }
  650. // Make sure any other build.exe's that get launched as child
  651. // processes don't try to connect to the script engine.
  652. SetEnvironmentVariable("__MTSCRIPT_ENV_ID", NULL);
  653. g_hMTEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  654. if (g_hMTEvent != NULL)
  655. {
  656. g_hMTThread = CreateThread(NULL,
  657. 0,
  658. (LPTHREAD_START_ROUTINE)MTScriptThread,
  659. NULL,
  660. 0,
  661. &g_dwMTThreadId);
  662. if (g_hMTThread)
  663. {
  664. // Wait for the thread to tell us it's ready.
  665. WaitForSingleObject(g_hMTEvent, INFINITE);
  666. ResetEvent(g_hMTEvent);
  667. if (!g_hMTThread)
  668. {
  669. // An error occurred connecting to the script engine.
  670. // We can't continue.
  671. BuildError("Unable to connect to script engine. Exiting.");
  672. exit(2);
  673. }
  674. fMTScriptSync = TRUE;
  675. }
  676. else
  677. {
  678. BuildError("Failed to launch script handling thread! (%d)", GetLastError());
  679. CloseHandle(g_hMTEvent);
  680. g_hMTEvent = NULL;
  681. fPause = FALSE;
  682. }
  683. }
  684. else
  685. {
  686. BuildError("Failed to create script communication event! (%d)", GetLastError());
  687. fPause = FALSE;
  688. }
  689. }
  690. //
  691. // The user should not have CHICAGO_PRODUCT in
  692. // their environment, as it can cause problems on other machines with
  693. // other users that don't have them set. The following warning
  694. // messages are intended to alert the user to the presence of these
  695. // environment variables.
  696. //
  697. if (getenv("CHICAGO_PRODUCT") != NULL) {
  698. BuildError("CHICAGO_PRODUCT was detected in the environment.\n" );
  699. BuildMsg(" ALL directories will be built targeting Chicago!\n" );
  700. fChicagoProduct = TRUE;
  701. }
  702. if (!fQuicky) {
  703. LoadMasterDB();
  704. BuildError("Computing Include file dependencies:\n");
  705. ScanIncludeEnv(SystemIncludeEnv);
  706. ScanGlobalIncludeDirectory(pszIncMfc);
  707. ScanGlobalIncludeDirectory(pszIncOak);
  708. ScanGlobalIncludeDirectory(pszIncDdk);
  709. ScanGlobalIncludeDirectory(pszIncWdm);
  710. ScanGlobalIncludeDirectory(pszIncSdk);
  711. ScanGlobalIncludeDirectory(pszIncPri);
  712. CountSystemIncludeDirs = CountIncludeDirs;
  713. }
  714. #if DBG
  715. fDebug = fDebugSave;
  716. #endif
  717. fFirstScan = TRUE;
  718. fPassZero = FALSE;
  719. ScanSourceDirectories( CurrentDirectory );
  720. if (!fQuicky) {
  721. if (SaveMasterDB() == FALSE) {
  722. BuildError("Unable to save the dependency database: %s\n", DbMasterName);
  723. }
  724. }
  725. c = '\n';
  726. if (!fLinkOnly && CountPassZeroDirs) {
  727. if (!fQuicky) {
  728. TotalFilesToCompile = 0;
  729. TotalLinesToCompile = 0L;
  730. for (i=0; i<CountPassZeroDirs; i++) {
  731. DirDB = PassZeroDirs[ i ];
  732. TotalFilesToCompile += DirDB->CountOfPassZeroFiles;
  733. TotalLinesToCompile += DirDB->PassZeroLines;
  734. }
  735. if (CountPassZeroDirs > 1 &&
  736. TotalFilesToCompile != 0 &&
  737. TotalLinesToCompile != 0L) {
  738. BuildMsgRaw(
  739. "Total of %d pass zero files (%s lines) to compile in %d directories\n\n",
  740. TotalFilesToCompile,
  741. FormatNumber( TotalLinesToCompile ),
  742. CountPassZeroDirs);
  743. }
  744. }
  745. TotalFilesCompiled = 0;
  746. TotalLinesCompiled = 0L;
  747. ElapsedCompileTime = 0L;
  748. if (fPause && !fMTScriptSync) {
  749. BuildMsg("Press enter to continue with compilations (or 'q' to quit)...");
  750. c = (char)getchar();
  751. }
  752. if ((CountPassZeroDirs > 0) && (c == '\n')) {
  753. CompilePassZeroDirectories();
  754. WaitForParallelThreads();
  755. //
  756. // Rescan now that we've generated all the generated files
  757. //
  758. CountPassZeroDirs = 0;
  759. CountCompileDirs = 0;
  760. CountLinkDirs = 0;
  761. UnsnapAllDirectories();
  762. fPassZero = FALSE;
  763. fFirstScan = FALSE;
  764. RecurseLevel = 0;
  765. if (fMTScriptSync) {
  766. WaitForResume(fPause, PE_PASS0_COMPLETE);
  767. fPauseDone = TRUE;
  768. }
  769. // This will compile directories if fQuicky is TRUE
  770. if (!fStopAfterPassZero) {
  771. ScanSourceDirectories( CurrentDirectory );
  772. }
  773. if (!fQuicky) {
  774. if (SaveMasterDB() == FALSE) {
  775. BuildError("Unable to save the dependency database: %s\n", DbMasterName);
  776. }
  777. }
  778. }
  779. }
  780. if (fMTScriptSync && !fPauseDone) {
  781. WaitForResume(fPause, PE_PASS0_COMPLETE);
  782. }
  783. if (fStopAfterPassZero) {
  784. BuildError("Stopping after pass zero requested: Pass0 done.\n");
  785. }
  786. if (!fStopAfterPassZero && !fLinkOnly && (c == '\n')) {
  787. if (!fQuicky) {
  788. TotalFilesToCompile = 0;
  789. TotalLinesToCompile = 0L;
  790. for (i=0; i<CountCompileDirs; i++) {
  791. DirDB = CompileDirs[ i ];
  792. TotalFilesToCompile += DirDB->CountOfFilesToCompile;
  793. TotalLinesToCompile += DirDB->SourceLinesToCompile;
  794. }
  795. if (CountCompileDirs > 1 &&
  796. TotalFilesToCompile != 0 &&
  797. TotalLinesToCompile != 0L) {
  798. BuildMsgRaw(
  799. "Total of %d source files (%s lines) to compile in %d directories\n\n",
  800. TotalFilesToCompile,
  801. FormatNumber( TotalLinesToCompile ),
  802. CountCompileDirs);
  803. }
  804. }
  805. TotalFilesCompiled = 0;
  806. TotalLinesCompiled = 0L;
  807. ElapsedCompileTime = 0L;
  808. if (fPause && !fMTScriptSync) {
  809. BuildMsg("Press enter to continue with compilations (or 'q' to quit)...");
  810. c = (char)getchar();
  811. }
  812. if (c == '\n') {
  813. // Does nothing if fQuicky is TRUE
  814. CompileSourceDirectories();
  815. WaitForParallelThreads();
  816. }
  817. }
  818. if (fMTScriptSync) {
  819. WaitForResume(fPause, PE_PASS1_COMPLETE);
  820. }
  821. if (!fStopAfterPassZero && !fCompileOnly && (c == '\n')) {
  822. LinkSourceDirectories();
  823. WaitForParallelThreads();
  824. }
  825. if (!fStopAfterPassZero && PostBuildCmd && !fMTScriptSync) {
  826. // If there's a post build process to invoke, do so but only if
  827. // not running under the buildcon.
  828. // PostBuildCmd is of the form <message to display><command to execute>
  829. // The Message is delimiated with curly brackets. ie:
  830. // POST_BUILD_PROCESS={Do randomness}randomness.cmd
  831. // would display:
  832. //
  833. // BUILD: Do randomness
  834. //
  835. // while randomness.cmd was running. The process is run synchronously and
  836. // we've still got the i/o pipes setup so any output will be logged to
  837. // build.log (and wrn/err if formated correctly)
  838. if (*PostBuildCmd == '{') {
  839. LPSTR PostBuildMessage = PostBuildCmd+1;
  840. LogMsg("Executing post build scripts %s\n", szAsterisks);
  841. while (*PostBuildCmd && *PostBuildCmd != '}')
  842. PostBuildCmd++;
  843. if (*PostBuildCmd == '}') {
  844. *PostBuildCmd = '\0';
  845. PostBuildCmd++;
  846. BuildMsg("%s\n", PostBuildMessage);
  847. LogMsg("%s\n", PostBuildMessage);
  848. ExecuteProgram(PostBuildCmd, "", "", TRUE);
  849. }
  850. } else {
  851. ExecuteProgram(PostBuildCmd, "", "", TRUE);
  852. }
  853. }
  854. if (fShowTree) {
  855. for (i = 0; i < CountShowDirs; i++) {
  856. PrintDirDB(ShowDirs[i], 1|4);
  857. }
  858. }
  859. }
  860. else {
  861. BuildError("No target machine specified\n");
  862. }
  863. if (!fUsage && !fQuery && fErrorLog) {
  864. ULONG cbLogMin = 32;
  865. ULONG cbWarnMin = 0;
  866. if (!fAlwaysKeepLogfile) {
  867. if (fQuicky && !fSemiQuicky && ftell(ErrFile) == 0) {
  868. cbLogMin = cbWarnMin = ULONG_MAX;
  869. }
  870. }
  871. CloseOrDeleteFile(&LogFile, LogDirectory, LogFileName, cbLogMin);
  872. CloseOrDeleteFile(&WrnFile, LogDirectory, WrnFileName, cbWarnMin);
  873. CloseOrDeleteFile(&ErrFile, LogDirectory, ErrFileName, 0L);
  874. if ( fCheckIncludePaths ) {
  875. CloseOrDeleteFile(&IncFile, LogDirectory, IncFileName, cbLogMin);
  876. }
  877. }
  878. BuildError("Done\n\n");
  879. if (fMTScriptSync) {
  880. WaitForResume(FALSE, PE_PASS2_COMPLETE);
  881. }
  882. if (NumberCompiles) {
  883. BuildMsgRaw(" %d file%s compiled", NumberCompiles, NumberCompiles == 1 ? "" : "s");
  884. if (NumberCompileWarnings) {
  885. BuildMsgRaw(" - %d Warning%s", NumberCompileWarnings, NumberCompileWarnings == 1 ? "" : "s");
  886. }
  887. if (NumberCompileErrors) {
  888. BuildMsgRaw(" - %d Error%s", NumberCompileErrors, NumberCompileErrors == 1 ? "" : "s");
  889. }
  890. if (ElapsedCompileTime) {
  891. BuildMsgRaw(" - %5ld LPS", TotalLinesCompiled / ElapsedCompileTime);
  892. }
  893. BuildMsgRaw(szNewLine);
  894. }
  895. if (NumberLibraries) {
  896. BuildMsgRaw(" %d librar%s built", NumberLibraries, NumberLibraries == 1 ? "y" : "ies");
  897. if (NumberLibraryWarnings) {
  898. BuildMsgRaw(" - %d Warning%s", NumberLibraryWarnings, NumberLibraryWarnings == 1 ? "" : "s");
  899. }
  900. if (NumberLibraryErrors) {
  901. BuildMsgRaw(" - %d Error%s", NumberLibraryErrors, NumberLibraryErrors == 1 ? "" : "s");
  902. }
  903. BuildMsgRaw(szNewLine);
  904. }
  905. if (NumberLinks) {
  906. BuildMsgRaw(" %d executable%sbuilt", NumberLinks, NumberLinks == 1 ? " " : "s ");
  907. if (NumberLinkWarnings) {
  908. BuildMsgRaw(" - %d Warning%s", NumberLinkWarnings, NumberLinkWarnings == 1 ? "" : "s");
  909. }
  910. if (NumberLinkErrors) {
  911. BuildMsgRaw(" - %d Error%s", NumberLinkErrors, NumberLinkErrors == 1 ? "" : "s");
  912. }
  913. BuildMsgRaw(szNewLine);
  914. }
  915. if (NumberBinplaces) {
  916. BuildMsgRaw(" %d file%sbinplaced", NumberBinplaces, NumberBinplaces == 1 ? " " : "s ");
  917. if (NumberBinplaceWarnings) {
  918. BuildMsgRaw(" - %d Warning%s", NumberBinplaceWarnings, NumberBinplaceWarnings == 1 ? "" : "s");
  919. }
  920. if (NumberBinplaceErrors) {
  921. BuildMsgRaw(" - %d Error%s", NumberBinplaceErrors, NumberBinplaceErrors == 1 ? "" : "s");
  922. }
  923. BuildMsgRaw(szNewLine);
  924. }
  925. ReportDirsUsage();
  926. FreeCmdStrings();
  927. FreeIncludePatterns( MAX_INCLUDE_PATTERNS, AcceptableIncludePatternList );
  928. FreeIncludePatterns( MAX_INCLUDE_PATTERNS, UnacceptableIncludePatternList );
  929. ReportMemoryUsage();
  930. ExitMTScriptThread();
  931. if (NumberCompileErrors || NumberLibraryErrors || NumberLinkErrors || NumberBinplaceErrors || fUsage) {
  932. return 1;
  933. }
  934. else {
  935. return( 0 );
  936. }
  937. }
  938. VOID
  939. ReportDirsUsage( VOID )
  940. {
  941. ULONG i;
  942. BOOLEAN fHeaderPrinted;
  943. if (!fShowUnusedDirs) {
  944. return;
  945. }
  946. fHeaderPrinted = FALSE;
  947. for (i=0; i<CountOptionalDirs; i++) {
  948. if (!OptionalDirsUsed[i]) {
  949. if (!fHeaderPrinted) {
  950. printf( "Unused BUILD_OPTIONS:" );
  951. fHeaderPrinted = TRUE;
  952. }
  953. printf( " %s", OptionalDirs[i] );
  954. }
  955. }
  956. for (i=0; i<CountExcludeDirs; i++) {
  957. if (!ExcludeDirsUsed[i]) {
  958. if (!fHeaderPrinted) {
  959. printf( "Unused BUILD_OPTIONS:" );
  960. fHeaderPrinted = TRUE;
  961. }
  962. printf( " ~%s", ExcludeDirs[i] );
  963. }
  964. }
  965. if (fHeaderPrinted) {
  966. printf( "\n" );
  967. }
  968. }
  969. //+---------------------------------------------------------------------------
  970. //
  971. // Function: SetObjDir
  972. //
  973. //----------------------------------------------------------------------------
  974. VOID
  975. SetObjDir(BOOL fAlternate)
  976. {
  977. iObjectDir = 0;
  978. if (fCheckedBuild) {
  979. if (fAlternate) {
  980. pszObjDir = szObjDirD;
  981. pszObjDirSlash = szObjDirSlashD;
  982. pszObjDirSlashStar = szObjDirSlashStarD;
  983. iObjectDir = 1;
  984. } else {
  985. pszObjDir = szObjDir;
  986. pszObjDirSlash = szObjDirSlash;
  987. pszObjDirSlashStar = szObjDirSlashStar;
  988. }
  989. }
  990. }
  991. //+---------------------------------------------------------------------------
  992. //
  993. // Function: AddTargetMachine
  994. //
  995. //----------------------------------------------------------------------------
  996. VOID
  997. AddTargetMachine(UINT iTarget)
  998. {
  999. UINT i;
  1000. for (i = 0; i < CountTargetMachines; i++) {
  1001. if (TargetMachines[i] == PossibleTargetMachines[iTarget]) {
  1002. assert(TargetToPossibleTarget[i] == iTarget);
  1003. return;
  1004. }
  1005. }
  1006. assert(CountTargetMachines < MAX_TARGET_MACHINES);
  1007. TargetToPossibleTarget[CountTargetMachines] = iTarget;
  1008. TargetMachines[CountTargetMachines++] = PossibleTargetMachines[iTarget];
  1009. }
  1010. //+---------------------------------------------------------------------------
  1011. //
  1012. // Function: ProcessParameters
  1013. //
  1014. //----------------------------------------------------------------------------
  1015. BOOL
  1016. ProcessParameters(
  1017. int argc,
  1018. LPSTR argv[],
  1019. BOOL SkipFirst
  1020. )
  1021. {
  1022. char c, *p;
  1023. int i;
  1024. BOOL Result;
  1025. if (DEBUG_1) {
  1026. BuildMsg("Parsing:");
  1027. for (i=1; i<argc; i++) {
  1028. BuildMsgRaw(" %s", argv[i]);
  1029. }
  1030. BuildMsgRaw(szNewLine);
  1031. }
  1032. Result = TRUE;
  1033. if (SkipFirst) {
  1034. --argc;
  1035. ++argv;
  1036. }
  1037. while (argc) {
  1038. p = *argv;
  1039. if (*p == '/' || *p == '-') {
  1040. if (DEBUG_1) {
  1041. BuildMsg("Processing \"-%s\" switch\n", p+1);
  1042. }
  1043. for (i = 0; i < MAX_TARGET_MACHINES; i++) {
  1044. if (!_stricmp(p, PossibleTargetMachines[i]->Switch) ||
  1045. !_stricmp(p, PossibleTargetMachines[i]->Switch2)) {
  1046. AddTargetMachine(i);
  1047. break;
  1048. }
  1049. }
  1050. if (i < MAX_TARGET_MACHINES) {
  1051. }
  1052. else
  1053. if (!_stricmp(p + 1, "all")) {
  1054. for (i = 0; i < MAX_TARGET_MACHINES; i++) {
  1055. AddTargetMachine(i);
  1056. }
  1057. }
  1058. else
  1059. if (!_stricmp(p + 1, "why")) {
  1060. fWhyBuild = TRUE;
  1061. }
  1062. else
  1063. while (c = *++p)
  1064. switch (toupper( c )) {
  1065. case '?':
  1066. fUsage = TRUE;
  1067. break;
  1068. case '$':
  1069. fDebug += 2; // yes, I want to *add* 2.
  1070. break;
  1071. case '#':
  1072. fCheckIncludePaths = TRUE;
  1073. fForce = TRUE;
  1074. break;
  1075. case '0':
  1076. fStopAfterPassZero = TRUE;
  1077. if (!fDependencySwitchUsed)
  1078. fDependencySwitchUsed = 3;
  1079. break;
  1080. case '1':
  1081. fQuicky = TRUE;
  1082. if (!fDependencySwitchUsed)
  1083. fDependencySwitchUsed = 2;
  1084. break;
  1085. case '2':
  1086. fSemiQuicky = TRUE;
  1087. fQuicky = TRUE;
  1088. if (!fDependencySwitchUsed)
  1089. fDependencySwitchUsed = 2;
  1090. break;
  1091. case '3':
  1092. fQuickZero = TRUE;
  1093. fSemiQuicky = TRUE;
  1094. fQuicky = TRUE;
  1095. if (!fDependencySwitchUsed)
  1096. fDependencySwitchUsed = 3;
  1097. break;
  1098. case 'A':
  1099. fSyncLink = TRUE;
  1100. break;
  1101. case 'B':
  1102. fFullErrors = TRUE;
  1103. break;
  1104. case 'C':
  1105. if (!_stricmp( p, "clean" )) {
  1106. MakeParametersTail = AppendString( MakeParametersTail,
  1107. "clean",
  1108. TRUE);
  1109. *p-- = '\0';
  1110. }
  1111. else
  1112. if (c == 'C') {
  1113. fCleanLibs = TRUE;
  1114. }
  1115. else {
  1116. fClean = TRUE;
  1117. }
  1118. break;
  1119. case 'D':
  1120. if (c == 'D') {
  1121. fDependencySwitchUsed = 1;
  1122. }
  1123. #if DBG
  1124. else {
  1125. fDebug |= 1;
  1126. }
  1127. break;
  1128. #endif
  1129. case 'E':
  1130. if (c == 'E') {
  1131. fAlwaysKeepLogfile = TRUE;
  1132. }
  1133. fErrorLog = TRUE;
  1134. break;
  1135. case 'F':
  1136. if (c == 'F') {
  1137. fAlwaysPrintFullPath = TRUE;
  1138. } else {
  1139. fForce = TRUE;
  1140. }
  1141. break;
  1142. case 'G':
  1143. fTargetDirs = TRUE;
  1144. break;
  1145. case 'I':
  1146. if (c == 'I') {
  1147. fNoThreadIndex = TRUE;
  1148. }
  1149. else {
  1150. BuildMsgRaw( "BUILD: /i switch ignored\n");
  1151. }
  1152. break;
  1153. case 'J': {
  1154. argc--, argv++;
  1155. if (!_stricmp( p, "jpath" )) {
  1156. // Allow BuildConsole to redirect the logfiles
  1157. strncpy(LogDirectory, *argv, sizeof(LogDirectory) - 1);
  1158. *p-- = '\0';
  1159. }
  1160. else
  1161. {
  1162. // Clear it out
  1163. memset(LogFileName, 0, sizeof(LogFileName));
  1164. memset(WrnFileName, 0, sizeof(WrnFileName));
  1165. memset(ErrFileName, 0, sizeof(ErrFileName));
  1166. memset(IncFileName, 0, sizeof(IncFileName));
  1167. // And set it to the arg passed in.
  1168. strncpy(LogFileName, *argv, sizeof(LogFileName) - 4);
  1169. strncpy(WrnFileName, *argv, sizeof(WrnFileName) - 4);
  1170. strncpy(ErrFileName, *argv, sizeof(ErrFileName) - 4);
  1171. strncpy(IncFileName, *argv, sizeof(IncFileName) - 4);
  1172. }
  1173. break;
  1174. }
  1175. case 'K':
  1176. fKeep = TRUE;
  1177. break;
  1178. case 'L':
  1179. if (c == 'L') {
  1180. fCompileOnly = TRUE;
  1181. }
  1182. else {
  1183. fLinkOnly = TRUE;
  1184. }
  1185. break;
  1186. case 'M':
  1187. if (c == 'M') {
  1188. fParallel = TRUE;
  1189. if (--argc) {
  1190. DefaultProcesses = atoi(*++argv);
  1191. if (DefaultProcesses == 0) {
  1192. --argv;
  1193. ++argc;
  1194. }
  1195. } else {
  1196. ++argc;
  1197. }
  1198. } else {
  1199. SetPriorityClass(GetCurrentProcess(),IDLE_PRIORITY_CLASS);
  1200. }
  1201. break;
  1202. case 'N':
  1203. if (_stricmp( p, "nmake") == 0) {
  1204. if (--argc) {
  1205. ++argv;
  1206. MakeParametersTail = AppendString( MakeParametersTail,
  1207. *argv,
  1208. TRUE);
  1209. }
  1210. else {
  1211. argc++;
  1212. BuildError("Argument to /NMAKE switch missing\n");
  1213. Result = FALSE;
  1214. }
  1215. *p-- = '\0';
  1216. break;
  1217. }
  1218. case 'O':
  1219. if (c == 'O') {
  1220. fGenerateObjectsDotMacOnly = TRUE;
  1221. }
  1222. else {
  1223. fShowOutOfDateFiles = TRUE;
  1224. }
  1225. break;
  1226. case 'P':
  1227. if (c == 'P') {
  1228. fPrintElapsed = TRUE;
  1229. } else {
  1230. fPause = TRUE;
  1231. }
  1232. break;
  1233. case 'Q':
  1234. fQuery = TRUE;
  1235. break;
  1236. case 'R':
  1237. if (--argc) {
  1238. fCleanRestart = TRUE;
  1239. ++argv;
  1240. CopyString(RestartDir, *argv, TRUE);
  1241. }
  1242. else {
  1243. argc++;
  1244. BuildError("Argument to /R switch missing\n");
  1245. Result = FALSE;
  1246. }
  1247. break;
  1248. case 'S':
  1249. fStatus = TRUE;
  1250. if (c == 'S') {
  1251. fStatusTree = TRUE;
  1252. }
  1253. break;
  1254. case 'T':
  1255. fShowTree = TRUE;
  1256. if (c == 'T') {
  1257. fShowTreeIncludes = TRUE;
  1258. }
  1259. break;
  1260. case 'U':
  1261. fShowUnusedDirs = TRUE;
  1262. break;
  1263. case 'V':
  1264. fEnableVersionCheck = TRUE;
  1265. break;
  1266. case 'W':
  1267. fShowWarningsOnScreen = TRUE;
  1268. break;
  1269. case 'X':
  1270. if (--argc) {
  1271. ++argv;
  1272. if (CountExcludeIncs >= MAX_EXCLUDE_INCS) {
  1273. static BOOL fError = FALSE;
  1274. if (!fError) {
  1275. BuildError(
  1276. "-x argument table overflow, using first %u entries\n",
  1277. MAX_EXCLUDE_INCS);
  1278. fError = TRUE;
  1279. }
  1280. }
  1281. else {
  1282. MakeString(
  1283. &ExcludeIncs[CountExcludeIncs++],
  1284. *argv,
  1285. TRUE,
  1286. MT_CMDSTRING);
  1287. }
  1288. }
  1289. else {
  1290. argc++;
  1291. BuildError("Argument to /X switch missing\n");
  1292. Result = FALSE;
  1293. }
  1294. break;
  1295. case 'Y':
  1296. fNoisyScan = TRUE;
  1297. break;
  1298. case 'Z':
  1299. fQuickZero = TRUE;
  1300. fSemiQuicky = TRUE;
  1301. fQuicky = TRUE;
  1302. if (!fDependencySwitchUsed)
  1303. fDependencySwitchUsed = 3;
  1304. break;
  1305. default:
  1306. BuildError("Invalid switch - /%c\n", c);
  1307. Result = FALSE;
  1308. break;
  1309. }
  1310. }
  1311. else
  1312. if (*p == '~') {
  1313. if (CountExcludeDirs >= MAX_EXCLUDE_DIRECTORIES) {
  1314. static BOOL fError = FALSE;
  1315. if (!fError) {
  1316. BuildError(
  1317. "Exclude directory table overflow, using first %u entries\n",
  1318. MAX_EXCLUDE_DIRECTORIES);
  1319. fError = TRUE;
  1320. }
  1321. }
  1322. else {
  1323. MakeString(
  1324. &ExcludeDirs[CountExcludeDirs++],
  1325. p + 1,
  1326. TRUE,
  1327. MT_CMDSTRING);
  1328. }
  1329. }
  1330. else {
  1331. for (i = 0; i < MAX_TARGET_MACHINES; i++) {
  1332. if (!_stricmp(p, PossibleTargetMachines[i]->MakeVariable)) {
  1333. AddTargetMachine(i);
  1334. break;
  1335. }
  1336. }
  1337. if (i >= MAX_TARGET_MACHINES) {
  1338. if (iscsym(*p) || *p == '.') {
  1339. if (CountOptionalDirs >= MAX_OPTIONAL_DIRECTORIES) {
  1340. static BOOL fError = FALSE;
  1341. if (!fError) {
  1342. BuildError(
  1343. "Optional directory table overflow, using first %u entries\n",
  1344. MAX_OPTIONAL_DIRECTORIES);
  1345. fError = TRUE;
  1346. }
  1347. }
  1348. else {
  1349. MakeString(
  1350. &OptionalDirs[CountOptionalDirs++],
  1351. p,
  1352. TRUE,
  1353. MT_CMDSTRING);
  1354. }
  1355. }
  1356. else
  1357. if (!strcmp(p, "*")) {
  1358. BuildAllOptionalDirs = TRUE;
  1359. }
  1360. else {
  1361. MakeParametersTail = AppendString(
  1362. MakeParametersTail,
  1363. p,
  1364. TRUE);
  1365. }
  1366. }
  1367. }
  1368. --argc;
  1369. ++argv;
  1370. }
  1371. return(Result);
  1372. }
  1373. //+---------------------------------------------------------------------------
  1374. //
  1375. // Function: GetEnvParameters
  1376. //
  1377. //----------------------------------------------------------------------------
  1378. VOID
  1379. GetEnvParameters(
  1380. LPSTR EnvVarName,
  1381. LPSTR DefaultValue,
  1382. int *pargc,
  1383. int maxArgc,
  1384. LPSTR argv[]
  1385. )
  1386. {
  1387. LPSTR p, p1, psz;
  1388. if (!(p = getenv(EnvVarName))) {
  1389. if (DefaultValue == NULL) {
  1390. return;
  1391. }
  1392. else {
  1393. p = DefaultValue;
  1394. }
  1395. }
  1396. else {
  1397. if (DEBUG_1) {
  1398. BuildMsg("Using %s=%s\n", EnvVarName, p);
  1399. }
  1400. }
  1401. MakeString(&psz, p, FALSE, MT_CMDSTRING);
  1402. p1 = psz;
  1403. while (*p1) {
  1404. while (*p1 <= ' ') {
  1405. if (!*p1) {
  1406. break;
  1407. }
  1408. p1++;
  1409. }
  1410. p = p1;
  1411. while (*p > ' ') {
  1412. if (*p == '#') {
  1413. *p = '=';
  1414. }
  1415. p++;
  1416. }
  1417. if (*p) {
  1418. *p++ = '\0';
  1419. }
  1420. MakeString(&argv[*pargc], p1, FALSE, MT_CMDSTRING);
  1421. if ((*pargc += 1) >= maxArgc) {
  1422. BuildError("Too many parameters (> %d)\n", maxArgc);
  1423. exit(1);
  1424. }
  1425. p1 = p;
  1426. }
  1427. FreeMem(&psz, MT_CMDSTRING);
  1428. }
  1429. //+---------------------------------------------------------------------------
  1430. //
  1431. // Function: FreeEnvParameters
  1432. //
  1433. //----------------------------------------------------------------------------
  1434. VOID
  1435. FreeEnvParameters(int argc, LPSTR argv[])
  1436. {
  1437. while (--argc >= 0) {
  1438. FreeMem(&argv[argc], MT_CMDSTRING);
  1439. }
  1440. }
  1441. //+---------------------------------------------------------------------------
  1442. //
  1443. // Function: FreeCmdStrings
  1444. //
  1445. //----------------------------------------------------------------------------
  1446. VOID
  1447. FreeCmdStrings(VOID)
  1448. {
  1449. #if DBG
  1450. UINT i;
  1451. for (i = 0; i < CountExcludeIncs; i++) {
  1452. FreeMem(&ExcludeIncs[i], MT_CMDSTRING);
  1453. }
  1454. for (i = 0; i < CountOptionalDirs; i++) {
  1455. FreeMem(&OptionalDirs[i], MT_CMDSTRING);
  1456. }
  1457. for (i = 0; i < CountExcludeDirs; i++) {
  1458. FreeMem(&ExcludeDirs[i], MT_CMDSTRING);
  1459. }
  1460. // It's possible the user may have done:
  1461. // <global macro> = <null>
  1462. // in a sources file. Don't free mem unless it's still set...
  1463. if (pszSdkLibDest)
  1464. FreeMem(&pszSdkLibDest, MT_DIRSTRING);
  1465. if (pszDdkLibDest)
  1466. FreeMem(&pszDdkLibDest, MT_DIRSTRING);
  1467. if (pszPublicInternalPath)
  1468. FreeMem(&pszPublicInternalPath, MT_DIRSTRING);
  1469. if (pszIncOs2)
  1470. FreeMem(&pszIncOs2, MT_DIRSTRING);
  1471. if (pszIncPosix)
  1472. FreeMem(&pszIncPosix, MT_DIRSTRING);
  1473. if (pszIncChicago)
  1474. FreeMem(&pszIncChicago, MT_DIRSTRING);
  1475. if (pszIncMfc)
  1476. FreeMem(&pszIncMfc, MT_DIRSTRING);
  1477. if (pszIncSdk)
  1478. FreeMem(&pszIncSdk, MT_DIRSTRING);
  1479. if (pszIncCrt)
  1480. FreeMem(&pszIncCrt, MT_DIRSTRING);
  1481. if (pszIncOak)
  1482. FreeMem(&pszIncOak, MT_DIRSTRING);
  1483. if (pszIncDdk)
  1484. FreeMem(&pszIncDdk, MT_DIRSTRING);
  1485. if (pszIncWdm)
  1486. FreeMem(&pszIncWdm, MT_DIRSTRING);
  1487. if (pszIncPri)
  1488. FreeMem(&pszIncPri, MT_DIRSTRING);
  1489. #endif
  1490. }
  1491. //+---------------------------------------------------------------------------
  1492. //
  1493. // Function: MungePossibleTarget
  1494. //
  1495. //----------------------------------------------------------------------------
  1496. VOID
  1497. MungePossibleTarget(
  1498. PTARGET_MACHINE_INFO pti
  1499. )
  1500. {
  1501. PCHAR s;
  1502. char *pszDir;
  1503. if (!pti) {
  1504. return;
  1505. }
  1506. // save "i386" string
  1507. pszDir = pti->ObjectDirectory[0];
  1508. // Create "$(_OBJ_DIR)\i386" string
  1509. s = malloc(12 + strlen(pszDir) + 1);
  1510. if (!s)
  1511. return;
  1512. sprintf(s, "$(_OBJ_DIR)\\%s", pszDir);
  1513. pti->ObjectMacro = s;
  1514. // Create "obj$(BUILD_ALT_DIR)\i386" string for default obj dir
  1515. s = malloc(strlen(szObjDir) + 1 + strlen(pszDir) + 1);
  1516. if (!s)
  1517. return;
  1518. sprintf(s, "%s\\%s", szObjDir, pszDir);
  1519. pti->ObjectDirectory[0] = s;
  1520. // Create "objd\i386" string for alternate checked obj dir
  1521. s = malloc(strlen(szObjDirD) + 1 + strlen(pszDir) + 1);
  1522. if (!s)
  1523. return;
  1524. sprintf(s, "%s\\%s", szObjDirD, pszDir);
  1525. pti->ObjectDirectory[1] = s;
  1526. }
  1527. //+---------------------------------------------------------------------------
  1528. //
  1529. // Function: GetIncludePatterns
  1530. //
  1531. //----------------------------------------------------------------------------
  1532. VOID
  1533. GetIncludePatterns(
  1534. LPSTR EnvVarName,
  1535. int maxArgc,
  1536. LPSTR argv[]
  1537. )
  1538. {
  1539. LPSTR p, p1, psz;
  1540. int argc;
  1541. argc = 0;
  1542. if ( ( p = getenv(EnvVarName ) ) == NULL ) {
  1543. return;
  1544. }
  1545. MakeString( &psz, p, FALSE, MT_DIRSTRING );
  1546. p1 = psz;
  1547. while ( *p1 ) {
  1548. while ( *p1 == ';' || *p1 == ' ' ) {
  1549. p1++;
  1550. }
  1551. p = p1;
  1552. while ( *p && *p != ';' ) {
  1553. p++;
  1554. }
  1555. if ( *p ) {
  1556. *p++ = '\0';
  1557. }
  1558. MakeString( &argv[argc], p1, FALSE, MT_DIRSTRING );
  1559. if ( ( argc += 1 ) == maxArgc ) {
  1560. BuildError( "Too many include patterns ( > %d)\n", maxArgc );
  1561. exit( 1 );
  1562. }
  1563. p1 = p;
  1564. }
  1565. FreeMem(&psz, MT_DIRSTRING);
  1566. }
  1567. //+---------------------------------------------------------------------------
  1568. //
  1569. // Function: FreeIncludePatterns
  1570. //
  1571. //----------------------------------------------------------------------------
  1572. VOID
  1573. FreeIncludePatterns(int argc, LPSTR argv[])
  1574. {
  1575. while ( argc ) {
  1576. if ( argv[--argc] ) {
  1577. FreeMem( &argv[argc], MT_DIRSTRING );
  1578. }
  1579. }
  1580. }