tools/baserom
changeset 42 e81b4e28b3e2
child 66 2a78c4ff2eab
equal deleted inserted replaced
41:4a2ffd3562a3 42:e81b4e28b3e2
       
     1 #!perl -w
       
     2 # baserom
       
     3 # 
       
     4 # Copyright (c) 2009 - 2010 Accenture. All rights reserved.
       
     5 # This component and the accompanying materials are made available
       
     6 # under the terms of the "Eclipse Public License v1.0"
       
     7 # which accompanies this distribution, and is available
       
     8 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     9 # 
       
    10 # Initial Contributors:
       
    11 # Accenture - Initial contribution
       
    12 #
       
    13 use strict;
       
    14 use Cwd;
       
    15 use Getopt::Long;
       
    16 use File::Path;
       
    17 
       
    18 #fwd decls for functions.
       
    19 sub CreateNewObeyFile();
       
    20 sub ProcessCommandLine();
       
    21 sub Usage();
       
    22 sub ConvertIbyLine($);
       
    23 sub FindMissingDeps($);
       
    24 sub ResolveMissingDeps($);
       
    25 sub FindIby($);
       
    26 sub CheckIbyContains($$);
       
    27 sub headerInfo($);
       
    28 sub trim($);
       
    29 sub Query($$);
       
    30 sub makeFullFileName($);
       
    31 
       
    32 
       
    33 # globals
       
    34 my $verbose = 0;
       
    35 my $help;
       
    36 my $epocroot = $ENV{"epocroot"};
       
    37 my $tempDir = $ENV{"temp"};
       
    38 my $romIncludeDir;
       
    39 my $obyName;
       
    40 my $obyPath;
       
    41 my $baseObeyFile = "tshell.oby";
       
    42 my $main = "armv5";
       
    43 my $build = "udeb";
       
    44 my $variant = "h4hrp";
       
    45 my $extraInclude = undef;
       
    46 
       
    47 my %ignoreDeps = ('scppnwdl.dll' => 1, 'drtaeabi.dll' => 1, 'drtrvct2_2.dll' => 1, 'dfpaeabi.dll' => 1, 'dfprvct2_2.dll' => 1);
       
    48 
       
    49 ProcessCommandLine();
       
    50 
       
    51 my $newObyFile;
       
    52 my $missingCount;
       
    53 my $continue;
       
    54 do {
       
    55   $continue = 0;
       
    56   $newObyFile = CreateNewObeyFile();
       
    57   my $missingFiles = FindMissingDeps($newObyFile);
       
    58   $missingCount = scalar(@$missingFiles);
       
    59   
       
    60   if ($missingCount) {
       
    61     #print "$missingCount missing dependancies:\n";
       
    62     #foreach my $dep (@$missingFiles) {
       
    63     #	if (defined $dep->[1]) {
       
    64     #		print "$dep->[0] UID3: $dep->[1]\n";
       
    65     #	} else {
       
    66     #		print "$dep->[0]\n";
       
    67     #	}
       
    68     #}
       
    69 
       
    70     if (Query("\nThere are $missingCount missing dependancies; resolve them now?", "yn")==0) {
       
    71 
       
    72     	ResolveMissingDeps($missingFiles);
       
    73     	
       
    74     	$continue = 1;
       
    75     	
       
    76     } else {
       
    77     	$newObyFile = CreateNewObeyFile();
       
    78     }
       
    79   }
       
    80 } while ($missingCount && $continue);
       
    81 
       
    82 print "New OBY file: $newObyFile\n\n";
       
    83 print "To build a ROM:\n";
       
    84 print "rom --type tshell_$obyName --inst $main --build $build --variant $variant\n";
       
    85 exit(0);
       
    86 
       
    87 
       
    88 sub ProcessCommandLine() {
       
    89 	Getopt::Long::Configure ("bundling");
       
    90 	GetOptions( 'h' => \$help, 
       
    91 	            'v+' => \$verbose, 
       
    92 	            'e=s' => \$epocroot, 
       
    93 	            'i=s' => \$romIncludeDir, 
       
    94 				'x=s' => \$extraInclude,
       
    95 	            'o=s' => \$baseObeyFile, 
       
    96 	            'V=s' => \$variant,
       
    97 	            't=s' => \$main,
       
    98 	            'b=s' => \$build);
       
    99 	Usage() if ($help);
       
   100 
       
   101 	$epocroot = "$epocroot\\" unless $epocroot =~ m/\\$/;
       
   102 	my ($drive) = (getcwd =~ m/^(\w)\:/);
       
   103 	die "Can't get current drive\n" unless $drive;
       
   104 	$epocroot = "$drive:$epocroot";
       
   105 	print "Using epocroot $epocroot\n" if ($verbose);
       
   106 
       
   107 
       
   108 
       
   109 	($romIncludeDir = "epoc32\\rom\\include") unless ($romIncludeDir);
       
   110 	$romIncludeDir =~ s/\\$//; # remove trailing \ if it exists
       
   111 	$romIncludeDir = "$epocroot$romIncludeDir";
       
   112 	print "Using include directory $romIncludeDir\n" if ($verbose);
       
   113 
       
   114 	unless (scalar (@ARGV) == 1) {
       
   115 		print "Inavlid arguments\n";
       
   116 		Usage();
       
   117 		}
       
   118 		
       
   119 	$obyPath = $ARGV[0];
       
   120 	if ($obyPath =~ m/.*[\\\/]([^.]+)\..*/i) {
       
   121 		$obyName = $1;
       
   122 	} else {
       
   123 		$obyName = $obyPath;
       
   124 	}
       
   125 	
       
   126 	die "ERROR: Build must be either 'udeb' or 'urel'\n" unless ($build =~ m/(udeb)|(urel)/i);
       
   127 	
       
   128 	print "Using variant $variant, build $main $build\n";
       
   129 }
       
   130 
       
   131 sub CreateNewObeyFile() {
       
   132 	unless (-d $obyName) {
       
   133 		mkdir $obyName or die "Can't create dir $obyName: $!\n";
       
   134 	}
       
   135 
       
   136 	open OBEY, "<$obyPath" or die "Can't open $obyPath: $!\n";
       
   137 
       
   138 
       
   139 	my %ibysProcessed;
       
   140 	my @ibyStack;
       
   141 	
       
   142 	my $obyBaseName;
       
   143 	if ($baseObeyFile =~ m/(.*)\.oby/i) {
       
   144 		$obyBaseName = $1;
       
   145 	} else {
       
   146 		$obyBaseName = "tshell";
       
   147 	}
       
   148 	
       
   149 	my $newObyName = "${obyBaseName}_$obyName.oby";
       
   150 
       
   151 	open TSHELL_OBY, "<$baseObeyFile" or die "Can't open $baseObeyFile: $!\n";
       
   152 	open TSHELL_NEW, ">$newObyName" or die "Can't write to $newObyName: $!\n";
       
   153 
       
   154 	print "Creating tshell_$obyName.oby\n";
       
   155 
       
   156 	while (my $line = <TSHELL_OBY>) {
       
   157 		print TSHELL_NEW "$line";
       
   158 	}
       
   159 
       
   160 	close (TSHELL_OBY);
       
   161 
       
   162 	while (my $line = <OBEY>) {
       
   163 		chomp $line;
       
   164 		if ($line =~ m/^#include\s+[<"](.*)[>"]/ ) {
       
   165 			my $iby = $1;
       
   166 			if (!$ibysProcessed{lc($iby)}) {
       
   167 				print "Adding $iby to stack\n" if ($verbose);
       
   168 				push @ibyStack, $iby;
       
   169 				$ibysProcessed{lc($iby)} = 1;
       
   170 				}
       
   171 			print TSHELL_NEW "#include \"$obyName\\$iby\"\n";
       
   172 			next;
       
   173 		} else {
       
   174 			print TSHELL_NEW ConvertIbyLine("$line");
       
   175 			print TSHELL_NEW "\n";
       
   176 		}
       
   177 	}
       
   178 
       
   179 	close TSHELL_NEW;
       
   180 
       
   181 	while (my $iby = pop(@ibyStack)) {
       
   182 		print "Processing $iby\n" if ($verbose);
       
   183 		my $fullIby = "$romIncludeDir\\$iby";
       
   184 		unless (-f $fullIby) {
       
   185 			warn "$fullIby does not exist\n" ;
       
   186 			next;
       
   187 		}
       
   188 		
       
   189 		my $fixedIby = $iby;
       
   190 		$fixedIby =~ s|^(\.\.[\\/])*||; # get rid of ..\ at path start
       
   191 		$fixedIby =~ s|^[\\/]||; # remove \ at start too
       
   192 		my ($ibyPath, $ibyFile) = ($fixedIby =~ m|^((?:.*[\\/])?)(.*)$|);
       
   193 		if (($ibyPath) && (!-d "$obyName\\$ibyPath")) {
       
   194 			$ibyPath =~ s|[\\/]$||;
       
   195 			mkpath("$obyName\\$ibyPath") or die "Can't create path $obyName\\$ibyPath: $!\n";
       
   196 			$ibyPath .= "/";
       
   197 		}
       
   198 		
       
   199 		my $newIby = "$obyName\\$ibyPath$ibyFile";
       
   200 		
       
   201 		#BEGIN TOMSCI
       
   202 		# For the purposes of finding #includes, we run $fulliby through CPP first so that we don't pick up includes that are #ifdef'd out
       
   203 		# To prevent the #includes being expanded, we have to change them in the file we run cpp over.
       
   204 		open IBY, "<$fullIby" or die "Can't open $fullIby: $!\n";		
       
   205 		open NOINCLUDEIBY, ">$newIby.noinclude" or die "Can't open $newIby.noinclude: $!\n";
       
   206 		while (my $line = <IBY>) {
       
   207 			$line =~ s/#include/BASEROMHASHINCLUDE/;
       
   208 			print NOINCLUDEIBY $line;
       
   209 		}
       
   210 		close IBY;
       
   211 		close NOINCLUDEIBY;
       
   212 		my $cppOpts = "-undef -traditional -lang-c++ -nostdinc -I . -I $romIncludeDir";
       
   213 		if ($extraInclude) {
       
   214 			if (!($newIby =~ /$extraInclude$/)) { # Make sure we don't include the extraInclude in itself
       
   215 				$cppOpts .= " -include $romIncludeDir\\$extraInclude";
       
   216 			}
       
   217 		}
       
   218 		
       
   219 		my $cmd .= "cpp $cppOpts $newIby.noinclude";
       
   220 		print "running: $cmd\n" if ($verbose);
       
   221 		open IBYCPP, "$cmd |" or die "Can't run '$cmd': $!\n";
       
   222 		while (my $line = <IBYCPP>) {
       
   223 			chomp $line;
       
   224 			#print "TOMSCI: $line\n";
       
   225 			if ($line =~ m/^BASEROMHASHINCLUDE\s+[<"](.*)[>"]/ ) {
       
   226 				my $iby = $1;
       
   227 				if (!$ibysProcessed{lc($iby)}) {
       
   228 					print "Adding $iby to stack\n" if ($verbose);
       
   229 					push @ibyStack, $iby;
       
   230 					$ibysProcessed{lc($iby)} = 1;
       
   231 				}
       
   232 			}
       
   233 		}
       
   234 		close IBYCPP;
       
   235 		#END TOMSCI
       
   236 
       
   237 		open IBY, "<$fullIby" or die "Can't open $fullIby: $!\n";		
       
   238 		open NEWIBY, ">$newIby" or die "Can't open $newIby: $!\n";
       
   239 		print "Creating $newIby\n" if ($verbose);
       
   240 		
       
   241 		while (my $line = <IBY>) {
       
   242 			chomp $line;
       
   243 			if ($line =~ m/^#include\s+[<"](.*)[>"]/ ) {
       
   244 				my $iby = $1;
       
   245 				#if (!$ibysProcessed{lc($iby)}) {
       
   246 				#	print "Adding $iby to stack\n" if ($verbose);
       
   247 				#	push @ibyStack, $iby;
       
   248 				#	$ibysProcessed{lc($iby)} = 1;
       
   249 				#	}
       
   250 				print NEWIBY "#include \"$iby\"\n";
       
   251 				next;
       
   252 			} else {
       
   253 				print NEWIBY ConvertIbyLine("$line");
       
   254 				print NEWIBY "\n";
       
   255 			}
       
   256 		}
       
   257 		
       
   258 		
       
   259 		close IBY;
       
   260 		close NEWIBY;
       
   261 	}
       
   262 	return $newObyName;
       
   263 }
       
   264 
       
   265 
       
   266 sub ConvertIbyLine($) {
       
   267 	my $line = shift;
       
   268 	
       
   269 	if ($line =~ m/^\s*\w*ECOM_PLUGIN(?:_UDEB)?\s*\(\s*(.*?)\s*,\s*(.*?)\s*\)\s*$/ ) {
       
   270 		my $dll = $1;
       
   271 		my $rsc = $2;
       
   272 		
       
   273 		my ($dllName) = $dll =~ m/^(.*?)\./;
       
   274 		$rsc =~ s/[A-Fa-f0-9]{8}\.rs[cs]/$dllName.rsc/; # Some broken IBYs specify .rss instead of .rsc
       
   275 		
       
   276 		return "file=\\epoc32\\release\\##MAIN\\##BUILD##\\$dll\t\"sys\\bin\\$dll\"\n".
       
   277 				"data=\\epoc32\\data\\Z\\resource\\Plugins\\$rsc\t\"resource\\plugins\\$rsc\"";
       
   278 	}
       
   279 	
       
   280 	if ($line =~ m|\\ABI_DIR\\|) {
       
   281 		$line =~ s|\\ABI_DIR\\|\\epoc32\\release\\##MAIN##\\|;
       
   282 	} else {
       
   283 		$line =~ s|ABI_DIR\\|\\epoc32\\release\\##MAIN##\\|;
       
   284 	}
       
   285 	$line =~ s|\\BUILD_DIR\\|\\##BUILD##\\|;
       
   286 	$line =~ s|\\DEBUG_DIR\\|\\##BUILD##\\|;
       
   287 	$line =~ s|\\USB_DIR\\|\\##BUILD##\\|;
       
   288 	$line =~ s|ZRESOURCE\\|\\epoc32\\data\\Z\\resource\\|;
       
   289 	$line =~ s|ZPRIVATE\\|\\epoc32\\data\\Z\\private\\|;
       
   290 	$line =~ s|ZSYSTEM\\|\\epoc32\\data\\Z\\system\\|;
       
   291 	$line =~ s|DATAZ_\\|\\epoc32\\data\\Z\\|;
       
   292 	
       
   293 	if ($line =~ m|MULTI_LINGUIFY\s*\(\s*RSC\s+(.*?)\s+(.*?)\s*\)|) {
       
   294 		my $localRsc = $1;
       
   295 		my $romRsc = $2;
       
   296 		
       
   297 		my @resources = <$epocroot$localRsc.R*>;
       
   298 		
       
   299 		if (scalar(@resources)) {
       
   300 			$localRsc = $resources[0];
       
   301 			my $er = $epocroot;
       
   302 			$er =~ s/\\/\\\\/g;
       
   303 			$localRsc =~ s|$er|\\|;
       
   304 			#print "FOUND: $localRsc\n";
       
   305 		} else {
       
   306 			print "WARNING: resource for $romRsc could not be found\n";
       
   307 			$localRsc .= ".RSC";
       
   308 		}
       
   309 		
       
   310 		$line = "data=$localRsc\t\"$romRsc.RSC\"";
       
   311 	}
       
   312 	
       
   313 	if ($line =~ m|^#\s*include (["^])(.*?)([">])(.*)$|) {
       
   314 		my ($firstQuote, $include, $lastQuote, $extra) = ($1, $2, $3, $4);
       
   315 		$include =~ s|^(\.\.[\\/])*||;
       
   316 		$include =~ s|^[\\/]||;
       
   317 		$line = "#include $firstQuote$include$lastQuote$extra\n";
       
   318 	}
       
   319 	
       
   320 	return $line;
       
   321 }
       
   322 
       
   323 
       
   324 sub Usage() {
       
   325 	require Pod::Text;
       
   326 	print "\n";
       
   327 	my $parser = Pod::Text->new();
       
   328 	$parser->parse_from_file($0);
       
   329 	exit;
       
   330 }
       
   331 
       
   332 
       
   333 sub FindMissingDeps($) {
       
   334 	my $obyFile = shift;
       
   335 	print "Checking dependancies...\n";
       
   336 	
       
   337 	my $ibys = {};
       
   338 	my $filesByName = {};
       
   339 	my $filesByUid = {};
       
   340 	
       
   341 	
       
   342 	# since cpp doesn't deal with macros inside #include's, do it manually here:
       
   343 	print "Manually processing $obyFile\n" if ($verbose);
       
   344 	open IBY, "<$obyFile" or die "Can't open $obyFile: $!\n";
       
   345 	my $ibyFile = "$tempDir\\baserom.tmp";
       
   346 	open TEMPIBY, ">$ibyFile" or die "Can't open $ibyFile: $!\n";
       
   347 	
       
   348 	while (my $line = <IBY>) {
       
   349 		$line =~ s/\#\#VARIANT\#\#/$variant/;
       
   350 		$line =~ s/^\s*#/#/;
       
   351 		print TEMPIBY $line;
       
   352 	}
       
   353 	close IBY;
       
   354 	close TEMPIBY;
       
   355 	
       
   356 	my $cppOpts = "-undef -traditional -lang-c++ -nostdinc -I . -I ${epocroot}epoc32 -DVARIANT=$variant -DBUILD=$build -DMAIN=$main -DEUSERDIR=$main -DKMAIN=$main";
       
   357 	
       
   358 	my $cmd .= "cpp $cppOpts $ibyFile";
       
   359 	print "running: $cmd\n" if ($verbose);
       
   360 	
       
   361 	open CPP, "$cmd |" or die "Can't run '$cmd': $!\n";
       
   362 	while (my $line = <CPP>) {
       
   363 		chomp $line;
       
   364 		#print "\tCPP:$.:$line\n";
       
   365 		$line =~ s/EPOCROOT##/\\/;
       
   366 		$line =~ s/##//g;
       
   367 		
       
   368 		my $executableSrc = undef;
       
   369 		my $executableTrg = undef;
       
   370 
       
   371 		if ($line =~ m/^# 1 "(.*)" 1/) {
       
   372 			my $includedIby = $1;
       
   373 			print "iby included by cpp: $includedIby\n" if ($verbose);
       
   374 			$ibys->{lc($includedIby)} = 1;
       
   375 		} elsif ($line =~ m/^#/) {
       
   376 			# ignore - line inserted by c preprocessor
       
   377 			$line = "";
       
   378 		} elsif ($line =~ m/^\s*file\s*=\s*(.*?)\s+(.*)$/) {
       
   379 			$executableSrc = $1;
       
   380 			$executableTrg = trim $2;
       
   381 		} elsif ($line =~ m/^\s*(device|extension|primary|variant|file)\[0x[0-9A-Fa-f]{8}\]\s*=\s*(.*?)\s+(.*)$/) {
       
   382 			$executableSrc = $2;
       
   383 			$executableTrg = trim $3;
       
   384 		} elsif ($line =~ m|^\s*ECOM_PLUGIN\(\s*(.*?)\s*,| ) {
       
   385 			$executableSrc = $1;
       
   386 			$executableTrg = $executableSrc;
       
   387 		} elsif ($line =~ m|^\s*secondary\s*=(.*?)\s+(.*)$| ) {
       
   388 			$executableSrc = $1;
       
   389 			$executableTrg = trim $2;
       
   390 		} elsif ($line =~ m|^\s*data\s*=(.*?)\s|) {
       
   391 			my $data = $1;
       
   392 			print "WARNING: file $data not found\n" unless (-f "$epocroot$data");
       
   393 		} elsif (length(trim($line))==0) {
       
   394 			# ignore empty line
       
   395 		} elsif ($line =~ m|^\s*REM\s.*$|i) {
       
   396 			# comment, ignore.
       
   397 		} elsif ($line =~ m|^\s*patchdata\s.*$| ) {
       
   398 			# patchdata - ignore
       
   399 		} elsif ($line =~ m|^files=$|) {
       
   400 			# tshell.oby contains this line, not sure why.
       
   401 		} elsif ($line =~ m/^\s*PlatSec(Diagnostics|Enforcement|ProcessIsolation|EnforceSysBin)\s*(ON|OFF)\s*$/) {
       
   402 			# ignore platsec stuff
       
   403 		} elsif ($line =~ m/^\s*(debugport|kerneltrace|memmodel|trace|collapse|multikernel|version|bootbinary|romsize|romlinearbase|romalign|(kernel)?dataaddress|kernelheap(max|min)|defaultstackreserve|romchecksum|nowrapper|pagingpolicy)/) {
       
   404 			# rom config stuff, ignore
       
   405 		} elsif ($line =~ m/^\s*#/) {
       
   406 			# We ignore any other preprocessor directive
       
   407 		} else {
       
   408 			print "OBY line not recognised: $line\n";
       
   409 		}
       
   410 		
       
   411 		if ((defined $executableSrc) && (! ($executableSrc =~ m|eka1_entry_stub\.dll$|)) ) {
       
   412 			
       
   413 			#die "Cannot find file ${epocroot}$executableSrc\n" unless (-f "${epocroot}$executableSrc");
       
   414 			# Assume anything like BTDEBUG_DIR should equate to urel
       
   415 			$executableSrc =~ s/\\[A-Z]+_DIR\\/\\urel\\/;
       
   416 			
       
   417 			if (!(-f "${epocroot}$executableSrc")) {
       
   418 				print "WARNING: Can't find ${epocroot}$executableSrc, skipping dependancy check\n";
       
   419 				next;
       
   420 			}
       
   421 			
       
   422 			my $exeOnly = lc $executableSrc;
       
   423 			$exeOnly =~ s/.*\\//;
       
   424 			my $exeOnlyTrg = lc $executableTrg;
       
   425 			$exeOnlyTrg =~ s/.*\\//;
       
   426 			
       
   427 			my $uid3 = (headerInfo("${epocroot}$executableSrc"))[3];
       
   428 			if (defined $uid3) {
       
   429 				if ($filesByName->{$exeOnlyTrg}) {
       
   430 				  print "WARNING: 2 files with name $exeOnlyTrg in rom\n";
       
   431 			  }	
       
   432 				$filesByName->{$exeOnlyTrg} = $executableSrc;
       
   433 				if (!($uid3 eq "00000000")) {
       
   434 					$filesByUid->{$uid3} = $executableSrc;
       
   435 					print "UID3 for $executableSrc: $uid3\n" if ($verbose>1);
       
   436 				}
       
   437 			} else {
       
   438 				print "WARNING: could not find UID3 for $executableSrc\n"
       
   439 			}
       
   440 			
       
   441 			
       
   442 		}
       
   443 
       
   444 	}
       
   445 	
       
   446 	close CPP;
       
   447 	
       
   448 	
       
   449 	# now check for missing dependancies
       
   450 	my @missingFiles;
       
   451 	
       
   452 	foreach my $dependancy (keys %$filesByName) {
       
   453 	
       
   454 		my $executable = $filesByName->{$dependancy};
       
   455 
       
   456 		$cmd = "elftran -dump i ${epocroot}$executable";
       
   457 		print "running: $cmd\n" if ($verbose);
       
   458 
       
   459 		open ELFTRAN, "$cmd|" or die "Couldn't run $cmd: $!\n";
       
   460 
       
   461 		while (my $line = <ELFTRAN>) {
       
   462 			if ($line =~ m/^\d+ imports from (.*)$/) {
       
   463 				my $dep = lc($1);
       
   464 				
       
   465 				my $depName = undef;
       
   466 				my $depUid = undef;
       
   467 				
       
   468 				if ($dep =~ m/^(.*?)\{[a-f0-9]{8}\}\[([a-f0-9]{8})\]\.(.*)$/ ) {
       
   469 					unless ($ignoreDeps{lc("$1.$3")}) {
       
   470 						$depName = "$1.$3";
       
   471 						$depUid = $2;
       
   472 					}
       
   473 				} elsif ($dep =~ m/^(.*?)\{[a-f0-9]{8}\}\.(.*)$/ ) {
       
   474 					unless ($ignoreDeps{lc("$1.$2")}) {
       
   475 						$depName = "$1.$2";
       
   476 					}
       
   477 				} else {
       
   478 					print "WARNING: dependancy name '$dep' could not be parsed\n";
       
   479 				}
       
   480 				
       
   481 				
       
   482 				if (defined $depName) {
       
   483 					print "$executable links to $depName\n" if ($verbose>1);
       
   484 					if ((defined $depUid) && ($filesByUid->{$depUid})) {
       
   485 						print "Found match by UID3: $filesByUid->{$depUid} ($depUid)\n" if ($verbose>1);
       
   486 					} elsif ($filesByName->{lc($depName)}) {
       
   487 						my $uid3 = $filesByName->{lc($depName)};
       
   488 						#print "WARNING: Found match by name but not UID: $depName UID3: $uid3 expected $depUid\n";
       
   489 					} else {
       
   490 						my $fullDepName = makeFullFileName($depName);
       
   491 						if (defined $depUid) {
       
   492 							print "Missing dependancy: $depName (UID3 $depUid) required by $executable\n";
       
   493 							$filesByUid->{$depUid} = $fullDepName;
       
   494 						} else {
       
   495 							print "Missing dependancy: $depName required by $executable\n";
       
   496 						}
       
   497 						push @missingFiles, [$depName, $depUid];
       
   498 						#print "WARNING: can't find dependancy $depName at $fullDepName\n" unless (-f $fullDepName);
       
   499 						$filesByName->{lc($depName)} = $fullDepName;
       
   500 					}
       
   501 				
       
   502 				}
       
   503 			}
       
   504 		}
       
   505 
       
   506 
       
   507 
       
   508 
       
   509 		close (ELFTRAN);
       
   510 	}
       
   511 	
       
   512 	return \@missingFiles;
       
   513 	
       
   514 }
       
   515 
       
   516 
       
   517 sub ResolveMissingDeps($) {
       
   518   my $missingFiles = shift;
       
   519   
       
   520 	my %addedIbys;
       
   521 
       
   522 	foreach my $depInfo (@$missingFiles) {
       
   523 	
       
   524 	  my $expectedDepPath = makeFullFileName $depInfo->[0];
       
   525 	
       
   526 		# find an IBY file than contains this dependancy
       
   527 		my $ibyFile = FindIby($depInfo->[0]);
       
   528 		
       
   529 		if (defined $ibyFile) {
       
   530 			print "\nFound $depInfo->[0] in $ibyFile\n";
       
   531 		} elsif (-f $expectedDepPath) {
       
   532 			if (Query("\nCan't find IBY file for $depInfo->[0] based on components exports.\nSearch all of $romIncludeDir instead?", "yn") == 0) {
       
   533 				print "Not implemented yet, sorry!\n";
       
   534 			}
       
   535 		} else {
       
   536 	    print "IBY file for $depInfo->[0] not found, and $expectedDepPath does not exist.\n";
       
   537 	  }
       
   538 		
       
   539 		my $lineToAdd = undef;
       
   540 		if (defined $ibyFile) {
       
   541 		
       
   542 			if ($addedIbys{$ibyFile}) {
       
   543 				print "$ibyFile already included.\n";
       
   544 			} else {
       
   545 		
       
   546 				my $continue;
       
   547 				
       
   548 				do {
       
   549 					$continue = 0;			
       
   550 					my $option = Query("Do you want to include whole (I)BY file, just the one (f)ile or (n)either? (or (v)iew the IBY contents)", "ifnv");
       
   551 					if ($option==0) {
       
   552 						$addedIbys{$ibyFile}=1;
       
   553 
       
   554 						my $romIncludeMatchStr = $romIncludeDir;
       
   555 						$romIncludeMatchStr =~ s|^\w\:\\||;
       
   556 						$romIncludeMatchStr =~ s|\\|\\\\|g;
       
   557 						my $shortIby = $ibyFile;
       
   558 						$shortIby =~ s|.*$romIncludeMatchStr||i;
       
   559 						$shortIby =~ s|^\\*||;
       
   560 						$lineToAdd = "#include \"$shortIby\"";
       
   561 					} elsif ($option==1) {
       
   562 						$lineToAdd = "file=ABI_DIR\\DEBUG_DIR\\$depInfo->[0]\t\\sys\\bin\\$depInfo->[0]";
       
   563 					} elsif ($option==3) {
       
   564 						$continue=1;
       
   565 						
       
   566 						open IBYFILE, "<$ibyFile" or die "ERROR: Can't open $ibyFile: $!\n";					
       
   567 						print "$ibyFile:\n";
       
   568 						while (<IBYFILE>) {
       
   569 							print;
       
   570 						}
       
   571 						print "\n";
       
   572 					}
       
   573 				} while ($continue);
       
   574 			}
       
   575 		} elsif (-f $expectedDepPath) {
       
   576 		  if (Query("\nIBY file for $depInfo->[0] not found; include single file?", "yn")==0) {
       
   577 			  $lineToAdd = "file=ABI_DIR\\DEBUG_DIR\\$depInfo->[0]\t\\sys\\bin\\$depInfo->[0]";
       
   578 			}
       
   579 		} else {
       
   580 		  # perhaps we could search in \release\$main\$build for a binary with the required UID3 value.
       
   581 		  # might be worth implementing later?
       
   582 		  print "WARNING: $expectedDepPath does not exist, manual resolution of dependancy likely needed.\n";
       
   583 		}
       
   584 		
       
   585 		
       
   586 		
       
   587 		if (defined $lineToAdd) {
       
   588 			open OBYFILE, ">>$obyName.oby" or die "Can't append to $obyName.oby: $!\n";
       
   589 			print "Adding line:\n";
       
   590 			print "$lineToAdd\n";
       
   591 			print OBYFILE "$lineToAdd\n";
       
   592 			close OBYFILE;
       
   593 		}
       
   594 		
       
   595 	}
       
   596 	
       
   597 	print "\n";
       
   598 
       
   599 }
       
   600 
       
   601 sub FindIby($) {
       
   602 	my $file = shift;
       
   603 	my $fullFile = makeFullFileName $file;
       
   604 	return undef unless (-f $fullFile);
       
   605 	my $cmd = "bininfo $fullFile";
       
   606 	print "$cmd\n" if ($verbose);
       
   607 	
       
   608 	my @ibys;
       
   609 	my $comp = undef;
       
   610 	
       
   611 	if (open BININFO, "$cmd |") {
       
   612 		while (my $line = <BININFO>) {
       
   613 			if ($line =~ m/^Component\:\s*(.*)$/) {
       
   614 				$comp = trim($1);
       
   615 				print "$comp owns $fullFile\n" if ($verbose>1);
       
   616 			}
       
   617 		}
       
   618 		close (BININFO);
       
   619 		
       
   620 		return undef unless defined ($comp);
       
   621 
       
   622 		$cmd = "bininfo $comp";
       
   623 		print "$cmd\n" if ($verbose);
       
   624 		if (open BININFO2, "$cmd |") {
       
   625 			while (my $line = <BININFO2>) {
       
   626 				if ($line =~ m/^File\s+Status\s*$/ ) {
       
   627 					# ignore header line
       
   628 				} elsif ($line =~ m/^\s*$/ ) {
       
   629 					# ignore emptry line
       
   630 				} elsif ($line =~ m/^(.*?)\s+\w+\s*$/ ) {
       
   631 					my $file = trim($1);
       
   632 					if ($file =~ m/\.iby$/i) {
       
   633 						push @ibys, $file;
       
   634 					}
       
   635 				} else {
       
   636 					print "WARNING: could not parse bininfo output '$line'\n" if ($verbose);
       
   637 				}
       
   638 			}
       
   639 			close BININFO2;	
       
   640 		
       
   641 		} else {
       
   642 			print "WARNING: could not run '$cmd': $!\n";
       
   643 			return undef;
       
   644 		}
       
   645 		
       
   646 		
       
   647 	} else {
       
   648 		print "WARNING: could not run '$cmd': $!\n";
       
   649 		return undef;
       
   650 	}
       
   651 	
       
   652 	my $num = scalar(@ibys);
       
   653 	print "$comp owns $num IBY file(s)\n" if ($verbose);
       
   654 	
       
   655 	return undef if ($num == 0);
       
   656 	return $ibys[0] if ($num == 1);
       
   657 	
       
   658 	my $compSubName;
       
   659 	if ($comp =~ m/.*_(.*)/ ) {
       
   660 		$compSubName = $1;
       
   661 	} else {
       
   662 		$compSubName = $comp;
       
   663 	}
       
   664 	
       
   665 	my $chosenIby = undef;
       
   666 	
       
   667 	foreach my $iby (@ibys) {
       
   668 		if ($iby =~ m/\\$compSubName\.iby$/i) {
       
   669 			$chosenIby = $iby;
       
   670 			print "Choosing IBY file $iby for component $comp based on name\n" if ($verbose);
       
   671 			last;
       
   672 		}
       
   673 	}
       
   674 	
       
   675 	return $chosenIby if ((defined $chosenIby) && (CheckIbyContains($chosenIby, $file)));
       
   676 	
       
   677 	# last resort: the first iby file that contains this file
       
   678 	
       
   679 	foreach my $iby (@ibys) {
       
   680 		return $iby if (CheckIbyContains($iby, $file));
       
   681 	}
       
   682 	
       
   683 	return undef;	
       
   684 	
       
   685 }
       
   686 
       
   687 sub CheckIbyContains($$) {
       
   688 	my $iby = shift;
       
   689 	my $file = shift;
       
   690 	print "Checking for $file in $iby\n" if ($verbose>1);
       
   691 	open IBYFILE, "<$iby" or return 0;
       
   692 	
       
   693 	my $found = 0;
       
   694 	while (my $line = <IBYFILE>) {
       
   695 		if ($line =~ m/\\$file\s/i) {
       
   696 			$found = 1;
       
   697 			last;
       
   698 		}
       
   699 	}
       
   700 	
       
   701 	close IBYFILE;
       
   702 	
       
   703 	print "$iby contains $file\n" if ($found && $verbose);
       
   704 	print "$iby does not contain $file\n" if ((!$found) && $verbose);
       
   705 		
       
   706 	return $found;
       
   707 }
       
   708 
       
   709 sub headerInfo($) {
       
   710 	my $file = shift;
       
   711 	my $cmd = "elftran -dump h $file";
       
   712 	print "running: $cmd\n" if ($verbose);
       
   713 	open ELFTRANUID, "$cmd|" or die "Couldn't run $cmd: $!\n";
       
   714 	
       
   715 	my ($flags, $uid1, $uid2, $uid3) = (undef, undef, undef, undef);
       
   716 	while (my $line = <ELFTRANUID>) {
       
   717 		if ($line =~ m/^Uids:\s+([\da-f]{8})\s+([\da-f]{8})\s+([\da-f]{8})\s+\(([\da-f]{8})\)$/ ) {
       
   718 			($uid1, $uid2, $uid3) = ($1, $2, $3);
       
   719 		} elsif ($line =~ m/^Flags:\s+([\da-f]{8})$/i) {
       
   720 			$flags = $1;
       
   721 		}
       
   722 	}
       
   723 	close (ELFTRANUID);
       
   724 	return ($flags, $uid1, $uid2, $uid3);
       
   725 }
       
   726 
       
   727 
       
   728 
       
   729 sub trim($) {
       
   730 	my $str= shift;
       
   731 	$str =~ s/^\s*//g;
       
   732 	$str =~ s/\s*$//g;
       
   733 	return $str;
       
   734 }
       
   735 
       
   736 sub Query($$) {
       
   737 	my $question = shift;
       
   738 	my $options = shift;
       
   739 	local $" = '/';
       
   740 	#" fix syntax highlighting from above in CW
       
   741 	my @options = split(//, $options);
       
   742 	while (1) {
       
   743 		print "$question [@options] ";
       
   744 		my $response = lc <STDIN>;
       
   745 		chomp $response;
       
   746 
       
   747 		if (length($response)==1) {
       
   748 			if ($options =~ m/$response/g) {
       
   749 				return pos($options)-1;
       
   750 			}
       
   751 		}
       
   752 	}
       
   753   
       
   754 }
       
   755 
       
   756 sub makeFullFileName($) {
       
   757   my $depName = shift;
       
   758   return "${epocroot}epoc32\\release\\$main\\$build\\$depName"
       
   759 }
       
   760 
       
   761 __END__
       
   762 
       
   763 =head1 NAME
       
   764 
       
   765 BaseRom - A tool to help you build a base ROM with selected user-side binaries.
       
   766 
       
   767 =head1 SYNOPSIS
       
   768 
       
   769 baserom [options] F<romname>
       
   770 
       
   771 options:
       
   772 
       
   773 =over
       
   774 
       
   775 =item -V variant
       
   776 
       
   777 Use the specified variant; defaults to C<h4hrp>. (note capital V).
       
   778 
       
   779 =item -t target
       
   780 
       
   781 Use the specified target architecture; defaults to C<armv5>.
       
   782 
       
   783 =item -b build
       
   784 
       
   785 Use the specified build; defaults to C<udeb>.
       
   786 
       
   787 =item -e F<\epocroot\>
       
   788 
       
   789 Use specified epocroot path instead of environment variable epocroot.
       
   790 
       
   791 =item -i F<\rom\include\directory>
       
   792 
       
   793 Use the specified directory to search for IBY files. Defaults to F<\epoc32\rom\include>.
       
   794 
       
   795 =item -o F<base.oby>
       
   796 
       
   797 Use the specified OBY file as the basis for the ROM. Defaults to F<tshell.oby>.
       
   798 
       
   799 =item -h
       
   800 
       
   801 help
       
   802 
       
   803 =item -v
       
   804 
       
   805 verbose (-vv very verbose)
       
   806 
       
   807 =item -x extraInclude
       
   808 
       
   809 If specified this file is included whenever preprocessing IBYs. It also prevents this file from being processed for dependancies itself. This option is needed when building an toolkit rom and should be set to C<-x fsh_config.iby>.
       
   810 
       
   811 =back
       
   812 
       
   813 =head1 DESCRIPTION
       
   814 
       
   815 The script is written to help you determine the dependancies that need to be included in a ROM to be able to use
       
   816 specific functionality. It also builds the appropriate OBY file.
       
   817 
       
   818 To use it:
       
   819 
       
   820 =over
       
   821 
       
   822 =item 1
       
   823 
       
   824 do a C<getsource base_e32> if you don't already have the source
       
   825 
       
   826 =item 2
       
   827 
       
   828 create a file F<myrom.oby> in F<\src\cedar\generic\base\e32\rombuild\>. In this, include the top level IBY file (or executables, etc) that 
       
   829 you need to include in your ROM. Use OBY syntax that is used by the main rombuild tool (i.e. not the base one), for example:
       
   830 
       
   831 	#include <mmf.iby>
       
   832 	file=ABI_DIR\BUILD_DIR\MyTestHarness.exe	sys\bin\MyTestHarness.exe
       
   833 
       
   834 =item 3
       
   835 
       
   836 run C<baserom myrom>. This will cause the script to create a new OBY file based on F<tshell.oby> called F<tshell_myrom.oby>.
       
   837 It will also copy any required IBY files from the default ROM include directory (F<\epoc32\rom\include> by default) into a new directory
       
   838 called F<myrom>. The format of the IBY files is converted for the base ROM building tool.
       
   839 
       
   840 =item 4
       
   841 
       
   842 The script will the check the dependancies for the executables in your ROM. Any files that are missing will be listed, and it will give
       
   843 you the option of attempting to resolve the dependancies.
       
   844 
       
   845 =item 5
       
   846 
       
   847 If you choose the resolve the dependancies, the script will search for appropriate IBY files and ask you whether you want to include
       
   848 the whole IBY file in your ROM, or just include the 1 dependancy via a C<file=> statement.
       
   849 
       
   850 =item 6
       
   851 
       
   852 Once you have worked through all the dependancies, it will start again from step 3, allowing you to iteratively resolve all your
       
   853 dependancies. Some often have to be resolved by hand, for example binaries that have a different name depending upon the variant 
       
   854 that you are building for.
       
   855 
       
   856 =item 7
       
   857 
       
   858 When you are done, it will tell you the command to use to build the ROM.
       
   859 
       
   860 =back
       
   861 
       
   862 =head1 NOTES
       
   863 
       
   864 =head2 Resolving dependancies
       
   865 
       
   866 Generally, when choosing whether or not to include an entire IBY file for a dependancy, you need to use to use some judgement. Including
       
   867 the whole IBY file has the benefit that you won't end up including a user-side DLL for a server but not the server itself. You should
       
   868 do this if you actually need to use the services provided by that server (ECOM is usually a good example of this).
       
   869 
       
   870 Including just the dependancy DLL is good if you only need to include it to satisfy linking requirements, but you never actually need to
       
   871 call into that DLL (i.e. to stop the rom build failing). For example, if your code links to F<c32.dll> but never actually uses it, it's best
       
   872 to just include that one file rather than including F<c32.iby>.
       
   873 
       
   874 Always including the whole IBY file generally results in the dependancies growing very fast until you are including pretty much the whole OS.
       
   875 
       
   876 Including F<wserv.iby> can cause problems in a C<tshell> ROM, as then you'll end up with two files trying to be F<EwSrv.exe> in the ROM.
       
   877 
       
   878 Generally, after a few iterations you can resolve most of the dependancies in your ROM, and those that remain must be done by hand, or can
       
   879 be ignored.
       
   880 
       
   881 =head3 Manually Resolving dependancies
       
   882 
       
   883 Some dependancies the script will fail to resolve automatically. For example, something that links to the screen driver F<ScDv.dll> will
       
   884 cause problems because F<ScDv.dll> doesn't exist in F<\epoc32\release\armv5\udeb> or similar places - it's actually called F<_omapqvga_scdv.dll>
       
   885 for the H4, and other things for other platforms.
       
   886 
       
   887 Generally, when the script has finished resolving dependancies automatically, you can work these out by yourself. In the example of F<ScDv.dll>, 
       
   888 looking in F<\epoc32\rom\include\base_h4hrp.iby> does the trick:
       
   889 
       
   890 	define   SCDV_DLL                _omapqvga_scdv.dll
       
   891 
       
   892 Then you can manually include the following line in your F<myrom.oby> file:
       
   893 
       
   894 	file=ABI_DIR\DEBUG_DIR\_omapqvga_scdv.dll \sys\bin\ScDv.dll
       
   895 
       
   896 The same trick for other files should work. After editing F<myrom.oby> you need to run the script on it again to update the generated OBY file.
       
   897 
       
   898 =head2 Finding IBY files
       
   899 
       
   900 When finding an IBY file for a given file, the tool does the following:
       
   901 
       
   902 =over
       
   903 
       
   904 =item 1
       
   905 
       
   906 determine the CBR component that owns the file, using C<bininfo>
       
   907 
       
   908 =item 2
       
   909 
       
   910 use C<bininfo> again to find a list of IBY files owned by that component.
       
   911 
       
   912 =item 3
       
   913 
       
   914 If it owns just 1 IBY file, use that if it includes the file we're looking for. Otherwise,
       
   915 
       
   916 =item 4
       
   917 
       
   918 Find the IBY file whose name closely matches the components name For example, for the component C<graphics_wserv> it will prefer
       
   919 an IBY file called F<wserv.iby>, or F<graphics_wserv.iby>. If one matches on this basis, use it. Otherwise,
       
   920 
       
   921 =item 5
       
   922 
       
   923 Use the first IBY file owned by the component that contains the file needed.
       
   924 
       
   925 =back
       
   926 
       
   927 =head1 COPYRIGHT
       
   928 
       
   929 Copyright (c) 2009 - 2010 Accenture. All rights reserved.
       
   930 
       
   931 =cut