replace nob with ms' build, move disk creation to build.bat, major comment cleanup, remove old and stupid tests, overhaul interrupt management with per-CPU vector allocation, affinity migration and safe teardown, add proper IOAPIC routing and PCI MSI/MSI-X/INTx support, migrate drivers to the new interrupt API, integrate ACPICA with a proper OS services layer, move ACPI firmware events, power button handling and S5 shutdown into acpi.sys, add parallel driver startup and atomic publication, replace PnP arrays with dynamic lists, redesign service startup again to be asynchronous, add delayed startup mode for services, allow omitting keys in services.ini, fix acpi ec deferred work handling, fix kernel threads having garbage exit code.

This commit is contained in:
maksw committed 2026-10-28 15:18:43 +01:00
1 parent d36f19509c
commit 36eef8f58d
696 files changed
+147281 -7530

No files matched your search

+34
View File
@@ -0,0 +1,34 @@
@echo off
setlocal
cd /d "%~dp0"
if /i "%~1"=="clean" (
if exist out rmdir /s /q out
exit /b 0
)
where cl.exe >nul 2>nul || (
echo build.bat: run from a Visual Studio Developer Command Prompt.
exit /b 1
)
if not exist out\obj mkdir out\obj
del /q out\obj\*.obj out\build.exe >nul 2>nul
set "CFLAGS=/nologo /W3 /wd4101 /wd4267 /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS /DVER_PRODUCTBUILD=0 /I."
cl %CFLAGS% /TC /std:c17 /Foout\obj\ /c ^
build.c builddb.c buildexe.c buildmak.c buildscn.c ^
buildsrc.c buildutl.c buildinc.c buildglobals.c watch.c || exit /b 1
cl %CFLAGS% /TP /std:c++17 /Foout\obj\buildscr.obj /c buildscr.cpp || exit /b 1
link /nologo /out:out\build.exe ^
out\obj\build.obj out\obj\builddb.obj out\obj\buildexe.obj ^
out\obj\buildmak.obj out\obj\buildscn.obj out\obj\buildsrc.obj ^
out\obj\buildutl.obj out\obj\buildinc.obj out\obj\buildglobals.obj ^
out\obj\buildscr.obj out\obj\watch.obj ^
ole32.lib user32.lib uuid.lib oleaut32.lib shell32.lib || exit /b 1
echo Built %CD%\out\build.exe for %VSCMD_ARG_TGT_ARCH%
+1731
View File
File diff suppressed because it is too large. Load diff
+1094
View File
File diff suppressed because it is too large. Load diff
+331
View File
@@ -0,0 +1,331 @@
<HTML>
<BODY>
<A NAME=BASEDIR><H3>BASEDIR</H3></A>
The BASEDIR macro refers to the base of the source tree.
By default,
<PRE> BASEDIR=$(_NTDRIVE)$(_NTROOT)</PRE>
The following three statements are equivalent, but using the third one is recommended.
<PRE>
TARGETLIBS=d:\nt\public\sdk\lib\*\kernel32.lib
TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\kernel32.lib
TARGETLIBS=$(<A HREF=#SDK_LIB_PATH>SDK_LIB_PATH</A>)\kernel32.lib
</PRE>
sources
dirs
makefile
makefile.inc
makefile.def
makefile.plt
build.dat
objects.mac
<A NAME=BUILD_DEFAULT_TARGETS><H3>BUILD_DEFAULT_TARGETS</H3></A>
This envirnoment variable specifies the platform for which you are building. This variables allows the possibly of cross platform compilation, when such compilers are available.
Here is an exmaple of this environment variable:
<PRE> BUILD_DEFAULT_TARGETS=-axp64</PRE>
<A NAME=BUILD_DEFAULT><H3>BUILD_DEFAULT</H3></A>
This envirnoment variable specifies the default options used by build.exe
Here is an example of this environment variable:
<PRE> BUILD_DEFAULT=-eswM -nmake -i</PRE>
<A NAME=BUILD_MAKE_PROGRAM><H3>BUILD_MAKE_PROGRAM</H3></A>
This envirnoment variable specifies the default program make executed by build.exe to in order to compile a directory.
The default value of this environment variable should be nmake.exe.
<A NAME=BUILD_OTPIONS><H3>BUILD_OPTIONS</H3></A>
By default, build.exe will traverse the entire source tree, processing the directories listed in the DIRS section of the dirs file.
This envirnoment variable specifies which of the optional directories, listed under </A HREF=#OPTIONAL_DIRS>OPTIONAL_DIRS</A> should be processed by build.exe
Here are some examples of this environment variable:
<PRE> BUILD_OPTIONS=OptDir1 OptDir2</PRE>
would cause build to also process all OptDir1 and OptDir2 directories listed under an OPTIONAL_DIRS section.
<PRE> BUILD_OPTIONS=~OptDir1 OptDir2</PRE>
would cause build to all OptDir2 directories listed under an OPTIONAL_DIRS section, but force it to skip over all OptDir1 directories, whether listed in the DIRS or OPTIONAL_DIRS section of a dirs file.
<A NAME=CRT_INC_PATH><H3>CRT_INC_PATH</H3></A>
<P>This envirnoment variable specifies the location of the C Runtime header files. The default value of this macro is:</P>
<PRE> $(BASEDIR)\public\sdk\inc\crt</PRE>
<P>Set this macro in your environment variables if you wish to override the default location of the C Runtime header files.<BR>
This macro should no be redefined from within a sources file.</P>
<A NAME=CRT_LIB_PATH><H3>CRT_LIB_PATH</H3></A>
<P>This envirnoment variable specifies the location of the C Runtime libraries. The default value of this macro is:</P>
<PRE> $(BASEDIR)\public\sdk\lib\crt</PRE>
<P>Set this macro in your environment variables if you wish to override the default location of the C runtime libraries.<BR>
This macro should no be redefined from within a sources file.</P>
<P>Here is an example of the usage of this macro:</P>
<PRE> TARGETLIB=$(CRT_LIB_PATH)\libcntpr.lib \<BR> $(SDK_LIB_PATH)\advapi32.lib</PRE>
<A NAME=DDK_INC_PATH><H3>DDK_INC_PATH</H3></A>
<P>This macro specifies the location of the DDK header files. The default value of this macro is:</P>
<PRE> $(BASEDIR)\public\ddk\inc</PRE>
<P>Set this macro in your environment variables if you wish to override the default location of the DDK header files.<BR>
This macro should no be redefined from within a sources file.</P>
<A NAME=DDK_LIB_DEST><H3>DDK_LIB_DEST</H3></A>
<P>This macro specifies the destination location of a DDK library. The default value of this macro is:</P>
<PRE> $(BASEDIR)\public\ddk\lib\*</PRE>
<P>Set this macro in your environment variables if you wish to override the default location of the DDK libraries.<BR>
This macro should no be redefined from within a sources file.</P>
<P>Here is an example of the usage of this macro:</P>
<PRE> TARGETPATHLIB=$(DDK_LIB_DEST)\ndis.lib</PRE>
<A NAME=DDK_LIB_PATH><H3>DDK_LIB_PATH</H3></A>
<P>This macro specifies the location of the DDK libraries. The default value of this macro is:</P>
<PRE> $(BASEDIR)\public\ddk\lib</PRE>
<P>Set this macro in your environment variables if you wish to override the default location of the DDK libraries.<BR>
This macro should no be redefined from within a sources file.</P>
<P>Here is an example of the usage of this macro:</P>
<PRE> TARGETLIB=$(DDK_LIB_PATH)\ndis.lib \<BR> $(DDK_LIB_PATH)\tdikrnl.lib</PRE>
<A NAME=DDK_LIB_PATH><H3>DDK_LIB_PATH</H3></A>
<P>This macro specifies the location of the DDK libraries. The default value of this macro is:</P>
<PRE> $(BASEDIR)\public\ddk\lib</PRE>
<P>Set this macro in your environment variables if you wish to override the default location of the DDK libraries.<BR>
This macro should no be redefined from within a sources file.</P>
<P>Here is an example of the usage of this macro:</P>
<PRE> TARGETLIB=$(DDK_LIB_PATH)\ndis.lib \<BR> $(DDK_LIB_PATH)\tdikrnl.lib</PRE>
<A NAME=MASTER_VERSION_FILE><H3>MASTER_VERSION_FILE</H3></A>
This macro contains the name of the master version file for Windows 2000.
It contains, among other things, the default operating system version number
which all binaries should have defined in the resource section.
The default value of this variable is $(<A HREF=#SDK_INC_PATH>SDK_INC_PATH</A>)\ntverp.h
You should not override this value in your environment variables unless your component is not integrated in the Windows 2000 product (please contact BryanT for more information).
<A NAME=OAK_INC_PATH><H3>OAK_INC_PATH</H3></A>
<P>This macro specifies the location of the OAK header files. The default value of this macro is:</P>
<PRE> $(BASEDIR)\public\oak\inc</PRE>
<P>Set this macro in your environment variables if you wish to override the default location of the OAK header files.<BR>
This macro should no be redefined from within a sources file.</P>
<A NAME=PRIVATE_INC_PATH><H3>PRIVATE_INC_PATH</H3></A>
<P>This macro specifies the location of the private windows 2000 header files. The default value of this macro is:</P>
<PRE> $(BASEDIR)\private\inc</PRE>
<P>Set this macro in your environment variables if you wish to override the default location of the private windows 2000 header files.<BR>
This macro should no be redefined from within a sources file.</P>
<A NAME=SDK_LIB_DEST><H3>SDK_LIB_DEST</H3></A>
<P>This macro specifies the destination location of a SDK library. The default value of this macro is:</P>
<PRE> $(BASEDIR)\public\sdk\lib\*</PRE>
<P>Set this macro in your environment variables if you wish to override the default location of the SDK libraries.<BR>
This macro should no be redefined from within a sources file.</P>
<P>Here is an example of the usage of this macro:</P>
<PRE> TARGETPATHLIB=$(SDK_LIB_DEST)\kernel32.lib</PRE>
<A NAME=SDK_LIB_PATH><H3>SDK_LIB_PATH</H3></A>
<P>This macro specifies the location of the SDK libraries. The default value of this macro is:</P>
<PRE> $(BASEDIR)\public\sdk\lib</PRE>
<P>Set this macro in your environment variables if you wish to override the default location of the SDK libraries.<BR>
This macro should no be redefined from within a sources file.</P>
<P>Here is an example of the usage of this macro:</P>
<PRE> TARGETLIB=$(SDK_LIB_PATH)\kernel32.lib \<BR> $(SDK_LIB_PATH)\advapi32.lib</PRE>
<A NAME=WDM_INC_PATH><H3>WDM_INC_PATH</H3></A>
<P>This macro specifies the location of the WDM header file. The default value of this macro is:</P>
<PRE> $(BASEDIR)\public\ddk\inc\wdm</PRE>
<P>Set this macro in your environment variables if you wish to override the default location of the WDM header files.<BR>
This macro should no be redefined from within a sources file.</P>
<A NAME=C_DEFINES><H3>C_DEFINES - <SMALL>optional</SMALL></H3></A>
Use this macro to specify switches you want passed to the compiler.
Typically, they are compiler #defines.
You might specify:
<PRE> C_DEFINES = -DENABLE_FEATURE1</PRE>
to define ENABLE_FEATURE1 to the compiler.
C_DEFINES gets passed to both the C compiler and the MIDL compiler.
Therefore, you cannot put compiler optimization or other machine or
tool specific switches in the C_DEFINES macro.
Use <A HREF=#MSC_OPTIMIZATION>MSC_OPTIMIZATION</A> for C compiler only optimizations
See also <A HREF=#ASM_DEFINES>ASM_DEFINES</A>, <A HREF=#RC_DEFINES>RC_DEFINES</A>
<A NAME=DLLORDER><H3>DLLORDER - <SMALL>optional</SMALL></H3></A>
When you are building a DLL, you can specify an order file that will be passed
to the linker. This order file lists the order in which functions should be
layed out in the image.
This is the same as <A HREF=#NTPROFILEINPUT>NTPROFILEINPUT</A> except that
a full name for the profile can be specified.
<A NAME=EXEPROFILEINPUT><H3>EXEPROFILEINPUT - <SMALL>obsolete</SMALL></H3></A>
Use <A HREF=#NTPROFILEINPUT>NTPROFILEINPUT</A> instead.
<A NAME=INCLUDES><H3>INCLUDES - <SMALL>optional</SMALL></H3></A>
<P>Build.exe use a default list of public include directories from which to search for header files.
The default list of include directories is dependent on the value of <A HREF=#TARGETTYPE>TARGETTYPE</A> in the sources file.</P>
<P>Use the INCLUDES macro to indicate an additional list of private include directories to be searched for include files during compilation.
Separate the entries in this list with a semicolon.
Path names can be absolute or relative.</P>
For example:
<PRE>
INCLUDES=..\inc;..\..\inc
INCLUDES=$(INCLUDES); \
h; \
..\headers;
</PRE>
The INCLUDES macro is read by build.exe and passed to the MAKE program.
The list of directories in the INCULDES macro will have precedence over the default include directories.
<A NAME=MAJORCOMP><H3>MAJORCOMP - <SMALL>obsolete</SMALL></H3></A>
Please remove from your sources file
<A NAME=MINORCOMP><H3>MINORCOMP - <SMALL>obsolete</SMALL></H3></A>
Please remove from your sources file
<A NAME=NO_NTDLL><H3>NO_NTDLL - <SMALL>optional</SMALL></H3></A>
Set this macro to 0 to force your binary <I>not</I> to link against NTDLL.LIB.
<A NAME=NTPROFILEINPUT><H3>NTPROFILEINPUT - <SMALL>optional</SMALL></H3></A>
When you are building a DLL, you can specify an order file that will be passed
to the linker. This order file lists the order in which functions should be
layed out in the image.
To use the profile, specify the following in your sources file:
<PRE> NTPROFILEINPUT=1</PRE>
If you set this value, build.exe expect to find
<PRE> $(TARGETNAME).prf</PRE>
in the current subdirectory.
<P> See also <A HREF=#DLLORDER>DLLORDER</A></P>
<A NAME=PNP_POWER><H3>PNP_POWER - <SMALL>obsolete</SMALL></H3></A>
Please remove from your sources file
<A NAME=SOURCES><H3>SOURCES - <SMALL>required</SMALL></H3></A>
<P>The SOURCES macro is the most important macro in a sources file.
It specifies the list of files to be compiled.
Build.exe will look at these files and generate a dependency list.
For any source file whose dependencies changed, build.exe will rebuild
this file.</P>
<P>Use this macro to list your source filenames (except for the file containing
main in the case where <A HREF=#UMAPPL>UMAPPL</A> or <A HREF=#UMTEST>UMTEST</A>
is used. Include the filename extension and separate the entries in this list
with spaces or tabs.</P>
<P>Nested paths are relative to the current SOURCES directory. Prefix a path
with <CODE>@/</CODE> to resolve it under <CODE>BASEDIR</CODE>:</P>
<PRE> SOURCES=main.c nested/worker.c @/shared/alpha/core.c</PRE>
<P>Project source paths remain inside BASEDIR. Object names include a stable
path-derived suffix, allowing identical source basenames from different directories.
The project makefile defines CC, CXX, AS, RC, and their matching flags for
explicit source rules.</P>
<A NAME=TARGETEXT><H3>TARGETEXT - <SMALL>optional</SMALL></H3></A>
Set this macro to specify the extension name (such as .cpl) when you want your binary to have something other than the default extension generated by <A HREF=#TARGETTYPE>TARGETTYPE</A>.
If you specify something unexpected, you will see a message "Unexpected Target Ext." If you want an extension added to the Build Utility, contact Bryan Tuttle (bryant).
<A NAME=TARGETLIBS><H3>TARGETLIBS - <SMALL>required</SMALL></H3></A>
<P>Set this macro to specify the set of libraries with which your final image must be linked.</P>
If your components generates a library (.lib) and this library must link in code from other libraries, use the <A HREF=#LINKLIBS>LINKLIBS</A> macro.
Use LINKLIBS only for the case that meets the following conditions:
You are building a dynamic link.
You are exporting something that's defined in some other component library that you also build.
In your dirs file in the subdirectory above, you have ordered it so that the component libraries are around before you build the dynamic link.
There is a similar macro called UMLIBSUMLIBS that you can use if you are building UMAPPLs.
<A NAME=TARGETNAME><H3>TARGETNAME - <SMALL>required</SMALL></H3></A>
Use this macro to specify the name of the binary being built, excluding the filename extension.
You must have this macro in your sources file.
<A NAME=TARGETPATH><H3>TARGETPATH - <SMALL>required</SMALL></H3></A>
Use this macro to specify the target directory in which the resulting binary will be placed.
Notice that object files always end up in the obj subdirectory. Object file can only be generated in the <A HREF=#$(O)>$(O)</A> directory.
You must have this macro in your sources file. For example:
<PRE> TARGETPATH=obj</PRE>
See Also <A HREF=#TARGETPATHLIB>TARGETPATHLIB</A>
<A NAME=TARGETPATHLIB><H3>TARGETPATHLIB - <SMALL>optional</SMALL></H3></A>
Set this value to specify where to put the import library associated with this binary. <BR>
When you are building a DLL, you create the DLL itself and you create an import library that other images can use to reference functions exported by your DLL. <BR>
<PRE> TARGETPATHLIB=$(SDK_LIB_PATH)mydll.lib</PRE>
<P>Setting <A HREF=#TARGETPATH>TARGETPATH</A> independently from TARGETPATHLIB allows the binary to be kept in the
current directory, while the .lib and .exp files can be shared with other components. </P>
<A NAME=TARGETTYPE><H3>TARGETTYPE - <SMALL>required</SMALL></H3></A>
Use this macro to specify the type of binary being built. This is typically LIBRARY or
DYNLINK (for DLLs), but can take other values. This is a required field in the sources file.
TARGETTYPE allows build.exe to select appropriate defaults for include paths and link options.
You must have this macro in your sources file.
The valid values for TARGETYPE include:
<TABLE CELLPADDING=3 BORDER=3>
<TR VALIGN=TOP><TH> TARGETTYPE values </TH><TH> File Extension </TH><TH> Description </TH>
<TR VALIGN=TOP><TD><A NAME=PROGLIB>PROGLIB</A> </TD><TD> .exe </TD><TD> Executable program which also exports functions for other programs. </TD></TR>
<TR VALIGN=TOP><TD><A NAME=PROGRAM>PROGRAM</A> </TD><TD> .exe </TD><TD> Simple user mode program. </TD></TR>
<TR VALIGN=TOP><TD><A NAME=DYNLINK>DYNLINK</A> </TD><TD> .dll </TD><TD> Dynamic Link Library (dll). </TD></TR>
<TR VALIGN=TOP><TD><A NAME=LIBRARY>LIBRARY</A> </TD><TD> .lib </TD><TD> Component library whose code will be linked into another binary (such as a dll). </TD></TR>
<TR VALIGN=TOP><TD><A NAME=DRIVER_LIBRARY>DRIVER_LIBRARY</A> </TD><TD> .lib </TD><TD> Component library for a driver. The only difference with the LIBRARY type is that the default header file include path is different. </TD></TR>
<TR VALIGN=TOP><TD><A NAME=DRIVER>DRIVER</A> </TD><TD> .sys </TD><TD> Kernel mode driver.
<TR VALIGN=TOP><TD><A NAME=EXPORT_DRIVER>EXPORT_DRIVER</A> </TD><TD> .sys </TD><TD> Kernel mode driver which also exports routines other drivers can link against and call. </TD></TR>
<TR VALIGN=TOP><TD><A NAME=HAL>HAL</A> </TD><TD> .dll </TD><TD> Hardware Abstraction Layer (HAL) </TD></TR>
<TR VALIGN=TOP><TD><A NAME=BOOTPGM>BOOTPGM</A> </TD><TD> .exe </TD><TD> Kernel mode driver. </TD></TR>
<TR VALIGN=TOP><TD><A NAME=MINIPORT>MINIPORT</A> </TD><TD> .sys </TD><TD> Kernel mode driver which does not link against ntoskrnl.lib or hal.lib. </TD></TR>
<TR VALIGN=TOP><TD><A NAME=GDI_DRIVER>GDI_DRIVER</A> </TD><TD> .dll </TD><TD> Kernel mode driver which only links against win32k.sys (Display or print driver). </TD></TR>
</TABLE>
<A NAME=UMAPPL><H3>UMAPPL</H3></A>
<A NAME=UMAPPLEXT><H3>UMAPPLEXT</H3></A>
Use this macro to specify the extension name (for example .COM or .SCR) that
will be appended to the name specified in <A HREF=#UMAPPL>UMAPPL</A>.
Use UMAPPLEXT when you want the extension to be something other than .exe.
Contact Bryan Tuttle if you need to add a new type of extension.
<A NAME=UMLIBS><H3>UMLIBS</H3></A>
<A NAME=UMTEST><H3>UMTEST</H3></A>
<H2>Sample Driver Sources File</H2>
<PRE>
<A HREF=#TARGETNAME>TARGETNAME</A>=sample
<A HREF=#TARGETPATH>TARGETPATH</A>=obj
<A HREF=#TARGETTYPE>TARGETTYPE</A>=<A HREF=#DRIVER>DRIVER</A>
<A HREF=#TARGETLIBS>TARGETLIBS</A>=$(<A HREF=#DDK_LIB_PATH>DDK_LIB_PATH</A>)\videoprt.lib
<A HREF=#SOURCES>SOURCES</A>=file1.c \<BR> file2.c \<BR> file3.c
</PRE>
</BODY></HTML>
+2081
View File
File diff suppressed because it is too large. Load diff
+3143
View File
File diff suppressed because it is too large. Load diff
+122
View File
@@ -0,0 +1,122 @@
// Standalone definitions for globals that were historically emitted as
// tentative definitions by every translation unit through build.h.
#include "build.h"
BOOL fDebug;
BOOL fUsage;
BOOL fStatus;
BOOL fStatusTree;
BOOL fShowTree;
BOOL fShowTreeIncludes;
BOOL fClean;
BOOL fCleanLibs;
BOOL fCleanRestart;
BOOL fRestartClean;
BOOL fRestartCleanLibs;
BOOL fPause;
BOOL fParallel;
BOOL fPrintElapsed;
BOOL fQuery;
BOOL fStopAfterPassZero;
BOOL fQuicky;
BOOL fQuickZero;
BOOL fSemiQuicky;
BOOL fShowOutOfDateFiles;
BOOL fSyncLink;
BOOL fForce;
BOOL fEnableVersionCheck;
BOOL fSilent;
BOOL fKeep;
BOOL fCompileOnly;
BOOL fLinkOnly;
BOOL fErrorLog;
BOOL fGenerateObjectsDotMacOnly;
BOOL fShowWarningsOnScreen;
BOOL fNoisyScan;
BOOL fFullErrors;
BOOL fWhyBuild;
BOOL fChicagoProduct;
BOOL fPassZero;
BOOL fFirstScan;
BOOL fAlwaysPrintFullPath;
BOOL fTargetDirs;
BOOL fAlwaysKeepLogfile;
BOOL fShowUnusedDirs;
BOOL fCheckIncludePaths;
BOOL fNoThreadIndex;
BOOL fMTScriptSync;
LPSTR AcceptableIncludePatternList[MAX_INCLUDE_PATTERNS + 1];
LPSTR UnacceptableIncludePatternList[MAX_INCLUDE_PATTERNS + 1];
LPSTR MakeProgram;
char MakeParameters[512];
LPSTR MakeParametersTail;
char MakeTargets[256];
char RestartDir[256];
char NtRoot[256];
char DbMasterName[256];
char *pszPublicInternalPath;
char *pszIncPri;
CRITICAL_SECTION TTYCriticalSection;
CHAR const *cmdexe;
LONG TotalFilesToCompile;
LONG TotalFilesCompiled;
LONG TotalLinesToCompile;
LONG TotalLinesCompiled;
ULONG ElapsedCompileTime;
DIRREC *CurrentCompileDirDB;
UINT CountTargetMachines;
TARGET_MACHINE_INFO *TargetMachines[MAX_TARGET_MACHINES];
UINT TargetToPossibleTarget[MAX_TARGET_MACHINES];
UINT CountOptionalDirs;
LPSTR OptionalDirs[MAX_OPTIONAL_DIRECTORIES];
BOOLEAN OptionalDirsUsed[MAX_OPTIONAL_DIRECTORIES];
BOOL BuildAllOptionalDirs;
UINT CountExcludeDirs;
LPSTR ExcludeDirs[MAX_EXCLUDE_DIRECTORIES];
BOOLEAN ExcludeDirsUsed[MAX_OPTIONAL_DIRECTORIES];
UINT CountExcludeIncs;
LPSTR ExcludeIncs[MAX_EXCLUDE_INCS];
UINT CountIncludeDirs;
UINT CountSystemIncludeDirs;
DIRREC *IncludeDirs[MAX_INCLUDE_DIRECTORIES];
UINT CountPassZeroDirs;
DIRREC *PassZeroDirs[MAX_BUILD_DIRECTORIES];
UINT CountCompileDirs;
DIRREC *CompileDirs[MAX_BUILD_DIRECTORIES];
UINT CountLinkDirs;
DIRREC *LinkDirs[MAX_BUILD_DIRECTORIES];
UINT CountShowDirs;
DIRREC *ShowDirs[MAX_BUILD_DIRECTORIES];
DIRREC *AllDirs;
CHAR CurrentDirectory[DB_MAX_PATH_LENGTH];
BOOL AllDirsInitialized;
BOOL AllDirsModified;
LPSTR BuildDefault;
LPSTR BuildParameters;
LPSTR SystemIncludeEnv;
LPSTR LocalIncludeEnv;
LPSTR BigBuf;
UINT BigBufSize;
UINT RecurseLevel;
FILE *LogFile;
FILE *WrnFile;
FILE *ErrFile;
FILE *IPGScriptFile;
FILE *IncFile;
ULONG BuildStartTime;
+540
View File
@@ -0,0 +1,540 @@
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1989 - 1994.
//
// File: buildinc.c
//
// Contents: This is the checking include module for the NT Build Tool (BUILD.EXE)
//
// Used for detecting the includes that do not satisfy the acceptable
// patterns.
//
// History: see SLM
//----------------------------------------------------------------------------
#include "build.h"
//+---------------------------------------------------------------------------
//
// Function: FoundCountedSequenceInString
//
// Synopsis: Roughly equivalent to "strstr" except that the substring doesn't
// have to be NULL-terminated.
//
// Arguments: [String] -- null-terminated string to search
// [Sequence] -- string to search for
// [Length] -- the length of the sequence
//----------------------------------------------------------------------------
LPCTSTR
FindCountedSequenceInString(
IN LPCTSTR String,
IN LPCTSTR Sequence,
IN DWORD Length
)
{
assert( Sequence );
assert( String );
if ( Length > 0 ) {
while ( *String ) {
while (( *String ) && ( *String != *Sequence )) {
String++;
}
if ( *String ) {
LPCTSTR SubString = String + 1;
LPCTSTR SubSequence = Sequence + 1;
DWORD Remaining = Length - 1;
while (( Remaining ) && ( *SubString++ == *SubSequence++ )) {
Remaining--;
}
if ( Remaining == 0 ) {
return String;
}
String++;
}
}
return NULL;
}
return String;
}
//+---------------------------------------------------------------------------
//
// Function: DoesInstanceMatchPattern
//
// Synopsis: Returns TRUE if pattern matches instance.
// Wildcards:
// * matches any text
// ? matches any and exactly one character
// # matches any text up to backslash character or end of string
//
// Arguments: [Instance] -- the string to be matched
// [Pattern] -- the pattern
//----------------------------------------------------------------------------
BOOL
DoesInstanceMatchPattern(
IN LPCTSTR Instance,
IN LPCTSTR Pattern
)
{
assert( Instance );
assert( Pattern );
while ( *Pattern ) {
if ( *Pattern == TEXT('*')) {
Pattern++;
while ( *Pattern == TEXT('*')) { // skip multiple '*' characters
Pattern++;
}
if ( *Pattern == 0 ) { // '*' at end of pattern matches rest
return TRUE;
}
if ( *Pattern == '?' ) { // '?' following '*'
//
// Expensive because we have to restart match for every
// character position remaining since '?' can match anything.
//
while ( *Instance ) {
if ( DoesInstanceMatchPattern( Instance, Pattern )) {
return TRUE;
}
Instance++;
}
return FALSE;
}
else {
//
// Now we know that next character in pattern is a regular
// character to be matched. Find out the length of that
// string to the next wildcard or end of string.
//
LPCTSTR NextWildCard = Pattern + 1;
DWORD MatchLength;
while (( *NextWildCard ) && ( *NextWildCard != TEXT('*')) && ( *NextWildCard != TEXT('?')) && ( *NextWildCard != TEXT('#'))) {
NextWildCard++;
}
MatchLength = (DWORD)(NextWildCard - Pattern); // always non-zero
//
// Now try to match with any instance of substring in pattern
// found in the instance.
//
Instance = FindCountedSequenceInString( Instance, Pattern, MatchLength );
while ( Instance ) {
if ( DoesInstanceMatchPattern( Instance + MatchLength, NextWildCard )) {
return TRUE;
}
Instance = FindCountedSequenceInString( Instance + 1, Pattern, MatchLength );
}
return FALSE;
}
}
else if ( *Pattern == TEXT('#')) {
//
// Match text up to backslash character or end of string
//
Pattern++;
while (( *Instance != 0 ) && ( *Instance != '\\' )) {
Instance++;
}
continue;
}
else if ( *Pattern == TEXT('?')) {
if ( *Instance == 0 ) {
return FALSE;
}
}
else if ( *Pattern != *Instance ) {
return FALSE;
}
Pattern++;
Instance++;
}
return ( *Instance == 0 );
}
//+---------------------------------------------------------------------------
//
// Function: CombinePaths
//
// Synopsis: Combine two strings to get a full path.
//
// Arguments: [ParentPath] -- head path
// [ChildPath] -- path to be added
// [TargetPath] -- full path
//----------------------------------------------------------------------------
LPSTR
CombinePaths(
IN LPCSTR ParentPath,
IN LPCSTR ChildPath,
OUT LPSTR TargetPath // can be same as ParentPath if want to append
)
{
ULONG ParentLength = strlen( ParentPath );
LPSTR p;
assert( ParentPath );
assert( ChildPath );
if ( ParentPath != TargetPath ) {
memcpy( TargetPath, ParentPath, ParentLength );
}
p = TargetPath + ParentLength;
if (( ParentLength > 0 ) &&
( *( p - 1 ) != '\\' ) &&
( *( p - 1 ) != '/' )) {
*p++ = '\\';
}
strcpy( p, ChildPath );
return TargetPath;
}
//+---------------------------------------------------------------------------
//
// Function: CreateRelativePath
//
// Synopsis: Determine the "canonical" path of one file relative to
// another file
//
// Arguments: [SourceAbsName] -- absolute path of the source file
// [TargetAbsName] -- absolute path of the target file
// [RelativePath] -- resulted relative path
//----------------------------------------------------------------------------
VOID
CreateRelativePath(
IN LPCSTR SourceAbsName, // must be lowercase
IN LPCSTR TargetAbsName, // must be lowercase
OUT LPSTR RelativePath // must be large enough
)
{
//
// First, walk through path components that match in Source and Target.
// For example:
//
// d:\nt\private\ntos\dd\efs.h
// d:\nt\private\windows\base\ntcrypto\des.h
// ^
// This is where the relative path stops going up (..)
// and starts going back down.
//
// So, the "cannonical" relative path generated should look like:
//
// ..\..\..\windows\base\ntcrypto\des.h
//
// For relative includes that are "below" the includer in the path should
// look like this:
//
// .\foo\bar\foobar.h
//
LPCSTR Source = SourceAbsName;
LPCSTR Target = TargetAbsName;
LPSTR Output = RelativePath;
ULONG PathSeparatorIndex;
BOOL AnyParent;
ULONG i;
assert( SourceAbsName );
assert( TargetAbsName );
PathSeparatorIndex = 0;
i = 0;
//
// Scan forward to first non-matching character, and keep track of
// most recent path separator character.
//
while (( Source[ i ] == Target[ i ] ) && ( Source[ i ] != 0 )) {
if ( Source[ i ] == '\\' ) {
PathSeparatorIndex = i;
}
++i;
}
//
// Coming out of this loop, there are 2 possibilities:
//
// 1) Found common ancestor path ( *PathSeparatorIndex == '\\' )
// 2) Don't have common ancestor ( *PathSeparatorIndex != '\\' )
//
if ( Source[ PathSeparatorIndex ] != '\\' ) {
strcpy( RelativePath, TargetAbsName );
return;
}
i = PathSeparatorIndex + 1;
//
// Now continue to walk down source path and insert a "..\" in the result
// for each path separator encountered.
//
AnyParent = FALSE;
while ( Source[ i ] != 0 ) {
if ( Source[ i ] == '\\' ) {
AnyParent = TRUE;
*Output++ = '.';
*Output++ = '.';
*Output++ = '\\';
}
++i;
}
if ( ! AnyParent ) {
//
// Relative path is below current directory.
//
*Output++ = '.';
*Output++ = '\\';
}
//
// Now we simply append what's remaining of the Target path from the
// ancestor match point.
//
strcpy( Output, Target + PathSeparatorIndex + 1 );
}
//+---------------------------------------------------------------------------
//
// Function: ShouldWarnInclude
//
// Synopsis: Returns true if the name of the included file matches a
// BUILD_UNACCEPTABLE_INCLUDES pattern or it does not match
// any of the patterns specified in BUILD_ACCEPTABLE_INCLUDES.
//
// Arguments: [CompilandFullName] -- name of the including file
// [IncludeeFullName] -- name of the included file
//----------------------------------------------------------------------------
BOOL
ShouldWarnInclude(
IN LPCSTR CompilandFullName,
IN LPCSTR IncludeeFullName
)
{
UINT i;
CHAR IncludeeRelativeName[ MAX_PATH ];
assert( CompilandFullName );
assert( IncludeeFullName );
CreateRelativePath( CompilandFullName, IncludeeFullName, IncludeeRelativeName );
//
// First we check for a match against any unacceptable include path
// because we always want to warn about these.
//
for ( i = 0; UnacceptableIncludePatternList[ i ] != NULL; i++ ) {
if ( DoesInstanceMatchPattern( IncludeeFullName, UnacceptableIncludePatternList[ i ] )) {
return TRUE;
}
if ( DoesInstanceMatchPattern( IncludeeRelativeName, UnacceptableIncludePatternList[ i ] )) {
return TRUE;
}
}
//
// If we get to here, the include path was not explicitly unacceptable, so
// we now want to see if it matches any acceptable paths. But, if no
// acceptable paths are specified, we don't want to warn.
//
if ( AcceptableIncludePatternList[ 0 ] == NULL ) {
return FALSE;
}
for ( i = 0; AcceptableIncludePatternList[ i ] != NULL; i++ ) {
if ( DoesInstanceMatchPattern( IncludeeFullName, AcceptableIncludePatternList[ i ] )) {
return FALSE;
}
if ( DoesInstanceMatchPattern( IncludeeRelativeName, AcceptableIncludePatternList[ i ] )) {
return FALSE;
}
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function: CheckIncludeForWarning
//
// Synopsis: Warnings if the dependency does not respect the
// BUILD_UNACCEPTABLE_INCLUDES or BUILD_ACCEPTABLE_INCLUDES
// restristions. Works with build -#.
//
// Arguments: [CompilandDir]
// [CompilandName]
// [IncluderDir]
// [IncluderName]
// [IncludeeDir]
// [IncludeeName]
//----------------------------------------------------------------------------
VOID
CheckIncludeForWarning(
IN LPCSTR CompilandDir,
IN LPCSTR CompilandName,
IN LPCSTR IncluderDir,
IN LPCSTR IncluderName,
IN LPCSTR IncludeeDir,
IN LPCSTR IncludeeName
)
{
CHAR CompilandFullName[ MAX_PATH ];
CHAR IncluderFullName[ MAX_PATH ];
CHAR IncludeeFullName[ MAX_PATH ];
assert( CompilandDir );
assert( CompilandName );
assert( IncluderDir );
assert( IncluderName );
assert( IncludeeDir );
assert( IncludeeName );
CombinePaths( CompilandDir, CompilandName, CompilandFullName );
CombinePaths( IncluderDir, IncluderName, IncluderFullName );
CombinePaths( IncludeeDir, IncludeeName, IncludeeFullName );
_strlwr( CompilandFullName );
_strlwr( IncluderFullName );
_strlwr( IncludeeFullName );
if ( IncFile ) {
fprintf(
IncFile,
"%s includes %s\r\n",
IncluderFullName,
IncludeeFullName
);
}
if ( ShouldWarnInclude( CompilandFullName, IncludeeFullName )) {
if ( strcmp( IncluderFullName, CompilandFullName ) == 0 ) {
if ( WrnFile ) {
fprintf(
WrnFile,
"WARNING: %s includes %s\n",
CompilandFullName,
IncludeeFullName
);
}
if ( fShowWarningsOnScreen ) {
BuildMsgRaw(
"WARNING: %s includes %s\n",
CompilandFullName,
IncludeeFullName
);
}
}
else {
if ( WrnFile ) {
fprintf(
WrnFile,
"WARNING: %s includes %s through %s\n",
CompilandFullName,
IncludeeFullName,
IncluderFullName
);
}
if ( fShowWarningsOnScreen ) {
BuildMsgRaw(
"WARNING: %s includes %s through %s\n",
CompilandFullName,
IncludeeFullName,
IncluderFullName
);
}
}
}
}
+3485
View File
File diff suppressed because it is too large. Load diff
+844
View File
@@ -0,0 +1,844 @@
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1989 - 1994
//
// File: buildscn.c
//
// Contents: Directory and File scanning functions for Build.exe
//
//
// History: 16-May-89 SteveWo Created
// ... see SLM logs
// 26-Jul-94 LyleC Cleanup/Add pass0 support
//
//----------------------------------------------------------------------------
#include "build.h"
//+---------------------------------------------------------------------------
//
// Function: AddShowDir
//
// Synopsis: Add a directory to the ShowDir array
//
//----------------------------------------------------------------------------
VOID
AddShowDir(DIRREC *pdr)
{
AssertDir(pdr);
if (CountShowDirs >= MAX_BUILD_DIRECTORIES) {
static BOOL fError = FALSE;
if (!fError) {
BuildError(
"Show Directory table overflow, using first %u entries\n",
MAX_BUILD_DIRECTORIES);
fError = TRUE;
}
}
else {
ShowDirs[CountShowDirs++] = pdr;
}
pdr->DirFlags |= DIRDB_SHOWN;
}
//+---------------------------------------------------------------------------
//
// Function: AddIncludeDir
//
// Synopsis: Add a directory to the IncludeDirs array
//
//----------------------------------------------------------------------------
VOID
AddIncludeDir(DIRREC *pdr, UINT *pui)
{
AssertDir(pdr);
assert(pdr->FindCount >= 1);
assert(*pui <= MAX_INCLUDE_DIRECTORIES);
if (*pui >= MAX_INCLUDE_DIRECTORIES) {
BuildError(
"Include Directory table overflow, %u entries allowed\n",
MAX_INCLUDE_DIRECTORIES);
exit(16);
}
IncludeDirs[(*pui)++] = pdr;
}
//+---------------------------------------------------------------------------
//
// Function: ScanGlobalIncludeDirectory
//
// Synopsis: Scans a global include directory and adds it to the
// IncludeDir array.
//
//----------------------------------------------------------------------------
VOID
ScanGlobalIncludeDirectory(LPSTR path)
{
DIRREC *pdr;
char FullPath[DB_MAX_PATH_LENGTH];
// Mark a compiler/system include directory before scanning it. In
// particular, modern MSVC's ATLMFC include path contains UTF-16 .rc
// resources which our byte-oriented include scanner cannot parse.
if (!CanonicalizePathName(path, CANONICALIZE_DIR, FullPath)) {
return;
}
pdr = LoadDirDB(FullPath);
if (pdr == NULL) {
return;
}
pdr->DirFlags |= DIRDB_GLOBAL_INCLUDES;
if (ScanDirectory(FullPath) != NULL) {
AddIncludeDir(pdr, &CountIncludeDirs);
if (fShowTreeIncludes && !(pdr->DirFlags & DIRDB_SHOWN)) {
AddShowDir(pdr);
}
}
}
//+---------------------------------------------------------------------------
//
// Function: ScanIncludeEnv
//
// Synopsis: Scans all include directories specified in the INCLUDE
// environment variable.
//
// Arguments: [IncludeEnv] -- value of the INCLUDE environment variable.
//
// Notes: The INCLUDE variable is a string with a list of directories
// separated by semicolons (;).
//
//----------------------------------------------------------------------------
VOID
ScanIncludeEnv(
LPSTR IncludeEnv
)
{
char path[DB_MAX_PATH_LENGTH] = {0};
LPSTR IncDir, IncDirEnd;
UINT cb;
if (!IncludeEnv) {
return;
}
if (DEBUG_1) {
BuildMsgRaw("ScanIncludeEnv(%s)\n", IncludeEnv);
}
IncDir = IncludeEnv;
while (*IncDir) {
IncDir++;
}
while (IncDir > IncludeEnv) {
IncDirEnd = IncDir;
while (IncDir > IncludeEnv) {
if (*--IncDir == ';') {
break;
}
}
if (*IncDir == ';') {
if (cb = (UINT)(IncDirEnd-IncDir-1)) {
strncpy( path, IncDir+1, cb );
}
} else {
if (cb = (UINT)(IncDirEnd-IncDir)) {
strncpy( path, IncDir, cb );
}
}
if (cb) {
path[ cb ] = '\0';
while (path[ 0 ] == ' ') {
strcpy( path, &path[ 1 ] );
cb--;
}
while (cb && path[--cb] == ' ') {
path[ cb ] = '\0';
}
if (path[0]) {
ScanGlobalIncludeDirectory(path);
}
}
}
}
//+---------------------------------------------------------------------------
//
// Function: ScanSubDir
//
// Synopsis: Scans all the files in the given directory, sets the
// directory flags appropriately (e.g. DIRDB_SOURCES, etc),
// and adds a list of interesting files to the Files list in
// the DirDB structure for the directory.
//
// Arguments: [pszDir] -- Name of directory to scan
// [pdr] -- [out] Filled in DIRREC on return
//
// Notes: An 'interesting' file is one which has a recognized
// extension. See the InsertFileDB and MatchFileDesc
// functions for more info.
//
//----------------------------------------------------------------------------
VOID
ScanSubDir(LPSTR pszDir, DIRREC *pdr)
{
char FileName[DB_MAX_PATH_LENGTH];
FILEREC *FileDB, **FileDBNext;
WIN32_FIND_DATA FindFileData;
HDIR FindHandle;
ULONG DateTime;
USHORT Attr;
strcat(pszDir, "\\");
strcat(pszDir, "*.*");
pdr->DirFlags |= DIRDB_SCANNED;
FindHandle = FindFirstFile(pszDir, &FindFileData);
if (FindHandle == (HDIR)INVALID_HANDLE_VALUE) {
if (DEBUG_1) {
BuildMsg("FindFirstFile(%s) failed.\n", pszDir);
}
return;
}
do {
Attr = (USHORT)(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
if ((Attr & FILE_ATTRIBUTE_DIRECTORY) &&
(!strcmp(FindFileData.cFileName, ".") ||
!strcmp(FindFileData.cFileName, ".."))) {
continue;
}
CopyString(FileName, FindFileData.cFileName, TRUE);
FileTimeToDosDateTime(&FindFileData.ftLastWriteTime,
((LPWORD) &DateTime) + 1,
(LPWORD) &DateTime);
if ((pdr->DirFlags & DIRDB_NEW) == 0 &&
(FileDB = LookupFileDB(pdr, FileName)) != NULL) {
if (FileDB->FileFlags & FILEDB_PASS0)
pdr->DirFlags |= DIRDB_PASS0;
//
// Clear the file missing flag, since we know the file exists now.
// This flag may be set if the file was generated during pass zero.
//
if (FileDB->FileFlags & FILEDB_FILE_MISSING)
FileDB->FileFlags &= ~FILEDB_FILE_MISSING;
//
// The time we last stored for this file is different than the
// actual time on the file, so force it to be rescanned.
//
if (FileDB->DateTime != DateTime) {
if (FileDB->FileFlags & (FILEDB_SOURCE | FILEDB_HEADER)) {
FileDB->FileFlags &= ~FILEDB_SCANNED;
}
else {
FileDB->FileFlags |= FILEDB_SCANNED;
}
if (DEBUG_1) {
BuildMsg(
"%s - DateTime (%lx != %lx)\n",
FileDB->Name,
FileDB->DateTime,
DateTime);
}
FileDB->DateTime = DateTime;
FileDB->Attr = Attr;
}
else {
FileDB->FileFlags |= FILEDB_SCANNED;
}
}
else {
FileDB = InsertFileDB(pdr, FileName, DateTime, Attr, 0);
}
} while (FindNextFile(FindHandle, &FindFileData));
FindClose(FindHandle);
if ((pdr->DirFlags & DIRDB_DIRS) && (pdr->DirFlags & DIRDB_SOURCES))
{
BuildError("%s\\sources. unexpected in directory with DIRS file\n",
pdr->Name);
BuildError("Ignoring %s\\sources.\n", pdr->Name);
pdr->DirFlags &= ~DIRDB_SOURCES;
}
//
// Scan each file in this directory unless using QuickZero
//
if (fQuickZero && fFirstScan)
{
return;
}
FileDBNext = &pdr->Files;
while (FileDB = *FileDBNext) {
if (!(FileDB->FileFlags & (FILEDB_DIR | FILEDB_SCANNED))) {
if ((pdr->DirFlags & DIRDB_GLOBAL_INCLUDES) &&
(FileDB->FileFlags & FILEDB_RC)) {
// System resource scripts are irrelevant to C/C++ header
// discovery. Some MSVC ATLMFC .rc files are UTF-16 and
// would otherwise produce bogus "null byte" diagnostics.
// Keep local project .rc files on the normal scanner path.
FileDB->FileFlags |= FILEDB_SCANNED;
}
else if (ScanFile(FileDB)) {
AllDirsModified = TRUE;
}
}
FileDBNext = &FileDB->Next;
}
DeleteUnscannedFiles(pdr);
}
//+---------------------------------------------------------------------------
//
// Function: ScanDirectory
//
// Synopsis: Tries to find the given directory in the database, and if
// not found calls ScanSubDir.
//
// Arguments: [pszDir] -- Directory to scan
//
// Returns: Filled in DIRREC structure for the directory.
//
// Notes: If fQuicky (-z or -Z options) are set, then instead of calling
// ScanSubDir, which is long, it just checks for known files, like
// 'sources' for 'makefile' to determine whether or not the
// directory should be compiled.
//
//----------------------------------------------------------------------------
PDIRREC
ScanDirectory(LPSTR pszDir)
{
DIRREC *pdr;
char FullPath[DB_MAX_PATH_LENGTH];
if (DEBUG_1) {
BuildMsgRaw("ScanDirectory(%s)\n", pszDir);
}
if (!CanonicalizePathName(pszDir, CANONICALIZE_DIR, FullPath)) {
if (DEBUG_1) {
BuildMsgRaw("CanonicalizePathName failed\n");
}
return(NULL);
}
pszDir = FullPath;
if ((pdr = LoadDirDB(pszDir)) == NULL) {
return(NULL);
}
if (fQuicky && (!fQuickZero)) {
if (!(pdr->DirFlags & DIRDB_SCANNED)) {
pdr->DirFlags |= DIRDB_SCANNED;
if (ProbeFile(pdr->Name, "sources") != -1) {
pdr->DirFlags |= DIRDB_SOURCES | DIRDB_MAKEFILE;
}
else
if (ProbeFile(pdr->Name, "mydirs") != -1 ||
ProbeFile(pdr->Name, "dirs") != -1 ||
ProbeFile(pdr->Name, pszTargetDirs) != -1) {
pdr->DirFlags |= DIRDB_DIRS;
if (ProbeFile(pdr->Name, "makefil0") != -1) {
pdr->DirFlags |= DIRDB_MAKEFIL0;
}
if (ProbeFile(pdr->Name, "makefil1") != -1) {
pdr->DirFlags |= DIRDB_MAKEFIL1;
}
if (ProbeFile(pdr->Name, "makefile") != -1) {
pdr->DirFlags |= DIRDB_MAKEFILE;
}
}
}
return(pdr);
}
if (pdr->DirFlags & DIRDB_SCANNED) {
return(pdr);
}
if (!RecurseLevel && fNoisyScan) {
ClearLine();
BuildMsgRaw(" Scanning %s ", pszDir);
if (fDebug || !(BOOL) _isatty(_fileno(stderr))) {
BuildMsgRaw(szNewLine);
}
}
ScanSubDir(pszDir, pdr);
if (!RecurseLevel) {
ClearLine();
}
return(pdr);
}
#define BUILD_TLIB_INCLUDE_STMT "importlib"
#define BUILD_TLIB_INCLUDE_STMT_LENGTH (sizeof( BUILD_TLIB_INCLUDE_STMT )-1)
#define BUILD_MIDL_INCLUDE_STMT "import"
#define BUILD_MIDL_INCLUDE_STMT_LENGTH (sizeof( BUILD_MIDL_INCLUDE_STMT )-1)
#define BUILD_RC_INCLUDE_STMT "rcinclude"
#define BUILD_RC_INCLUDE_STMT_LENGTH (sizeof( BUILD_RC_INCLUDE_STMT )-1)
#define BUILD_ASN_INCLUDE_STMT "--<"
#define BUILD_ASN_INCLUDE_STMT_LENGTH (sizeof( BUILD_ASN_INCLUDE_STMT )-1)
#define BUILD_INCLUDE_STMT "include"
#define BUILD_INCLUDE_STMT_LENGTH (sizeof( BUILD_INCLUDE_STMT )-1)
#define BUILD_VER_COMMENT "/*++ BUILD Version: "
#define BUILD_VER_COMMENT_LENGTH (sizeof( BUILD_VER_COMMENT )-1)
#define BUILD_MASM_VER_COMMENT ";;;; BUILD Version: "
#define BUILD_MASM_VER_COMMENT_LENGTH (sizeof( BUILD_MASM_VER_COMMENT )-1)
//+---------------------------------------------------------------------------
//
// Function: IsIncludeStatement
//
// Synopsis: Tries to determine whether or not a given line contains an
// include statement (e.g. #include <foobar.h> ).
//
// Arguments: [pfr] -- FILEREC of file being scanned
// [p] -- Current line of file
//
// Returns: NULL if line is not an include statment. Returns pointer to
// beginning of filename if it is (e.g. <foobar.h> ).
//
// Notes: The returned filename includes the surrounding quotes or
// brackets, if any. Also, the pointer is just a pointer into
// the given string, not a separate copy.
//
// Supported statements are:
// All file types: #include <filename> and #include "filename"
// MIDL files: import "filename"
// RC files: rcinclude filename
// MKTYPLIB files: importlib("filename")
//
//----------------------------------------------------------------------------
#define IsTokenPrefix0(psz, szToken, cchToken) \
(strncmp((psz), (szToken), (cchToken)) == 0)
#define IsTokenPrefix(psz, szToken, cchToken) \
(IsTokenPrefix0((psz), (szToken), (cchToken)) && \
(psz)[cchToken] != '\0')
#define IsTokenMatch(psz, szToken, cchToken) \
(IsTokenPrefix((psz), (szToken), (cchToken)) && \
!iscsym((psz)[cchToken]))
#define IsCiTokenPrefix0(psz, szToken, cchToken) \
(_strnicmp((psz), (szToken), (cchToken)) == 0)
#define IsCiTokenPrefix(psz, szToken, cchToken) \
(IsCiTokenPrefix0((psz), (szToken), (cchToken)) && \
(psz)[cchToken] != '\0')
#define IsCiTokenMatch(psz, szToken, cchToken) \
(IsCiTokenPrefix((psz), (szToken), (cchToken)) && \
!iscsym((psz)[cchToken]))
LPSTR
IsIncludeStatement(FILEREC *pfr, LPSTR p)
{
if (!p || *p == '\0')
return NULL;
if (!(pfr->FileFlags & (FILEDB_MASM | FILEDB_MIDL | FILEDB_MKTYPLIB | FILEDB_RC | FILEDB_ASN))) {
if (*p != '#') {
return(NULL);
}
}
if (*p == '#')
p++;
while (isspace(*p)) {
p++;
}
if (IsTokenMatch(p, BUILD_INCLUDE_STMT, BUILD_INCLUDE_STMT_LENGTH)) {
p += BUILD_INCLUDE_STMT_LENGTH;
}
else
if ((pfr->FileFlags & FILEDB_MASM) &&
IsCiTokenMatch(p, BUILD_INCLUDE_STMT, BUILD_INCLUDE_STMT_LENGTH)) {
p += BUILD_INCLUDE_STMT_LENGTH;
}
else
if ((pfr->FileFlags & FILEDB_MIDL) &&
IsTokenMatch(p, BUILD_MIDL_INCLUDE_STMT, BUILD_MIDL_INCLUDE_STMT_LENGTH)) {
p += BUILD_MIDL_INCLUDE_STMT_LENGTH;
}
else
if ((pfr->FileFlags & FILEDB_RC) &&
IsTokenMatch(p, BUILD_RC_INCLUDE_STMT, BUILD_RC_INCLUDE_STMT_LENGTH)) {
p += BUILD_RC_INCLUDE_STMT_LENGTH;
}
else
if ((pfr->FileFlags & FILEDB_ASN) &&
IsTokenPrefix0(p, BUILD_ASN_INCLUDE_STMT, BUILD_ASN_INCLUDE_STMT_LENGTH)) {
p += BUILD_ASN_INCLUDE_STMT_LENGTH;
}
else
if ((pfr->FileFlags & FILEDB_MKTYPLIB) &&
IsTokenMatch(p, BUILD_TLIB_INCLUDE_STMT, BUILD_TLIB_INCLUDE_STMT_LENGTH)) {
p += BUILD_TLIB_INCLUDE_STMT_LENGTH;
while (isspace(*p)) {
p++;
}
if (*p == '(') // Skip the open paren and get to the quote.
p++;
}
else {
return(NULL);
}
while (isspace(*p)) {
p++;
}
return(p);
}
//+---------------------------------------------------------------------------
//
// Function: IsPragmaHdrStop
//
// Synopsis: Determines if the given line is a #pragma hdrstop line
//
// Arguments: [p] -- String to analyze
//
// Returns: TRUE if the line is a pragma hdrstop
//
//----------------------------------------------------------------------------
BOOL
IsPragmaHdrStop(LPSTR p)
{
static char szPragma[] = "pragma";
static char szHdrStop[] = "hdrstop";
if (*p == '#') {
while (*++p == ' ') {
;
}
if (strncmp(p, szPragma, sizeof(szPragma) - 1) == 0 &&
*(p += sizeof(szPragma) - 1) == ' ') {
while (*p == ' ') {
p++;
}
if (strncmp(p, szHdrStop, sizeof(szHdrStop) - 1) == 0 &&
!iscsym(p[sizeof(szHdrStop) - 1])) {
return(TRUE);
}
}
}
return(FALSE);
}
//+---------------------------------------------------------------------------
//
// Function: ScanFile
//
// Synopsis: Scans the given file to determine files which it includes.
//
// Arguments: [FileDB] -- File to scan.
//
// Returns: TRUE if successful
//
// Notes: This function is a nop if the given file does not have either
// the FILEDB_SOURCE or FILEDB_HEADER flag set.
// (see InsertSourceDB)
//
// Note that the performance of this function is critical since
// it is called for every file in each directory.
//
//----------------------------------------------------------------------------
#define ASN_NONE 0 // not in Asn INCLUDES statement
#define ASN_START 1 // expectimg "INCLUDES" token
#define ASN_FILENAME 2 // expecting a quoted "filename"
#define ASN_COMMA 3 // expecting end token (">--") or comma
#define ASN_CONTINUATION 8 // expecting comment token first
char *
AsnStateToString(UINT AsnState)
{
static char buf[100];
char *psz;
switch (AsnState & ~ASN_CONTINUATION) {
case ASN_NONE: psz = "None"; break;
case ASN_START: psz = "Start"; break;
case ASN_FILENAME: psz = "Filename"; break;
case ASN_COMMA: psz = "Comma"; break;
default: psz = "???"; break;
}
sprintf(buf, "%s%s", psz, (AsnState & ASN_CONTINUATION)? "+Cont" : "");
return(buf);
}
BOOL
ScanFile(
PFILEREC FileDB
)
{
FILE *FileHandle;
char CloseQuote;
LPSTR p;
LPSTR IncludeFileName, TextLine;
BOOL fFirst = TRUE;
USHORT IncFlags = 0;
UINT i, cline;
UINT AsnState = ASN_NONE;
if ((FileDB->FileFlags & (FILEDB_SOURCE | FILEDB_HEADER)) == 0) {
FileDB->FileFlags |= FILEDB_SCANNED;
return(TRUE);
}
//
// Don't scan non-pass-zero files if we're doing pass zero.
//
if (fPassZero && (FileDB->FileFlags & FILEDB_PASS0) == 0)
return TRUE;
if (!SetupReadFile(
FileDB->Dir->Name,
FileDB->Name,
FileDB->pszCommentToEOL,
&FileHandle)) {
return(FALSE);
}
if (!RecurseLevel && fNoisyScan) {
ClearLine();
BuildMsgRaw(
" Scanning %s ",
FormatPathName(FileDB->Dir->Name, FileDB->Name));
if (!(BOOL) _isatty(_fileno(stderr))) {
BuildMsgRaw(szNewLine);
}
}
FileDB->SourceLines = 0;
FileDB->Version = 0;
MarkIncludeFileRecords( FileDB );
FileDB->FileFlags |= FILEDB_SCANNED;
AllDirsModified = TRUE;
while ((TextLine = ReadLine(FileHandle)) != NULL) {
if (fFirst) {
fFirst = FALSE;
if (FileDB->FileFlags & FILEDB_HEADER) {
if (FileDB->FileFlags & FILEDB_MASM) {
if (!strncmp( TextLine,
BUILD_MASM_VER_COMMENT,
BUILD_MASM_VER_COMMENT_LENGTH)) {
FileDB->Version = (USHORT)
atoi( TextLine + BUILD_MASM_VER_COMMENT_LENGTH);
}
}
else
if (!strncmp( TextLine,
BUILD_VER_COMMENT,
BUILD_VER_COMMENT_LENGTH)) {
FileDB->Version = (USHORT)
atoi( TextLine + BUILD_VER_COMMENT_LENGTH);
}
}
}
if (AsnState != ASN_NONE) {
p = TextLine;
}
else {
p = IsIncludeStatement(FileDB, TextLine);
}
if (p != NULL) {
USHORT IncFlagsNew = IncFlags;
if (FileDB->FileFlags & FILEDB_ASN) {
if (AsnState & ASN_CONTINUATION) {
if (p[0] != '-' || p[1] != '-') {
AsnState = ASN_NONE; // ignore includes and ...
p = NULL;
break; // get next line
}
p += 2;
AsnState &= ~ASN_CONTINUATION;
}
moreasn:
while (p != NULL) {
while (isspace(*p)) {
p++;
}
if (*p == '\0') {
AsnState |= ASN_CONTINUATION;
goto nextline; // get next line
}
switch (AsnState) {
case ASN_NONE:
AsnState = ASN_START;
continue; // re-enter state machine
case ASN_START:
if (!IsTokenPrefix0(
p,
"INCLUDES",
sizeof("INCLUDES") - 1)) {
goto terminate;
}
AsnState = ASN_FILENAME;
p += sizeof("INCLUDES") - 1;
continue; // re-enter state machine
case ASN_FILENAME:
if (*p != '"') {
goto terminate;
}
AsnState = ASN_COMMA;
goto parsefilename;
case ASN_COMMA:
if (*p == '>' && p[1] == '-' && p[2] == '-') {
goto terminate;
}
if (*p != ',') {
goto terminate;
}
p++;
AsnState = ASN_FILENAME;
continue; // re-enter state machine
}
assert(FALSE); // Bad AsnState
terminate:
AsnState = ASN_NONE; // ignore includes statement, & ...
nextline:
p = NULL; // get next line
break;
}
}
parsefilename:
if (p != NULL) {
CloseQuote = (UCHAR) 0xff;
if (*p == '<') {
p++;
CloseQuote = '>';
}
else
if (*p == '"') {
p++;
IncFlagsNew |= INCLUDEDB_LOCAL;
CloseQuote = '"';
}
else
if (FileDB->FileFlags & FILEDB_MASM) {
IncFlagsNew |= INCLUDEDB_LOCAL;
CloseQuote = ';';
}
else {
// C/C++ permits macro-expanded include operands, e.g.
// #include _STL_INTRIN_HEADER
// The compiler/preprocessor owns expansion of these.
// They cannot be resolved reliably by build.exe's textual
// scanner, so leave them opaque instead of reporting a
// malformed include.
continue;
}
IncludeFileName = p;
while (*p != '\0' && *p != CloseQuote && *p != ' ') {
p++;
}
if (CloseQuote == ';' && (*p == ' ' || *p == '\0')) {
CloseQuote = *p;
}
if (*p != CloseQuote || CloseQuote == (UCHAR) 0xff) {
BuildError(
"%s - invalid include statement: %s\n",
FormatPathName(FileDB->Dir->Name, FileDB->Name),
TextLine);
break;
}
*p = '\0';
CopyString(IncludeFileName, IncludeFileName, TRUE);
for (i = 0; i < CountExcludeIncs; i++) {
if (!strcmp(IncludeFileName, ExcludeIncs[i])) {
IncludeFileName = NULL;
break;
}
}
if (IncludeFileName != NULL) {
InsertIncludeDB(FileDB, IncludeFileName, IncFlagsNew);
}
if (FileDB->FileFlags & FILEDB_ASN) {
p++;
goto moreasn;
}
}
}
else
if (IncFlags == 0 &&
(FileDB->FileFlags & (FILEDB_ASM | FILEDB_MASM | FILEDB_MIDL | FILEDB_ASN | FILEDB_RC | FILEDB_HEADER)) == 0 &&
IsPragmaHdrStop(TextLine)) {
IncFlags = INCLUDEDB_POST_HDRSTOP;
}
}
CloseReadFile(&cline);
FileDB->SourceLines = cline;
DeleteIncludeFileRecords( FileDB );
if (!RecurseLevel) {
ClearLine();
}
return(TRUE);
}
+467
View File
@@ -0,0 +1,467 @@
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995
//
// File: buildscr.cpp
//
// Contents: Implementation of the code which talks to the MTScript engine
// when doing a distributed build using the build console.
//
//----------------------------------------------------------------------------
#include "scrproc.h"
#include "build.h"
#include "buildscr.h"
#define INITGUID
#include <guiddef.h>
DEFINE_GUID(CLSID_LocalScriptedProcess, 0x854c316f,0xc854,0x4a77,0xb1,0x89,0x60,0x68,0x59,0xe4,0x39,0x1b);
DEFINE_GUID(IID_IScriptedProcess, 0x854c3171,0xc854,0x4a77,0xb1,0x89,0x60,0x68,0x59,0xe4,0x39,0x1b);
DEFINE_GUID(IID_IScriptedProcessSink, 0x854c3172,0xc854,0x4a77,0xb1,0x89,0x60,0x68,0x59,0xe4,0x39,0x1b);
DEFINE_GUID(CLSID_ObjectDaemon,0x854c3184,0xc854,0x4a77,0xb1,0x89,0x60,0x68,0x59,0xE4,0x39,0x1b);
DEFINE_GUID(IID_IConnectedMachine,0x854c316c,0xc854,0x4a77,0xb1,0x89,0x60,0x68,0x59,0xe4,0x39,0x1b);
DEFINE_GUID(IID_IObjectDaemon,0x854c3183,0xc854,0x4a77,0xb1,0x89,0x60,0x68,0x59,0xE4,0x39,0x1b);
#define MAX_RETRIES 2
HANDLE g_hMTEvent = NULL;
HANDLE g_hMTThread = NULL;
DWORD g_dwMTThreadId = 0;
//+---------------------------------------------------------------------------
//
// Function: WaitForResume
//
// Synopsis: Sends a "phase complete" message to the script engine and then
// waits for it to tell us to resume (if specified).
//
// Arguments: [fPause] -- If TRUE, we wait for a resume command
// [pe] -- Message to send to the script engine
//
//----------------------------------------------------------------------------
void
WaitForResume(BOOL fPause, PROC_EVENTS pe)
{
if (g_hMTEvent)
{
HANDLE aHandles[2] = { g_hMTEvent, g_hMTThread };
ResetEvent(g_hMTEvent);
PostThreadMessage(g_dwMTThreadId, pe, 0, 0);
if (fPause)
{
// Wait until either the event object is signaled or the thread dies
WaitForMultipleObjects(2, aHandles, FALSE, INFINITE);
}
}
}
//+---------------------------------------------------------------------------
//
// Function: ExitMTScriptThread
//
// Synopsis: Tells the thread talking to the MTScript engine to exit.
//
//----------------------------------------------------------------------------
void
ExitMTScriptThread()
{
if (g_hMTEvent)
{
PostThreadMessage(g_dwMTThreadId, PE_EXIT, 0, 0);
WaitForSingleObject(g_hMTThread, INFINITE);
CloseHandle(g_hMTThread);
CloseHandle(g_hMTEvent);
}
}
//+---------------------------------------------------------------------------
//
// Function: SendStatus
//
// Synopsis: Sends a status message to the MTScript engine with the
// current number of errors, warnings, and completed files.
//
// Arguments: [pSP] -- Pointer to MTScript engine interface
//
//----------------------------------------------------------------------------
void
SendStatus(IScriptedProcess *pSP)
{
wchar_t achBuf[300];
long lRet;
static ULONG cErrorsPrev = MAXDWORD;
static ULONG cWarnPrev = MAXDWORD;
static ULONG cFilesPrev = MAXDWORD;
ULONG cErrors = NumberCompileErrors + NumberLibraryErrors + NumberLinkErrors + NumberBinplaceErrors;
ULONG cWarn = NumberCompileWarnings + NumberLibraryWarnings + NumberLinkWarnings + NumberBinplaceWarnings;
ULONG cFiles = NumberCompiles + NumberLibraries + NumberLinks /* + NumberBinplaces */;
// Only send status if it's changed since last time we did it.
if ( cErrors != cErrorsPrev
|| cWarn != cWarnPrev
|| cFiles != cFilesPrev)
{
cErrorsPrev = cErrors;
cWarnPrev = cWarn;
cFilesPrev = cFiles;
wsprintfW(achBuf, L"errors=%d,warnings=%d,files=%d", cErrors, cWarn, cFiles);
pSP->SendData(L"status", achBuf, &lRet);
}
}
//+---------------------------------------------------------------------------
//
// Function: HandleMessage
//
// Synopsis: Handles a message that has come across our message queue.
//
// Arguments: [pmsg] -- Message
// [pSP] -- Pointer to MTScript engine interface
//
//----------------------------------------------------------------------------
BOOL
HandleMessage(MSG *pmsg, IScriptedProcess *pSP)
{
long lRet;
HRESULT hr = S_OK;
switch (pmsg->message)
{
case PE_PASS0_COMPLETE:
SendStatus(pSP);
hr = pSP->SendData(L"pass 0 complete", L"", &lRet);
break;
case PE_PASS1_COMPLETE:
SendStatus(pSP);
hr = pSP->SendData(L"pass 1 complete", L"", &lRet);
break;
case PE_PASS2_COMPLETE:
SendStatus(pSP);
hr = pSP->SendData(L"pass 2 complete", L"", &lRet);
break;
case PE_EXIT:
SendStatus(pSP);
hr = pSP->SendData(L"build complete", L"", &lRet);
return TRUE;
break;
}
if (hr)
{
BuildErrorRaw("\nBUILD: Communication with script engine failed: %x", hr);
}
return (hr) ? TRUE : FALSE;
}
const DWORD UPDATE_INTERVAL = 2 * 1000; // Update every 2 seconds
//+---------------------------------------------------------------------------
//
// Function: MTScriptThread
//
// Synopsis: Thread entrypoint. Initializes and then sits around
// handling various events.
//
// Arguments: [pv] -- Not used.
//
//----------------------------------------------------------------------------
DWORD WINAPI
MTScriptThread(LPVOID pv)
{
HRESULT hr;
IScriptedProcess * pSP = NULL;
wchar_t achBuf[100];
MSG msg;
DWORD dwRet;
CProcessSink cps;
BOOL fExit = FALSE;
int cRetries = 0;
BuildMsg("Establishing connection with Script engine...\n");
LogMsg("Establishing connection with Script engine...\n");
// Force Windows to create a message queue for this thread, since we will
// be communicated to via PostThreadMessage.
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
// If anything fails we just quit this thread and communication with
// the MTScript engine won't happen.
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
if (hr)
{
BuildErrorRaw("BUILD: CoInitializeEx failed with %x\n", hr);
goto Cleanup;
}
hr = S_FALSE;
while (hr)
{
pSP = NULL;
IObjectDaemon *pIObjectDaemon;
hr = CoCreateInstance(CLSID_ObjectDaemon, NULL, CLSCTX_SERVER,
IID_IObjectDaemon, (LPVOID*)&pIObjectDaemon);
if (!hr)
{
IDispatch *pIDispatch;
BSTR bstrProgID = SysAllocString(L"MTScript.Remote");
BSTR bstrIdentity = SysAllocString(_wgetenv(L"__MTSCRIPT_ENV_IDENTITY"));
hr = pIObjectDaemon->OpenInterface(bstrIdentity, bstrProgID, (BOOL)FALSE, (IDispatch**)&pIDispatch);
if (!hr)
{
IConnectedMachine *pIConnectedMachine;
hr = pIDispatch->QueryInterface(IID_IConnectedMachine, (LPVOID*)&pIConnectedMachine);
if (!hr)
{
hr = pIConnectedMachine->CreateIScriptedProcess(GetCurrentProcessId(), (wchar_t *)_wgetenv(L"__MTSCRIPT_ENV_ID"), (IScriptedProcess **)&pSP);
pIConnectedMachine->Release();
}
else
{
BuildMsg("CreateIScriptedProcess failed with %x.\n", hr);
LogMsg("CreateIScriptedProcess failed with %x.\n", hr);
}
pIDispatch->Release();
}
else
{
BuildMsg("OpenInterface failed with %x.\n", hr);
LogMsg("OpenInterface failed with %x.\n", hr);
}
SysFreeString(bstrProgID);
SysFreeString(bstrIdentity);
pIObjectDaemon->Release();
}
else
{
BuildMsg("CoCreateInstance failed with %x.\n", hr);
LogMsg("CoCreateInstance failed with %x.\n", hr);
}
if (!hr)
{
hr = pSP->SetProcessSink(&cps);
if (hr)
{
BuildMsg("SetProcessSink failed with %x.\n", hr);
LogMsg("SetProcessSink failed with %x.\n", hr);
}
}
if (hr)
{
if (cRetries >= MAX_RETRIES)
{
BuildErrorRaw("BUILD: FATAL: Connection to script engine could not be established. (%x)\n", hr);
goto Cleanup;
}
if (pSP)
{
pSP->Release();
pSP = NULL;
}
BuildMsg("Connection to script engine failed with %x, retries=%d...\n", hr, cRetries);
LogMsg("Connection to script engine failed with %x, retries=%d...\n", hr, cRetries);
Sleep(500);
cRetries++;
}
}
BuildMsg("Connection to script engine established...\n");
LogMsg("Connection to script engine established...\r\n");
// Tell build.c that it can continue
SetEvent(g_hMTEvent);
while (TRUE)
{
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (HandleMessage(&msg, pSP))
{
fExit = TRUE;
}
}
if (fExit)
{
break;
}
dwRet = MsgWaitForMultipleObjects(0,
NULL,
FALSE,
UPDATE_INTERVAL,
QS_ALLINPUT);
if (dwRet == WAIT_OBJECT_0)
{
// A message is coming through on our message queue. Just loop
// around.
}
else if (dwRet == WAIT_TIMEOUT)
{
SendStatus(pSP);
}
else
{
// MWFMO failed. Just bail out.
break;
}
}
Cleanup:
if (pSP)
{
pSP->SetProcessSink(NULL);
pSP->Release();
}
CoUninitialize();
if (hr)
{
g_hMTThread = NULL;
}
SetEvent(g_hMTEvent);
return 0;
}
// ***********************************************************************
//
// CProcessSink implementation
//
// We hand this class to the MTScript engine so it can communicate back
// to us.
//
// ***********************************************************************
CProcessSink::CProcessSink()
{
_ulRefs = 1;
}
HRESULT
CProcessSink::QueryInterface(REFIID riid, LPVOID *ppv)
{
if (riid == IID_IUnknown || riid == IID_IScriptedProcessSink)
{
*ppv = (IScriptedProcessSink*)this;
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
((IUnknown *)*ppv)->AddRef();
return S_OK;
}
ULONG
CProcessSink::AddRef()
{
return InterlockedIncrement((long*)&_ulRefs);
}
ULONG
CProcessSink::Release()
{
if (InterlockedDecrement((long*)&_ulRefs) == 0)
{
_ulRefs = 0xFF;
delete this;
return 0;
}
return _ulRefs;
}
//+---------------------------------------------------------------------------
//
// Member: CProcessSink::RequestExit, public
//
// Synopsis: Called when the MTScript engine wants us to quit. If we don't,
// it will terminate us.
//
//----------------------------------------------------------------------------
HRESULT
CProcessSink::RequestExit()
{
// There is no easy way to tell build.exe to abort. We'll just let
// MTScript terminate us.
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Member: CProcessSink::ReceiveData, public
//
// Synopsis: Called when the MTScript engine wants to send us a message.
//
// Arguments: [pszType] -- String giving the message
// [pszData] -- String giving data associated with the message.
// [plReturn] -- A place we can return a value back.
//
//----------------------------------------------------------------------------
HRESULT
CProcessSink::ReceiveData(wchar_t *pszType, wchar_t *pszData, long *plReturn)
{
*plReturn = 0;
if (wcscmp(pszType, L"resume") == 0)
{
SetEvent(g_hMTEvent);
}
else
{
*plReturn = -1; // Signals an error
}
return S_OK;
}
+35
View File
@@ -0,0 +1,35 @@
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995
//
// File: buildscr.h
//
// Contents: Header file defining the objects needed to interface with
// the MTScript engine.
//
//----------------------------------------------------------------------------
class CProcessSink : public IScriptedProcessSink
{
public:
CProcessSink();
~CProcessSink() {}
// IUnknown methods
STDMETHOD(QueryInterface) (REFIID riid, LPVOID * ppv);
STDMETHOD_(ULONG, AddRef) (void);
STDMETHOD_(ULONG, Release) (void);
// IScriptedProcessSink methods
STDMETHOD(RequestExit)();
STDMETHOD(ReceiveData)(wchar_t *pszType,
wchar_t *pszData,
long *plReturn);
private:
ULONG _ulRefs;
};
+2177
View File
File diff suppressed because it is too large. Load diff
+1818
View File
File diff suppressed because it is too large. Load diff
View File
Whitespace-only changes.
Binary file not shown.
Binary file not shown.
+93
View File
@@ -0,0 +1,93 @@
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; Help Project File for BUILD
;
; This file is maintained by RoboHELP. Do not modify this file directly.
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
[OPTIONS]
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; The Options section contains the following information:
;
; The optional BMROOT= entry sets the directories in which the Help Compiler
; will look for graphics.
;
; The CONTENTS= tells WinHelp which topic contains the contents.
;
; The TITLE= is displayed in the Title Bar of WINHELP.EXE
;
; The BUILD= setting allows you to create different Help systems from
; the same source file.
;
; The COMPRESS= option tells the Help Compiler how much to compress
; the Help file.
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;BMROOT=C:\ROBOHELP
TITLE=Build Process
BUILD=WINDOWS
NOTES=1
OLDKEYPHRASE=NO
OPTCDROM=0
REPORT=YES
ERRORLOG=D:\builddocs\Build.ERR
CONTENTS=Contents
COMPRESS=12
[BUILDTAGS]
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; The Build Tags section specifies to the Help Compiler the names
; of all the valid build tags used in this Help project.
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
WINDOWS
[CONFIG]
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; The Config section defines macros which will run at startup.
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
[FILES]
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; The Files section specifies the RTF files for a project.
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
BUILD.RTF
[ALIAS]
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; The Alias section sets up aliases for Topic IDs in your Help system.
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
[MAP]
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; The Map section specifies the project HH files.
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
[BITMAPS]
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; The Bitmaps section specifies the referenced bitmaps used in
; your help system.
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
[WINDOWS]
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; The Windows section contains all of the information about the windows
; in a Help project.
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
;Gloss = "Glossary",(100,100,350,350),0,(255,255,255),(255,255,255)
(w95sec)=,,20740,(r14745599),(r14745599),f2
main="",,28164,(255,255,224),(128,255,255),f0
[BAGGAGE]
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
; The Baggage section specifies any additional files.
;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+27
View File
@@ -0,0 +1,27 @@
[Project]
Help Compiler=HCW.EXE
Remove Unused=0
Version=512
ConvertedFromV1=0
HasGlossary=0
Automatic Map Files=0
NextFile=2
IncludeRTF=0
Extra Language=0
[Document Files]
BUILD.DOC=1
[File Properties]
HasProperties=1
BrowseType=0
AutoMapFile=0
StartingWith=0
IncrementBy=20
NextTopicNumber=0
StartingNumber=1
BrowseString=BUILD:0
DefaultBuildTag=
[.RBH]
CopyTo=0
PreBatch=
PostBatch=
AutoFixRTF=0
Binary file not shown.
File diff suppressed because it is too large. Load diff
Binary file not shown.
Binary file not shown.
+3038
View File
File diff suppressed because it is too large. Load diff
+191
View File
@@ -0,0 +1,191 @@
/* Small external watch supervisor. Each build runs in a fresh child process. */
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#include <wchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <wctype.h>
struct WatchState {
HANDLE directory;
HANDLE changed;
volatile LONG generation;
};
/* Exclude generated object directories, caches and build logs. */
static int IgnoreChange(const WCHAR *name, DWORD length)
{
WCHAR component[260];
DWORD i = 0;
while (i < length) {
DWORD j = 0;
while (i < length && (name[i] == L'\\' || name[i] == L'/')) ++i;
while (i < length && name[i] != L'\\' && name[i] != L'/') {
if (j + 1 < 260) component[j++] = towlower(name[i]);
++i;
}
component[j] = 0;
if (!wcscmp(component, L"obj") || !wcscmp(component, L"objd") ||
!wcscmp(component, L"out") || !wcscmp(component, L".git") ||
!wcscmp(component, L".vs")) return 1;
if (i >= length) {
if (!wcscmp(component, L"build.dat") ||
!wcscmp(component, L"build.log") ||
!wcscmp(component, L"build.err") ||
!wcscmp(component, L"build.wrn") ||
!wcscmp(component, L"build.inc")) return 1;
}
}
return 0;
}
static DWORD WINAPI WatchThread(void *param)
{
struct WatchState *state = (struct WatchState *)param;
BYTE buffer[32768];
DWORD bytes;
for (;;) {
if (!ReadDirectoryChangesW(state->directory, buffer, sizeof(buffer), TRUE,
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_CREATION,
&bytes, NULL, NULL)) return 1;
if (bytes) {
BYTE *cursor = buffer;
for (;;) {
FILE_NOTIFY_INFORMATION *info = (FILE_NOTIFY_INFORMATION *)cursor;
if (!IgnoreChange(info->FileName, info->FileNameLength / sizeof(WCHAR))) {
InterlockedIncrement(&state->generation);
SetEvent(state->changed);
break;
}
if (!info->NextEntryOffset) break;
cursor += info->NextEntryOffset;
}
}
}
}
/* Quote an individual argument according to the Win32 CRT argv rules. */
static void AddQuoted(WCHAR *dst, const WCHAR *src, size_t *position)
{
size_t slash = 0;
dst[(*position)++] = L'"';
while (*src) {
if (*src == L'\\') { ++slash; ++src; continue; }
if (*src == L'"') {
while (slash--) dst[(*position)++] = L'\\';
dst[(*position)++] = L'\\';
dst[(*position)++] = L'"';
slash = 0;
++src;
continue;
}
while (slash) { dst[(*position)++] = L'\\'; --slash; }
dst[(*position)++] = *src++;
}
while (slash--) { dst[(*position)++] = L'\\'; dst[(*position)++] = L'\\'; }
dst[(*position)++] = L'"';
dst[*position] = 0;
}
static WCHAR *MakeChildCommand(int argc, WCHAR **argv)
{
size_t capacity = 4, pos = 0;
WCHAR *command;
int i;
for (i = 0; i < argc; ++i) capacity += wcslen(argv[i]) * 2 + 5;
command = (WCHAR *)calloc(capacity, sizeof(WCHAR));
if (!command) return NULL;
for (i = 0; i < argc; ++i) {
if (!argv[i] || !argv[i][0]) continue;
if (pos) command[pos++] = L' ';
AddQuoted(command, argv[i], &pos);
}
return command;
}
static int RunChild(WCHAR *command)
{
PROCESS_INFORMATION pi = {0};
STARTUPINFOW si = {0};
DWORD status = 1;
si.cb = sizeof(si);
if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
fwprintf(stderr, L"BUILD: error: cannot launch build (%lu)\n", GetLastError());
return 1;
}
WaitForSingleObject(pi.hProcess, INFINITE);
GetExitCodeProcess(pi.hProcess, &status);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return (int)status;
}
/* Return -1 for a normal build; otherwise supervise -w until Ctrl+C. */
int TryWatchMode(void)
{
int argc, i, watch = 0;
WCHAR **argv = CommandLineToArgvW(GetCommandLineW(), &argc);
WCHAR *command;
struct WatchState state = {0};
HANDLE worker;
DWORD threadId;
if (!argv) return -1;
for (i = 1; i < argc; ++i) {
WCHAR *arg = argv[i];
size_t j, k;
if (arg[0] != L'-' && arg[0] != L'/') continue;
if (!_wcsicmp(arg + 1, L"why")) continue;
/* Keep whole-word and target switches unchanged. */
if (wcslen(arg) > 1 && wcschr(L"aAcCnN", arg[1]) &&
(wcslen(arg) > 3)) continue;
for (j = 1, k = 1; arg[j]; ++j) {
if (arg[j] == L'w' || arg[j] == L'W') {
watch = 1;
} else {
arg[k++] = arg[j];
}
}
arg[k] = 0;
if (k == 1) argv[i][0] = 0;
}
if (!watch) { LocalFree(argv); return -1; }
command = MakeChildCommand(argc, argv);
LocalFree(argv);
if (!command) return 1;
state.changed = CreateEventW(NULL, FALSE, FALSE, NULL);
state.directory = CreateFileW(L".", FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (!state.changed || state.directory == INVALID_HANDLE_VALUE) {
fprintf(stderr, "BUILD: error: unable to watch project directory\n");
free(command);
return 1;
}
worker = CreateThread(NULL, 0, WatchThread, &state, 0, &threadId);
if (!worker) {
fprintf(stderr, "BUILD: error: unable to start watcher\n");
free(command);
return 1;
}
for (;;) {
LONG before = InterlockedCompareExchange(&state.generation, 0, 0);
RunChild(command);
if (before == InterlockedCompareExchange(&state.generation, 0, 0)) {
printf("BUILD: Watching...\n");
fflush(stdout);
{
HANDLE signals[2] = { state.changed, worker };
if (WaitForMultipleObjects(2, signals, FALSE, INFINITE) != WAIT_OBJECT_0) {
fprintf(stderr, "BUILD: error: watcher stopped\n");
free(command);
return 1;
}
}
}
Sleep(200);
/* Drain coalesced notifications before next build. */
ResetEvent(state.changed);
}
}