1732 lines
51 KiB
C
1732 lines
51 KiB
C
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1989 - 1994.
|
|
//
|
|
// File: build.c
|
|
//
|
|
// Contents: Parameter processing and main entry point for Build.exe
|
|
//
|
|
// History: 16-May-89 SteveWo Created
|
|
// ... See SLM log
|
|
// 26-Jul-94 LyleC Cleanup/Add Pass0 support
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "build.h"
|
|
|
|
#ifndef VER_PRODUCTBUILD
|
|
#define VER_PRODUCTBUILD 0
|
|
#endif
|
|
|
|
static BOOL
|
|
FileExistsInDirectory(
|
|
LPCSTR Directory,
|
|
LPCSTR FileName
|
|
)
|
|
{
|
|
CHAR Path[DB_MAX_PATH_LENGTH];
|
|
|
|
sprintf(Path, "%s\\%s", Directory, FileName);
|
|
return _access(Path, 0) == 0;
|
|
}
|
|
|
|
static VOID
|
|
ResolveBaseDirectory(VOID)
|
|
{
|
|
CHAR Candidate[DB_MAX_PATH_LENGTH];
|
|
CHAR Original[DB_MAX_PATH_LENGTH];
|
|
CHAR *Slash;
|
|
LPCSTR BaseDir;
|
|
DWORD Length;
|
|
|
|
BaseDir = getenv("BASEDIR");
|
|
if (BaseDir && *BaseDir) {
|
|
Length = GetFullPathNameA(BaseDir, sizeof(Candidate), Candidate, NULL);
|
|
if (Length == 0 || Length >= sizeof(Candidate)) {
|
|
BuildError("Unable to resolve BASEDIR=%s\n", BaseDir);
|
|
exit(1);
|
|
}
|
|
} else {
|
|
Length = GetCurrentDirectoryA(sizeof(Candidate), Candidate);
|
|
if (Length == 0 || Length >= sizeof(Candidate)) {
|
|
BuildError("Unable to resolve the current directory\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
strcpy(Original, Candidate);
|
|
|
|
if (!(BaseDir && *BaseDir)) {
|
|
for (;;) {
|
|
if (FileExistsInDirectory(Candidate, "project.mk")) {
|
|
break;
|
|
}
|
|
|
|
Slash = strrchr(Candidate, '\\');
|
|
if (!Slash) {
|
|
strcpy(Candidate, Original);
|
|
break;
|
|
}
|
|
|
|
if (Slash == Candidate + 2 && Candidate[1] == ':') {
|
|
if (Slash[1] == '\0') {
|
|
strcpy(Candidate, Original);
|
|
break;
|
|
}
|
|
Slash[1] = '\0';
|
|
continue;
|
|
}
|
|
|
|
*Slash = '\0';
|
|
}
|
|
}
|
|
|
|
strcpy(NtRoot, Candidate);
|
|
if (!SetEnvironmentVariableA("BASEDIR", NtRoot)) {
|
|
BuildError("Unable to set BASEDIR=%s\n", NtRoot);
|
|
exit(1);
|
|
}
|
|
sprintf(DbMasterName, "%s\\%s", NtRoot, DBMASTER_NAME);
|
|
}
|
|
|
|
static LPCSTR
|
|
DefaultProcessorArchitecture(VOID)
|
|
{
|
|
LPCSTR Architecture = getenv("VSCMD_ARG_TGT_ARCH");
|
|
|
|
// A Visual Studio developer prompt explicitly tells us which toolchain
|
|
// target is active. Prefer that for cross-target prompts.
|
|
if (Architecture && *Architecture) {
|
|
if (!_stricmp(Architecture, "x64") || !_stricmp(Architecture, "amd64"))
|
|
return "AMD64";
|
|
if (!_stricmp(Architecture, "x86"))
|
|
return "x86";
|
|
if (!_stricmp(Architecture, "ia64"))
|
|
return "IA64";
|
|
if (!_stricmp(Architecture, "arm64"))
|
|
return "ARM64";
|
|
}
|
|
|
|
// Otherwise prefer the architecture of this build.exe. This keeps a
|
|
// standalone x64 bootstrap from unexpectedly defaulting to i386 because
|
|
// of inherited process-environment quirks.
|
|
#if defined(_M_ARM64)
|
|
return "ARM64";
|
|
#elif defined(_M_IA64)
|
|
return "IA64";
|
|
#elif defined(_M_AMD64) || defined(_WIN64)
|
|
return "AMD64";
|
|
#else
|
|
Architecture = getenv("PROCESSOR_ARCHITECTURE");
|
|
if (Architecture && *Architecture) {
|
|
return Architecture;
|
|
}
|
|
return "x86";
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Target machine info:
|
|
//
|
|
// SourceSubDirMask, Description, Switch, MakeVariable,
|
|
// SourceVariable, ObjectVariable, AssociateDirectory,
|
|
// SourceDirectory, ObjectDirectory
|
|
//
|
|
|
|
TARGET_MACHINE_INFO i386TargetMachine = {
|
|
TMIDIR_I386, "i386", "-386", "-x86", "386=1",
|
|
"i386_SOURCES", "386_OBJECTS", "i386",
|
|
"i386", "i386dirs", { "i386" },
|
|
DIR_INCLUDE_X86 | DIR_INCLUDE_WIN32
|
|
};
|
|
|
|
TARGET_MACHINE_INFO ia64TargetMachine = {
|
|
TMIDIR_IA64, "IA64", "-ia64", "-merced", "IA64=1",
|
|
"IA64_SOURCES", "IA64_OBJECTS", "ia64",
|
|
"ia64", "ia64dirs", { "ia64" },
|
|
DIR_INCLUDE_IA64 | DIR_INCLUDE_RISC | DIR_INCLUDE_WIN64
|
|
};
|
|
|
|
TARGET_MACHINE_INFO Amd64TargetMachine = {
|
|
TMIDIR_AMD64, "AMD64", "-amd64", "-amd64", "AMD64=1",
|
|
"AMD64_SOURCES", "AMD64_OBJECTS", "amd64",
|
|
"amd64", "amd64dirs", { "amd64" },
|
|
DIR_INCLUDE_AMD64 | DIR_INCLUDE_RISC | DIR_INCLUDE_WIN64
|
|
};
|
|
|
|
TARGET_MACHINE_INFO Arm64TargetMachine = {
|
|
TMIDIR_ARM64, "ARM64", "-arm64", "-aarch64", "ARM64=1",
|
|
"ARM64_SOURCES", "ARM64_OBJECTS", "arm64",
|
|
"arm64", "arm64dirs", { "arm64" },
|
|
DIR_INCLUDE_ARM64 | DIR_INCLUDE_RISC | DIR_INCLUDE_WIN64
|
|
};
|
|
|
|
TARGET_MACHINE_INFO *PossibleTargetMachines[MAX_TARGET_MACHINES] = {
|
|
&i386TargetMachine,
|
|
&ia64TargetMachine,
|
|
&Amd64TargetMachine,
|
|
&Arm64TargetMachine
|
|
};
|
|
|
|
UINT NumberCompileWarnings;
|
|
UINT NumberCompileErrors;
|
|
UINT NumberCompiles;
|
|
UINT NumberLibraries;
|
|
UINT NumberLibraryWarnings;
|
|
UINT NumberLibraryErrors;
|
|
UINT NumberLinks;
|
|
UINT NumberLinkWarnings;
|
|
UINT NumberLinkErrors;
|
|
UINT NumberBinplaces;
|
|
UINT NumberBinplaceWarnings;
|
|
UINT NumberBinplaceErrors;
|
|
|
|
//
|
|
// Machine specific target dirs default. If one there is only one build
|
|
// target and a target specific dirs file is selected, then this gets
|
|
// filled with a pointer to the target specific dirs filename.
|
|
//
|
|
|
|
LPSTR pszTargetDirs = "";
|
|
|
|
#define AltDirMaxSize 10 // Maximum size for alternate obj dir name
|
|
|
|
CHAR LogDirectory[DB_MAX_PATH_LENGTH] = ".";
|
|
CHAR LogFileName[DB_MAX_PATH_LENGTH] = "build";
|
|
CHAR WrnFileName[DB_MAX_PATH_LENGTH] = "build";
|
|
CHAR ErrFileName[DB_MAX_PATH_LENGTH] = "build";
|
|
CHAR IncFileName[DB_MAX_PATH_LENGTH] = "build";
|
|
|
|
CHAR szObjRoot[DB_MAX_PATH_LENGTH];
|
|
CHAR *pszObjRoot;
|
|
|
|
CHAR szBuildAltDir[DB_MAX_PATH_LENGTH];
|
|
CHAR *pszBuildAltDir = NULL;
|
|
|
|
CHAR szObjDir[DB_MAX_PATH_LENGTH];
|
|
CHAR szObjDirSlash[DB_MAX_PATH_LENGTH];
|
|
CHAR szObjDirSlashStar[DB_MAX_PATH_LENGTH];
|
|
|
|
CHAR szObjDirD[DB_MAX_PATH_LENGTH];
|
|
CHAR szObjDirSlashD[DB_MAX_PATH_LENGTH];
|
|
CHAR szObjDirSlashStarD[DB_MAX_PATH_LENGTH];
|
|
|
|
CHAR *pszObjDir = szObjDir;
|
|
CHAR *pszObjDirSlash = szObjDirSlash;
|
|
CHAR *pszObjDirSlashStar = szObjDirSlashStar;
|
|
CHAR *pszObjDirD = szObjDirD;
|
|
|
|
BOOL fCheckedBuild = TRUE;
|
|
ULONG iObjectDir = 0;
|
|
BOOL fDependencySwitchUsed;
|
|
BOOL fCmdLineDependencySwitchUsed;
|
|
BOOL fCmdLineQuicky;
|
|
BOOL fCmdLineSemiQuicky;
|
|
BOOL fCmdLineQuickZero;
|
|
CHAR *BuildProduct;
|
|
|
|
ULONG DefaultProcesses = 0;
|
|
CHAR *szBuildTag;
|
|
|
|
#define MAX_ENV_ARG 512
|
|
|
|
const char szNewLine[] = "\n";
|
|
const char szUsage[] =
|
|
"Usage: build [-M[ n]][-w][-e][-f][-q][-c] [-why] [-clean]\n"
|
|
" [-386|-amd64|-ia64|-arm64] [-nmake arg]\n"
|
|
" -M [n] parallel build (automatic up to 32 workers)\n"
|
|
" -w watch tree and rebuild on changes\n"
|
|
" -e write build logs\n"
|
|
" -f rescan dependencies\n"
|
|
" -q query only\n"
|
|
" -c clean object files\n"
|
|
" -why explain rebuilds\n"
|
|
" -clean run project clean rules\n";
|
|
|
|
|
|
BOOL
|
|
ProcessParameters(int argc, LPSTR argv[], BOOL SkipFirst);
|
|
|
|
VOID
|
|
GetEnvParameters(
|
|
LPSTR EnvVarName,
|
|
LPSTR DefaultValue,
|
|
int *pargc,
|
|
int maxArgc,
|
|
LPSTR argv[]);
|
|
|
|
VOID
|
|
FreeEnvParameters(int argc, LPSTR argv[]);
|
|
|
|
VOID
|
|
FreeCmdStrings(VOID);
|
|
|
|
VOID
|
|
MungePossibleTarget(
|
|
PTARGET_MACHINE_INFO pti
|
|
);
|
|
|
|
VOID
|
|
GetIncludePatterns(
|
|
LPSTR EnvVarName,
|
|
int maxArgc,
|
|
LPSTR argv[]);
|
|
|
|
VOID
|
|
FreeIncludePatterns(
|
|
int argc,
|
|
LPSTR argv[]);
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: main
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
int
|
|
__cdecl main(
|
|
int argc,
|
|
LPSTR argv[]
|
|
)
|
|
{
|
|
char c;
|
|
PDIRREC DirDB;
|
|
UINT i;
|
|
int EnvArgc = 0;
|
|
LPSTR EnvArgv[ MAX_ENV_ARG ] = {0};
|
|
LPSTR s, s1;
|
|
LPSTR PostBuildCmd;
|
|
BOOL fPauseDone = FALSE;
|
|
#if DBG
|
|
BOOL fDebugSave;
|
|
|
|
fDebug = 0;
|
|
#endif
|
|
|
|
{
|
|
int watchResult = TryWatchMode();
|
|
if (watchResult >= 0) return watchResult;
|
|
}
|
|
|
|
strcpy(szObjDir, "obj");
|
|
strcpy(szObjDirSlash, "obj\\");
|
|
strcpy(szObjDirSlashStar, "obj\\*");
|
|
strcpy(szObjDirD, "objd");
|
|
strcpy(szObjDirSlashD, "objd\\");
|
|
strcpy(szObjDirSlashStarD, "objd\\*");
|
|
|
|
/*
|
|
* The historical tool closed every CRT descriptor from 3 through _NFILE.
|
|
* Modern MSVC treats _close() on an invalid descriptor as an invalid-
|
|
* parameter failure, which can terminate the process before normal startup.
|
|
* Do not sweep the CRT descriptor table; inherited handles are the caller's
|
|
* responsibility and are not needed by build.exe.
|
|
*/
|
|
|
|
pGetFileAttributesExA = (BOOL (WINAPI *)(LPCSTR, GET_FILEEX_INFO_LEVELS, LPVOID))
|
|
GetProcAddress(GetModuleHandle("kernel32.dll"), "GetFileAttributesExA");
|
|
|
|
if (pGetFileAttributesExA) {
|
|
pDateTimeFile = DateTimeFile2;
|
|
} else {
|
|
pDateTimeFile = DateTimeFile;
|
|
}
|
|
|
|
InitializeCriticalSection(&TTYCriticalSection);
|
|
|
|
s1 = getenv("COMSPEC");
|
|
if (s1) {
|
|
cmdexe = s1;
|
|
} else {
|
|
cmdexe = "cmd.exe";
|
|
}
|
|
|
|
{
|
|
SYSTEMTIME st;
|
|
FILETIME ft;
|
|
|
|
GetSystemTime(&st);
|
|
SystemTimeToFileTime(&st, &ft);
|
|
|
|
FileTimeToDosDateTime( &ft,
|
|
((LPWORD)&BuildStartTime)+1,
|
|
(LPWORD)&BuildStartTime
|
|
);
|
|
}
|
|
|
|
BigBufSize = 0xFFF0;
|
|
AllocMem(BigBufSize, &BigBuf, MT_IOBUFFER);
|
|
|
|
// All env parsing should happen here (after the cmd line is processed)
|
|
|
|
ResolveBaseDirectory();
|
|
|
|
|
|
s = getenv("_OBJ_ROOT");
|
|
if (s) {
|
|
pszObjRoot = strcpy(szObjRoot, s);
|
|
}
|
|
|
|
s = getenv("BUILD_ALT_DIR");
|
|
if (s) {
|
|
if (strlen(s) > sizeof(szObjDir) - strlen(szObjDir) - 1) {
|
|
BuildError("environment variable BUILD_ALT_DIR may not be longer than %d characters.\n",
|
|
sizeof(szObjDir) - strlen(szObjDir) - 1);
|
|
exit(1);
|
|
}
|
|
strcat(szObjDir, s);
|
|
strcpy(szObjDirSlash, szObjDir);
|
|
strcpy(szObjDirSlashStar, szObjDir);
|
|
strcat(szObjDirSlash, "\\");
|
|
strcat(szObjDirSlashStar, "\\*");
|
|
strcat(LogFileName, s);
|
|
strcat(WrnFileName, s);
|
|
strcat(ErrFileName, s);
|
|
strcat(IncFileName, s);
|
|
BuildMsg("Object root set to: ==> obj%s\n", s);
|
|
}
|
|
|
|
s = getenv("NTDEBUG");
|
|
if (!s || *s == '\0' || strcmp(s, "retail") == 0 || strcmp(s, "ntsdnodbg") == 0) {
|
|
fCheckedBuild = FALSE;
|
|
}
|
|
|
|
s = getenv("OS2_INC_PATH");
|
|
if (s) {
|
|
MakeString(&pszIncOs2, s, TRUE, MT_DIRSTRING);
|
|
} else {
|
|
MakeExpandedString(&pszIncOs2, "\\public\\sdk\\inc\\os2");
|
|
}
|
|
s = getenv("POSIX_INC_PATH");
|
|
if (s) {
|
|
MakeString(&pszIncPosix, s, TRUE, MT_DIRSTRING);
|
|
} else {
|
|
MakeExpandedString(&pszIncPosix, "\\public\\sdk\\inc\\posix");
|
|
}
|
|
s = getenv("CHICAGO_INC_PATH");
|
|
if (s) {
|
|
MakeString(&pszIncChicago, s, TRUE, MT_DIRSTRING);
|
|
} else {
|
|
MakeExpandedString(&pszIncChicago, "\\public\\sdk\\inc\\chicago");
|
|
}
|
|
s = getenv("CRT_INC_PATH");
|
|
if (s) {
|
|
MakeString(&pszIncCrt, s, TRUE, MT_DIRSTRING);
|
|
} else {
|
|
MakeExpandedString(&pszIncCrt, "\\public\\sdk\\inc\\crt");
|
|
}
|
|
s = getenv("SDK_INC_PATH");
|
|
if (s) {
|
|
MakeString(&pszIncSdk, s, TRUE, MT_DIRSTRING);
|
|
} else {
|
|
MakeExpandedString(&pszIncSdk, "\\public\\sdk\\inc");
|
|
}
|
|
s = getenv("OAK_INC_PATH");
|
|
if (s) {
|
|
MakeString(&pszIncOak, s, TRUE, MT_DIRSTRING);
|
|
} else {
|
|
MakeExpandedString(&pszIncOak, "\\public\\oak\\inc");
|
|
}
|
|
s = getenv("DDK_INC_PATH");
|
|
if (s) {
|
|
MakeString(&pszIncDdk, s, TRUE, MT_DIRSTRING);
|
|
} else {
|
|
MakeExpandedString(&pszIncDdk, "\\public\\ddk\\inc");
|
|
}
|
|
s = getenv("WDM_INC_PATH");
|
|
if (s) {
|
|
MakeString(&pszIncWdm, s, TRUE, MT_DIRSTRING);
|
|
} else {
|
|
MakeExpandedString(&pszIncWdm, "\\public\\ddk\\inc\\wdm");
|
|
}
|
|
s = getenv("PRIVATE_INC_PATH");
|
|
if (s) {
|
|
MakeString(&pszIncPri, s, TRUE, MT_DIRSTRING);
|
|
} else {
|
|
MakeExpandedString(&pszIncPri, "\\private\\inc");
|
|
}
|
|
s = getenv("MFC_INCLUDES");
|
|
if (s) {
|
|
MakeString(&pszIncMfc, s, TRUE, MT_DIRSTRING);
|
|
} else {
|
|
MakeExpandedString(&pszIncMfc, "\\public\\sdk\\inc\\mfc42");
|
|
}
|
|
s = getenv("SDK_LIB_DEST");
|
|
if (s) {
|
|
MakeString(&pszSdkLibDest, s, TRUE, MT_DIRSTRING);
|
|
} else {
|
|
MakeExpandedString(&pszSdkLibDest, "\\public\\sdk\\lib");
|
|
}
|
|
s = getenv("DDK_LIB_DEST");
|
|
if (s) {
|
|
MakeString(&pszDdkLibDest, s, TRUE, MT_DIRSTRING);
|
|
} else {
|
|
MakeExpandedString(&pszDdkLibDest, "\\public\\sdk\\lib");
|
|
}
|
|
|
|
s = getenv("PUBLIC_INTERNAL_PATH");
|
|
if (s) {
|
|
MakeString(&pszPublicInternalPath, s, TRUE, MT_DIRSTRING);
|
|
} else {
|
|
MakeExpandedString(&pszPublicInternalPath, "\\public\\internal");
|
|
}
|
|
|
|
|
|
szBuildTag = getenv("BUILD_TAG");
|
|
|
|
strcpy( MakeParameters, "" );
|
|
MakeParametersTail = AppendString( MakeParameters,
|
|
"/c BUILDMSG=Stop.",
|
|
FALSE);
|
|
|
|
RecurseLevel = 0;
|
|
|
|
#if DBG
|
|
if ((s = getenv("BUILD_DEBUG_FLAG")) != NULL) {
|
|
i = atoi(s);
|
|
if (!isdigit(*s)) {
|
|
i = 1;
|
|
}
|
|
BuildMsg("Debug Output Enabled: %u ==> %u\n", fDebug, fDebug | i);
|
|
fDebug |= i;
|
|
}
|
|
#endif
|
|
|
|
if (!(MakeProgram = getenv( "BUILD_MAKE_PROGRAM" ))) {
|
|
MakeProgram = "NMAKE.EXE";
|
|
}
|
|
|
|
if (s = getenv("BUILD_PATH")) {
|
|
SetEnvironmentVariable("PATH", s);
|
|
}
|
|
|
|
if (s = getenv("COPYCMD")) {
|
|
if (!strchr(s, 'y') && !strchr(s, 'Y')) {
|
|
// COPYCMD is set, but /y isn't a part of it. Add /Y.
|
|
s1 = malloc(strlen(s) + sizeof(" /Y") + 1);
|
|
if (s1) {
|
|
strcpy(s1, s);
|
|
strcat(s1, " /Y");
|
|
SetEnvironmentVariable("COPYCMD", s1);
|
|
}
|
|
}
|
|
} else {
|
|
// COPYCMD not set. Do so.
|
|
SetEnvironmentVariable("COPYCMD", "/Y");
|
|
}
|
|
|
|
PostBuildCmd = getenv("BUILD_POST_PROCESS");
|
|
|
|
SystemIncludeEnv = getenv( "INCLUDE" );
|
|
GetCurrentDirectory( sizeof( CurrentDirectory ), CurrentDirectory );
|
|
|
|
for (i = 0; i < MAX_TARGET_MACHINES; i++) {
|
|
TargetMachines[i] = NULL;
|
|
TargetToPossibleTarget[i] = 0;
|
|
MungePossibleTarget(PossibleTargetMachines[i]);
|
|
}
|
|
|
|
if (!(BuildProduct = getenv("BUILD_PRODUCT"))) {
|
|
BuildProduct = "";
|
|
}
|
|
|
|
if (!ProcessParameters( argc, argv, TRUE )) {
|
|
fUsage = TRUE;
|
|
} else {
|
|
fCmdLineDependencySwitchUsed = fDependencySwitchUsed;
|
|
fCmdLineQuicky = fQuicky;
|
|
fCmdLineSemiQuicky = fSemiQuicky;
|
|
fCmdLineQuickZero = fQuickZero;
|
|
GetEnvParameters( "BUILD_DEFAULT", NULL, &EnvArgc, MAX_ENV_ARG, EnvArgv );
|
|
GetEnvParameters( "BUILD_OPTIONS", NULL, &EnvArgc, MAX_ENV_ARG, EnvArgv );
|
|
if (CountTargetMachines == 0) {
|
|
LPCSTR Architecture = DefaultProcessorArchitecture();
|
|
|
|
if (!_stricmp(Architecture, "IA64"))
|
|
GetEnvParameters( "BUILD_DEFAULT_TARGETS", "-ia64", &EnvArgc, MAX_ENV_ARG, EnvArgv );
|
|
else
|
|
if (!_stricmp(Architecture, "ARM64"))
|
|
GetEnvParameters( "BUILD_DEFAULT_TARGETS", "-arm64", &EnvArgc, MAX_ENV_ARG, EnvArgv );
|
|
else
|
|
if (!_stricmp(Architecture, "AMD64") || !_stricmp(Architecture, "x64"))
|
|
GetEnvParameters( "BUILD_DEFAULT_TARGETS", "-amd64", &EnvArgc, MAX_ENV_ARG, EnvArgv );
|
|
else
|
|
GetEnvParameters( "BUILD_DEFAULT_TARGETS", "-386", &EnvArgc, MAX_ENV_ARG, EnvArgv );
|
|
}
|
|
if (!ProcessParameters( EnvArgc, EnvArgv, FALSE )) {
|
|
fUsage = TRUE;
|
|
}
|
|
}
|
|
FreeEnvParameters(EnvArgc, EnvArgv);
|
|
|
|
if (!fUsage && CountTargetMachines == 1) {
|
|
LPCSTR vsTarget = getenv("VSCMD_ARG_TGT_ARCH");
|
|
if (vsTarget && *vsTarget) {
|
|
LPCSTR actual = TargetMachines[0]->Description;
|
|
if ((_stricmp(vsTarget, "x64") == 0 && _stricmp(actual, "amd64") != 0) ||
|
|
(_stricmp(vsTarget, "amd64") == 0 && _stricmp(actual, "amd64") != 0) ||
|
|
(_stricmp(vsTarget, "x86") == 0 && _stricmp(actual, "i386") != 0) ||
|
|
(_stricmp(vsTarget, "arm64") == 0 && _stricmp(actual, "arm64") != 0)) {
|
|
BuildError("error: target/toolchain mismatch (%s/%s)\n", actual, vsTarget);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
if (!fUsage && !fQuery && !SearchPathA(NULL, MakeProgram, NULL, 0, NULL, NULL)) {
|
|
BuildError("error: %s missing\n", MakeProgram);
|
|
return 1;
|
|
}
|
|
|
|
if (!fUsage && !fGenerateObjectsDotMacOnly) {
|
|
if (!_stricmp(BuildProduct, "NT")) {
|
|
if (fCmdLineDependencySwitchUsed) {
|
|
fDependencySwitchUsed = fCmdLineDependencySwitchUsed;
|
|
fQuicky = fCmdLineQuicky;
|
|
fSemiQuicky = fCmdLineSemiQuicky;
|
|
fQuickZero = fCmdLineQuickZero;
|
|
}
|
|
if (!fDependencySwitchUsed) {
|
|
BuildError("(Fatal Error) One of either /D, /Z, /z, or /3 is required for NT builds\n");
|
|
exit( 1 );
|
|
} else {
|
|
if (fDependencySwitchUsed == 1) {
|
|
if (fQuicky) {
|
|
BuildError("(Fatal Error) switch can not be used with /Z, /z, or /3\n");
|
|
exit( 1 );
|
|
}
|
|
BuildMsgRaw( "BUILD: /D specified - The NT build lab will not accept build requests using this switch\n");
|
|
}
|
|
if (fDependencySwitchUsed == 2){
|
|
if (fStopAfterPassZero) {
|
|
BuildError("(Fatal Error) switch /0 can not be used with /z\n");
|
|
exit( 1 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
GetIncludePatterns( "BUILD_ACCEPTABLE_INCLUDES", MAX_INCLUDE_PATTERNS, AcceptableIncludePatternList );
|
|
GetIncludePatterns( "BUILD_UNACCEPTABLE_INCLUDES", MAX_INCLUDE_PATTERNS, UnacceptableIncludePatternList );
|
|
|
|
if (( fCheckIncludePaths ) &&
|
|
( AcceptableIncludePatternList[ 0 ] == NULL ) &&
|
|
( UnacceptableIncludePatternList[ 0 ] == NULL )) {
|
|
|
|
BuildMsgRaw( "WARNING: -# specified without BUILD_[UN]ACCEPTABLE_INCLUDES set\n" );
|
|
}
|
|
|
|
|
|
if (fCleanRestart) {
|
|
if (fClean) {
|
|
fClean = FALSE;
|
|
fRestartClean = TRUE;
|
|
}
|
|
else
|
|
if (fCleanLibs) {
|
|
fCleanLibs = FALSE;
|
|
fRestartCleanLibs = TRUE;
|
|
}
|
|
else {
|
|
BuildError("/R switch only valid with /c or /C switch.\n");
|
|
fUsage = TRUE;
|
|
}
|
|
}
|
|
|
|
NumberProcesses = 1;
|
|
if (fParallel || getenv("BUILD_MULTIPROCESSOR")) {
|
|
SYSTEM_INFO SystemInfo;
|
|
|
|
if (DefaultProcesses == 0) {
|
|
GetSystemInfo(&SystemInfo);
|
|
NumberProcesses = SystemInfo.dwNumberOfProcessors;
|
|
} else {
|
|
NumberProcesses = DefaultProcesses;
|
|
}
|
|
if (NumberProcesses == 1) {
|
|
fParallel = FALSE;
|
|
} else {
|
|
if (NumberProcesses > 32) {
|
|
if (DefaultProcesses != 0) {
|
|
BuildError("error: maximum worker count is 32\n");
|
|
exit(1);
|
|
}
|
|
NumberProcesses = 32;
|
|
}
|
|
fParallel = TRUE;
|
|
BuildMsg("Using %d child processes\n", NumberProcesses);
|
|
}
|
|
}
|
|
|
|
if (fUsage) {
|
|
BuildMsgRaw(
|
|
"\nBUILD: Version %x.%02x.%04d\n\n",
|
|
BUILD_VERSION >> 8,
|
|
BUILD_VERSION & 0xFF,
|
|
VER_PRODUCTBUILD);
|
|
BuildMsgRaw(szUsage);
|
|
}
|
|
else
|
|
if (CountTargetMachines != 0) {
|
|
BuildError(
|
|
"%s for ",
|
|
fLinkOnly? "Link" : (fCompileOnly? "Compile" : "Compile and Link"));
|
|
for (i = 0; i < CountTargetMachines; i++) {
|
|
BuildErrorRaw(i==0? "%s" : ", %s", TargetMachines[i]->Description);
|
|
AppendString(
|
|
MakeTargets,
|
|
TargetMachines[i]->MakeVariable,
|
|
TRUE);
|
|
|
|
}
|
|
|
|
BuildErrorRaw(szNewLine);
|
|
|
|
//
|
|
// If there is one and only one build target and target dirs has
|
|
// been enabled, then fill in the appropriate target dirs name.
|
|
//
|
|
|
|
if (CountTargetMachines == 1) {
|
|
if (fTargetDirs == TRUE) {
|
|
pszTargetDirs = TargetMachines[0]->TargetDirs;
|
|
FileDesc[0].pszPattern = TargetMachines[0]->TargetDirs;
|
|
}
|
|
}
|
|
|
|
if (DEBUG_1) {
|
|
if (CountExcludeIncs) {
|
|
BuildError("Include files that will be excluded:");
|
|
for (i = 0; i < CountExcludeIncs; i++) {
|
|
BuildErrorRaw(i == 0? " %s" : ", %s", ExcludeIncs[i]);
|
|
}
|
|
BuildErrorRaw(szNewLine);
|
|
}
|
|
if (CountOptionalDirs) {
|
|
BuildError("Optional Directories that will be built:");
|
|
for (i = 0; i < CountOptionalDirs; i++) {
|
|
BuildErrorRaw(i == 0? " %s" : ", %s", OptionalDirs[i]);
|
|
}
|
|
BuildErrorRaw(szNewLine);
|
|
}
|
|
if (CountExcludeDirs) {
|
|
BuildError("Directories that will be NOT be built:");
|
|
for (i = 0; i < CountExcludeDirs; i++) {
|
|
BuildErrorRaw(i == 0? " %s" : ", %s", ExcludeDirs[i]);
|
|
}
|
|
BuildErrorRaw(szNewLine);
|
|
}
|
|
BuildMsg("MakeParameters == %s\n", MakeParameters);
|
|
BuildMsg("MakeTargets == %s\n", MakeTargets);
|
|
}
|
|
|
|
#if DBG
|
|
fDebugSave = fDebug;
|
|
// fDebug = 0;
|
|
#endif
|
|
|
|
//
|
|
// Generate the _objects.mac file if requested
|
|
//
|
|
|
|
if (fGenerateObjectsDotMacOnly) {
|
|
DIRSUP DirSup;
|
|
ULONG DateTimeSources;
|
|
|
|
DirDB = ScanDirectory( CurrentDirectory );
|
|
|
|
if (DirDB && (DirDB->DirFlags & (DIRDB_DIRS | DIRDB_SOURCES))) {
|
|
if (!ReadSourcesFile(DirDB, &DirSup, &DateTimeSources)) {
|
|
BuildError("Current directory not a SOURCES directory.\n");
|
|
return( 1 );
|
|
}
|
|
|
|
GenerateObjectsDotMac(DirDB, &DirSup, DateTimeSources);
|
|
|
|
FreeDirSupData(&DirSup);
|
|
ReportDirsUsage();
|
|
FreeCmdStrings();
|
|
ReportMemoryUsage();
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
if (!fQuery && fErrorLog) {
|
|
strcat(LogFileName, ".log");
|
|
if (!MyOpenFile(LogDirectory, LogFileName, "wb", &LogFile, TRUE)) {
|
|
BuildError("(Fatal Error) Unable to open log file\n");
|
|
exit( 1 );
|
|
}
|
|
CreatedBuildFile(LogDirectory, LogFileName);
|
|
|
|
strcat(WrnFileName, ".wrn");
|
|
if (!MyOpenFile(LogDirectory, WrnFileName, "wb", &WrnFile, FALSE)) {
|
|
BuildError("(Fatal Error) Unable to open warning file\n");
|
|
exit( 1 );
|
|
}
|
|
CreatedBuildFile(LogDirectory, WrnFileName);
|
|
|
|
strcat(ErrFileName, ".err");
|
|
if (!MyOpenFile(LogDirectory, ErrFileName, "wb", &ErrFile, FALSE)) {
|
|
BuildError("(Fatal Error) Unable to open error file\n");
|
|
exit( 1 );
|
|
}
|
|
CreatedBuildFile(LogDirectory, ErrFileName);
|
|
|
|
if ( fCheckIncludePaths ) {
|
|
|
|
strcat( IncFileName, ".inc");
|
|
if (!MyOpenFile( LogDirectory, IncFileName, "wb", &IncFile, FALSE ) ) {
|
|
BuildError( "(Fatal Error) Unable to open include log file\n");
|
|
exit( 1 );
|
|
}
|
|
CreatedBuildFile( LogDirectory, IncFileName );
|
|
}
|
|
}
|
|
else {
|
|
LogFile = NULL;
|
|
WrnFile = NULL;
|
|
ErrFile = NULL;
|
|
IncFile = NULL;
|
|
}
|
|
|
|
s = getenv("__MTSCRIPT_ENV_ID");
|
|
if (s) {
|
|
|
|
if (fDependencySwitchUsed == 2 && fPause)
|
|
{
|
|
BuildError("Cannot combine -z (or -2) and -p switches under MTScript");
|
|
exit(1);
|
|
}
|
|
|
|
// Make sure any other build.exe's that get launched as child
|
|
// processes don't try to connect to the script engine.
|
|
SetEnvironmentVariable("__MTSCRIPT_ENV_ID", NULL);
|
|
|
|
g_hMTEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
if (g_hMTEvent != NULL)
|
|
{
|
|
g_hMTThread = CreateThread(NULL,
|
|
0,
|
|
(LPTHREAD_START_ROUTINE)MTScriptThread,
|
|
NULL,
|
|
0,
|
|
&g_dwMTThreadId);
|
|
|
|
if (g_hMTThread)
|
|
{
|
|
// Wait for the thread to tell us it's ready.
|
|
WaitForSingleObject(g_hMTEvent, INFINITE);
|
|
|
|
ResetEvent(g_hMTEvent);
|
|
|
|
if (!g_hMTThread)
|
|
{
|
|
// An error occurred connecting to the script engine.
|
|
// We can't continue.
|
|
BuildError("Unable to connect to script engine. Exiting.");
|
|
exit(2);
|
|
}
|
|
|
|
fMTScriptSync = TRUE;
|
|
}
|
|
else
|
|
{
|
|
BuildError("Failed to launch script handling thread! (%d)", GetLastError());
|
|
|
|
CloseHandle(g_hMTEvent);
|
|
g_hMTEvent = NULL;
|
|
fPause = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BuildError("Failed to create script communication event! (%d)", GetLastError());
|
|
fPause = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The user should not have CHICAGO_PRODUCT in
|
|
// their environment, as it can cause problems on other machines with
|
|
// other users that don't have them set. The following warning
|
|
// messages are intended to alert the user to the presence of these
|
|
// environment variables.
|
|
//
|
|
|
|
if (getenv("CHICAGO_PRODUCT") != NULL) {
|
|
BuildError("CHICAGO_PRODUCT was detected in the environment.\n" );
|
|
BuildMsg(" ALL directories will be built targeting Chicago!\n" );
|
|
fChicagoProduct = TRUE;
|
|
}
|
|
|
|
if (!fQuicky) {
|
|
LoadMasterDB();
|
|
|
|
BuildError("Computing Include file dependencies:\n");
|
|
|
|
ScanIncludeEnv(SystemIncludeEnv);
|
|
ScanGlobalIncludeDirectory(pszIncMfc);
|
|
ScanGlobalIncludeDirectory(pszIncOak);
|
|
ScanGlobalIncludeDirectory(pszIncDdk);
|
|
ScanGlobalIncludeDirectory(pszIncWdm);
|
|
ScanGlobalIncludeDirectory(pszIncSdk);
|
|
ScanGlobalIncludeDirectory(pszIncPri);
|
|
CountSystemIncludeDirs = CountIncludeDirs;
|
|
}
|
|
|
|
#if DBG
|
|
fDebug = fDebugSave;
|
|
#endif
|
|
fFirstScan = TRUE;
|
|
fPassZero = FALSE;
|
|
ScanSourceDirectories( CurrentDirectory );
|
|
|
|
if (!fQuicky) {
|
|
if (SaveMasterDB() == FALSE) {
|
|
BuildError("Unable to save the dependency database: %s\n", DbMasterName);
|
|
}
|
|
}
|
|
|
|
c = '\n';
|
|
if (!fLinkOnly && CountPassZeroDirs) {
|
|
if (!fQuicky) {
|
|
TotalFilesToCompile = 0;
|
|
TotalLinesToCompile = 0L;
|
|
|
|
for (i=0; i<CountPassZeroDirs; i++) {
|
|
DirDB = PassZeroDirs[ i ];
|
|
|
|
TotalFilesToCompile += DirDB->CountOfPassZeroFiles;
|
|
TotalLinesToCompile += DirDB->PassZeroLines;
|
|
}
|
|
|
|
if (CountPassZeroDirs > 1 &&
|
|
TotalFilesToCompile != 0 &&
|
|
TotalLinesToCompile != 0L) {
|
|
|
|
BuildMsgRaw(
|
|
"Total of %d pass zero files (%s lines) to compile in %d directories\n\n",
|
|
TotalFilesToCompile,
|
|
FormatNumber( TotalLinesToCompile ),
|
|
CountPassZeroDirs);
|
|
}
|
|
}
|
|
|
|
TotalFilesCompiled = 0;
|
|
TotalLinesCompiled = 0L;
|
|
ElapsedCompileTime = 0L;
|
|
|
|
if (fPause && !fMTScriptSync) {
|
|
BuildMsg("Press enter to continue with compilations (or 'q' to quit)...");
|
|
c = (char)getchar();
|
|
}
|
|
|
|
if ((CountPassZeroDirs > 0) && (c == '\n')) {
|
|
CompilePassZeroDirectories();
|
|
WaitForParallelThreads();
|
|
|
|
//
|
|
// Rescan now that we've generated all the generated files
|
|
//
|
|
CountPassZeroDirs = 0;
|
|
CountCompileDirs = 0;
|
|
CountLinkDirs = 0;
|
|
|
|
UnsnapAllDirectories();
|
|
|
|
fPassZero = FALSE;
|
|
fFirstScan = FALSE;
|
|
RecurseLevel = 0;
|
|
|
|
if (fMTScriptSync) {
|
|
WaitForResume(fPause, PE_PASS0_COMPLETE);
|
|
|
|
fPauseDone = TRUE;
|
|
}
|
|
|
|
// This will compile directories if fQuicky is TRUE
|
|
if (!fStopAfterPassZero) {
|
|
ScanSourceDirectories( CurrentDirectory );
|
|
}
|
|
|
|
if (!fQuicky) {
|
|
if (SaveMasterDB() == FALSE) {
|
|
BuildError("Unable to save the dependency database: %s\n", DbMasterName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fMTScriptSync && !fPauseDone) {
|
|
WaitForResume(fPause, PE_PASS0_COMPLETE);
|
|
}
|
|
|
|
if (fStopAfterPassZero) {
|
|
BuildError("Stopping after pass zero requested: Pass0 done.\n");
|
|
}
|
|
|
|
if (!fStopAfterPassZero && !fLinkOnly && (c == '\n')) {
|
|
if (!fQuicky) {
|
|
TotalFilesToCompile = 0;
|
|
TotalLinesToCompile = 0L;
|
|
|
|
for (i=0; i<CountCompileDirs; i++) {
|
|
DirDB = CompileDirs[ i ];
|
|
|
|
TotalFilesToCompile += DirDB->CountOfFilesToCompile;
|
|
TotalLinesToCompile += DirDB->SourceLinesToCompile;
|
|
}
|
|
|
|
if (CountCompileDirs > 1 &&
|
|
TotalFilesToCompile != 0 &&
|
|
TotalLinesToCompile != 0L) {
|
|
|
|
BuildMsgRaw(
|
|
"Total of %d source files (%s lines) to compile in %d directories\n\n",
|
|
TotalFilesToCompile,
|
|
FormatNumber( TotalLinesToCompile ),
|
|
CountCompileDirs);
|
|
}
|
|
}
|
|
|
|
TotalFilesCompiled = 0;
|
|
TotalLinesCompiled = 0L;
|
|
ElapsedCompileTime = 0L;
|
|
|
|
if (fPause && !fMTScriptSync) {
|
|
BuildMsg("Press enter to continue with compilations (or 'q' to quit)...");
|
|
c = (char)getchar();
|
|
}
|
|
|
|
if (c == '\n') {
|
|
// Does nothing if fQuicky is TRUE
|
|
CompileSourceDirectories();
|
|
WaitForParallelThreads();
|
|
}
|
|
}
|
|
|
|
if (fMTScriptSync) {
|
|
WaitForResume(fPause, PE_PASS1_COMPLETE);
|
|
}
|
|
|
|
if (!fStopAfterPassZero && !fCompileOnly && (c == '\n')) {
|
|
LinkSourceDirectories();
|
|
WaitForParallelThreads();
|
|
}
|
|
|
|
if (!fStopAfterPassZero && PostBuildCmd && !fMTScriptSync) {
|
|
// If there's a post build process to invoke, do so but only if
|
|
// not running under the buildcon.
|
|
|
|
// PostBuildCmd is of the form <message to display><command to execute>
|
|
// The Message is delimiated with curly brackets. ie:
|
|
// POST_BUILD_PROCESS={Do randomness}randomness.cmd
|
|
|
|
// would display:
|
|
//
|
|
// BUILD: Do randomness
|
|
//
|
|
// while randomness.cmd was running. The process is run synchronously and
|
|
// we've still got the i/o pipes setup so any output will be logged to
|
|
// build.log (and wrn/err if formated correctly)
|
|
|
|
if (*PostBuildCmd == '{') {
|
|
LPSTR PostBuildMessage = PostBuildCmd+1;
|
|
LogMsg("Executing post build scripts %s\n", szAsterisks);
|
|
while (*PostBuildCmd && *PostBuildCmd != '}')
|
|
PostBuildCmd++;
|
|
|
|
if (*PostBuildCmd == '}') {
|
|
*PostBuildCmd = '\0';
|
|
PostBuildCmd++;
|
|
BuildMsg("%s\n", PostBuildMessage);
|
|
LogMsg("%s\n", PostBuildMessage);
|
|
ExecuteProgram(PostBuildCmd, "", "", TRUE);
|
|
}
|
|
} else {
|
|
ExecuteProgram(PostBuildCmd, "", "", TRUE);
|
|
}
|
|
}
|
|
|
|
if (fShowTree) {
|
|
for (i = 0; i < CountShowDirs; i++) {
|
|
PrintDirDB(ShowDirs[i], 1|4);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
BuildError("No target machine specified\n");
|
|
}
|
|
|
|
if (!fUsage && !fQuery && fErrorLog) {
|
|
ULONG cbLogMin = 32;
|
|
ULONG cbWarnMin = 0;
|
|
|
|
if (!fAlwaysKeepLogfile) {
|
|
if (fQuicky && !fSemiQuicky && ftell(ErrFile) == 0) {
|
|
cbLogMin = cbWarnMin = ULONG_MAX;
|
|
}
|
|
}
|
|
CloseOrDeleteFile(&LogFile, LogDirectory, LogFileName, cbLogMin);
|
|
CloseOrDeleteFile(&WrnFile, LogDirectory, WrnFileName, cbWarnMin);
|
|
CloseOrDeleteFile(&ErrFile, LogDirectory, ErrFileName, 0L);
|
|
if ( fCheckIncludePaths ) {
|
|
CloseOrDeleteFile(&IncFile, LogDirectory, IncFileName, cbLogMin);
|
|
}
|
|
}
|
|
if (NumberCompileErrors || NumberLibraryErrors || NumberLinkErrors ||
|
|
NumberBinplaceErrors || BuildChildFailures) {
|
|
BuildError("Failed (%ld errors)\n\n",
|
|
(long)(NumberCompileErrors + NumberLibraryErrors + NumberLinkErrors +
|
|
NumberBinplaceErrors + BuildChildFailures));
|
|
} else {
|
|
BuildError("Done\n\n");
|
|
}
|
|
|
|
if (fMTScriptSync) {
|
|
WaitForResume(FALSE, PE_PASS2_COMPLETE);
|
|
}
|
|
|
|
if (NumberCompiles) {
|
|
BuildMsgRaw(" %d file%s compiled", NumberCompiles, NumberCompiles == 1 ? "" : "s");
|
|
if (NumberCompileWarnings) {
|
|
BuildMsgRaw(" - %d Warning%s", NumberCompileWarnings, NumberCompileWarnings == 1 ? "" : "s");
|
|
}
|
|
if (NumberCompileErrors) {
|
|
BuildMsgRaw(" - %d Error%s", NumberCompileErrors, NumberCompileErrors == 1 ? "" : "s");
|
|
}
|
|
|
|
if (ElapsedCompileTime) {
|
|
BuildMsgRaw(" - %5ld LPS", TotalLinesCompiled / ElapsedCompileTime);
|
|
}
|
|
|
|
BuildMsgRaw(szNewLine);
|
|
}
|
|
|
|
if (NumberLibraries) {
|
|
BuildMsgRaw(" %d librar%s built", NumberLibraries, NumberLibraries == 1 ? "y" : "ies");
|
|
if (NumberLibraryWarnings) {
|
|
BuildMsgRaw(" - %d Warning%s", NumberLibraryWarnings, NumberLibraryWarnings == 1 ? "" : "s");
|
|
}
|
|
if (NumberLibraryErrors) {
|
|
BuildMsgRaw(" - %d Error%s", NumberLibraryErrors, NumberLibraryErrors == 1 ? "" : "s");
|
|
}
|
|
BuildMsgRaw(szNewLine);
|
|
}
|
|
|
|
if (NumberLinks) {
|
|
BuildMsgRaw(" %d executable%sbuilt", NumberLinks, NumberLinks == 1 ? " " : "s ");
|
|
if (NumberLinkWarnings) {
|
|
BuildMsgRaw(" - %d Warning%s", NumberLinkWarnings, NumberLinkWarnings == 1 ? "" : "s");
|
|
}
|
|
if (NumberLinkErrors) {
|
|
BuildMsgRaw(" - %d Error%s", NumberLinkErrors, NumberLinkErrors == 1 ? "" : "s");
|
|
}
|
|
BuildMsgRaw(szNewLine);
|
|
}
|
|
|
|
if (NumberBinplaces) {
|
|
BuildMsgRaw(" %d file%sbinplaced", NumberBinplaces, NumberBinplaces == 1 ? " " : "s ");
|
|
if (NumberBinplaceWarnings) {
|
|
BuildMsgRaw(" - %d Warning%s", NumberBinplaceWarnings, NumberBinplaceWarnings == 1 ? "" : "s");
|
|
}
|
|
if (NumberBinplaceErrors) {
|
|
BuildMsgRaw(" - %d Error%s", NumberBinplaceErrors, NumberBinplaceErrors == 1 ? "" : "s");
|
|
}
|
|
BuildMsgRaw(szNewLine);
|
|
}
|
|
|
|
ReportDirsUsage();
|
|
FreeCmdStrings();
|
|
FreeIncludePatterns( MAX_INCLUDE_PATTERNS, AcceptableIncludePatternList );
|
|
FreeIncludePatterns( MAX_INCLUDE_PATTERNS, UnacceptableIncludePatternList );
|
|
ReportMemoryUsage();
|
|
|
|
ExitMTScriptThread();
|
|
|
|
if (NumberCompileErrors || NumberLibraryErrors || NumberLinkErrors || NumberBinplaceErrors || BuildChildFailures || fUsage) {
|
|
return 1;
|
|
}
|
|
else {
|
|
return( 0 );
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ReportDirsUsage( VOID )
|
|
{
|
|
ULONG i;
|
|
BOOLEAN fHeaderPrinted;
|
|
|
|
if (!fShowUnusedDirs) {
|
|
return;
|
|
}
|
|
|
|
fHeaderPrinted = FALSE;
|
|
for (i=0; i<CountOptionalDirs; i++) {
|
|
if (!OptionalDirsUsed[i]) {
|
|
if (!fHeaderPrinted) {
|
|
printf( "Unused BUILD_OPTIONS:" );
|
|
fHeaderPrinted = TRUE;
|
|
}
|
|
printf( " %s", OptionalDirs[i] );
|
|
}
|
|
}
|
|
|
|
for (i=0; i<CountExcludeDirs; i++) {
|
|
if (!ExcludeDirsUsed[i]) {
|
|
if (!fHeaderPrinted) {
|
|
printf( "Unused BUILD_OPTIONS:" );
|
|
fHeaderPrinted = TRUE;
|
|
}
|
|
printf( " ~%s", ExcludeDirs[i] );
|
|
}
|
|
}
|
|
|
|
if (fHeaderPrinted) {
|
|
printf( "\n" );
|
|
}
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SetObjDir
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
SetObjDir(BOOL fAlternate)
|
|
{
|
|
iObjectDir = 0;
|
|
if (fCheckedBuild) {
|
|
if (fAlternate) {
|
|
pszObjDir = szObjDirD;
|
|
pszObjDirSlash = szObjDirSlashD;
|
|
pszObjDirSlashStar = szObjDirSlashStarD;
|
|
iObjectDir = 1;
|
|
} else {
|
|
pszObjDir = szObjDir;
|
|
pszObjDirSlash = szObjDirSlash;
|
|
pszObjDirSlashStar = szObjDirSlashStar;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AddTargetMachine
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
AddTargetMachine(UINT iTarget)
|
|
{
|
|
UINT i;
|
|
|
|
for (i = 0; i < CountTargetMachines; i++) {
|
|
if (TargetMachines[i] == PossibleTargetMachines[iTarget]) {
|
|
assert(TargetToPossibleTarget[i] == iTarget);
|
|
return;
|
|
}
|
|
}
|
|
assert(CountTargetMachines < MAX_TARGET_MACHINES);
|
|
TargetToPossibleTarget[CountTargetMachines] = iTarget;
|
|
TargetMachines[CountTargetMachines++] = PossibleTargetMachines[iTarget];
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: ProcessParameters
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
ProcessParameters(
|
|
int argc,
|
|
LPSTR argv[],
|
|
BOOL SkipFirst
|
|
)
|
|
{
|
|
char c, *p;
|
|
int i;
|
|
BOOL Result;
|
|
|
|
if (DEBUG_1) {
|
|
BuildMsg("Parsing:");
|
|
for (i=1; i<argc; i++) {
|
|
BuildMsgRaw(" %s", argv[i]);
|
|
}
|
|
BuildMsgRaw(szNewLine);
|
|
}
|
|
|
|
Result = TRUE;
|
|
if (SkipFirst) {
|
|
--argc;
|
|
++argv;
|
|
}
|
|
while (argc) {
|
|
p = *argv;
|
|
if (*p == '/' || *p == '-') {
|
|
if (DEBUG_1) {
|
|
BuildMsg("Processing \"-%s\" switch\n", p+1);
|
|
}
|
|
|
|
for (i = 0; i < MAX_TARGET_MACHINES; i++) {
|
|
if (!_stricmp(p, PossibleTargetMachines[i]->Switch) ||
|
|
!_stricmp(p, PossibleTargetMachines[i]->Switch2)) {
|
|
AddTargetMachine(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i < MAX_TARGET_MACHINES) {
|
|
}
|
|
else
|
|
if (!_stricmp(p + 1, "all")) {
|
|
for (i = 0; i < MAX_TARGET_MACHINES; i++) {
|
|
AddTargetMachine(i);
|
|
}
|
|
}
|
|
else
|
|
if (!_stricmp(p + 1, "why")) {
|
|
fWhyBuild = TRUE;
|
|
}
|
|
else
|
|
while (c = *++p)
|
|
switch (toupper( c )) {
|
|
case '?':
|
|
fUsage = TRUE;
|
|
break;
|
|
|
|
case 'C':
|
|
if (!_stricmp(p, "clean")) {
|
|
MakeParametersTail = AppendString(MakeParametersTail, "clean", TRUE);
|
|
*p-- = '\0';
|
|
} else if (c == 'c') {
|
|
fClean = TRUE;
|
|
} else {
|
|
Result = FALSE;
|
|
}
|
|
break;
|
|
case 'E':
|
|
fErrorLog = TRUE;
|
|
break;
|
|
case 'F':
|
|
fForce = TRUE;
|
|
break;
|
|
case 'M':
|
|
if (c != 'M') { Result = FALSE; break; }
|
|
fParallel = TRUE;
|
|
if (argc > 1 && isdigit((unsigned char)(* (argv + 1))[0])) {
|
|
long n = strtol(*(argv + 1), NULL, 10);
|
|
if (n < 1 || n > 32) { Result = FALSE; break; }
|
|
DefaultProcesses = (ULONG)n;
|
|
--argc;
|
|
++argv;
|
|
}
|
|
break;
|
|
case 'N':
|
|
if (_stricmp(p, "nmake") == 0) {
|
|
if (argc > 1) {
|
|
--argc;
|
|
++argv;
|
|
MakeParametersTail = AppendString(MakeParametersTail, *argv, TRUE);
|
|
} else {
|
|
Result = FALSE;
|
|
}
|
|
*p-- = '\0';
|
|
} else {
|
|
Result = FALSE;
|
|
}
|
|
break;
|
|
case 'Q':
|
|
fQuery = TRUE;
|
|
break;
|
|
case 'W':
|
|
// -w is intercepted by the supervising watcher before main.
|
|
Result = FALSE;
|
|
break;
|
|
default:
|
|
BuildError("Invalid switch - /%c\n", c);
|
|
Result = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
if (*p == '~') {
|
|
if (CountExcludeDirs >= MAX_EXCLUDE_DIRECTORIES) {
|
|
static BOOL fError = FALSE;
|
|
|
|
if (!fError) {
|
|
BuildError(
|
|
"Exclude directory table overflow, using first %u entries\n",
|
|
MAX_EXCLUDE_DIRECTORIES);
|
|
fError = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
MakeString(
|
|
&ExcludeDirs[CountExcludeDirs++],
|
|
p + 1,
|
|
TRUE,
|
|
MT_CMDSTRING);
|
|
}
|
|
}
|
|
else {
|
|
for (i = 0; i < MAX_TARGET_MACHINES; i++) {
|
|
if (!_stricmp(p, PossibleTargetMachines[i]->MakeVariable)) {
|
|
AddTargetMachine(i);
|
|
break;
|
|
}
|
|
}
|
|
if (i >= MAX_TARGET_MACHINES) {
|
|
if (iscsym(*p) || *p == '.') {
|
|
if (CountOptionalDirs >= MAX_OPTIONAL_DIRECTORIES) {
|
|
static BOOL fError = FALSE;
|
|
|
|
if (!fError) {
|
|
BuildError(
|
|
"Optional directory table overflow, using first %u entries\n",
|
|
MAX_OPTIONAL_DIRECTORIES);
|
|
fError = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
MakeString(
|
|
&OptionalDirs[CountOptionalDirs++],
|
|
p,
|
|
TRUE,
|
|
MT_CMDSTRING);
|
|
}
|
|
}
|
|
else
|
|
if (!strcmp(p, "*")) {
|
|
BuildAllOptionalDirs = TRUE;
|
|
}
|
|
else {
|
|
MakeParametersTail = AppendString(
|
|
MakeParametersTail,
|
|
p,
|
|
TRUE);
|
|
}
|
|
}
|
|
}
|
|
--argc;
|
|
++argv;
|
|
}
|
|
return(Result);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: GetEnvParameters
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
GetEnvParameters(
|
|
LPSTR EnvVarName,
|
|
LPSTR DefaultValue,
|
|
int *pargc,
|
|
int maxArgc,
|
|
LPSTR argv[]
|
|
)
|
|
{
|
|
LPCSTR Value;
|
|
WCHAR *CommandLine;
|
|
LPWSTR *WideArgv;
|
|
int WideArgc;
|
|
int ValueChars;
|
|
int i;
|
|
static const WCHAR Prefix[] = L"build.exe ";
|
|
|
|
Value = getenv(EnvVarName);
|
|
if (!Value) {
|
|
if (DefaultValue == NULL) {
|
|
return;
|
|
}
|
|
Value = DefaultValue;
|
|
}
|
|
else if (DEBUG_1) {
|
|
BuildMsg("Using %s=%s\n", EnvVarName, Value);
|
|
}
|
|
|
|
ValueChars = MultiByteToWideChar(CP_ACP, 0, Value, -1, NULL, 0);
|
|
if (!ValueChars) {
|
|
BuildError("Unable to parse %s\n", EnvVarName);
|
|
exit(1);
|
|
}
|
|
|
|
CommandLine = (WCHAR *)malloc(sizeof(Prefix) +
|
|
(ValueChars * sizeof(WCHAR)));
|
|
if (!CommandLine) {
|
|
BuildError("Unable to allocate command line for %s\n", EnvVarName);
|
|
exit(1);
|
|
}
|
|
|
|
wcscpy(CommandLine, Prefix);
|
|
if (!MultiByteToWideChar(CP_ACP,
|
|
0,
|
|
Value,
|
|
-1,
|
|
CommandLine + ((sizeof(Prefix) / sizeof(Prefix[0])) - 1),
|
|
ValueChars)) {
|
|
free(CommandLine);
|
|
BuildError("Unable to convert %s\n", EnvVarName);
|
|
exit(1);
|
|
}
|
|
|
|
WideArgv = CommandLineToArgvW(CommandLine, &WideArgc);
|
|
free(CommandLine);
|
|
if (!WideArgv) {
|
|
BuildError("Unable to parse %s\n", EnvVarName);
|
|
exit(1);
|
|
}
|
|
|
|
for (i = 1; i < WideArgc; i++) {
|
|
LPSTR Argument;
|
|
int ArgumentBytes;
|
|
LPSTR q;
|
|
|
|
if (*pargc >= maxArgc) {
|
|
LocalFree(WideArgv);
|
|
BuildError("Too many parameters (> %d)\n", maxArgc);
|
|
exit(1);
|
|
}
|
|
|
|
ArgumentBytes = WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
WideArgv[i],
|
|
-1,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
if (!ArgumentBytes) {
|
|
LocalFree(WideArgv);
|
|
BuildError("Unable to convert a parameter from %s\n", EnvVarName);
|
|
exit(1);
|
|
}
|
|
|
|
Argument = (LPSTR)malloc(ArgumentBytes);
|
|
if (!Argument || !WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
WideArgv[i],
|
|
-1,
|
|
Argument,
|
|
ArgumentBytes,
|
|
NULL,
|
|
NULL)) {
|
|
if (Argument) {
|
|
free(Argument);
|
|
}
|
|
LocalFree(WideArgv);
|
|
BuildError("Unable to convert a parameter from %s\n", EnvVarName);
|
|
exit(1);
|
|
}
|
|
|
|
for (q = Argument; *q; q++) {
|
|
if (*q == '#') {
|
|
*q = '=';
|
|
}
|
|
}
|
|
|
|
MakeString(&argv[*pargc], Argument, FALSE, MT_CMDSTRING);
|
|
(*pargc)++;
|
|
free(Argument);
|
|
}
|
|
|
|
LocalFree(WideArgv);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: FreeEnvParameters
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
FreeEnvParameters(int argc, LPSTR argv[])
|
|
{
|
|
while (--argc >= 0) {
|
|
FreeMem(&argv[argc], MT_CMDSTRING);
|
|
}
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: FreeCmdStrings
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
FreeCmdStrings(VOID)
|
|
{
|
|
#if DBG
|
|
UINT i;
|
|
|
|
for (i = 0; i < CountExcludeIncs; i++) {
|
|
FreeMem(&ExcludeIncs[i], MT_CMDSTRING);
|
|
}
|
|
for (i = 0; i < CountOptionalDirs; i++) {
|
|
FreeMem(&OptionalDirs[i], MT_CMDSTRING);
|
|
}
|
|
for (i = 0; i < CountExcludeDirs; i++) {
|
|
FreeMem(&ExcludeDirs[i], MT_CMDSTRING);
|
|
}
|
|
// It's possible the user may have done:
|
|
// <global macro> = <null>
|
|
|
|
// in a sources file. Don't free mem unless it's still set...
|
|
|
|
if (pszSdkLibDest)
|
|
FreeMem(&pszSdkLibDest, MT_DIRSTRING);
|
|
if (pszDdkLibDest)
|
|
FreeMem(&pszDdkLibDest, MT_DIRSTRING);
|
|
if (pszPublicInternalPath)
|
|
FreeMem(&pszPublicInternalPath, MT_DIRSTRING);
|
|
if (pszIncOs2)
|
|
FreeMem(&pszIncOs2, MT_DIRSTRING);
|
|
if (pszIncPosix)
|
|
FreeMem(&pszIncPosix, MT_DIRSTRING);
|
|
if (pszIncChicago)
|
|
FreeMem(&pszIncChicago, MT_DIRSTRING);
|
|
if (pszIncMfc)
|
|
FreeMem(&pszIncMfc, MT_DIRSTRING);
|
|
if (pszIncSdk)
|
|
FreeMem(&pszIncSdk, MT_DIRSTRING);
|
|
if (pszIncCrt)
|
|
FreeMem(&pszIncCrt, MT_DIRSTRING);
|
|
if (pszIncOak)
|
|
FreeMem(&pszIncOak, MT_DIRSTRING);
|
|
if (pszIncDdk)
|
|
FreeMem(&pszIncDdk, MT_DIRSTRING);
|
|
if (pszIncWdm)
|
|
FreeMem(&pszIncWdm, MT_DIRSTRING);
|
|
if (pszIncPri)
|
|
FreeMem(&pszIncPri, MT_DIRSTRING);
|
|
#endif
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: MungePossibleTarget
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
MungePossibleTarget(
|
|
PTARGET_MACHINE_INFO pti
|
|
)
|
|
{
|
|
PCHAR s;
|
|
char *pszDir;
|
|
|
|
if (!pti) {
|
|
return;
|
|
}
|
|
|
|
// save "i386" string
|
|
|
|
pszDir = pti->ObjectDirectory[0];
|
|
|
|
// Create "$(_OBJ_DIR)\i386" string
|
|
|
|
s = malloc(12 + strlen(pszDir) + 1);
|
|
if (!s)
|
|
return;
|
|
sprintf(s, "$(_OBJ_DIR)\\%s", pszDir);
|
|
pti->ObjectMacro = s;
|
|
|
|
// Create "obj$(BUILD_ALT_DIR)\i386" string for default obj dir
|
|
|
|
s = malloc(strlen(szObjDir) + 1 + strlen(pszDir) + 1);
|
|
if (!s)
|
|
return;
|
|
sprintf(s, "%s\\%s", szObjDir, pszDir);
|
|
pti->ObjectDirectory[0] = s;
|
|
|
|
// Create "objd\i386" string for alternate checked obj dir
|
|
|
|
s = malloc(strlen(szObjDirD) + 1 + strlen(pszDir) + 1);
|
|
if (!s)
|
|
return;
|
|
sprintf(s, "%s\\%s", szObjDirD, pszDir);
|
|
pti->ObjectDirectory[1] = s;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: GetIncludePatterns
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
GetIncludePatterns(
|
|
LPSTR EnvVarName,
|
|
int maxArgc,
|
|
LPSTR argv[]
|
|
)
|
|
{
|
|
LPSTR p, p1, psz;
|
|
int argc;
|
|
|
|
argc = 0;
|
|
|
|
if ( ( p = getenv(EnvVarName ) ) == NULL ) {
|
|
return;
|
|
}
|
|
|
|
MakeString( &psz, p, FALSE, MT_DIRSTRING );
|
|
|
|
p1 = psz;
|
|
while ( *p1 ) {
|
|
while ( *p1 == ';' || *p1 == ' ' ) {
|
|
p1++;
|
|
}
|
|
p = p1;
|
|
while ( *p && *p != ';' ) {
|
|
p++;
|
|
}
|
|
if ( *p ) {
|
|
*p++ = '\0';
|
|
}
|
|
MakeString( &argv[argc], p1, FALSE, MT_DIRSTRING );
|
|
if ( ( argc += 1 ) == maxArgc ) {
|
|
BuildError( "Too many include patterns ( > %d)\n", maxArgc );
|
|
exit( 1 );
|
|
}
|
|
|
|
p1 = p;
|
|
}
|
|
|
|
FreeMem(&psz, MT_DIRSTRING);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: FreeIncludePatterns
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
FreeIncludePatterns(int argc, LPSTR argv[])
|
|
{
|
|
while ( argc ) {
|
|
if ( argv[--argc] ) {
|
|
FreeMem( &argv[argc], MT_DIRSTRING );
|
|
}
|
|
}
|
|
}
|