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.

961 lines
32 KiB

  1. @rem ='
  2. @echo off
  3. REM ------------------------------------------------------------------
  4. REM
  5. REM SYMCD.cmd
  6. REM Create Symbol CD.
  7. REM
  8. REM Copyright (c) Microsoft Corporation. All rights reserved.
  9. REM
  10. REM ------------------------------------------------------------------
  11. perl -x "%~f0" %*
  12. goto :EOF
  13. REM ';
  14. #!perl
  15. use strict;
  16. use lib $ENV{RAZZLETOOLPATH} . "\\sp";
  17. use lib $ENV{RAZZLETOOLPATH} . "\\PostBuildScripts";
  18. use lib $ENV{RAZZLETOOLPATH};
  19. use PbuildEnv;
  20. use ParseArgs;
  21. use File::Basename;
  22. use IO::File;
  23. use Win32;
  24. use File::Path;
  25. use File::Copy;
  26. use IO::File;
  27. use Delegate;
  28. use Logmsg;
  29. use SymMake;
  30. #
  31. # SFS: SYMBOL FILESPECS
  32. # SFN: SYMBOL FILENAMES
  33. # ST: SYMBOL TOOL
  34. # SDIR: SYMBOL DIRECTORIES
  35. # SOPT: SYMBOL OPTIONS
  36. # COPT: COMMAND OPTIONS
  37. #
  38. my (%SFS, %SFN, %ST, %SDIR, %SOPT, %COPT);
  39. my ($NTPostBld, $BuildArch, $BuildType, $RazzleToolPath, $BuildLogs, $Lang, $CoverageBuild,
  40. $MungePath, $SymbolCD, $CabSize, $SymbolCDHandle, $Delegate, $ARCH, %DontShip, %SymBad
  41. );
  42. my ($Symbol_Path_Creator);
  43. sub Usage { print<<USAGE; exit(1) }
  44. Create Symbol CD.
  45. SymCD [-l lang] [-m | -t]
  46. -l lang to specify which language
  47. -m run only munge public
  48. -t run all sections
  49. If you define Official_Build_Machine, the script creates the cabs.
  50. If not, the default does only munge public symbols.
  51. For example, if you only want to munge public symbols on official
  52. build machine, you can specify 'symcd.cmd /m'.
  53. PS:
  54. The 'Official_Build_Machine' is the environment variable to set
  55. to as a official build machine.
  56. USAGE
  57. sub Dependencies {
  58. if ( !open DEPEND, ">>$ENV{_NTPOSTBLD}\\..\\build_logs\\dependencies.txt" ) {
  59. errmsg("Unable to open dependency list file.");
  60. die;
  61. }
  62. print DEPEND<<DEPENDENCIES;
  63. \[$0\]
  64. IF {...} ADD {}
  65. DEPENDENCIES
  66. close DEPEND;
  67. exit;
  68. }
  69. my $qfe;
  70. #
  71. # parse the command line arguments
  72. #
  73. parseargs(
  74. 'l:' => \$Lang,
  75. 'm' => \$COPT{'NEED_MUNGE_PUBLIC'},
  76. 't' => \$COPT{'NEED_ALL'},
  77. '?' => \&Usage,
  78. 'plan' => \&Dependencies,
  79. 'qfe:' => \$qfe
  80. );
  81. if ( -f "$ENV{_NTPOSTBLD}\\..\\build_logs\\skip.txt" ) {
  82. if ( !open SKIP, "$ENV{_NTPOSTBLD}\\..\\build_logs\\skip.txt" ) {
  83. errmsg("Unable to open skip list file.");
  84. die;
  85. }
  86. while (<SKIP>) {
  87. chomp;
  88. exit if lc$_ eq lc$0;
  89. }
  90. close SKIP;
  91. }
  92. &main;
  93. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  94. #
  95. # main()
  96. # - symcd main function; according the $SOPT (symcd options) to do below steps,
  97. # 1. munge public symbols,
  98. # 2. create symbols.inf, symbols.cdf and symbols.ddf,
  99. # 3. according symbols(n).ddf and symbols.cdf, create symbols(n).cab and symbols.cat
  100. # 4. merge symbols(n).cab to symbols.cab
  101. # 5. sign symbols.cab and symbols.cat
  102. # PS. for 2 - 5, we create both update and full packages
  103. #
  104. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  105. sub main
  106. {
  107. my (%pkinfo, $symcd);
  108. my $pkinfoptr = \%pkinfo;
  109. &Initial_Variables();
  110. # If localize builds, do nothing
  111. if (!&IsUSA() and !$qfe) {
  112. logmsg "Language = $Lang. Do not create symbolcd.";
  113. return;
  114. }
  115. &Prepare_Reference_Files();
  116. &Munge_Public() if ($SOPT{'NEED_MUNGE_PUBLIC'});
  117. if ($SOPT{'NEED_CREATE_SYMBOLCD_TXT'}) {
  118. if ($SOPT{'USE_SYMLIST'}) {
  119. # &Create_SymbolCD_TXT_1_field();
  120. errmsg("Cannot find the symupd.txt");
  121. } else {
  122. Create_SymbolCD_TXT_3_fields();
  123. }
  124. }
  125. # create symbols.inf, symbols.cdf and symbols(n).ddf
  126. &Create_Make_File($pkinfoptr) if ($SOPT{'NEED_CREATE_MAKE_FILE'});
  127. undef $symcd; # Free memory; unload full symbolcd.txt
  128. &Create_SymbolCAT() if ($SOPT{'NEED_CREATE_SYMBOLCAT'});
  129. &Create_SymbolCAB($pkinfoptr) if ($SOPT{'NEED_CREATE_SYMBOLCAB'});
  130. $Delegate->Start() if (($SOPT{'NEED_CREATE_SYMBOLCAT'} ne '') || ($SOPT{'NEED_CREATE_SYMBOLCAB'} ne ''));
  131. while(!$Delegate->AllJobDone()) {$Delegate->CompleteAll(); sleep 5;}
  132. &Merge_SymbolCAB($pkinfoptr) if ($SOPT{'NEED_CREATE_SYMBOLCAB'});
  133. &Sign_Files($pkinfoptr) if ($SOPT{'NEED_SIGN_FILES'});
  134. }
  135. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  136. #
  137. # Munge public symbols
  138. #
  139. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  140. sub Munge_Public
  141. {
  142. my ($filename, $filepath, $fileext);
  143. my ($mySymbol, $mySymbolPath, $myBinary, $myMungePath, $oldMungePath, $newMungePath);
  144. my ($c_ext, @myCompOpt);
  145. my ($optCL, $optML, $optLINK);
  146. my @ppdirs = &Exists("$MungePath\\*.*");
  147. @myCompOpt = @ENV{qw(_CL_ _ML_ _LINK_)} if (lc$ENV{'_BuildArch'} eq 'x86');
  148. logmsg("Adding type info to some public pdb files for debugging...");
  149. for (@ppdirs) {
  150. next if (!-d);
  151. ($filename, $filepath, $fileext) = FileParse($_);
  152. if (length($fileext) ne '3') {
  153. errmsg("$_ name has the wrong format.");
  154. return;
  155. }
  156. $mySymbol = &SymbolPath("$NTPostBld\\symbols", "retail", "$filename\.$fileext");
  157. $mySymbolPath = &SymbolPath("$NTPostBld\\symbols", "retail");
  158. $myBinary = "$NTPostBld\\$filename\.$fileext";
  159. if (-f $mySymbol) {
  160. $myMungePath = "$MungePath\\$filename\.$fileext";
  161. ($oldMungePath, $newMungePath) = ("$myMungePath\\original", "$myMungePath\\updated");
  162. logmsg("Working on $filename\.$fileext");
  163. ## See if we need to do anything, or if the symbol file has already been updated
  164. ## If the symbol file passes symbol checking, with types present then don't update it.
  165. if (!&IsSymchkFailed($myBinary, $mySymbolPath, "/o")) {
  166. logmsg("Skipping $filename\.$fileext because it's public pdb already has type info in it.");
  167. next;
  168. }
  169. mkpath([$oldMungePath, $newMungePath]);
  170. ## See if the pdb, if it exists, in original matches the exe in binaries
  171. if (&IsSymchkFailed($myBinary, $oldMungePath, $SOPT{'PUB_SYM_FLAG'})) {
  172. logmsg("Saving a copy of $filename\.pdb to $oldMungePath");
  173. copy($mySymbol, $oldMungePath) or errmsg("copy $mySymbol to $oldMungePath failed.");
  174. if (&IsSymchkFailed($myBinary, $oldMungePath, $SOPT{'PUB_SYM_FLAG'})) {
  175. errmsg("cannot copy the correct pdb file to $oldMungePath\.");
  176. next;
  177. }
  178. }
  179. if (&Exists("$myMungePath\\*.*") > 0) {
  180. if (!copy("$oldMungePath\\$filename\.pdb", $newMungePath)) {
  181. errmsg("copy failed for $oldMungePath\\$filename\.pdb to $newMungePath\.");
  182. next;
  183. }
  184. logmsg("Pushing type info into the stripped $filename\.pdb");
  185. $c_ext = (-e "$myMungePath\\$filename\.c")? "c": "cpp";
  186. if (&IsVC7PDB("$newMungePath\\$filename\.pdb")) {
  187. logmsg("This is a vc7 pdb");
  188. @ENV{qw(_CL_ _ML_ _LINK_)} = ();
  189. } else {
  190. logmsg("This is a vc6 pdb");
  191. @ENV{qw(_CL_ _ML_ _LINK_)} = @myCompOpt;
  192. }
  193. logmsg("cl /nologo /Zi /Gz /c $myMungePath\\$filename\.$c_ext /Fd" . "$newMungePath\\$filename\.pdb /Fo" . "$newMungePath\\$filename\.obj");
  194. if (system("cl /nologo /Zi /Gz /c $myMungePath\\$filename\.$c_ext /Fd" . "$newMungePath\\$filename\.pdb /Fo" . "$newMungePath\\$filename\.obj") > 0) {
  195. errmsg("cl /Zi /Gz /c $myMungePath\\$filename\.$c_ext /Fd" . "$newMungePath\\$filename\.pdb had errors.");
  196. next;
  197. }
  198. if (&IsSymchkFailed($myBinary, $newMungePath, "/o $SOPT{'PUB_SYM_FLAG'}")) {
  199. errmsg("the munged $newMungePath\\$filename\.pdb doesn't match $myBinary.");
  200. next;
  201. }
  202. logmsg("Copying $newMungePath\\$filename\.pdb to $mySymbolPath\\$fileext");
  203. copy("$newMungePath\\$filename\.pdb", "$mySymbolPath\\$fileext");
  204. if (&IsSymchkFailed($myBinary, $mySymbolPath, "/o $SOPT{'PUB_SYM_FLAG'}")) {
  205. copy("$oldMungePath\\$filename\.pdb", "$mySymbolPath\\$fileext");
  206. errmsg("the munged $newMungePath\\$filename\.pdb didn't get copied to $mySymbolPath\\$fileext\.");
  207. logmsg("Copying the original pdb back to $mySymbolPath\\$fileext");
  208. copy("$oldMungePath\\$filename\.$fileext", "$mySymbolPath\\$fileext") or do {
  209. errmsg("cannot get $filename\.$fileext symbols copied to $mySymbolPath\\$fileext\.");
  210. next;
  211. }
  212. }
  213. }
  214. } else {
  215. logmsg("Skipping $filename\.$fileext because $mySymbol does not exist.");
  216. }
  217. }
  218. @ENV{qw(_CL_ _ML_ _LINK_)} = @myCompOpt if (lc$ENV{'_BuildArch'} eq 'x86');
  219. return;
  220. }
  221. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  222. #
  223. # Create symbolcd.txt from a 3 fields (bin,pri,pub) symupd.txt
  224. #
  225. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  226. sub Create_SymbolCD_TXT_3_fields
  227. {
  228. my ($fh, $bin, $pri, $pub, $binname, $binext, $pubname, $pubpath, $pubext, $pripath, $symbol, $availsym, $weight, $binnameext);
  229. my ($symdontship, $pubdontexist, $pubdontmatch, $badpubdontmatch, $symdorec, $dupsymdomatch, $dupsymdontmatch) = (0) x 7;
  230. my $duplicate = {};
  231. my (@results, @lists);
  232. local $_;
  233. logmsg("Examining the update list to compute the list of symbol files ...");
  234. # Read symupd.txt
  235. $fh = new IO::File $SFS{'SYMUPD'};
  236. while (<$fh>) {
  237. chomp;
  238. next if (!/\S/);
  239. ($bin, $pri, $pub) = split(/\,/, $_);
  240. # skip if not defined $pub
  241. if ($pub !~ /\S/) {
  242. logmsg("Skipping $bin - Reason \#1.");
  243. $pubdontexist++;
  244. next;
  245. }
  246. #
  247. # $weight = 2 if public symbol file path starts with symbols\retail
  248. # = 1 if public symbol file path starts with symbols, but not with symbols\retail
  249. # = 0 if public symbol file path doesn't start with symbols
  250. #
  251. # We will sort first by weight in order to give priority to symbol file that are in these directories.
  252. # This is to give priority to US symbols and symbols in symbols\retail over symbols for various languages.
  253. # Also it gives priority to symbols in symbols\retail versus symbols in other directories like symbols\idw.
  254. #
  255. # One case that this is trying to solve is the SP drop of spuninst.dll, update.exe and spcustom.dll where
  256. # all the languages work with the US symbols, but each language has a symbol file checked in that is different.
  257. # The symbols work, but the only difference is a path in the symbol file. This is happened during the BBT process
  258. # and the SP team checked in the actual symbols that got created for each language. In this case, they won't get
  259. # errors because symchk passes for all of them with the US symbol. We do the sort by weight in order to give
  260. # preference to the US symbol.
  261. #
  262. $weight = ($pub=~/^symbols[^\\]*\\(retail)?/i)?((defined $1)?2:1):0;
  263. push @lists, [$bin, $pri, $pub, $weight];
  264. }
  265. $fh->close();
  266. # Sort symupd.txt by symbols\retail first
  267. @results = sort {&sort_symupd($a,$b)} @lists;
  268. undef @lists;
  269. # Write to symbolcd.txt
  270. $SymbolCDHandle = new IO::File ">" . $SFS{'CD'};
  271. N1: for (@results) {
  272. # N1: while (<$fh>) {
  273. ($bin, $pri, $pub) = @{$_};
  274. ($binname, $binext) = (FileParse($bin))[0,2];
  275. ($pubname, $pubpath, $pubext) = FileParse($pub);
  276. ($binnameext) = (fileparse($bin))[0];
  277. $symbol = "$pubname\.$pubext";
  278. $pripath = (FileParse($pri))[1];
  279. # skip if the binary name is in symdontship.txt
  280. if (exists $DontShip{lc"$binname\.$binext"}) {
  281. logmsg("Skipping $bin - Reason \#2.");
  282. # logmsg("Skipping $bin because it\'s in symdontship.txt.");
  283. $symdontship++;
  284. next;
  285. }
  286. # skip if the public symbol file is not defined or is a directory
  287. if (!-f "$NTPostBld\\$pub") {
  288. logmsg("Skipping $bin - Reason \#1.");
  289. $pubdontexist++;
  290. next;
  291. }
  292. if (!-f "$NTPostBld\\$pri") {
  293. logmsg("Warnning - private symbols ($pri) for $bin does not exist.");
  294. }
  295. # skip if the public symbols does not match the binary
  296. if (&IsSymchkFailed("$NTPostBld\\$bin", "$NTPostBld\\$pubpath", $SOPT{'PUB_SYM_FLAG'})) {
  297. if (!exists $SymBad{lc(basename($bin))}) {
  298. errmsg("Error - symbols $pub does not match with $bin"); # because it\'s public pdb $pub does not match with its binary");
  299. $pubdontmatch++;
  300. } else {
  301. logmsg("Skipping $bin - Reason \#3."); # bad symbols for $bin because it\'s public pdb $pub does not match");
  302. $badpubdontmatch++;
  303. }
  304. next;
  305. }
  306. if (&IsSymchkFailed("$NTPostBld\\$bin", "$NTPostBld\\$pripath")) {
  307. logmsg("Warnning - private pdb ($pri) does not match with its binary $bin.");
  308. }
  309. if (exists $duplicate->{$binnameext}->{$symbol}) {
  310. if ((exists $duplicate->{$binnameext}->{$symbol}->{$bin}) ||
  311. (exists $duplicate->{$binnameext}->{$symbol}->{$pub})) {
  312. $symdorec++;
  313. next;
  314. }
  315. # Because we record binary name and symbol, we loop each key to get public symbol path
  316. for $availsym (keys %{$duplicate->{$binnameext}->{$symbol}}) {
  317. next if ($availsym !~ /(pdb|dbg)$/i); # ignore the binary
  318. #
  319. # If the file passes with the symbol we have already put into symbolcd.txt, then ignore this and don't
  320. # put the duplicate symbol into symbolcd.txt. Since symchk passes, don't give an error saying that there
  321. # are duplicates
  322. #
  323. if (!&IsSymchkFailed("$NTPostBld\\$bin", dirname("$NTPostBld\\$availsym"), $SOPT{'PUB_SYM_FLAG'})) {
  324. $dupsymdomatch++;
  325. next N1;
  326. }
  327. }
  328. if (exists $SymBad{lc(basename($bin))}) {
  329. logmsg("Skipping $bin - Reason \#3."); # bad symbols for $bin because it\'s public pdb $pub does not match");
  330. $badpubdontmatch++;
  331. next;
  332. }
  333. errmsg("Error - $bin has duplicate symbols ($pub) and mismatch with other symbols."); # $bin has the same symbol file $symbol with other binaries");
  334. $dupsymdontmatch++;
  335. next;
  336. }
  337. print $SymbolCDHandle "$bin,$pubname\.$pubext,$pub,$binext\n"; #$symbol,$subsympath,$installpathname\n";
  338. $duplicate->{$binnameext}->{$symbol}->{$bin} = 1;
  339. $duplicate->{$binnameext}->{$symbol}->{$pub} = 1;
  340. }
  341. $SymbolCDHandle->close();
  342. logmsg(sprintf("Reason 1: %d files skipped because its public symbols is not exist.", $pubdontexist));
  343. logmsg(sprintf("Reason 2: %d files skipped because its in symdontship.txt.", $symdontship));
  344. logmsg(sprintf("Reason 3: %d files skipped because the public symbol file does not match but listed in symbad.txt.", $badpubdontmatch));
  345. logmsg(sprintf("Reason 4: %d files skipped because it is a duplicate line in update list", $symdorec));
  346. logmsg(sprintf("Reason 5: %d files skipped because the binary match with other exist symbols", $dupsymdomatch));
  347. logmsg(sprintf("Error 1: %d files were errors because the public symbol file does not match with its binary.", $pubdontmatch));
  348. logmsg(sprintf("Error 2: %d files were errors because the public symbol file has duplicate install path with other symbols.", $dupsymdontmatch));
  349. logmsg(sprintf("Total files skipped + error = %d",
  350. $symdontship + $pubdontexist + $pubdontmatch + $badpubdontmatch + $symdorec + $dupsymdomatch + $dupsymdontmatch));
  351. }
  352. #
  353. # sort_symupd($a,$b)
  354. # - Sort first by the $weight (hight to low) and then second by the path and name of the binary in alphabetical order.
  355. # The second sort is equivalent to the order that symupd.txt is given to the script in the first place.
  356. # - we keep this function here for easy reference (see Create_SymbolCD_TXT_3_fields)
  357. #
  358. sub sort_symupd
  359. {
  360. return ($_[1]->[3] <=> $_[0]->[3]) or ($_[0]->[0] cmp $_[1]->[0]);
  361. }
  362. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  363. #
  364. # Create_Make_File($pkinfoptr)
  365. # - Create the make file (symbols.ddf, symbols.cdf and symbols.inf)
  366. #
  367. # IN: an empty packageinfo hash reference
  368. #
  369. # OUT: none
  370. #
  371. # REMARK: it store package information to $pkinfoptr
  372. # for example, $pkinfoptr->{'FULL'} =
  373. # 'CABNAME' = $SDIR{'FULL_CAB'}\\$SFN{'FULL_CAB'}
  374. # ...
  375. #
  376. # we store information to $pkinfoptr, because SymMake::Create_Symbols_DDF, SymMake::Create_Symbols_CDF,
  377. # and SymMake::Create_Symbols_IDF are working with $pkinfoptr
  378. #
  379. # and, $pkinfoptr->{'DDFLIST'} stored the ddf filenames we created from SymMake::Create_Symbols_DDF
  380. # according this, we can check the makecab process make the cab or not
  381. #
  382. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  383. sub Create_Make_File
  384. {
  385. my ($pkinfoptr) = @_;
  386. my ($symcd, $packagetype);
  387. if (defined $CoverageBuild) {
  388. logmsg("Coverage build ... skipping making the cab file");
  389. return;
  390. }
  391. logmsg("Creating the makefile and the DDF's for creating the cabs");
  392. $symcd = new SymMake $ARCH, $NTPostBld;
  393. for $packagetype (qw(FULL UPDATE)) {
  394. &SymMake::RegisterPackage($pkinfoptr, $packagetype, {
  395. 'CABNAME' => $SDIR{$packagetype . '_CAB'} . '\\' . $SFN{$packagetype . '_CAB'},
  396. 'DDFNAME' => $SDIR{$packagetype . '_DDF'} . '\\' . $SFN{$packagetype . '_DDF'},
  397. 'INFNAME' => $SDIR{$packagetype . '_INF'} . '\\' . $SFN{$packagetype . '_INF'},
  398. 'CDFNAME' => $SDIR{$packagetype . '_CDF'} . '\\' . $SFN{$packagetype . '_CDF'},
  399. 'CATNAME' => $SDIR{$packagetype . '_CAT'} . '\\' . $SFN{$packagetype . '_CAT'},
  400. 'CABSIZE' => $CabSize,
  401. });
  402. # register the package type ('FULL' or 'UPDATE')
  403. $symcd->{'PKTYPE'} = $packagetype;
  404. # read "$ARCH\\symbolcd\\symbolcd.txt" for 'FULL' and $ENV{_NTPOSTBLD}\\symbolcd\\symbolcd.txt for 'UPDATE'
  405. $symcd->ReadSource();
  406. }
  407. # create symbols.ddf, symbols.cdf and symbols.inf
  408. $symcd->Create_Symbols_DDF($pkinfoptr); # Return $pkinfoptr->{$packagetype}->{CABLIST}
  409. $symcd->Create_Symbols_CDF($pkinfoptr);
  410. $symcd->Create_Symbols_INF($pkinfoptr);
  411. undef $symcd;
  412. }
  413. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  414. #
  415. # Create_SymbolCAT($packagetype)
  416. # - 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'})
  417. # - register checkexistsub the verifying function
  418. #
  419. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  420. sub Create_SymbolCAT
  421. {
  422. my ($packagetype);
  423. for $packagetype (qw(FULL UPDATE)) {
  424. my $chkexistsub = &Check_Exist_File(
  425. $SDIR{$packagetype . '_CAT'} . '\\' . $SFN{$packagetype . '_CAT'} . '.CAT',
  426. $SDIR{$packagetype . '_CDF'} . '\\' . $SFN{$packagetype . '_CDF'} . '.CAT.LOG');
  427. logmsg("Delegating to create $SFN{$packagetype . '_CAT'}\.CAT");
  428. $Delegate->AddJob($packagetype . '_CATALOG',
  429. "$ST{'CAB'} " . join(' ',
  430. '-f' => $SFN{$packagetype . '_CDF'},
  431. '-s' => $SDIR{$packagetype . '_CDF'},
  432. '-t' => 'CAT',
  433. '-d' => $SDIR{$packagetype . '_CAT'}),
  434. $chkexistsub,
  435. 1); # priority
  436. }
  437. }
  438. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  439. #
  440. # Create_SymbolCAB($packagetype)
  441. # - add job to job queue for creating symbols(n).cab (symcab.cmd -f $ddfname -s $SDIR{'FULL_DDF'} -t 'CAB' -d $SDIR{'FULL_CAB'})
  442. # - register checkexistsub the verifying function
  443. #
  444. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  445. sub Create_SymbolCAB
  446. {
  447. my ($pkinfoptr) = shift;
  448. my ($packagetype, $ddfname, $cabname);
  449. for $packagetype (qw(FULL UPDATE)) {
  450. logmsg("Delegating to create $SFN{$packagetype . '_CAB'}\.CAB");
  451. for $ddfname (keys %{$pkinfoptr->{$packagetype}->{'DDFLIST'}}) {
  452. my $chkexistsub;
  453. next if (!-e $ddfname);
  454. $cabname = (FileParse($pkinfoptr->{$packagetype}->{'DDFLIST'}->{$ddfname}))[0];
  455. $ddfname = (FileParse($ddfname))[0];
  456. $chkexistsub = &Check_Exist_File(
  457. $SDIR{$packagetype . '_CAB'} . '\\' . $cabname . '.CAB',
  458. $SDIR{$packagetype . '_DDF'} . '\\' . $ddfname . '.CAB.LOG');
  459. $Delegate->AddJob($packagetype . $ddfname . '_CAB',
  460. "$ST{'CAB'} " . join(' ',
  461. '-f' => $ddfname,
  462. '-s' => $SDIR{$packagetype . '_DDF'},
  463. '-t' => 'CAB',
  464. '-d' => $SDIR{$packagetype . '_CAB'}),
  465. $chkexistsub,
  466. $ddfname);
  467. }
  468. }
  469. }
  470. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  471. #
  472. # Merge_SymbolCAB($pkinfoptr)
  473. # - merge the symbols(n).cab to symbols.cab with cabbench.exe
  474. #
  475. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  476. sub Merge_SymbolCAB
  477. {
  478. my ($pkinfoptr) = shift;
  479. my ($packagetype, $mergecommand, $cabname);
  480. $pkinfoptr->{'FULL'}->{'DDFLIST'} = {%{$pkinfoptr->{'FULL'}->{'DDFLIST'}}, %{$pkinfoptr->{'UPDATE'}->{'DDFLIST'}}};
  481. for $packagetype (qw(FULL UPDATE)) {
  482. logmsg("Merging cabs into $SFN{$packagetype . '_CAB'}\.cab");
  483. $mergecommand = "";
  484. for $cabname (sort values %{$pkinfoptr->{$packagetype}->{'DDFLIST'}}) {
  485. $mergecommand .= 'load ' . $cabname . ' merge ';
  486. }
  487. $mergecommand .= 'save ' . $SDIR{$packagetype . '_PKG'} . '\\' . $SFN{$packagetype . '_CAB'} . '.cab';
  488. # According the cabbench syntax, remove first merge
  489. $mergecommand =~ s/ merge / /;
  490. system("$ST{'BENCH'} $mergecommand");
  491. }
  492. }
  493. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  494. #
  495. # Sign_Files()
  496. # - sign the exist cab and cat files
  497. #
  498. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  499. sub Sign_Files {
  500. my ($packagetype, $myBuildType, $myBuildArch, $mypkgdir, $catfile, %signhash);
  501. logmsg("Test signing files on CD");
  502. for $packagetype (qw(FULL UPDATE)) {
  503. for $myBuildType (qw(fre chk)) {
  504. for $myBuildArch (qw(x86 amd64 ia64)) {
  505. $mypkgdir = &{$Symbol_Path_Creator->{$packagetype}}($SDIR{$packagetype . '_CD'} . '\\Symbols', $myBuildArch, $myBuildType);
  506. $catfile = $mypkgdir . $SFN{'CAT'} . '.CAT';
  507. if ((!exists $signhash{lc$mypkgdir}) && (-e $catfile)) {
  508. system("$ST{'SIGN'} $catfile");
  509. }
  510. }
  511. }
  512. }
  513. }
  514. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  515. #
  516. # Initial variables
  517. #
  518. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  519. sub Initial_Variables
  520. {
  521. # Set Variables
  522. $Lang = $ENV{'LANG'} if ("$Lang" eq "");
  523. $ENV{'LANG'} = $Lang;
  524. $BuildArch = $ENV{'_BuildArch'};
  525. $BuildType = $ENV{'_BuildType'};
  526. $NTPostBld = $ENV{'_NTPostBld'};
  527. $MungePath = "$NTPostBld\\pp";
  528. $SymbolCD = "$NTPostBld\\SymbolCD";
  529. $RazzleToolPath = $ENV{'RazzleToolPath'};
  530. $BuildLogs = "$NTPostBld\\build_logs";
  531. $CabSize = 60000000;
  532. $SymbolCDHandle = '';
  533. $Delegate = new Delegate 3, $ENV{'NUMBER_OF_PROCESSORS'} * 2;
  534. $ARCH = "\\\\arch\\archive\\ms\\windows\\windows_xp\\rtm\\2600\\$BuildType\\all\\$BuildArch\\pub";
  535. $Symbol_Path_Creator = {
  536. 'FULL' => \&Full_Package_Path,
  537. 'UPDATE' => \&Update_Package_Path
  538. };
  539. # SDIR: SYMBOL DIRECTORIES
  540. %SDIR = (
  541. 'SYMBOLCD' => $SymbolCD,
  542. 'PUBSYM' => "$NTPostBld\\Symbols",
  543. 'FULL_CD' => "$NTPostBld\\SymbolCD\\CD",
  544. 'FULL_PKG' => &{$Symbol_Path_Creator->{'FULL'}}("$NTPostBld\\SymbolCD\\CD\\Symbols", $BuildArch, $BuildType),
  545. 'FULL_INF' => &{$Symbol_Path_Creator->{'FULL'}}("$NTPostBld\\SymbolCD\\CD\\Symbols", $BuildArch, $BuildType),
  546. 'FULL_CAB' => "$SymbolCD\\CABs\\FULL",
  547. 'FULL_DDF' => "$SymbolCD\\DDF\\FULL",
  548. 'FULL_CDF' => "$SymbolCD\\DDF\\FULL",
  549. 'FULL_CAT' => &{$Symbol_Path_Creator->{'FULL'}}("$NTPostBld\\SymbolCD\\CD\\Symbols", $BuildArch, $BuildType),
  550. 'UPDATE_CD' => "$NTPostBld\\SymbolCD\\UPD",
  551. 'UPDATE_PKG' => &{$Symbol_Path_Creator->{'UPDATE'}}("$NTPostBld\\SymbolCD\\UPD\\Symbols", $BuildArch, $BuildType),
  552. 'UPDATE_INF' => &{$Symbol_Path_Creator->{'UPDATE'}}("$NTPostBld\\SymbolCD\\UPD\\Symbols", $BuildArch, $BuildType),
  553. 'UPDATE_CAB' => "$SymbolCD\\CABs\\UPDATE",
  554. 'UPDATE_DDF' => "$SymbolCD\\DDF\\UPDATE",
  555. 'UPDATE_CDF' => "$SymbolCD\\DDF\\UPDATE",
  556. 'UPDATE_CAT' => &{$Symbol_Path_Creator->{'UPDATE'}}("$NTPostBld\\SymbolCD\\UPD\\Symbols", $BuildArch, $BuildType),
  557. );
  558. # SFS: SYMBOL FILESPECS
  559. %SFS = (
  560. 'CD' => $SDIR{'SYMBOLCD'} . '\\SymbolCD.txt',
  561. 'BLDNUM' => &{$Symbol_Path_Creator->{'FULL'}}("$NTPostBld\\SymbolCD\\CD\\Symbols", $BuildArch, $BuildType) . "\\QFEnum.txt",
  562. 'LIST' => $SDIR{'SYMBOLCD'} . '\\SymList.txt',
  563. 'BAD' => $SDIR{'SYMBOLCD'} . '\\SymBad.txt',
  564. 'SYMUPD' => $SDIR{'SYMBOLCD'} . '\\SymUpd.txt',
  565. 'CAGENERR' => $SDIR{'SYMBOLCD'} . '\\cabgenerr.log',
  566. 'EXCLUDE' => $SDIR{'SYMBOLCD'} . '\\Exclude.txt',
  567. 'BINDIFF' => $BuildLogs . '\\bindiff.txt',
  568. 'WITHTYPES' => $SDIR{'SYMBOLCD'} . '\\SymbolsWithTypes.txt',
  569. 'DONTSHIP' => $SDIR{'SYMBOLCD'} . '\\SymDontShip.txt'
  570. );
  571. # SFN: SYMBOL FILENAMES
  572. %SFN = (
  573. 'FULL_INF' => 'Symbols',
  574. 'FULL_CAB' => 'Symbols',
  575. 'FULL_DDF' => 'Symbols',
  576. 'FULL_CDF' => 'Symbols',
  577. 'FULL_CAT' => 'Symbols',
  578. 'UPDATE_INF' => 'Symbols',
  579. 'UPDATE_CAB' => 'Symbols',
  580. 'UPDATE_DDF' => 'Symbols',
  581. 'UPDATE_CDF' => 'Symbols',
  582. 'UPDATE_CAT' => 'Symbols',
  583. );
  584. # ST: SYMBOL TOOL
  585. %ST = (
  586. 'MAKE' => "symmake.exe",
  587. 'PERL' => "perl.exe",
  588. 'CHECK' => "symchk.exe",
  589. 'BENCH' => "cabbench.exe",
  590. 'DUMP' => "pdbdump.exe",
  591. 'SIGN' => $RazzleToolPath . "\\ntsign.cmd",
  592. 'CAB' => $RazzleToolPath . "\\sp\\symcab.cmd"
  593. );
  594. # SOPT: SYMBOL OPTIONS
  595. #
  596. # the default option is doing all steps
  597. #
  598. %SOPT = (
  599. 'PUB_SYM_FLAG' => '/p',
  600. 'RUN_ALWAYS' => 1,
  601. 'NEED_MUNGE_PUBLIC' => 1,
  602. 'NEED_CREATE_SYMBOLCD_TXT' => 1,
  603. 'NEED_CREATE_MAKE_FILE' => 1,
  604. 'NEED_CREATE_SYMBOLCAT' => 1,
  605. 'NEED_CREATE_SYMBOLCAB' => 1,
  606. 'NEED_SIGN_FILES' => 1,
  607. 'NEED_FLAT_DIR' => 1,
  608. 'NEED_CLEAN_BUILD' => 1,
  609. 'FLAT_SYMBOL_PATH' => undef,
  610. 'USE_SYMLIST' => undef
  611. );
  612. if ((defined $COPT{'NEED_ALL'}) && (defined $COPT{'NEED_MUNGE_PUBLIC'})) {
  613. errmsg("Error options! Please specify either -m or -t");
  614. exit(1);
  615. }
  616. # if neither is official build machine, nor assign -t in command line,
  617. # or if is official build machine, but assign -m in command line,
  618. #
  619. # we will only munge public symbols
  620. #
  621. if (((!exists $ENV{'OFFICIAL_BUILD_MACHINE'}) &&
  622. (!defined $COPT{'NEED_ALL'})) ||
  623. ((exists $ENV{'OFFICIAL_BUILD_MACHINE'}) &&
  624. (defined $COPT{'NEED_MUNGE_PUBLIC'}))) {
  625. @SOPT{qw(NEED_MUNGE_PUBLIC
  626. NEED_CREATE_SYMBOLCD_TXT
  627. NEED_CREATE_MAKE_FILE
  628. NEED_CREATE_SYMBOLCAT
  629. NEED_CREATE_SYMBOLCAB
  630. NEED_SIGN_FILES)} = (1, undef, undef, undef, undef, undef);
  631. }
  632. # if ($SOPT{'NEED_CLEAN_BUILD'}) {
  633. # rmtree([@SDIR{qw(FULL_DDF FULL_CD FULL_CAB UPDATE_DDF UPDATE_CD UPDATE_CAB)}]);
  634. # }
  635. }
  636. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  637. #
  638. # Prepare_Reference_Files
  639. # - prepare the files we referenced in the program or for symbol testing
  640. # - we prepare below files
  641. # exclude.txt, symbolswithtypes.txt, symdontship.txt, symbad.txt
  642. #
  643. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  644. sub Prepare_Reference_Files
  645. {
  646. my ($exclude, $filename, @filelist, @filelist2);
  647. my ($symlistwithtypes, $symdontship, $symbad);
  648. # Make paths
  649. mkpath([values %SDIR]);
  650. # Exclude.txt
  651. if (!-e $SFS{'EXCLUDE'}) {
  652. $exclude = new IO::File $SFS{'EXCLUDE'}, 'w';
  653. copy($RazzleToolPath . '\\symdontship.txt', $exclude) or errmsg("copy symdontship.txt to $SFS{'EXCLUDE'} failed.");
  654. autoflush $exclude 1;
  655. copy($RazzleToolPath . '\\symbolswithtypes.txt', $exclude) or errmsg("copy symbolswithtypes.txt to $SFS{'EXCLUDE'} failed.");
  656. $exclude->close();
  657. }
  658. # SymbolsWithTypes.txt
  659. $symlistwithtypes = new IO::File "$RazzleToolPath\\symbolswithtypes.txt";
  660. chomp(@filelist = <$symlistwithtypes>);
  661. $symlistwithtypes->close();
  662. $symlistwithtypes = new IO::File $SFS{'WITHTYPES'}, 'w';
  663. for $filename (@filelist) {
  664. print $symlistwithtypes $NTPostBld . '\\' . $filename . "\n";
  665. }
  666. $symlistwithtypes->close();
  667. # SymDontShip.txt
  668. copy("$RazzleToolPath\\SymDontShip.txt", $SFS{'DONTSHIP'});
  669. $symdontship = new IO::File "$RazzleToolPath\\SymDontShip.txt", 'r';
  670. chomp(@filelist = <$symdontship>);
  671. @filelist2 = map({s/\s*\;.*$//;($_ eq '')?():lc$_;} @filelist);
  672. $symdontship->close();
  673. @DontShip{@filelist2} = (1) x ($#filelist2 + 1);
  674. # SymBad.txt
  675. copy("$RazzleToolPath\\SymBad.txt", $SFS{'BAD'});
  676. $symbad = new IO::File $SFS{'BAD'}, 'r';
  677. chomp(@filelist=<$symbad>);
  678. @filelist2 = map({s/\s*\;.*$//;($_ eq '')?():lc$_;} @filelist);
  679. $symbad->close();
  680. @SymBad{@filelist2} = (1) x ($#filelist2 + 1);
  681. # QFEnum.txt
  682. # we put current build number into the symbol install directory for the Customer Support CD
  683. # we could use it to determine the which build the symbols CD belong to
  684. copy("$NTPostBld\\congeal_scripts\\__qfenum__", $SFS{'BLDNUM'}) if (-e "$NTPostBld\\congeal_scripts\\__qfenum__");
  685. if (-e $SFS{'SYMUPD'}) {
  686. $SOPT{'USE_SYMLIST'} = undef;
  687. } elsif (-e $SFS{'LIST'}) {
  688. $SOPT{'USE_SYMLIST'} = 'yes';
  689. } elsif ($SOPT{'NEED_CREATE_MAKE_FILE'}) {
  690. logmsg("Either $SFS{'SYMUPD'} or $SFS{'LIST'} need to be provided.");
  691. logmsg("No update. exit.");
  692. exit;
  693. }
  694. }
  695. ####################################################################################
  696. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  697. #
  698. # Small Subroutine
  699. #
  700. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  701. #
  702. # IsSymchkFailed($binary, $symbol, $extraopt)
  703. # - call symchk.exe to verify $binary matches with $symbol
  704. #
  705. sub IsSymchkFailed {
  706. my ($binary, $symbol, $extraopt) = @_;
  707. my ($fh, $record_error, $record_log, $result);
  708. local $_;
  709. if (defined $extraopt) {
  710. if ($extraopt =~ /2\>/) {
  711. $record_error = 1;
  712. }
  713. if ($extraopt =~ /[^2]\>/) {
  714. $record_log = 1;
  715. }
  716. $extraopt =~ s/2?\>.*$//g;
  717. }
  718. $fh = new IO::File "$ST{'CHECK'} /t $binary /s $symbol $extraopt |";
  719. while (<$fh>) {
  720. chomp;
  721. $result = $1 if /FAILED files = (\d+)/;
  722. logmsg($_) if ($record_log);
  723. logmsg($_) if (($record_error) && (/^ERROR/i));
  724. }
  725. undef $fh;
  726. return $result;
  727. }
  728. #
  729. # SymbolPath($root, $subdir, $filename)
  730. # - return the symbol path for the binary
  731. #
  732. sub SymbolPath
  733. {
  734. my ($root, $subdir, $filename) = @_;
  735. $root .= "\\$subdir" if (!$SOPT{'FLAT_SYMBOL_PATH'});
  736. if (defined $filename) {
  737. $filename =~ /\.([^\.]+)$/;
  738. $root .= "\\$1\\$`";
  739. return "$root\.pdb" if (-e "$root\.pdb");
  740. return "$root\.dbg" if (-e "$root\.dbg");
  741. $root .= ".pdb";
  742. }
  743. return $root;
  744. }
  745. #
  746. # Full_Package_Path($root, $myarch, $mytype)
  747. # - for compatible reason, we create a function to construct the path of the symbols.exe of the full package
  748. #
  749. sub Full_Package_Path
  750. {
  751. my ($root, $myarch, $mytype) = @_;
  752. $mytype =~ s/fre/retail/ig;
  753. $mytype =~ s/chk/debug/ig;
  754. return "$root\\$myarch\\$mytype"; # temporary
  755. }
  756. #
  757. # Update_Package_Path($root, $myarch, $mytype)
  758. # - for compatible reason, we create a function to construct the path of the symbols.exe of the update package
  759. #
  760. sub Update_Package_Path
  761. {
  762. my ($root, $myarch, $mytype) = @_;
  763. return $root; # \\$myarch\\$mytype"; # temporary
  764. }
  765. #
  766. # IsVC7PDB($pdbspec)
  767. # - because the MD5 hash value is 0000-0000-0000-000000000000 for the symbols built by VC6 or older
  768. # - we can use it to determine the pdb is VC7 or not
  769. #
  770. sub IsVC7PDB {
  771. my ($pdbspec) = shift;
  772. my $fh = new IO::File "$ST{'DUMP'} $pdbspec hdr |";
  773. local $_;
  774. while (<$fh>) {
  775. return 0 if /0000-0000-0000-000000000000/i;
  776. }
  777. return 1;
  778. }
  779. #
  780. # Check_Exist_File($filename, $logfile)
  781. # - this is a function generator, which generates a function for checking the $filename exist or not
  782. # - it also check if the $logfile has 'ERROR:' in it
  783. #
  784. sub Check_Exist_File
  785. {
  786. my ($filename, $logfile) = @_;
  787. return sub {
  788. if (-e $filename) {
  789. return 1;
  790. } else {
  791. my $fh = new IO::File $logfile;
  792. for (<$fh>) {
  793. chomp;
  794. next if (!/.+ERROR\: /i);
  795. errmsg("Error - $'");
  796. }
  797. $fh->close();
  798. logmsg("$filename did not get created.");
  799. return 0;
  800. }
  801. };
  802. }
  803. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  804. #
  805. # Common Subroutine
  806. #
  807. # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  808. sub FileParse
  809. {
  810. my ($name, $path, $ext) = fileparse(shift, '\.[^\.]+$');
  811. $ext =~ s/^\.//;
  812. return $name, $path, $ext;
  813. }
  814. sub IsUSA
  815. {
  816. return (lc$ENV{'lang'} eq 'usa');
  817. }
  818. sub Exists
  819. {
  820. my @list = glob(shift);
  821. return (wantarray)?@list:$#list + 1;
  822. }
  823. 1;
  824. __END__