@rem =' @echo off REM ------------------------------------------------------------------ REM REM SYMCD.cmd REM Create Symbol CD. REM REM Copyright (c) Microsoft Corporation. All rights reserved. REM REM ------------------------------------------------------------------ perl -x "%~f0" %* goto :EOF REM '; #!perl use strict; use lib $ENV{RAZZLETOOLPATH} . "\\PostBuildScripts"; use lib $ENV{RAZZLETOOLPATH}; use PbuildEnv; use ParseArgs; use File::Basename; use IO::File; use Win32; use File::Path; use File::Copy; use IO::File; use Logmsg; use SymMake; use SymDelegate; # # SFS: SYMBOL FILESPECS # SFN: SYMBOL FILENAMES # ST: SYMBOL TOOL # SDIR: SYMBOL DIRECTORIES # SOPT: SYMBOL OPTIONS # COPT: COMMAND OPTIONS # my (%SFS, %SFN, %ST, %SDIR, %SOPT, %COPT); my ($NTPostBld, $BuildArch, $BuildType, $RazzleToolPath, $BuildLogs, $Lang, $CoverageBuild, $MungePath, $SymbolCD, $CabSize, $SymbolCDHandle, $Delegate, $ARCH, %DontShip, %SymBad ); # my ($Project); my ($Symbol_Path_Creator); sub Usage { print<>$ENV{_NTPOSTBLD}\\..\\build_logs\\dependencies.txt" ) { errmsg("Unable to open dependency list file."); die; } print DEPEND< \$Lang, # 'p:' => \$Project, 'm' => \$COPT{'NEED_MUNGE_PUBLIC'}, 't' => \$COPT{'NEED_ALL'}, '?' => \&Usage, 'plan' => \&Dependencies, 'qfe:' => \$qfe ); if ( -f "$ENV{_NTPOSTBLD}\\..\\build_logs\\skip.txt" ) { if ( !open SKIP, "$ENV{_NTPOSTBLD}\\..\\build_logs\\skip.txt" ) { errmsg("Unable to open skip list file."); die; } while () { chomp; exit if lc$_ eq lc$0; } close SKIP; } &main; # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # main() # - symcd main function; according the $SOPT (symcd options) to do below steps, # 1. munge public symbols, # 2. create symbols.inf, symbols.cdf and symbols.ddf, # 3. according symbols(n).ddf and symbols.cdf, create symbols(n).cab and symbols.cat # 4. merge symbols(n).cab to symbols.cab # 5. sign symbols.cab and symbols.cat # PS. for 2 - 5, we create both update and full packages # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * sub main { my (%pkinfo, $symcd); my $pkinfoptr = \%pkinfo; &Initial_Variables(); # If localize builds, do nothing if (!&IsUSA() and !$qfe) { logmsg "Language = $Lang. Do not create symbolcd."; return; } &Prepare_Reference_Files(); &Munge_Public() if ($SOPT{'NEED_MUNGE_PUBLIC'}); if ($SOPT{'NEED_CREATE_SYMBOLCD_TXT'}) { if ($SOPT{'USE_SYMLIST'}) { # &Create_SymbolCD_TXT_1_field(); errmsg("Cannot find the symupd.txt"); } else { Create_SymbolCD_TXT_3_fields(); } } # create symbols.inf, symbols.cdf and symbols(n).ddf &Create_Make_File($pkinfoptr) if ($SOPT{'NEED_CREATE_MAKE_FILE'}); undef $symcd; # Free memory; unload full symbolcd.txt &Create_SymbolCAT() if ($SOPT{'NEED_CREATE_SYMBOLCAT'}); &Create_SymbolCAB($pkinfoptr) if ($SOPT{'NEED_CREATE_SYMBOLCAB'}); $Delegate->Start() if (($SOPT{'NEED_CREATE_SYMBOLCAT'} ne '') || ($SOPT{'NEED_CREATE_SYMBOLCAB'} ne '')); while(!$Delegate->AllJobDone()) {$Delegate->CompleteAll(); sleep 5;} &Merge_SymbolCAB($pkinfoptr) if ($SOPT{'NEED_CREATE_SYMBOLCAB'}); &Sign_Files($pkinfoptr) if ($SOPT{'NEED_SIGN_FILES'}); } # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Munge public symbols # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * sub Munge_Public { my ($filename, $filepath, $fileext); my ($mySymbol, $mySymbolPath, $myBinary, $myMungePath, $oldMungePath, $newMungePath); my ($c_ext, @myCompOpt); my ($optCL, $optML, $optLINK); my @ppdirs = &Exists("$MungePath\\*.*"); @myCompOpt = @ENV{qw(_CL_ _ML_ _LINK_)} if (lc$ENV{'_BuildArch'} eq 'x86'); logmsg("Adding type info to some public pdb files for debugging..."); for (@ppdirs) { next if (!-d); ($filename, $filepath, $fileext) = FileParse($_); if (length($fileext) ne '3') { errmsg("$_ name has the wrong format."); return; } $mySymbol = &SymbolPath("$NTPostBld\\symbols", "retail", "$filename\.$fileext"); $mySymbolPath = &SymbolPath("$NTPostBld\\symbols", "retail"); $myBinary = "$NTPostBld\\$filename\.$fileext"; if (-f $mySymbol) { $myMungePath = "$MungePath\\$filename\.$fileext"; ($oldMungePath, $newMungePath) = ("$myMungePath\\original", "$myMungePath\\updated"); logmsg("Working on $filename\.$fileext"); ## See if we need to do anything, or if the symbol file has already been updated ## If the symbol file passes symbol checking, with types present then don't update it. if (!&IsSymchkFailed($myBinary, $mySymbolPath, "/o")) { logmsg("Skipping $filename\.$fileext because it's public pdb already has type info in it."); next; } mkpath([$oldMungePath, $newMungePath]); ## See if the pdb, if it exists, in original matches the exe in binaries if (&IsSymchkFailed($myBinary, $oldMungePath, $SOPT{'PUB_SYM_FLAG'})) { logmsg("Saving a copy of $filename\.pdb to $oldMungePath"); copy($mySymbol, $oldMungePath) or errmsg("copy $mySymbol to $oldMungePath failed."); if (&IsSymchkFailed($myBinary, $oldMungePath, $SOPT{'PUB_SYM_FLAG'})) { errmsg("cannot copy the correct pdb file to $oldMungePath\."); next; } } if (&Exists("$myMungePath\\*.*") > 0) { if (!copy("$oldMungePath\\$filename\.pdb", $newMungePath)) { errmsg("copy failed for $oldMungePath\\$filename\.pdb to $newMungePath\."); next; } logmsg("Pushing type info into the stripped $filename\.pdb"); $c_ext = (-e "$myMungePath\\$filename\.c")? "c": "cpp"; if (&IsVC7PDB("$newMungePath\\$filename\.pdb")) { logmsg("This is a vc7 pdb"); @ENV{qw(_CL_ _ML_ _LINK_)} = (); } else { logmsg("This is a vc6 pdb"); @ENV{qw(_CL_ _ML_ _LINK_)} = @myCompOpt; } logmsg("cl /nologo /Zi /Gz /c $myMungePath\\$filename\.$c_ext /Fd" . "$newMungePath\\$filename\.pdb /Fo" . "$newMungePath\\$filename\.obj"); if (system("cl /nologo /Zi /Gz /c $myMungePath\\$filename\.$c_ext /Fd" . "$newMungePath\\$filename\.pdb /Fo" . "$newMungePath\\$filename\.obj") > 0) { errmsg("cl /Zi /Gz /c $myMungePath\\$filename\.$c_ext /Fd" . "$newMungePath\\$filename\.pdb had errors."); next; } if (&IsSymchkFailed($myBinary, $newMungePath, "/o $SOPT{'PUB_SYM_FLAG'}")) { errmsg("the munged $newMungePath\\$filename\.pdb doesn't match $myBinary."); next; } logmsg("Copying $newMungePath\\$filename\.pdb to $mySymbolPath\\$fileext"); copy("$newMungePath\\$filename\.pdb", "$mySymbolPath\\$fileext"); if (&IsSymchkFailed($myBinary, $mySymbolPath, "/o $SOPT{'PUB_SYM_FLAG'}")) { copy("$oldMungePath\\$filename\.pdb", "$mySymbolPath\\$fileext"); errmsg("the munged $newMungePath\\$filename\.pdb didn't get copied to $mySymbolPath\\$fileext\."); logmsg("Copying the original pdb back to $mySymbolPath\\$fileext"); copy("$oldMungePath\\$filename\.$fileext", "$mySymbolPath\\$fileext") or do { errmsg("cannot get $filename\.$fileext symbols copied to $mySymbolPath\\$fileext\."); next; } } } } else { logmsg("Skipping $filename\.$fileext because $mySymbol does not exist."); } } @ENV{qw(_CL_ _ML_ _LINK_)} = @myCompOpt if (lc$ENV{'_BuildArch'} eq 'x86'); return; } # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Create symbolcd.txt from a 3 fields (bin,pri,pub) symupd.txt # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * sub Create_SymbolCD_TXT_3_fields { my ($fh, $bin, $pri, $pub, $binname, $binext, $pubname, $pubpath, $pubext, $pripath, $symbol, $availsym, $weight, $binnameext); my ($symdontship, $pubdontexist, $pubdontmatch, $badpubdontmatch, $symdorec, $dupsymdomatch, $dupsymdontmatch) = (0) x 7; my $duplicate = {}; my (@results, @lists); local $_; logmsg("Examining the update list to compute the list of symbol files ..."); # Read symupd.txt $fh = new IO::File $SFS{'SYMUPD'}; while (<$fh>) { chomp; next if (!/\S/); ($bin, $pri, $pub) = split(/\,/, $_); # skip if not defined $pub if ($pub !~ /\S/) { logmsg("Skipping $bin - Reason \#1."); $pubdontexist++; next; } # # $weight = 2 if public symbol file path starts with symbols\retail # = 1 if public symbol file path starts with symbols, but not with symbols\retail # = 0 if public symbol file path doesn't start with symbols # # We will sort first by weight in order to give priority to symbol file that are in these directories. # This is to give priority to US symbols and symbols in symbols\retail over symbols for various languages. # Also it gives priority to symbols in symbols\retail versus symbols in other directories like symbols\idw. # # One case that this is trying to solve is the SP drop of spuninst.dll, update.exe and spcustom.dll where # all the languages work with the US symbols, but each language has a symbol file checked in that is different. # The symbols work, but the only difference is a path in the symbol file. This is happened during the BBT process # and the SP team checked in the actual symbols that got created for each language. In this case, they won't get # errors because symchk passes for all of them with the US symbol. We do the sort by weight in order to give # preference to the US symbol. # $weight = ($pub=~/^symbols[^\\]*\\(retail)?/i)?((defined $1)?2:1):0; push @lists, [$bin, $pri, $pub, $weight]; } $fh->close(); # Sort symupd.txt by symbols\retail first @results = sort {&sort_symupd($a,$b)} @lists; undef @lists; # Write to symbolcd.txt $SymbolCDHandle = new IO::File ">" . $SFS{'CD'}; N1: for (@results) { # N1: while (<$fh>) { ($bin, $pri, $pub) = @{$_}; ($binname, $binext) = (FileParse($bin))[0,2]; ($pubname, $pubpath, $pubext) = FileParse($pub); ($binnameext) = (fileparse($bin))[0]; $symbol = "$pubname\.$pubext"; $pripath = (FileParse($pri))[1]; # skip if the binary name is in symdontship.txt if (exists $DontShip{lc"$binname\.$binext"}) { logmsg("Skipping $bin - Reason \#2."); # logmsg("Skipping $bin because it\'s in symdontship.txt."); $symdontship++; next; } # skip if the public symbol file is not defined or is a directory if (!-f "$NTPostBld\\$pub") { logmsg("Skipping $bin - Reason \#1."); $pubdontexist++; next; } if (!-f "$NTPostBld\\$pri") { logmsg("Warnning - private symbols ($pri) for $bin does not exist."); } # skip if the public symbols does not match the binary if (&IsSymchkFailed("$NTPostBld\\$bin", "$NTPostBld\\$pubpath", $SOPT{'PUB_SYM_FLAG'})) { if (!exists $SymBad{lc(basename($bin))}) { errmsg("Error - symbols $pub does not match with $bin"); # because it\'s public pdb $pub does not match with its binary"); $pubdontmatch++; } else { logmsg("Skipping $bin - Reason \#3."); # bad symbols for $bin because it\'s public pdb $pub does not match"); $badpubdontmatch++; } next; } if (&IsSymchkFailed("$NTPostBld\\$bin", "$NTPostBld\\$pripath")) { logmsg("Warnning - private pdb ($pri) does not match with its binary $bin."); } if (exists $duplicate->{$binnameext}->{$symbol}) { if ((exists $duplicate->{$binnameext}->{$symbol}->{$bin}) || (exists $duplicate->{$binnameext}->{$symbol}->{$pub})) { $symdorec++; next; } # Because we record binary name and symbol, we loop each key to get public symbol path for $availsym (keys %{$duplicate->{$binnameext}->{$symbol}}) { next if ($availsym !~ /(pdb|dbg)$/i); # ignore the binary # # If the file passes with the symbol we have already put into symbolcd.txt, then ignore this and don't # put the duplicate symbol into symbolcd.txt. Since symchk passes, don't give an error saying that there # are duplicates # if (!&IsSymchkFailed("$NTPostBld\\$bin", dirname("$NTPostBld\\$availsym"), $SOPT{'PUB_SYM_FLAG'})) { $dupsymdomatch++; next N1; } } if (exists $SymBad{lc(basename($bin))}) { logmsg("Skipping $bin - Reason \#3."); # bad symbols for $bin because it\'s public pdb $pub does not match"); $badpubdontmatch++; next; } errmsg("Error - $bin has duplicate symbols ($pub) and mismatch with other symbols."); # $bin has the same symbol file $symbol with other binaries"); $dupsymdontmatch++; next; } print $SymbolCDHandle "$bin,$pubname\.$pubext,$pub,$binext\n"; #$symbol,$subsympath,$installpathname\n"; $duplicate->{$binnameext}->{$symbol}->{$bin} = 1; $duplicate->{$binnameext}->{$symbol}->{$pub} = 1; } $SymbolCDHandle->close(); logmsg(sprintf("Reason 1: %d files skipped because its public symbols is not exist.", $pubdontexist)); logmsg(sprintf("Reason 2: %d files skipped because its in symdontship.txt.", $symdontship)); logmsg(sprintf("Reason 3: %d files skipped because the public symbol file does not match but listed in symbad.txt.", $badpubdontmatch)); logmsg(sprintf("Reason 4: %d files skipped because it is a duplicate line in update list", $symdorec)); logmsg(sprintf("Reason 5: %d files skipped because the binary match with other exist symbols", $dupsymdomatch)); logmsg(sprintf("Error 1: %d files were errors because the public symbol file does not match with its binary.", $pubdontmatch)); logmsg(sprintf("Error 2: %d files were errors because the public symbol file has duplicate install path with other symbols.", $dupsymdontmatch)); logmsg(sprintf("Total files skipped + error = %d", $symdontship + $pubdontexist + $pubdontmatch + $badpubdontmatch + $symdorec + $dupsymdomatch + $dupsymdontmatch)); } # # sort_symupd($a,$b) # - Sort first by the $weight (hight to low) and then second by the path and name of the binary in alphabetical order. # The second sort is equivalent to the order that symupd.txt is given to the script in the first place. # - we keep this function here for easy reference (see Create_SymbolCD_TXT_3_fields) # sub sort_symupd { return ($_[1]->[3] <=> $_[0]->[3]) or ($_[0]->[0] cmp $_[1]->[0]); } # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Create_Make_File($pkinfoptr) # - Create the make file (symbols.ddf, symbols.cdf and symbols.inf) # # IN: an empty packageinfo hash reference # # OUT: none # # REMARK: it store package information to $pkinfoptr # for example, $pkinfoptr->{'FULL'} = # 'CABNAME' = $SDIR{'FULL_CAB'}\\$SFN{'FULL_CAB'} # ... # # we store information to $pkinfoptr, because SymMake::Create_Symbols_DDF, SymMake::Create_Symbols_CDF, # and SymMake::Create_Symbols_IDF are working with $pkinfoptr # # and, $pkinfoptr->{'DDFLIST'} stored the ddf filenames we created from SymMake::Create_Symbols_DDF # according this, we can check the makecab process make the cab or not # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * sub Create_Make_File { my ($pkinfoptr) = @_; my ($symcd, $packagetype); if (defined $CoverageBuild) { logmsg("Coverage build ... skipping making the cab file"); return; } logmsg("Creating the makefile and the DDF's for creating the cabs"); $symcd = new SymMake $ARCH, $NTPostBld; for $packagetype (qw(FULL UPDATE)) { &SymMake::RegisterPackage($pkinfoptr, $packagetype, { 'CABNAME' => $SDIR{$packagetype . '_CAB'} . '\\' . $SFN{$packagetype . '_CAB'}, 'DDFNAME' => $SDIR{$packagetype . '_DDF'} . '\\' . $SFN{$packagetype . '_DDF'}, 'INFNAME' => $SDIR{$packagetype . '_INF'} . '\\' . $SFN{$packagetype . '_INF'}, 'CDFNAME' => $SDIR{$packagetype . '_CDF'} . '\\' . $SFN{$packagetype . '_CDF'}, 'CATNAME' => $SDIR{$packagetype . '_CAT'} . '\\' . $SFN{$packagetype . '_CAT'}, 'CABSIZE' => $CabSize, }); # register the package type ('FULL' or 'UPDATE') $symcd->{'PKTYPE'} = $packagetype; # read "$ARCH\\symbolcd\\symbolcd.txt" for 'FULL' and $ENV{_NTPOSTBLD}\\symbolcd\\symbolcd.txt for 'UPDATE' $symcd->ReadSource(); } # create symbols.ddf, symbols.cdf and symbols.inf $symcd->Create_Symbols_DDF($pkinfoptr); # Return $pkinfoptr->{$packagetype}->{CABLIST} $symcd->Create_Symbols_CDF($pkinfoptr); $symcd->Create_Symbols_INF($pkinfoptr); undef $symcd; } # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Create_SymbolCAT($packagetype) # - add job to job queue for creating symbols.cat (symcab.cmd -f $SFN{'FULL_CDF'} -s $SDIR{'FULL_CDF'} -t 'CAT' -d $SDIR{'FULL_CAT'}) # - register checkexistsub the verifying function # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * sub Create_SymbolCAT { my ($packagetype); for $packagetype (qw(FULL UPDATE)) { my $chkexistsub = &Check_Exist_File( $SDIR{$packagetype . '_CAT'} . '\\' . $SFN{$packagetype . '_CAT'} . '.CAT', $SDIR{$packagetype . '_CDF'} . '\\' . $SFN{$packagetype . '_CDF'} . '.CAT.LOG'); logmsg("Delegating to create $SFN{$packagetype . '_CAT'}\.CAT"); $Delegate->AddJob($packagetype . '_CATALOG', "$ST{'CAB'} " . join(' ', '-f' => $SFN{$packagetype . '_CDF'}, '-s' => $SDIR{$packagetype . '_CDF'}, '-t' => 'CAT', '-d' => $SDIR{$packagetype . '_CAT'}), $chkexistsub, 1); # priority } } # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Create_SymbolCAB($packagetype) # - add job to job queue for creating symbols(n).cab (symcab.cmd -f $ddfname -s $SDIR{'FULL_DDF'} -t 'CAB' -d $SDIR{'FULL_CAB'}) # - register checkexistsub the verifying function # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * sub Create_SymbolCAB { my ($pkinfoptr) = shift; my ($packagetype, $ddfname, $cabname); for $packagetype (qw(FULL UPDATE)) { logmsg("Delegating to create $SFN{$packagetype . '_CAB'}\.CAB"); for $ddfname (keys %{$pkinfoptr->{$packagetype}->{'DDFLIST'}}) { my $chkexistsub; next if (!-e $ddfname); $cabname = (FileParse($pkinfoptr->{$packagetype}->{'DDFLIST'}->{$ddfname}))[0]; $ddfname = (FileParse($ddfname))[0]; $chkexistsub = &Check_Exist_File( $SDIR{$packagetype . '_CAB'} . '\\' . $cabname . '.CAB', $SDIR{$packagetype . '_DDF'} . '\\' . $ddfname . '.CAB.LOG'); $Delegate->AddJob($packagetype . $ddfname . '_CAB', "$ST{'CAB'} " . join(' ', '-f' => $ddfname, '-s' => $SDIR{$packagetype . '_DDF'}, '-t' => 'CAB', '-d' => $SDIR{$packagetype . '_CAB'}), $chkexistsub, $ddfname); } } } # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Merge_SymbolCAB($pkinfoptr) # - merge the symbols(n).cab to symbols.cab with cabbench.exe # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * sub Merge_SymbolCAB { my ($pkinfoptr) = shift; my ($packagetype, $mergecommand, $cabname); $pkinfoptr->{'FULL'}->{'DDFLIST'} = {%{$pkinfoptr->{'FULL'}->{'DDFLIST'}}, %{$pkinfoptr->{'UPDATE'}->{'DDFLIST'}}}; for $packagetype (qw(FULL UPDATE)) { # If there is no cab generated, we don't merge 'nothing'. next if (scalar(values %{$pkinfoptr->{$packagetype}->{'DDFLIST'}}) eq 0); logmsg("Merging cabs into $SFN{$packagetype . '_CAB'}\.cab"); $mergecommand = ""; for $cabname (sort values %{$pkinfoptr->{$packagetype}->{'DDFLIST'}}) { $mergecommand .= 'load ' . $cabname . ' merge '; } $mergecommand .= 'save ' . $SDIR{$packagetype . '_PKG'} . '\\' . $SFN{$packagetype . '_CAB'} . '.cab'; # According the cabbench syntax, remove first merge $mergecommand =~ s/ merge / /; system("$ST{'BENCH'} $mergecommand"); } } # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Sign_Files() # - sign the exist cab and cat files # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * sub Sign_Files { my ($packagetype, $myBuildType, $myBuildArch, $mypkgdir, $catfile, %signhash); logmsg("Test signing files on CD"); for $packagetype (qw(FULL UPDATE)) { for $myBuildType (qw(fre chk)) { for $myBuildArch (qw(x86 amd64 ia64)) { $mypkgdir = &{$Symbol_Path_Creator->{$packagetype}}($SDIR{$packagetype . '_CD'} . '\\Symbols', $myBuildArch, $myBuildType); $catfile = $mypkgdir . $SFN{'CAT'} . '.CAT'; if ((!exists $signhash{lc$mypkgdir}) && (-e $catfile)) { system("$ST{'SIGN'} $catfile"); } } } } } # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Initial variables # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * sub Initial_Variables { # Set Variables $Lang = $ENV{'LANG'} if ("$Lang" eq ""); $ENV{'LANG'} = $Lang; $BuildArch = $ENV{'_BuildArch'}; $BuildType = $ENV{'_BuildType'}; $NTPostBld = $ENV{'_NTPostBld'}; # $NTPostBld = "d:\\Ins_Sym\\$Project\\$Lang"; $MungePath = "$NTPostBld\\pp"; $SymbolCD = "$NTPostBld\\SymbolCD"; $RazzleToolPath = $ENV{'RazzleToolPath'}; $BuildLogs = "$NTPostBld\\build_logs"; $CabSize = 60000000; $SymbolCDHandle = ''; $Delegate = new Delegate 3, $ENV{'NUMBER_OF_PROCESSORS'} * 4; # $ARCH = "\\\\arch\\archive\\ms\\windows\\windows_xp\\rtm\\2600\\$BuildType\\all\\$BuildArch\\pub"; $ARCH = "d:\\Ins_Sym\\Win2k\\$Lang\\symbols"; $Symbol_Path_Creator = { 'FULL' => \&Full_Package_Path, 'UPDATE' => \&Update_Package_Path }; # SDIR: SYMBOL DIRECTORIES %SDIR = ( 'SYMBOLCD' => $SymbolCD, 'PUBSYM' => "$NTPostBld\\Symbols", 'FULL_CD' => "$NTPostBld\\SymbolCD\\CD", 'FULL_PKG' => &{$Symbol_Path_Creator->{'FULL'}}("$NTPostBld\\SymbolCD\\CD\\Symbols", $BuildArch, $BuildType), 'FULL_INF' => &{$Symbol_Path_Creator->{'FULL'}}("$NTPostBld\\SymbolCD\\CD\\Symbols", $BuildArch, $BuildType), 'FULL_CAB' => "$SymbolCD\\CABs\\FULL", 'FULL_DDF' => "$SymbolCD\\DDF\\FULL", 'FULL_CDF' => "$SymbolCD\\DDF\\FULL", 'FULL_CAT' => &{$Symbol_Path_Creator->{'FULL'}}("$NTPostBld\\SymbolCD\\CD\\Symbols", $BuildArch, $BuildType), 'UPDATE_CD' => "$NTPostBld\\SymbolCD\\UPD", 'UPDATE_PKG' => &{$Symbol_Path_Creator->{'UPDATE'}}("$NTPostBld\\SymbolCD\\UPD\\Symbols", $BuildArch, $BuildType), 'UPDATE_INF' => &{$Symbol_Path_Creator->{'UPDATE'}}("$NTPostBld\\SymbolCD\\UPD\\Symbols", $BuildArch, $BuildType), 'UPDATE_CAB' => "$SymbolCD\\CABs\\UPDATE", 'UPDATE_DDF' => "$SymbolCD\\DDF\\UPDATE", 'UPDATE_CDF' => "$SymbolCD\\DDF\\UPDATE", 'UPDATE_CAT' => &{$Symbol_Path_Creator->{'UPDATE'}}("$NTPostBld\\SymbolCD\\UPD\\Symbols", $BuildArch, $BuildType), ); # SFS: SYMBOL FILESPECS %SFS = ( 'CD' => $SDIR{'SYMBOLCD'} . '\\SymbolCD.txt', 'BLDNUM' => &{$Symbol_Path_Creator->{'FULL'}}("$NTPostBld\\SymbolCD\\CD\\Symbols", $BuildArch, $BuildType) . "\\QFEnum.txt", 'LIST' => $SDIR{'SYMBOLCD'} . '\\SymList.txt', 'BAD' => $SDIR{'SYMBOLCD'} . '\\SymBad.txt', 'SYMUPD' => $SDIR{'SYMBOLCD'} . '\\SymUpd.txt', 'CAGENERR' => $SDIR{'SYMBOLCD'} . '\\cabgenerr.log', 'EXCLUDE' => $SDIR{'SYMBOLCD'} . '\\Exclude.txt', 'BINDIFF' => $BuildLogs . '\\bindiff.txt', 'WITHTYPES' => $SDIR{'SYMBOLCD'} . '\\SymbolsWithTypes.txt', 'DONTSHIP' => $SDIR{'SYMBOLCD'} . '\\SymDontShip.txt' ); # SFN: SYMBOL FILENAMES %SFN = ( 'FULL_INF' => 'Symbols', 'FULL_CAB' => 'Symbols', 'FULL_DDF' => 'Symbols', 'FULL_CDF' => 'Symbols', 'FULL_CAT' => 'Symbols', 'UPDATE_INF' => 'Symbols', 'UPDATE_CAB' => 'Symbols', 'UPDATE_DDF' => 'Symbols', 'UPDATE_CDF' => 'Symbols', 'UPDATE_CAT' => 'Symbols', ); # ST: SYMBOL TOOL %ST = ( 'MAKE' => "symmake.exe", 'PERL' => "perl.exe", 'CHECK' => "symchk.exe", 'BENCH' => "cabbench.exe", 'DUMP' => "pdbdump.exe", 'SIGN' => $RazzleToolPath . "\\ntsign.cmd", 'CAB' => $RazzleToolPath . "\\sp\\symcab.cmd" ); # SOPT: SYMBOL OPTIONS # # the default option is doing all steps # %SOPT = ( 'PUB_SYM_FLAG' => '/p', 'GOLD_BUILD' => 1, 'RUN_ALWAYS' => 1, 'NEED_MUNGE_PUBLIC' => undef, 'NEED_CREATE_SYMBOLCD_TXT' => undef, 'NEED_CREATE_MAKE_FILE' => 1, 'NEED_CREATE_SYMBOLCAT' => 1, 'NEED_CREATE_SYMBOLCAB' => 1, 'NEED_SIGN_FILES' => 1, 'NEED_FLAT_DIR' => 1, 'NEED_CLEAN_BUILD' => 1, 'FLAT_SYMBOL_PATH' => undef, 'USE_SYMLIST' => undef ); if ((defined $COPT{'NEED_ALL'}) && (defined $COPT{'NEED_MUNGE_PUBLIC'})) { errmsg("Error options! Please specify either -m or -t"); exit(1); } # if neither is official build machine, nor assign -t in command line, # or if is official build machine, but assign -m in command line, # # we will only munge public symbols # if (((!exists $ENV{'OFFICIAL_BUILD_MACHINE'}) && (!defined $COPT{'NEED_ALL'})) || ((exists $ENV{'OFFICIAL_BUILD_MACHINE'}) && (defined $COPT{'NEED_MUNGE_PUBLIC'}))) { @SOPT{qw(NEED_MUNGE_PUBLIC NEED_CREATE_SYMBOLCD_TXT NEED_CREATE_MAKE_FILE NEED_CREATE_SYMBOLCAT NEED_CREATE_SYMBOLCAB NEED_SIGN_FILES)} = (1, undef, undef, undef, undef, undef); } # if ($SOPT{'NEED_CLEAN_BUILD'}) { # rmtree([@SDIR{qw(FULL_DDF FULL_CD FULL_CAB UPDATE_DDF UPDATE_CD UPDATE_CAB)}]); # } } # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Prepare_Reference_Files # - prepare the files we referenced in the program or for symbol testing # - we prepare below files # exclude.txt, symbolswithtypes.txt, symdontship.txt, symbad.txt # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * sub Prepare_Reference_Files { my ($exclude, $filename, @filelist, @filelist2); my ($symlistwithtypes, $symdontship, $symbad); # Make paths mkpath([values %SDIR]); # If GOLD build if ( ) { $ENV{'TEMP'} = "$ARCH\\symbolcd"; mkpath([$ENV{'TEMP'}]); } return; # Exclude.txt if (!-e $SFS{'EXCLUDE'}) { $exclude = new IO::File $SFS{'EXCLUDE'}, 'w'; copy($RazzleToolPath . '\\symdontship.txt', $exclude) or errmsg("copy symdontship.txt to $SFS{'EXCLUDE'} failed."); autoflush $exclude 1; copy($RazzleToolPath . '\\symbolswithtypes.txt', $exclude) or errmsg("copy symbolswithtypes.txt to $SFS{'EXCLUDE'} failed."); $exclude->close(); } # SymbolsWithTypes.txt $symlistwithtypes = new IO::File "$RazzleToolPath\\symbolswithtypes.txt"; chomp(@filelist = <$symlistwithtypes>); $symlistwithtypes->close(); $symlistwithtypes = new IO::File $SFS{'WITHTYPES'}, 'w'; for $filename (@filelist) { print $symlistwithtypes $NTPostBld . '\\' . $filename . "\n"; } $symlistwithtypes->close(); # SymDontShip.txt copy("$RazzleToolPath\\SymDontShip.txt", $SFS{'DONTSHIP'}); $symdontship = new IO::File "$RazzleToolPath\\SymDontShip.txt", 'r'; chomp(@filelist = <$symdontship>); @filelist2 = map({s/\s*\;.*$//;($_ eq '')?():lc$_;} @filelist); $symdontship->close(); @DontShip{@filelist2} = (1) x ($#filelist2 + 1); # SymBad.txt copy("$RazzleToolPath\\SymBad.txt", $SFS{'BAD'}); $symbad = new IO::File $SFS{'BAD'}, 'r'; chomp(@filelist=<$symbad>); @filelist2 = map({s/\s*\;.*$//;($_ eq '')?():lc$_;} @filelist); $symbad->close(); @SymBad{@filelist2} = (1) x ($#filelist2 + 1); # QFEnum.txt # we put current build number into the symbol install directory for the Customer Support CD # we could use it to determine the which build the symbols CD belong to # copy("$NTPostBld\\congeal_scripts\\__qfenum__", $SFS{'BLDNUM'}) if (-e "$NTPostBld\\congeal_scripts\\__qfenum__"); if (-e $SFS{'SYMUPD'}) { $SOPT{'USE_SYMLIST'} = undef; } elsif (-e $SFS{'LIST'}) { $SOPT{'USE_SYMLIST'} = 'yes'; } elsif ($SOPT{'NEED_CREATE_MAKE_FILE'}) { logmsg("Either $SFS{'SYMUPD'} or $SFS{'LIST'} need to be provided."); logmsg("No update. exit."); exit; } } #################################################################################### # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Small Subroutine # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # IsSymchkFailed($binary, $symbol, $extraopt) # - call symchk.exe to verify $binary matches with $symbol # sub IsSymchkFailed { my ($binary, $symbol, $extraopt) = @_; my ($fh, $record_error, $record_log, $result); local $_; if (defined $extraopt) { if ($extraopt =~ /2\>/) { $record_error = 1; } if ($extraopt =~ /[^2]\>/) { $record_log = 1; } $extraopt =~ s/2?\>.*$//g; } $fh = new IO::File "$ST{'CHECK'} /t $binary /s $symbol $extraopt |"; while (<$fh>) { chomp; $result = $1 if /FAILED files = (\d+)/; logmsg($_) if ($record_log); logmsg($_) if (($record_error) && (/^ERROR/i)); } undef $fh; return $result; } # # SymbolPath($root, $subdir, $filename) # - return the symbol path for the binary # sub SymbolPath { my ($root, $subdir, $filename) = @_; $root .= "\\$subdir" if (!$SOPT{'FLAT_SYMBOL_PATH'}); if (defined $filename) { $filename =~ /\.([^\.]+)$/; $root .= "\\$1\\$`"; return "$root\.pdb" if (-e "$root\.pdb"); return "$root\.dbg" if (-e "$root\.dbg"); $root .= ".pdb"; } return $root; } # # Full_Package_Path($root, $myarch, $mytype) # - for compatible reason, we create a function to construct the path of the symbols.exe of the full package # sub Full_Package_Path { my ($root, $myarch, $mytype) = @_; $mytype =~ s/fre/retail/ig; $mytype =~ s/chk/debug/ig; return "$root\\$myarch\\$mytype"; # temporary } # # Update_Package_Path($root, $myarch, $mytype) # - for compatible reason, we create a function to construct the path of the symbols.exe of the update package # sub Update_Package_Path { my ($root, $myarch, $mytype) = @_; return $root; # \\$myarch\\$mytype"; # temporary } # # IsVC7PDB($pdbspec) # - because the MD5 hash value is 0000-0000-0000-000000000000 for the symbols built by VC6 or older # - we can use it to determine the pdb is VC7 or not # sub IsVC7PDB { my ($pdbspec) = shift; my $fh = new IO::File "$ST{'DUMP'} $pdbspec hdr |"; local $_; while (<$fh>) { return 0 if /0000-0000-0000-000000000000/i; } return 1; } # # Check_Exist_File($filename, $logfile) # - this is a function generator, which generates a function for checking the $filename exist or not # - it also check if the $logfile has 'ERROR:' in it # sub Check_Exist_File { my ($filename, $logfile) = @_; return sub { if (-e $filename) { return 1; } else { my $fh = new IO::File $logfile; for (<$fh>) { chomp; next if (!/.+ERROR\: /i); errmsg("Error - $'"); } $fh->close(); logmsg("$filename did not get created."); return 0; } }; } # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # # Common Subroutine # # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * sub FileParse { my ($name, $path, $ext) = fileparse(shift, '\.[^\.]+$'); $ext =~ s/^\.//; return $name, $path, $ext; } sub IsUSA { # return (lc$ENV{'lang'} eq 'usa'); return 1; } sub Exists { my @list = glob(shift); return (wantarray)?@list:$#list + 1; } 1; __END__