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

1370 lines
44 KiB

@perl -x -w %0 %*
@goto :eof
#!perl
# line 5
################################################################################
# 05-Jun-00 : skupec: Add fail safes to avoid hangs in post build
# 1) delete all old lock files before we start
# 2) set max. wait limit for new process to 30*2 seconds
#
# 01-Jul-00 : skupec: Convert to use Win32::Process to avoid sporadic hangs
# that are showing up in postbuild.
#
# 10-Nov-00 : skupec: Add Verbose mode
# No longer use \lib[fre|chk]\%arch%. Now just \lib\%arch%
#
# 11-Jan-01 : skupec: Don't ship checked versions of the tools.
#
# 10-Feb-01 : skupec: Create per-architecture cabs for tools. Instead of just
# TOOL_*.cab, we now also have TOOL_*x.cab and TOOL_*i.cab
# (x86/ia64 respectively) IFF per-arch directories exist
# when cabbing is done. TOOL_*.cab should still be the
# primary cab in cabs.ini so a single checkbox will install
# on either platform.
#
# 27-Feb-01 : skupec: Modify the cabbing of \incs to properly handle the new
# platform specific subdir layout.
#
# 04-Apr-01 : skupec: Add cabbing of legacy libs for Win2K DDK env
#
# 17-May-01 : skupec: Add DDK_DBG[i|x] cabs only on CHK builds
#
# 02-May-02 : skupec: forked for XPSP builds
#
# 09-Jul-02 : skupec: add QFE build num to cabs.ini
#
use lib $ENV{RAZZLETOOLPATH} . '\\postbuildscripts';
use PbuildEnv;
use BuildName;
# Only accept one parameter which must be numeric
my ($numproc, $lpCount, $force, $spoof,$verbose) = (2,0,0,0,0);
for ($lpCount=0; $lpCount <= ($#ARGV); $lpCount++) {
SWITCH: {
Dependencies() if lc $ARGV[$lpCount] eq "-plan";
if ((substr($ARGV[$lpCount],0,1) eq "-") or (substr($ARGV[$lpCount],0,1) eq "/")) {
for ($i=1;$i<length($ARGV[$lpCount]);$i++) {
exit(Usage()) if uc(substr($ARGV[$lpCount],$i,1)) eq "?";
exit(Usage()) if uc(substr($ARGV[$lpCount],$i,1)) eq "H";
if (uc substr($ARGV[$lpCount],$i,1) eq "L") {
if ($ARGV[$lpCount] =~ /:+(.*)/) {
if ((defined $1) and ($1 ne "")) { # handle -l:<language>
$lang = $1;
} else { # handle -l: where language was forgotten
$lang = "usa";
}
$ARGV[$lpCount] =~ s/:+(.*)//;
} elsif (defined $ARGV[$lpCount+1]) { # handle -l <language>
$lang = $ARGV[$lpCount+1];
splice(@ARGV,$lpCount+1,1);
} else { # handle -l where language was forgotten
$lang = "usa"; # default
}
unless (uc $lang eq "USA") { # only execute on USA
exit 0;
}
next;
} elsif (uc substr($ARGV[$lpCount],$i,1) eq "N") {
if (defined($ARGV[$lpCount+1]) and ($ARGV[$lpCount+1] =~ /^\d*$/)) {
$numproc=$ARGV[$lpCount+1];
splice(@ARGV,$lpCount+1,1);
} else {
exit(Usage());
}
} elsif (uc substr($ARGV[$lpCount],$i,1) eq "F") {
$force = 1;
} elsif (uc substr($ARGV[$lpCount],$i,1) eq "S") {
$spoof = 1;
} elsif (uc substr($ARGV[$lpCount],$i,1) eq "V") {
$verbose = 1;
} else {
print("-",substr($ARGV[$lpCount],$i,1)," switch ignored. Use '-?' or '-h' to get usage.\n");
}
}
} else {
print("$ARGV[$lpCount] argument ignored.\n");
}
1; #Last line should do nothing
}
}
if ( -f "$ENV{_NTPOSTBLD}\\..\\build_logs\\skip.txt" ) {
if ( !open SKIP, "$ENV{_NTPOSTBLD}\\..\\build_logs\\skip.txt" ) {
print STDERR "ERROR: Unable to open skip list file.\n";
die;
}
while (<SKIP>) {
chomp;
exit if lc$_ eq lc$0;
}
close SKIP;
}
if ($spoof) {
# nothing to do for spoofing in XPSP builds, we're currently hardcoding $bldno=2600
}
# Only build if (1) -f is passed, (2) %OFFICIAL_BUILD_MACHINE% is set, or (3) %__BUILDMACHINE__% == LB6RI
if (! defined $ENV{OFFICIAL_BUILD_MACHINE} && (! $force) && (uc($ENV{__BUILDMACHINE__}) ne "LB6RI") ) {
print STDERR "Not building because this isn't an official build machine. Use -f to force.\n";
exit 0;
};
print(STDERR "$0: Started. ");
use strict;
# use Win32;
use Win32::Process;
# Set %temp% as working directory
Win32::SetCwd $ENV{Temp};
my $time = time();
my $hLogFile;
my $handle;
################################################################################
#
# Create .tmp file so postbuild.cmd knows we're running.
#
################################################################################
open (hLogFile, ">$ENV{TEMP}\\ddkcabs.tmp") || die("Can't open $ENV{TEMP}\\ddkcabs.tmp for writing: $!\n");
print (hLogFile "1");
close (hLogFile);
################################################################################
#
# Find the correct logfile to use
#
################################################################################
# Either use the defined log file
if (defined $ENV{LOGFILE}) {
$handle="$ENV{LOGFILE}";
# or use our default log file.
} else {
$handle="$ENV{TEMP}\\ddkcabs.log";
}
print(STDERR "Writing log to $handle.\n");
################################################################################
#
# Test for all conditions that require us to terminate early.
#
################################################################################
# If %_DDK_NOCAB% is defined, don't make CABS
if (defined $ENV{_DDK_NOCAB} ) {
logmsg("_DDK_NOCAB is set. Not making CABS.");
unlink("$ENV{TEMP}\\ddkcabs.tmp");
exit(0);
}
# If any of the needed environment variables aren't defined, output an
# error and abort the cabbing process
foreach ("_NTDRIVE","_NTROOT","_BUILDARCH","_BUILDTYPE","_NTPOSTBLD","RazzleToolPath","PROCESSOR_ARCHITECTURE","NUMBER_OF_PROCESSORS") {
unless (defined $ENV{$_}) {
logerror("Aborting: \%$_\% is not defined.");
unlink("$ENV{TEMP}\\ddkcabs.tmp");
exit(0);
}
}
# Don't build on AXP64 or Alpha
if ($ENV{_BuildArch} =~ /^(axp64|alpha)/i) {
unlink("$ENV{TEMP}\\ddkcabs.tmp");
logmsg("DDK unsupported on $ENV{_BuildArch}. Exiting.");
exit(0);
}
################################################################################
#
# Global Variables
#
################################################################################
my $bldno = 2600;
#
# Add QFE build num if available
#
if (-e "$ENV{_NTPOSTBLD}\\ddk_cd\\common\\QFE_NUM.TXT") {
if ( open(hQFE,"$ENV{_NTPOSTBLD}\\ddk_cd\\common\\QFE_NUM.TXT") ) {
my $QFENum = <hQFE>;
close(hQFE);
chomp $QFENum;
$QFENum =~ s/^\s*//;
$QFENum =~ s/\s*$//;
$bldno = "$bldno.$QFENum";
}
}
logdebug("$numproc processes per processor");
my $MAX_PROCESSES = $ENV{NUMBER_OF_PROCESSORS}*$numproc;
my @Processes;
my $exe = "$ENV{RazzleToolPath}\\$ENV{PROCESSOR_ARCHITECTURE}\\cabarc.exe";
my $global_param = " -s 6144 -m MSZIP -i 1 N ";
my $INCREMENTAL = 0; # Full build by default
my %MAKECAB;
my @dir_list1;
my @dir_list2;
my $dir;
my $dir2;
my $file;
my $cabname;
my $samplename;
my $friendlyname;
my $kit;
my $i;
sub TRUE {return(1);} # BOOLEAN TRUE
sub FALSE {return(0);} # BOOLEAN FALSE
my $CABDEBUG = FALSE;
$CABDEBUG = TRUE if (defined($ENV{_CABDEBUG}));
my $bindir;
my $sdkincs = "$ENV{_NTPOSTBLD}\\ddk_flat\\inc";
# Directory to look for .lib's in
my $libdir = "lib\\wxp";
if (uc($ENV{_BuildArch}) eq "IA64") {
$libdir .= "\\ia64";
} else {
$libdir .= "\\i386";
}
################################################################################
#
# Determine if we should build incrementally
#
################################################################################
#
# Incremental DDKs disabled for XPSP
#
# --------------------------------------------------------------------------
# Make the samples CABs. One cab per 2nd level directory under src. Name of each cab is
# the first 4 character of the first level directory + the first 6 of the second level
# directory.
# --------------------------------------------------------------------------
SAMPLES:{
foreach $kit ("ddk","ifs", "hal", "processor") {
mkdir("$ENV{_NTPOSTBLD}\\${kit}_cd\\common", 777) unless (-e "$ENV{_NTPOSTBLD}\\${kit}_cd\\common");
opendir(hDIR, "$ENV{_NTPOSTBLD}\\${kit}_flat\\src"); # Get the first level directories
@dir_list1=readdir(hDIR);
closedir(hDIR);
foreach $dir (@dir_list1) {
# Skip . & .. as well as non-directory files (which shouldn't be there anyhow).
next unless ((-d "$ENV{_NTPOSTBLD}\\${kit}_flat\\src\\$dir") and ($dir ne ".") and ($dir ne ".."));
chomp $dir;
opendir(hDIR, "$ENV{_NTPOSTBLD}\\${kit}_flat\\src\\$dir"); # Get the second level directories
@dir_list2=readdir(hDIR);
closedir(hDIR);
foreach $dir2 (@dir_list2) {
# Skip . & .. as well as non-directory files (which shouldn't be there anyhow).
next unless ((-d "$ENV{_NTPOSTBLD}\\${kit}_flat\\src\\$dir\\$dir2") and ($dir2 ne ".") and ($dir2 ne ".."));
chomp $dir2;
$cabname=sprintf("%s_%s\n",uc(substr($dir,0,4)),lc(substr($dir2,0,6)));
chomp $cabname;
next if (($INCREMENTAL) and (! defined $MAKECAB{$cabname}));
# Create a complete listing of files under the second level directory
system("dir $ENV{_NTPOSTBLD}\\${kit}_flat\\src\\$dir\\$dir2 /s/b/a-d > ${dir}${dir2}.ddk.ini 2>nul");
# Create the .ini
CreateCAB ("${dir}${dir2}.ddk.ini","$cabname","Samples","$dir", "$kit", "$bldno");
}
}
}
}
# --------------------------------------------------------------------------
DDKINCS: {
if ($INCREMENTAL) {
last DDKINCS unless ( defined $MAKECAB{DDKINCS} );
}
# Get the WXP INCS
system("dir $ENV{_NTPOSTBLD}\\ddk_flat\\inc\\ddk\\wxp /s/b/a-d > ddkincs.ddk.ini 2>nul");
system("dir $ENV{_NTPOSTBLD}\\ddk_flat\\inc\\ddk\\wdm\\wxp /s/b/a-d >> ddkincs.ddk.ini 2>nul");
# Create the .ini
CreateCAB( "ddkincs.ddk.ini","DDKINCS","Build_Environment",
"DDK_Include_Files", "DDK", $bldno);
# Get the W2K backport incs
system("dir $ENV{_NTPOSTBLD}\\ddk_flat\\inc\\ddk\\w2k /s/b/a-d > w2k_incs.ddk.ini 2>nul");
system("dir $ENV{_NTPOSTBLD}\\ddk_flat\\inc\\ddk\\wdm\\w2k /s/b/a-d >> w2k_incs.ddk.ini 2>nul");
# Create the .ini
CreateCAB( "w2k_incs.ddk.ini","W2K_INCS","Build_Environment",
"DDK_Include_Files", "DDK", $bldno);
}
# --------------------------------------------------------------------------
IFSINCS: {
if ($INCREMENTAL) {
last IFSINCS unless ( defined $MAKECAB{IFSINCS} );
}
system("dir $ENV{_NTPOSTBLD}\\ifs_flat\\inc /s/b/a-d > ifsincs.ddk.ini 2>nul");
# Create the .ini
CreateCAB( "ifsincs.ddk.ini","IFSINCS","Build_Environment",
"IFS_Include_Files","IFS",$bldno);
}
# --------------------------------------------------------------------------
PDKINCS: {
if ($INCREMENTAL) {
last PDKINCS unless ( defined $MAKECAB{PDKINCS} );
}
system("dir $ENV{_NTPOSTBLD}\\processor_flat\\inc /s/b/a-d > pdkincs.ddk.ini 2>nul");
# Create the .ini
CreateCAB( "pdkincs.ddk.ini","PDKINCS","Build_Environment",
"PDK_Include_Files","processor",$bldno);
}
# --------------------------------------------------------------------------
HALINCS: {
if ($INCREMENTAL) {
last HALINCS unless ( defined $MAKECAB{HALINCS} );
}
system("dir $ENV{_NTPOSTBLD}\\HAL_flat\\inc /s/b/a-d > HALincs.ddk.ini 2>nul");
# Create the .ini
CreateCAB( "HALincs.ddk.ini","HALINCS","Build_Environment",
"HAL_Include_Files","HAL",$bldno);
}
# --------------------------------------------------------------------------
HALBINS: {
if ($INCREMENTAL) {
last HALBINS unless ( defined $MAKECAB{HALBINS} );
}
# List all files under \inc\ddk\...
system("dir $ENV{_NTPOSTBLD}\\HAL_flat\\bin /s/b/a-d > HALbins.ddk.ini 2>nul");
# Create the .ini
CreateCAB( "HALbins.ddk.ini","HALBINS","Build_Environment",
"HAL_Binary_Files","HAL",$bldno);
}
# --------------------------------------------------------------------------
DDKDBG: {
if ($INCREMENTAL) {
last DDKDBG unless ( defined $MAKECAB{DDKDBG} );
}
# Make DBG cabs only on CHK builds
last DDKDBG if (uc $ENV{_BuildType} ne "CHK");
my $plat = substr($ENV{_BUILDARCH}, 0, 1);
system("dir $ENV{_NTPOSTBLD}\\ddk_flat\\debug /s/b/a-d > ddkdbg.ddk.ini 2>nul");
# Create the .ini
CreateCAB( "ddkdbg.ddk.ini","DDK_DBG${plat}","Build_Environment",
"Extra_Debug_Files","DDK",$bldno);
}
# --------------------------------------------------------------------------
DDKTOOLS: {
if ($INCREMENTAL) {
last DDKTOOLS unless ( defined $MAKECAB{DDKTOOLS} );
}
# We don't want to ship checked versions of the tools
last DDKTOOLS if (uc $ENV{_BuildType} eq "CHK");
opendir(hDIR, "$ENV{_NTPOSTBLD}\\DDK_flat\\tools"); # Get the first level directories
@dir_list1=readdir(hDIR);
closedir(hDIR);
foreach $dir (@dir_list1) {
# Skip . & .. as well as non-directory files (which shouldn't be there anyhow).
next unless ((-d "$ENV{_NTPOSTBLD}\\DDK_flat\\tools\\$dir") and ($dir ne ".") and ($dir ne ".."));
chomp $dir;
$cabname=sprintf("%s_%s\n","TOOL",lc substr($dir,0,6) );
chomp $cabname;
next if (($INCREMENTAL) and (! defined $MAKECAB{$cabname}));
##
## Need to handle tools on the per-arch basis. Can't just look for \%arch, since
## the tools may also have files in root. (.htm's, etc). Instead, break we'll
## break this into 3 cabs per tool, TOOL_%tool%, TOOL_%tool%x (x86) TOOL_%tool%i (ia64)
##
# At tools\\$dir, now, we need all the sub dirs
my @subs = `dir $ENV{_NTPOSTBLD}\\DDK_flat\\tools\\$dir /s/b/ad`;
my $sub;
my $plat = substr($ENV{_BUILDARCH}, 0, 1);
# Drop in an empty file as placeholder so we can force the general cab for this tool
# to be built.
system("echo. >$ENV{_NTPOSTBLD}\\DDK_flat\\tools\\$dir\\.empty");
# Make sure we're not appending to old .ini's
unlink("TOOLS${dir}${plat}.ddk.ini") if (-e "TOOLS${dir}${plat}.ddk.ini");
unlink("TOOLS${dir}.ddk.ini") if (-e "TOOLS${dir}.ddk.ini");
# Now, create the .ini for the common cab
foreach (`dir $ENV{_NTPOSTBLD}\\DDK_flat\\tools\\$dir /b/a-d`) {
chomp;
system("echo $ENV{_NTPOSTBLD}\\DDK_flat\\tools\\$dir\\$_ >> TOOLS${dir}.ddk.ini");
}
# For every subdir, if it ends in %arch%, create the arch specific cab, otherwise
# create the general cab.
foreach $sub (@subs) {
chomp $sub;
if ($sub =~ /DDK_flat\\.*\\$ENV{_BUILDARCH}/i) {
system("dir $ENV{_NTPOSTBLD}\\DDK_flat\\tools\\$dir /s/b/a-d >> TOOLS${dir}${plat}.ddk.ini 2>nul");
} elsif ( uc($ENV{_BUILDARCH}) eq "X86" ) {
# i386 is a valid alias of x86
if ($sub =~ /DDK_flat\\.*\\i386/i) {
system("dir $ENV{_NTPOSTBLD}\\DDK_flat\\tools\\$dir /s/b/a-d >> TOOLS${dir}${plat}.ddk.ini 2>nul");
}
}
}
# Create the cabs
CreateCAB ("TOOLS${dir}.ddk.ini","${cabname}","Build_Environment","${dir}_TOOL", "ddk", "$bldno");
CreateCAB ("TOOLS${dir}${plat}.ddk.ini","${cabname}${plat}","Build_Environment","${dir}_TOOL", "ddk", "$bldno")
if (-e "TOOLS${dir}${plat}.ddk.ini"); # May not have arch-specific cab
}
}
# --------------------------------------------------------------------------
IFSTOOLS: {
if ($INCREMENTAL) {
last IFSTOOLS unless ( defined $MAKECAB{IFSTOOLS} );
}
# List all files under \inc\ddk\...
system("dir $ENV{_NTPOSTBLD}\\IFS_flat\\tools /s/b/a-d > ifstools.ddk.ini 2>nul");
# Create the .ini
CreateCAB( "ifstools.ddk.ini","IFSTOOLS","Build_Environment",
"Development_Tools","IFS",$bldno);
}
# --------------------------------------------------------------------------
SDKINCS: {
if ($INCREMENTAL) {
last SDKINCS unless ( defined $MAKECAB{SDKINCS} );
}
# List all files under \inc\.
opendir(hDIR, "$sdkincs");
@dir_list1 = readdir(hDIR);
closedir(hDIR);
#
# Look for all WXP specific headers
#
opendir(hDIR, "$sdkincs\\wxp");
@dir_list2 = readdir(hDIR);
closedir(hDIR);
foreach (@dir_list2) {
$_ = "wxp\\$_";
}
push(@dir_list1, @dir_list2);
undef(@dir_list2);
#
# Look for all CRT headers
#
opendir(hDIR, "$sdkincs\\crt");
@dir_list2 = readdir(hDIR);
closedir(hDIR);
foreach (@dir_list2) {
$_ = "crt\\$_";
}
push(@dir_list1, @dir_list2);
undef(@dir_list2);
opendir(hDIR, "$sdkincs\\crt\\sys");
@dir_list2 = readdir(hDIR);
closedir(hDIR);
foreach (@dir_list2) {
$_ = "crt\\sys\\$_";
}
push(@dir_list1, @dir_list2);
undef(@dir_list2);
opendir(hDIR, "$sdkincs\\crt\\gl");
@dir_list2 = readdir(hDIR);
closedir(hDIR);
foreach (@dir_list2) {
$_ = "crt\\gl\\$_";
}
push(@dir_list1, @dir_list2);
undef(@dir_list2);
opendir(hDIR, "$sdkincs\\crt\\wxp");
@dir_list2 = readdir(hDIR);
closedir(hDIR);
foreach (@dir_list2) {
$_ = "crt\\wxp\\$_";
}
push(@dir_list1, @dir_list2);
undef(@dir_list2);
open(sdk1, ">sdk1.ddk.ini");
open(sdk2, ">sdk2.ddk.ini");
open(sdk3, ">sdk3.ddk.ini");
for ($i=0;$i<=$#dir_list1;$i++) {
next if ($dir_list1[$i] =~ /\.$/);
next if (-d "$sdkincs\\$dir_list1[$i]");
if (($i%3) == 0) {
print(sdk1 "$sdkincs\\$dir_list1[$i]\n");
} elsif (($i%3) == 1) {
print(sdk2 "$sdkincs\\$dir_list1[$i]\n");
} else {
print(sdk3 "$sdkincs\\$dir_list1[$i]\n");
}
}
close(sdk1);
close(sdk2);
close(sdk3);
# CAB 1
# Create the .ini
CreateCAB( "sdk1.ddk.ini","SDKINCS1","Build_Environment",
"SDK_Include_Files","DDK",$bldno);
# CAB 2
# Create the .ini
CreateCAB( "sdk2.ddk.ini","SDKINCS2","Build_Environment",
"SDK_Include_Files","DDK",$bldno);
# CAB 3
# Create the .ini
CreateCAB( "sdk3.ddk.ini","SDKINCS3","Build_Environment",
"SDK_Include_Files","DDK",$bldno);
}
# --------------------------------------------------------------------------
DDKLIBS: {
if ($INCREMENTAL) {
last DDKLIBS unless ( defined $MAKECAB{DDKLIBS} );
}
if ( -e "$ENV{_NTPOSTBLD}\\ddk_flat\\lib\\w2k\\i386" && (uc($ENV{_BuildArch}) eq "X86")) {
# List all files under \inc\ddk\...
system("dir $ENV{_NTPOSTBLD}\\ddk_flat\\lib\\w2k /s/b/a-d > w2klibs.ddk.ini 2>nul");
# Create the .ini
CreateCAB( "w2klibs.ddk.ini","W2K_LIBS","Build_Environment",
"W2K_Library_Files","DDK",$bldno);
}
if (uc($ENV{_BUILDARCH}) eq "IA64") {
$cabname="IA6dLIB";
} else {
$cabname="X86dLIB";
}
$samplename ="$ENV{_BuildArch}_Libraries";
$friendlyname="$ENV{_BuildArch}_Libraries";
# List all files under \tools
opendir(hDIR, "$ENV{_NTPOSTBLD}\\ddk_flat\\$libdir");
@dir_list1=readdir hDIR;
closedir(hDIR);
open(LIBS1, ">libs1.ddk.ini");
open(LIBS2, ">libs2.ddk.ini");
open(LIBS3, ">libs3.ddk.ini");
for ($i=0;$i<=$#dir_list1;$i++) {
next if ($dir_list1[$i] =~ /^\./);
if (($i % 3) == 0) {
print(LIBS1 "$ENV{_NTPOSTBLD}\\ddk_flat\\$libdir\\$dir_list1[$i]\n");
} elsif (($i % 3) == 1) {
print(LIBS2 "$ENV{_NTPOSTBLD}\\ddk_flat\\$libdir\\$dir_list1[$i]\n");
} else {
print(LIBS3 "$ENV{_NTPOSTBLD}\\ddk_flat\\$libdir\\$dir_list1[$i]\n");
}
}
close(LIBS1);
close(LIBS2);
close(LIBS3);
# CAB 1
# Create the .ini
CreateCAB( "libs1.ddk.ini","${cabname}1","Build_Environment",
"${samplename}","DDK",$bldno);
# CAB 2
# Create the .ini
CreateCAB( "libs2.ddk.ini","${cabname}2","Build_Environment",
"$samplename","DDK",$bldno);
# CAB 3
# Create the .ini
CreateCAB( "libs3.ddk.ini","${cabname}3","Build_Environment",
"$samplename","DDK",$bldno);
}
# --------------------------------------------------------------------------
IFSLIBS: {
if ($INCREMENTAL) {
last IFSLIBS unless ( defined $MAKECAB{IFSLIBS} );
}
if (uc($ENV{_BUILDARCH}) eq "IA64") {
$cabname="IA6iLIB";
} else {
$cabname="X86iLIB";
}
# List all files under \inc\ddk\...
system("dir $ENV{_NTPOSTBLD}\\ifs_flat\\$libdir /s/b/a-d > ifslibs.ddk.ini 2>nul");
# Create the .ini
CreateCAB( "ifslibs.ddk.ini","${cabname}1","Build_Environment",
"Library_Files","IFS",$bldno);
}
# --------------------------------------------------------------------------
PDKLIBS: {
if ($INCREMENTAL) {
last PDKLIBS unless ( defined $MAKECAB{PDKLIBS} );
}
if (uc($ENV{_BUILDARCH}) eq "IA64") {
$cabname="IA6pLIB";
} else {
$cabname="X86pLIB";
}
# List all files under \inc\ddk\...
system("dir $ENV{_NTPOSTBLD}\\processor_flat\\$libdir /s/b/a-d > pdklibs.ddk.ini 2>nul");
# Create the .ini
CreateCAB( "pdklibs.ddk.ini","${cabname}1","Build_Environment",
"Library_Files","processor",$bldno);
}
# --------------------------------------------------------------------------
HALLIBS: {
if ($INCREMENTAL) {
last HALLIBS unless ( defined $MAKECAB{HALLIBS} );
}
if (uc($ENV{_BUILDARCH}) eq "IA64") {
$cabname="IA6hLIB";
} else {
$cabname="X86hLIB";
}
# List all files under \inc\ddk\...
system("dir $ENV{_NTPOSTBLD}\\hal_flat\\$libdir /s/b/a-d > hallibs.ddk.ini 2>nul");
# Create the .ini
CreateCAB( "hallibs.ddk.ini","${cabname}1","Build_Environment",
"Library_Files","HAL",$bldno);
}
# --------------------------------------------------------------------------
DDKBINS: {
if ($INCREMENTAL) {
last DDKBINS unless ( defined $MAKECAB{DDKBINS} );
}
$bindir ="$ENV{_NTPOSTBLD}\\ddk_flat\\bin";
# List all files under bin
opendir(hDIR, "$bindir"); # Get the first level directories
@dir_list1=readdir(hDIR);
closedir(hDIR);
open(hDIR, ">cmnbins.ddk.ini");
foreach $dir (@dir_list1) {
# Skip . & .. as well as files.
next if ( -d "$bindir\\$dir");
next if (($dir eq ".") or ($dir eq ".."));
print(hDIR "$bindir\\$dir\n");
}
close(hDIR);
system("dir $ENV{_NTPOSTBLD}\\ddk_flat\\bin\\wppconfig /s/b/a-d >>cmnbins.ddk.ini 2>nul");
# Create the .ini
CreateCAB( "cmnbins.ddk.ini","CMNBINS","Build_Environment",
"Comon_Build_Tools","DDK",$bldno);
if (uc($ENV{_BUILDARCH}) eq "IA64") {
$cabname="IA6dBIN";
} else {
$cabname="X86bBIN";
}
$samplename ="$ENV{_BuildArch}_$ENV{_BuildType}_Binaries";
$friendlyname="$ENV{_BuildArch}_$ENV{_BuildType}_Binaries";
if (-e "$bindir\\x86") {
# List all files under bin\x86
opendir(hDIR, "$bindir\\x86"); # Get the first level directories
@dir_list1=readdir(hDIR);
closedir(hDIR);
open(hDIR, ">x86bins.ddk.ini");
foreach $dir (@dir_list1) {
# Skip . & .. as well as directory files (which shouldn't be there anyhow).
next unless ((! -d "$bindir\\x86\\$dir") and ($dir ne ".") and ($dir ne ".."));
print(hDIR "$bindir\\x86\\$dir\n");
}
close(hDIR);
# Create the .ini
CreateCAB( "x86bins.ddk.ini","X86dBINS","Build_Environment",
"X86_Build_Tools","DDK",$bldno);
}
if (-e "$bindir\\ia64") {
# List all files under bin\ia64
opendir(hDIR, "$bindir\\ia64"); # Get the first level directories
@dir_list1=readdir(hDIR);
closedir(hDIR);
open(hDIR, ">ia64bins.ddk.ini");
foreach $dir (@dir_list1) {
# Skip . & .. as well as directory files (which shouldn't be there anyhow).
next unless ((! -d "$bindir\\ia64\\$dir") and ($dir ne ".") and ($dir ne ".."));
print(hDIR "$bindir\\ia64\\$dir\n");
}
close(hDIR);
# Create the .ini
CreateCAB( "ia64bins.ddk.ini","IA6dBINS","Build_Environment",
"IA64_Build_Tools","DDK",$bldno);
}
}
# --------------------------------------------------------------------------
COREDDK: {
if ($INCREMENTAL) {
last COREDDK unless ( defined $MAKECAB{COREDDK} );
}
system("dir $ENV{_NTPOSTBLD}\\ddk_flat /b/a-d > core.ddk.ini 2>nul");
# Create the .ini
CreateCAB( "core.ddk.ini","COREDDK","Build_Environment",
"DDK_Core_Files","DDK",$bldno);
}
# --------------------------------------------------------------------------
COREPDK: {
if ($INCREMENTAL) {
last COREPDK unless ( defined $MAKECAB{COREPDK} );
}
last COREPDK unless (-e "$ENV{_NTPOSTBLD}\\processor_flat\\src\\processor");
@dir_list1=`dir $ENV{_NTPOSTBLD}\\processor_flat\\src\\processor /b/a-d`;
foreach (@dir_list1) {
next if (m/^\s*$/);
chomp;
system("echo $ENV{_NTPOSTBLD}\\processor_flat\\src\\processor\\$_ >> pdkcore.ddk.ini");
}
# Create the .ini
CreateCAB( "pdkcore.ddk.ini","COREPDK","Build_Environment",
"PDK_Core_Files","processor",$bldno);
}
# --------------------------------------------------------------------------
COREHAL: {
if ($INCREMENTAL) {
last COREHAL unless ( defined $MAKECAB{COREHAL} );
}
last COREHAL unless (-e "$ENV{_NTPOSTBLD}\\hal_flat\\src\\hals");
@dir_list1=`dir $ENV{_NTPOSTBLD}\\hal_flat\\src\\hals /b/a-d`;
foreach (@dir_list1) {
next if (m/^\s*$/);
chomp;
system("echo $ENV{_NTPOSTBLD}\\hal_flat\\src\\hals\\$_ >> halcore.ddk.ini");
}
# Create the .ini
CreateCAB( "halcore.ddk.ini","COREHAL","Build_Environment",
"HAL_Core_Files","HAL",$bldno);
}
# --------------------------------------------------------------------------
COREIFS: {
if ($INCREMENTAL) {
last COREIFS unless ( defined $MAKECAB{COREIFS} );
}
last COREIFS unless (-e "$ENV{_NTPOSTBLD}\\ifs_flat");
@dir_list1=`dir $ENV{_NTPOSTBLD}\\ifs_flat\\src\\filesys /b/a-d`;
foreach (@dir_list1) {
next if (m/^\s*$/);
chomp;
system("echo $ENV{_NTPOSTBLD}\\ifs_flat\\src\\filesys\\$_ >> ifscore.ddk.ini");
}
# Create the .ini
CreateCAB( "ifscore.ddk.ini","COREIFS","Build_Environment",
"IFS_Core_Files","IFS",$bldno);
}
# --------------------------------------------------------------------------
DDKDOCS: {
if ($INCREMENTAL) {
last DDKDOCS unless ( defined $MAKECAB{DDKDOCS} );
}
# Make the Docs
opendir(hDir, "$ENV{_NTPOSTBLD}\\ddk_flat\\help")||warn("Can't open $ENV{_NTPOSTBLD}\\ddk_flat\\help: $!\n");
@dir_list1=readdir(hDir);
closedir(hDir);
my @general_cab;
foreach $file (@dir_list1) {
next if ($file =~ /^\./);
next if ($file =~ /\.chi$/); # Don't use .chi, use .chm below
next if (-d "$ENV{_NTPOSTBLD}\\ddk_flat\\help\\$file");
if ($file =~ /\.chm$/i) {
# We have a .chm
$file =~ s/\.chm$//i; # Remove the extension
system("dir $ENV{_NTPOSTBLD}\\ddk_flat\\help\\$file.* /s/b/a-d > $file.ddk.ini 2>nul");
$file=uc($file); # Force uppercase
# Create the .ini
CreateCAB( "$file.ddk.ini","$file","Documentation",
"${file}_Doc","DDK",$bldno);
} else {
system("dir $ENV{_NTPOSTBLD}\\ddk_flat\\help\\$file /s/b/a-d >> general_docs.ddk.ini 2>nul");
}
}
CreateCAB("general_docs.ddk.ini","CMNDOCS", "Documentation", "Common_Docs_Files", "DDK",$bldno);
}
# --------------------------------------------------------------------------
IFSDOCS: {
if ($INCREMENTAL) {
last IFSDOCS unless ( defined $MAKECAB{IFSDOCS} );
}
# Make the Docs
opendir(hDir, "$ENV{_NTPOSTBLD}\\ifs_flat\\help")||warn("Can't open $ENV{_NTPOSTBLD}\\ifs_flat\\help: $!\n");
@dir_list1=readdir(hDir);
closedir(hDir);
foreach $file (@dir_list1) {
next if ($file =~ /^\./);
next if ($file =~ /\.chi$/); # Don't use .chi, use .chm below
next if (-d "$ENV{_NTPOSTBLD}\\ifs_flat\\help\\$file");
if ($file =~ /\.chm$/i) {
# We have a .chm
$file =~ s/\.chm$//i; # Remove the extension
system("dir $ENV{_NTPOSTBLD}\\ifs_flat\\help\\$file.* /s/b/a-d > $file.ddk.ini 2>nul");
$file=uc($file); # Force uppercase
# Create the .ini
CreateCAB( "$file.ddk.ini","$file","Documentation",
"${file}_Doc","IFS",$bldno);
} else {
logdebug("Not including \\help\\$file\n");
}
}
}
# Don't exit until all subprocesses have completed.
WaitForAllProcesses();
if (-e "$ENV{_NTPOSTBLD}\\ddk_cd\\common\\cabs.in_") {
system("copy $ENV{_NTPOSTBLD}\\ddk_cd\\common\\cabs.in_ $ENV{_NTPOSTBLD}\\ddk_cd\\common\\cabs.ini >nul");
open(hF, ">>$ENV{_NTPOSTBLD}\\ddk_cd\\common\\cabs.ini");
print(hF "Build=$bldno\n");
close(hF);
}
if (-e "$ENV{_NTPOSTBLD}\\ifs_cd\\common\\cabs.in_") {
system("copy $ENV{_NTPOSTBLD}\\ifs_cd\\common\\cabs.in_ $ENV{_NTPOSTBLD}\\ifs_cd\\common\\cabs.ini >nul");
open(hF, ">>$ENV{_NTPOSTBLD}\\ifs_cd\\common\\cabs.ini");
print(hF "Build=$bldno\n");
close(hF);
}
if (-e "$ENV{_NTPOSTBLD}\\hal_cd\\common\\cabs.in_") {
system("copy $ENV{_NTPOSTBLD}\\hal_cd\\common\\cabs.in_ $ENV{_NTPOSTBLD}\\hal_cd\\common\\cabs.ini >nul");
open(hF, ">>$ENV{_NTPOSTBLD}\\hal_cd\\common\\cabs.ini");
print(hF "Build=$bldno\n");
close(hF);
}
if (-e "$ENV{_NTPOSTBLD}\\processor_cd\\common\\cabs.in_") {
system("copy $ENV{_NTPOSTBLD}\\processor_cd\\common\\cabs.in_ $ENV{_NTPOSTBLD}\\processor_cd\\common\\cabs.ini >nul");
open(hF, ">>$ENV{_NTPOSTBLD}\\processor_cd\\common\\cabs.ini");
print(hF "Build=$bldno\n");
close(hF);
}
$time = time() - $time;
logmsg("Total run time: $time seconds.\n");
print(STDERR "$0: Finished.\n\n");
END {
# Delete .tmp file so postbuild.cmd knows the script has finished
unlink ("$ENV{TEMP}\\ddkcabs.tmp");
}
# --------------------------------------------------------------------------
# Creates a CAB and INF from a list of files
# --------------------------------------------------------------------------
sub CreateCAB {
print(".") unless ($verbose); # Print something so the user knows the script is still running
my $filelist = shift;
my $cabname = shift;
my $groupname = shift;
my $samplename = shift;
my $kit = shift;
my $bldno = shift;
my $FileIndex = -1;
my $friendlyname = $samplename;
my $GroupIndex = -1;
my $InfCopyFileList = "InfFiles";
my $PrevCommand = "";
my $PrevDestDir = "";
my $TotalSize = 0;
my @files;
my $file;
my $FileProcessed;
my $hFILE;
my $NewSection;
my $source_file;
my $source_dir;
my $dest_dir;
my $ERRORLEVEL;
my $FileSize;
my $CabFileName;
chomp($cabname);
unless (-e $filelist) {
logerror("$filelist did not exist - cannot build cab.");
return(5);
}
# These files get rolled into the INF once the entire filelist
# is processed.
open(hFILE, ">${cabname}_DestDirsFiles")
|| die("Couldn't write to ${cabname}_DestDirsFile: $!\n");
printf(hFILE "[DestinationDirs]\n");
close(hFILE);
open(hFILE, ">${cabname}_SourceFiles")
|| die("Couldn't write to ${cabname}_SourceFiles: $!\n");
printf(hFILE "\n");
close(hFILE);
open(hFILE, ">${cabname}_SourceDisk")
|| die("Couldn't write to ${cabname}_SourceDisk: $!\n");
printf(hFILE "[SourceDisksFiles]\n");
close(hFILE);
#
# Process the filelist
#
open(hFILE, "$filelist");
@files=<hFILE>;
close(hFILE);
# For every file in the list, split it up into the format expected by genddkcab.bat:
# $source_dir, $source_file, $dest_dir, $dest_file, $command
foreach $file (@files) {
chomp($file);
$file =~ m/^(.*)\\.*$/;
# source_dir is %_NTPOSTBLD%\[ddk|hal|ifs]_flat + dest_dir
if (! defined($1)) {
$source_dir = "$ENV{_NTPOSTBLD}\\ddk_flat";
} else {
$source_dir = $1;
}
$file =~ m/^.*\\(.*)$/;
# source_file is filename
if (! defined($1)) {
$source_file = $file;
} else {
$source_file = $1;
}
$file =~ m/^.*_flat(\\.*\\).*$/;
# dest_dir is dir less %_NTPOSTBLD%\[ddk|hal|ifs]_flat
if (! defined($1)) {
$dest_dir= "\\";
} else {
$dest_dir= $1;
}
$FileProcessed=FALSE;
# Optimization to not generate excessive install sections in the inf.
$NewSection=TRUE;
$NewSection=FALSE if (uc($dest_dir) eq uc($PrevDestDir));
$PrevDestDir=$dest_dir;
if ($NewSection) {
$GroupIndex+=1;
open(hDDF, ">>${cabname}_DestDirsFiles");
printf(hDDF "Files_${GroupIndex}=49000,\"$dest_dir\"\n");
close(hDDF);
$InfCopyFileList="${InfCopyFileList},Files_${GroupIndex}";
open(hDDF, ">>${cabname}_SourceFiles");
printf(hDDF "[Files_${GroupIndex}]\n");
close(hDDF);
}
if (! -e "$source_dir\\$source_file") {
logerror("489: File $source_dir\\$source_file does not exist");
next;
}
# Move on to the next file number
$FileIndex += 1;
# Generate the name of the file within the cabfile.
$CabFileName="${cabname}_FILE_${FileIndex}";
# process the source file into the temporary cabfile name
$ERRORLEVEL=system("COPY $source_dir\\$source_file $CabFileName >nul 2>nul");
# check for errors
if ($ERRORLEVEL) {
logerror("545: COPY of file $source_dir\\$source_file failed (ErrorLevel $ERRORLEVEL)");
}
# Get the size of the file, so the size requirements of the cab can be computed.
$FileSize = (stat("$CabFileName"))[7];
printf("adding $CabFileName size $FileSize\n") if ($CABDEBUG);
$TotalSize += $FileSize;
# Write the DestinationFileName, CabFileName into the inf so the files
# can be extracted and installed properly.
open(hDDF, ">>${cabname}_SourceDisk")
|| die("Couldn't write to ${cabname}_SourceDisk: $!\n");;
printf(hDDF "${CabFileName}=1,,$FileSize\n");
close(hDDF);
open(hDDF, ">>${cabname}_SourceFiles");
printf(hDDF "$source_file,$CabFileName,,\n");
close(hDDF);
}
# If there were not files, just leave
if ($FileIndex == -1) {
logdebug("241: Skipping $cabname - no files in the cab");
unlink("$filelist") ||die("$!\n");;
unlink("${cabname}_SourceFiles") ||die("$!\n");;
unlink("${cabname}_SourceDisk") ||die("$!\n");;
unlink("${cabname}_DestDirsFiles")||die("$!\n");;
return(15);
}
if ($verbose) {
print STDERR "Creating $cabname\n";
}
# Create the INF
CreateINF($cabname, $friendlyname, $InfCopyFileList, $FileIndex, $TotalSize);
# start cabarc
CreateNewProcess($cabname, $kit);
# Delete the temporary file list
unlink("$filelist");
return(1);
}
# --------------------------------------------------------------------------
# Builds the installation inf
# --------------------------------------------------------------------------
sub CreateINF {
my $CabName = shift;
my $FriendlyName = shift;
my $InfCopyFileList = shift;
my $FileIndex = shift;
my $TotalSize = shift;
my @lines;
open(hFILE, ">>${CabName}.inf")||return(25);
print hFILE<<EOF;
[Version]
AdvancedInf = 2
Signature =\"\$CHICAGO\$\"
SetupClass = Base
[DefaultInstall]
CopyFiles=${InfCopyFileList}
CustomDestination= PDCDest
RequiredEngine = setupapi;
AddReg = RegVersion,DocKey
[DefaultUninstall]
DelFiles=${InfCopyFileList}
CustomDestination= PDCDest
DelReg = RegVersion,DocKey
EOF
open(hADDFILE, "<${CabName}_DestDirsFiles");
@lines=<hADDFILE>;
close(hADDFILE);
foreach (@lines) {
printf(hFILE "$_");
}
unlink("${CabName}_DestDirsFiles")||die("$!\n");;
print hFILE<<EOF;
InfFiles=17,\"msddk\\${bldno}\"
DefaultDestDir=49000,\"${CabName}\"
[RegVersion]
\"HKLM\",\"SOFTWARE\\Microsoft\\WINDDK\\Restart\\Cabs\",\"${CabName}\",0,\"done\"
[PDCDest]
49000,49001,49002=SDKCust, 17
[SDKCust]
;if key below exists, use this string to seed install path
\"HKLM\", \"Software\\Microsoft\\WINDDK\", \"SFNDirectory\",,\"%DefaultDir%\"
[DocKey]
[InfFiles]
${CabName}.inf
EOF
open(hADDFILE, "<${CabName}_SourceFiles");
@lines=<hADDFILE>;
close(hADDFILE);
foreach (@lines) {
printf(hFILE "$_");
}
unlink("${CabName}_SourceFiles")||die("$!\n");;
printf(hFILE "\n");
printf(hFILE "[SourceDisksNames]\n");
printf(hFILE "1=\"${CabName}.cab\",${CabName}.cab,0\n");
open(hADDFILE, "<${CabName}_SourceDisk");
@lines=<hADDFILE>;
close(hADDFILE);
foreach (@lines) {
printf(hFILE "$_");
}
unlink("${CabName}_SourceDisk")||die("$!\n");
$FileIndex++;
printf(hFILE "\n\n");
printf(hFILE "[Strings]\n");
printf(hFILE "FriendlyName=${FriendlyName}\n");
printf(hFILE "AppKey=SOFTWARE\\Microsoft\\WINDDK\n");
printf(hFILE "FileCount=${FileIndex}\n");
printf(hFILE "TotalSize=${TotalSize}\n");
close(hFILE);
return(0);
}
# --------------------------------------------------------------------------
# Starts a new process once there is room in the process table
# --------------------------------------------------------------------------
sub CreateNewProcess {
my $CabName = shift;
my $kit = shift;
my $ERRORLEVEL = 0;
my $ExitCode = 0;
my $i;
# Limit total running processes- label/goto construct needed because otherwise
# all processes are tested for instead of just finding the first one that has
# finished.
top:
while (@Processes >= $MAX_PROCESSES) {
for ($i=0;$i<=$#Processes;$i++) {
$Processes[$i][0]->GetExitCode( $ExitCode );
if ($ExitCode != 259 ) {
# Do post processes commands before removing it
$ERRORLEVEL= system("move /Y $Processes[$i][1].CAB $ENV{_NTPOSTBLD}\\$Processes[$i][2]_cd\\Common >nul 2>nul");
logerror("341: $Processes[$i][1].CAB could not be placed") if ($ERRORLEVEL);
$ERRORLEVEL= system("move /Y $Processes[$i][1].INF $ENV{_NTPOSTBLD}\\$Processes[$i][2]_cd\\Common >nul 2>nul");
logerror("342: $Processes[$i][1].INF could not be placed") if ($ERRORLEVEL);
$ERRORLEVEL=system("del /f $Processes[$i][1]_FILE_* 2>nul");
splice(@Processes,$i,1);
$i--; # Decrement count since the array changed
goto top;
}
}
sleep(2);
}
# Create the new process
Win32::Process::Create($i, $exe, "$exe $global_param ${CabName}.cab ${CabName}_FILE_*",
0, DETACHED_PROCESS, "$ENV{TEMP}");
# Update the process table
push(@Processes, [$i,$CabName,$kit]);
}
# --------------------------------------------------------------------------
# Waits for all currently running processes to finish
# --------------------------------------------------------------------------
sub WaitForAllProcesses {
my $i;
my $ERRORLEVEL = 0;
for ($i=0;$i<=$#Processes;$i++) {
# Wait for current process to end
print(".") unless ($verbose);
$Processes[$i][0]->Wait( INFINITE );
# Do post processes commands
$ERRORLEVEL= system("move /Y $Processes[$i][1].CAB $ENV{_NTPOSTBLD}\\$Processes[$i][2]_cd\\Common >nul 2>nul");
$ERRORLEVEL+=system("move /Y $Processes[$i][1].INF $ENV{_NTPOSTBLD}\\$Processes[$i][2]_cd\\Common >nul 2>nul");
logerror(__LINE__.": $Processes[$i][1] could not be placed") if ($ERRORLEVEL);
$ERRORLEVEL=system("del /f $Processes[$i][1]_FILE_* 2>nul");
}
print("\n");
}
# --------------------------------------------------------------------------
# Error logging routines
# --------------------------------------------------------------------------
sub logdebug { my($errormsg)="DEBUG_MSG : @_";
logprint($errormsg);
return(TRUE);}
sub logerror { my($errormsg)="ERROR_MSG : @_";
logprint($errormsg);
return(TRUE);}
sub logmsg { my($errormsg)="BUILD_MSG : @_";
logprint($errormsg);
return(TRUE);}
sub logprint { open(hLogFile,">>$handle")||warn("@_\n");
printf(hLogFile "$0 : @_\n");
close(hLogFile);
return(TRUE);}
# --------------------------------------------------------------------------
# Program description and usage
# --------------------------------------------------------------------------
sub Usage {
print "
Usage: $0 [-n <N>] [-f] [-l <language>] [-s] [-v]
This tool requires a Razzle window.
Generates CABs for the Kernelmode Development Kits. N, which is
optional, indicates the number of processes to start per processor.
The default value is 2.
By default, $0 will exit early if the environment variable
OFFICAL_BUILD_MACHINE is not defined. To override this behavior,
and for CAB generation, use -F.
-L is used, and any language other than 'usa' is passed, CAB
generation will not take place.
-V turns on verbose mode. See what cabs are being built.
-S spoofs full postbuild. (DDKCabs.bat otherwise relies upon build_number.cmd)
Dependencies:
o The following environment variables are expected to be defined:
%_NTDRIVE%, %_NTROOT%, %_BUILDARCH%, %_BUILDTYPE%, %_NTPOSTBLD%,
%RazzleToolPath%, %NUMBER_OF_PROCESSORS%, %TEMP%, and
%PROCESSOR_ARCHITECTURE%.
o The following directory trees are assumed to exist:
1) %_NTPOSTBLD%\\ddk_cd
2) %_NTPOSTBLD%\\ddk_flat
3) %_NTPOSTBLD%\\ifs_cd
4) %_NTPOSTBLD%\\ifs_flat
5) %_NTPOSTBLD%\\hal_cd
6) %_NTPOSTBLD%\\hal_flat
";
return(30);
}
# --------------------------------------------------------------------------
# List dependencies needed for this script.
# --------------------------------------------------------------------------
sub Dependencies {
if ( !open DEPEND, ">>$ENV{_NTPOSTBLD}\\..\\build_logs\\dependencies.txt" ) {
print STDERR "ERROR: Unable to open dependency list file.\n";
die;
}
print DEPEND<<DEPENDENCIES;
\[$0\]
IF {...} ADD {}
DEPENDENCIES
close DEPEND;
exit;
}
__END__
:endofperl