toolsandutils/e32tools/rombuild/romnibus.pl
branchGCC_SURGE
changeset 80 d82e43335b24
equal deleted inserted replaced
79:f7dee603db09 80:d82e43335b24
       
     1 #!/usr/bin/perl
       
     2 #
       
     3 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 # All rights reserved.
       
     5 # This component and the accompanying materials are made available
       
     6 # under the terms of the License "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 # Nokia Corporation - initial contribution.
       
    12 #
       
    13 # Contributors:
       
    14 # Mike Kinghan, mikek@symbian.org, for Symbian Foundation
       
    15 #
       
    16 # Description:
       
    17 #
       
    18 # romnibus.pl - Yet another rombuild wrapper. This one's claim to fame is that
       
    19 # it works in Linux and in Windows, works when invoked from sbsv2 and when
       
    20 # not invoked from sbsv2.
       
    21 #
       
    22 # Pre-processes the .oby/iby files then invokes rombuild.exe
       
    23 # (or other specified builder)
       
    24 
       
    25 # First, read our config file
       
    26 
       
    27 use strict;
       
    28 use Getopt::Long;
       
    29 use Cwd;
       
    30 use Cwd 'abs_path';
       
    31 use File::Spec;
       
    32 
       
    33 my $on_windows;
       
    34 my $epocroot_vol;
       
    35 my $epocroot_dir;
       
    36 my $epocroot_file;
       
    37 my %dir_listings = ();	
       
    38 my %opts=();
       
    39 my $param_count = scalar(@ARGV);
       
    40 my (@assps, @builds, %variants, @templates, %flags, %insts, %zip, %builder);
       
    41 my $main;
       
    42 my $kmain;
       
    43 my $toroot;
       
    44 my $e32path;
       
    45 my $rombuildpath;
       
    46 my $euserdir;
       
    47 my $elocldir;
       
    48 my $kbdir;
       
    49 my $romname;
       
    50 my $single;
       
    51 my $smain;
       
    52 my $pagedCode;
       
    53 my $debug;
       
    54 my $quiet;
       
    55 my $toolpath;
       
    56 my $epoc32path;
       
    57 my $epocroot;
       
    58 my $lc_epocroot;
       
    59 my $drive = "";
       
    60 my $base_path;
       
    61 my $line;
       
    62 sub Variant_GetMacroHRHFile;
       
    63 sub is_RVCT_build($);
       
    64 sub parse_cfg;
       
    65 sub ASSPS;
       
    66 sub BUILDS;
       
    67 sub TEMPLATES;
       
    68 sub usage;
       
    69 sub rectify($$$);
       
    70 sub match_abbrev($$);
       
    71 sub check_opts;
       
    72 sub lookup_file_info($$);
       
    73 sub lookupSymbolInfo($$);
       
    74 sub parse_patch_data($$);
       
    75 sub gen_file;
       
    76 sub nix_fixes {
       
    77 #	Fix case-sensitivity offenders for unix/linux environment.
       
    78 	my $e32plat_pm = File::Spec->catfile($toolpath,"e32plat.pm");
       
    79 	my $armutl_pm = File::Spec->catfile($toolpath,"armutl.pm");
       
    80 	my $bpabiutl_pm = File::Spec->catfile($toolpath,"bpabiutl.pm");
       
    81 	my $e32variant_pm = File::Spec->catfile($toolpath,"e32variant.pm");
       
    82 	my $E32Plat_pm = File::Spec->catfile($toolpath,"E32Plat.pm");
       
    83 	my $Armutl_pm = File::Spec->catfile($toolpath,"Armutl.pm");
       
    84 	my $BPABIutl_pm = File::Spec->catfile($toolpath,"BPABIutl.pm");
       
    85 	my $E32Variant_pm = File::Spec->catfile($toolpath,"E32Variant.pm");
       
    86 	# Create symlinks for case-sensitively misnamed modules we need.
       
    87 	unless ( -f $E32Plat_pm or -l $E32Plat_pm) {
       
    88 		symlink($e32plat_pm,$E32Plat_pm);
       
    89 	}
       
    90 	unless ( -f $Armutl_pm or -l $Armutl_pm) {
       
    91 		symlink($armutl_pm,$Armutl_pm);
       
    92 	}
       
    93 	unless ( -f $BPABIutl_pm or -l $BPABIutl_pm) {
       
    94 		symlink($bpabiutl_pm,$BPABIutl_pm);
       
    95 	}
       
    96 	unless ( -f $E32Variant_pm or -l $E32Variant_pm) {
       
    97 		symlink($e32variant_pm,$E32Variant_pm);
       
    98 	}
       
    99 	# Make uppercase symlinks to all .bsf files in /epoc32/tools
       
   100 	my @bsf_files = glob(File::Spec->catfile($toolpath,"*.bsf"));
       
   101 	foreach my $bsf_file (@bsf_files) {
       
   102 		my ($vol,$dirs,$file) = File::Spec->splitpath($bsf_file);
       
   103 		$file =~ /^(\S+)\.bsf/;
       
   104 		my $uc_stem = uc($1);
       
   105 		my $uc_bsf_file = File::Spec->catpath($vol,$dirs,($uc_stem .".bsf"));
       
   106 		unless ( -f $uc_bsf_file or -l $uc_bsf_file ) {
       
   107 			symlink($bsf_file,$uc_bsf_file) or die "Can't symlink $bsf_file -> $uc_bsf_file. $!";
       
   108 		}
       
   109 	}
       
   110 }
       
   111 
       
   112 
       
   113 BEGIN {
       
   114 	$on_windows = $^O =~ /^MSWin/ ? 1 : 0;
       
   115 	$epocroot = $ENV{EPOCROOT};
       
   116 	die "ERROR: Must set the EPOCROOT environment variable.\n" if (!defined($epocroot));
       
   117 	print "Environmental epocroot - >$epocroot<\n";
       
   118 	$epocroot =~ s/:$/:\//, if $on_windows;
       
   119 	$epocroot = abs_path($epocroot);
       
   120 	die "ERROR: EPOCROOT must specify an existing directory.\n" if (!-d $epocroot);
       
   121 	($epocroot_vol,$epocroot_dir,$epocroot_file) = File::Spec->splitpath($epocroot);
       
   122 	$epocroot = File::Spec->catfile(($epocroot_vol,$epocroot_dir,$epocroot_file),undef);
       
   123 	print "EPOCROOT=$ENV{EPOCROOT} resolved as \"$epocroot\"\n";
       
   124 	$lc_epocroot = lc($epocroot);
       
   125 	$epoc32path = File::Spec->catfile($epocroot,"epoc32");
       
   126 	$toolpath = File::Spec->catfile($epoc32path,"tools");
       
   127 	push @INC, $toolpath;
       
   128 	nix_fixes(), unless ($on_windows);
       
   129 }
       
   130 
       
   131 
       
   132 my $result = GetOptions (\%opts, "assp=s",
       
   133 						 "inst=s",
       
   134 						 "type=s",
       
   135 						 "variant=s",
       
   136 						 "build=s", 
       
   137 						 "conf=s",
       
   138 						 "name=s",
       
   139 						 "modules=s",
       
   140 						 "xabi=s",
       
   141 						 "clean",
       
   142 						 "quiet",
       
   143 						 "help",
       
   144 						 "debug",
       
   145 						 "zip",
       
   146 						 "symbol",
       
   147 						 "noheader",
       
   148 						 "kerneltrace=s",
       
   149 						 "rombuilder=s",
       
   150 						 "define=s@",
       
   151 						 "rofsbuilder=s",
       
   152 						 "compress",
       
   153 						 );
       
   154 
       
   155 $debug = $opts{debug};
       
   156 $quiet = $opts{quiet} unless $debug;
       
   157 
       
   158 my $cwd = Cwd::cwd();
       
   159 my ($vol,$dirs,$file) = File::Spec->splitpath($cwd);
       
   160 $drive = $vol, if ($on_windows);
       
   161 my @path_parts = File::Spec->splitdir($dirs);
       
   162 while(@path_parts[-1] ne "sf") {
       
   163 	pop(@path_parts);
       
   164 }
       
   165 $base_path = File::Spec->catdir((@path_parts,"os"));
       
   166 $base_path = "$drive$base_path", if ($on_windows);
       
   167 $rombuildpath = File::Spec->catfile($base_path,"kernelhwsrv","kernel","eka","rombuild");
       
   168 $base_path .= ($on_windows ? '\\' : '/');  
       
   169 $e32path = ($on_windows ? "\\sf\\os" : "/sf/os"); 
       
   170 
       
   171 use E32Plat;
       
   172 {
       
   173         Plat_Init($toolpath . ($on_windows ? '\\' : '/'));
       
   174 }
       
   175 
       
   176 if ($debug) {
       
   177 	print "epocroot = $epocroot\n";
       
   178 	print "epoc32path = $epoc32path\n";
       
   179 	print "drive = $drive\n";
       
   180 	print "toolpath = $toolpath\n";
       
   181 	print "toroot = $toroot\n";
       
   182 	print "e32path = $e32path\n";
       
   183 	print "rombuildpath = $rombuildpath\n";
       
   184 	print "base_path = $base_path\n";
       
   185 }
       
   186 
       
   187 #my $cppflags="-P -undef -Wno-endif-labels -traditional -lang-c++ -nostdinc -iwithprefixbefore $rombuildpath -I $rombuildpath -I $drive$epoc32path ";
       
   188 my $cppflags="-P -undef -Wno-endif-labels -traditional -lang-c++ -nostdinc -I $rombuildpath -I $epoc32path ";
       
   189 
       
   190 # Include variant hrh file defines when processing oby and ibys with cpp
       
   191 # (Code copied from \\EPOC\master\cedar\generic\tools\romkit\tools\buildrom.pm -
       
   192 # it used relative path to the working dir but we are using absolute path seems neater)
       
   193 
       
   194 my $variantMacroHRHFile = Variant_GetMacroHRHFile();
       
   195 if($variantMacroHRHFile){
       
   196 	my ($ignore1,$dir,$file) = File::Spec->splitpath($variantMacroHRHFile);
       
   197 	$cppflags .= " -I " . File::Spec->catpath($epocroot_vol,$dir,undef) . " -include " . File::Spec->catpath($epocroot_vol,$dir,$file); 
       
   198 }
       
   199 
       
   200 if($param_count == 0 || $opts{'help'} || !$result) {
       
   201 	usage();
       
   202 	exit 0;
       
   203 }
       
   204 
       
   205 # Now check that the options we have make sense
       
   206 
       
   207 checkopts();
       
   208 
       
   209 if (!$quiet) {
       
   210 	print "Starting directory: ", Cwd::cwd(), "\n";
       
   211 	print <<EOF;
       
   212 OPTIONS:
       
   213 \tTYPE: $opts{'type'}
       
   214 \tVARIANT: $opts{'variant'}
       
   215 \tINSTRUCTION SET: $opts{'inst'}
       
   216 \tBUILD: $opts{'build'}
       
   217 \tMODULES: $opts{'modules'}
       
   218 EOF
       
   219 }
       
   220 
       
   221 #Pick out the type file
       
   222 my $skel = "$opts{'type'}.oby";
       
   223 unless (-e $skel) {
       
   224 	$skel= File::Spec->catfile($rombuildpath,"$opts{'type'}.oby");
       
   225 }
       
   226 unless (-e $skel) {
       
   227 	die "Can't find type file for type $opts{'type'}, $!";
       
   228 }
       
   229 
       
   230 print "Using type file $skel\n" if !$quiet;
       
   231 
       
   232 # If clean is specified, zap all the image and .oby files
       
   233 
       
   234 if($opts{'clean'}) {
       
   235 	unlink glob("*.img");
       
   236 	unlink "rom.oby";
       
   237 	unlink "rombuild.log";
       
   238 	unlink glob("*.rofs");
       
   239 	unlink "rofsbuild.log";
       
   240 }
       
   241 
       
   242 # Now pre-pre-process this file to point to the right places for .ibys
       
   243 # Unfortunately cpp won't do macro replacement in #include strings, so
       
   244 # we have to do it by hand
       
   245 
       
   246 my $k = $opts{kerneltrace};
       
   247 
       
   248 if ($opts{assp}=~/^m(\S+)/i) {
       
   249 	$kbdir="kb$1";
       
   250 	$kbdir="kbarm" if (lc $1 eq 'eig');
       
   251 } else {
       
   252 	$kbdir="kb$opts{assp}";
       
   253 }
       
   254 $single=1 if ($opts{assp}=~/^s(\S+)/i);
       
   255 
       
   256 if ($single) {
       
   257 	# Hackery to cope with old compiler
       
   258 	if ($main eq 'MARM') {
       
   259 		$smain='SARM';
       
   260 	} else {
       
   261 		$smain="S$main";
       
   262 	}
       
   263 } else {
       
   264 	$smain=$main;
       
   265 }
       
   266 
       
   267 unless ($on_windows) {
       
   268 	$main = lc($main);
       
   269 	$kmain = lc($kmain);
       
   270 }
       
   271 
       
   272 
       
   273 open(X, "$skel") || die "Can't open type file $skel, $!";
       
   274 open(OUT, "> rom1.tmp") || die "Can't open output file, $!";
       
   275 
       
   276 # First output the ROM name
       
   277 print OUT "\nromname=$romname\n";
       
   278 while(<X>) {
       
   279 	s/\#\#ASSP\#\#/$opts{'assp'}/;
       
   280 	s/\#\#VARIANT\#\#/$opts{'variant'}/;
       
   281 	s/\#\#BUILD\#\#/$opts{'build'}/;
       
   282 	s/\#\#MAIN\#\#/$main/;
       
   283 	s/\#\#KMAIN\#\#/$kmain/;
       
   284 	s/\#\#E32PATH\#\#/$e32path/;
       
   285 	s/\#\#BASEPATH\#\#/$base_path/;
       
   286 	s/\#\#EUSERDIR\#\#/$euserdir/;
       
   287 	s/\#\#ELOCLDIR\#\#/$elocldir/;
       
   288 	s/\#\#KBDIR\#\#/$kbdir/;
       
   289 	unless ($on_windows) {
       
   290 		if (m/#include/) {
       
   291 			s|\\|\/|g;
       
   292 			lc;
       
   293 		}
       
   294 	}
       
   295 	print OUT;
       
   296 }
       
   297 
       
   298 close X;
       
   299 close OUT;
       
   300 
       
   301 # Use cpp to pull in include chains and replace defines
       
   302 
       
   303 my $defines = "";
       
   304 $defines .= "-D MAIN=$main ";
       
   305 $defines .= "-D KMAIN=$kmain ";
       
   306 $defines .= "-D EUSERDIR=$euserdir ";
       
   307 $defines .= "-D ELOCLDIR=$elocldir ";
       
   308 $defines .= "-D E32PATH=$e32path ";
       
   309 $defines .= "-D BASEPATH=$base_path ";
       
   310 $defines .= "-D EPOCROOT=$epocroot ";
       
   311 $defines .= "-D SMAIN=$smain " if $smain;
       
   312 
       
   313 foreach (@{$opts{'define'}}) {
       
   314 	my @array=split(/,/,$_);
       
   315 	foreach (@array) {
       
   316 		$defines.="-D ".uc $_." ";
       
   317 		$pagedCode = 1 if $_ eq 'PAGED_CODE';
       
   318 		}
       
   319 	}
       
   320 
       
   321 if ($opts{'modules'}) {
       
   322 	my @array=split(/,/,$opts{'modules'});
       
   323 	foreach (@array) {
       
   324 		$defines.="-D ".uc $_." ";
       
   325 		}
       
   326 	}
       
   327 
       
   328 foreach (keys %opts) {
       
   329 	next if ($_ eq 'name');
       
   330 	next if ($_ eq 'modules');
       
   331 	next if ($_ eq 'zip');
       
   332 	next if ($_ eq 'symbol');
       
   333 	next if ($_ eq 'kerneltrace');
       
   334 	next if ($_ eq 'define');
       
   335 	$defines.="-D ".uc $_."=".$opts{$_}." ";
       
   336 	$defines.="-D ".uc $_."_".$opts{$_}." ";
       
   337 }
       
   338 
       
   339 $defines.="-D SINGLE " if ($single);
       
   340 $defines.="-D RVCT " if (IsRVCTBuild($main));
       
   341 
       
   342 print "Using defines $defines\n" if !$quiet;
       
   343 
       
   344 my $ret=1;
       
   345 my $cppcmd;
       
   346 if($opts{'build'}=~/^u/i and $on_windows) {
       
   347 	# Unicode build
       
   348 	$cppcmd = File::Spec->catfile($epoc32path,"gcc","bin","cpp") . " $cppflags -D UNICODE $defines rom1.tmp rom2.tmp";
       
   349 } else {
       
   350 	$cppcmd = "cpp $cppflags $defines rom1.tmp rom2.tmp";
       
   351 }
       
   352 print "Executing CPP:\n\t$cppcmd\n" if $debug;
       
   353 $ret = system($cppcmd);
       
   354 die "ERROR EXECUTING CPP\n" if $ret;
       
   355 
       
   356 # Purge remarks and blank lines. Complete source filenames and adapt them to host filesystem.
       
   357 rectify("rom2.tmp", "rom3.tmp", $k);
       
   358 
       
   359 # scan tmp file and generate auxiliary files, if required
       
   360 open TMP, "rom3.tmp" or die("Can't open rom3.tmp\n");
       
   361 while ($line=<TMP>)
       
   362 	{
       
   363 	if ($line=~/\s*gentestpaged/i) {
       
   364 		genfile("paged");	}
       
   365 	if ($line=~/\s*gentestnonpaged/i) {
       
   366 		genfile("nonpaged");	}
       
   367 	}
       
   368 
       
   369 parsePatchData("rom3.tmp", "rom4.tmp");
       
   370 
       
   371 # break down the oby file into rom, rofs and extensions oby files
       
   372 
       
   373 my $oby_index =0;
       
   374 my $dumpfile="rom.oby";
       
   375 my $rofs=0;
       
   376 my $extension=0;
       
   377 my $corerofsname="";
       
   378 open DUMPFILE, ">$dumpfile" or die("Can't create $dumpfile\n");
       
   379 open TMP, "rom4.tmp" or die("Can't open rom4.tmp\n");
       
   380 while ($line=<TMP>)
       
   381 	{
       
   382 	if ($line=~/^\s*rofsname/i)
       
   383 		{
       
   384 		close DUMPFILE;							# close rom.oby or previous rofs#/extension#.oby
       
   385 		$oby_index=1;
       
   386 		$corerofsname=$line;
       
   387 		$corerofsname =~ s/rofsname\s*=\s*//i;		# save core rofs name
       
   388 		chomp($corerofsname);
       
   389 		unlink $corerofsname || print "unable to delete $corerofsname";
       
   390 		my $dumpfile="rofs".$rofs.".oby";
       
   391 		$rofs++;
       
   392 		open DUMPFILE, ">$dumpfile" or (close TMP and die("Can't create $dumpfile\n"));
       
   393 		}
       
   394 
       
   395 	if ($line=~/^\s*coreimage/i)
       
   396 		{
       
   397 		close DUMPFILE;							# close rofs.oby
       
   398 		if ($oby_index ne 1) {
       
   399 			close TMP;
       
   400 			die "Must specify ROFS image before ROFS extension\n";
       
   401 		}
       
   402 		my $name=$line;
       
   403 		$name =~ s/coreimage\s*=\s*//i;		# read core rofs name
       
   404 		chomp($name); 			# remove trailing \n
       
   405 		if ($name ne $corerofsname) {
       
   406 			close TMP;
       
   407 			die "This extension does not relate to previous ROFS\n";
       
   408 		}
       
   409 		$oby_index=33;						# open window
       
   410 		my $dumpfile="extension".$extension.".oby";
       
   411 		$extension++;
       
   412 		open DUMPFILE, ">$dumpfile" or (close TMP and die("Can't create $dumpfile\n"));
       
   413 		}
       
   414 
       
   415 	if ($line=~/^\s*extensionrofs/i)
       
   416 		{
       
   417 		$oby_index=3 if ($oby_index eq 2);
       
   418 		}
       
   419 
       
   420 	if (($oby_index eq 2) && !($line=~/^\s*$/)) {
       
   421 		close TMP;
       
   422 		die "Bad ROFS extension specification\n";
       
   423 	}
       
   424 	print DUMPFILE $line;
       
   425 	$oby_index=2 if ($oby_index eq 33);		# close window
       
   426 	}
       
   427 close DUMPFILE;
       
   428 close TMP;
       
   429 
       
   430 # For paged roms that use rofs, move all data= lines in rom which are not 'paging_unmovable' to rofs, so that paged ram-loaded code
       
   431 # is automatically put into rofs
       
   432 rename('rom.oby', 'rom4.tmp') || die;
       
   433 
       
   434 open(IN, 'rom4.tmp') || die "Can't read rom4.tmp";
       
   435 open(ROM, '>rom.oby') || die "Can't write to rom.oby";
       
   436 
       
   437 if ($oby_index >= 1 && $pagedCode)	{
       
   438 	open(ROFS, '>>rofs0.oby') || die "Can't append to rofs0.oby";
       
   439 }
       
   440 
       
   441 while ($line=<IN>)
       
   442 {
       
   443 	if(($oby_index >= 1) && ($pagedCode) && ($line=~/^\s*data\s*=/) && !($line=~/\.*paging_unmovable\s*/)) {
       
   444 		print ROFS $line;
       
   445 	}
       
   446 	else {
       
   447 		$line=~s/paging_unmovable//;
       
   448 		print ROM $line;
       
   449 	}
       
   450 }
       
   451 
       
   452 close IN;
       
   453 close ROM;
       
   454 
       
   455 if ($oby_index >= 1 && $pagedCode)	{
       
   456 	close ROFS;
       
   457 }
       
   458 	unlink 'rom4.tmp';
       
   459 
       
   460 my $flags;
       
   461 
       
   462 foreach (@{$flags{$opts{'assp'}}}) {
       
   463 	$flags.=" -$_";
       
   464 }
       
   465 
       
   466 if($opts{'noheader'}) {
       
   467 	$flags.=" -no-header";
       
   468 }
       
   469 
       
   470 if($opts{'compress'}) {
       
   471 	$flags.=" -compress";
       
   472 }
       
   473 
       
   474 my $builder = $opts{'rombuilder'};
       
   475 if ($on_windows) {
       
   476 	$builder = File::Spec->catfile($toolpath,"rombuild.exe") unless ($builder);
       
   477 }
       
   478 else {
       
   479 	$builder = File::Spec->catfile($toolpath,"rombuild") unless ($builder);
       
   480 	unless ( -x $builder ) {
       
   481 		chmod 0755,$builder;
       
   482 	}
       
   483 }
       
   484 
       
   485 print "$builder $flags -type-safe-link -S rom.oby 2>&1\n\n";
       
   486 
       
   487 open(Y, "$builder $flags -type-safe-link -S rom.oby 2>&1 | ") || 
       
   488 	die "Can't start $builder command, $!";
       
   489 
       
   490 my $nerrors=0;
       
   491 my $nwarnings=0;
       
   492 
       
   493 while(<Y>) {
       
   494 	my $error=(/^error:/i);
       
   495 	my $warning=(/^warning:/i);
       
   496 	print if ($error or $warning or !$quiet);
       
   497 	$nerrors++ if ($error);
       
   498 	$nwarnings++ if ($warning);
       
   499 }
       
   500 
       
   501 print "\nGenerated .oby file is rom.oby\n" if !$quiet;
       
   502 print "\nGenerated image file is $romname\n" if (!$nerrors);
       
   503 
       
   504 my$rerrors;
       
   505 my $rofsbuilder;
       
   506 if ($rofs) {
       
   507 	$rofsbuilder = $opts{'rofsbuilder'};
       
   508 	$rofsbuilder = "rofsbuild" unless ($rofsbuilder);
       
   509 	for(my $i=0;$i<$rofs;++$i) {
       
   510 		print "Executing $rofsbuilder on main rofs\n" if !$quiet;
       
   511 		my $image="rofs".$i.".oby";
       
   512 		system("$rofsbuilder $image");
       
   513 		if ($? != 0)
       
   514 			{
       
   515 			print "$rofsbuilder $image returned $?\n";
       
   516 			$rerrors++;
       
   517 			}
       
   518 		rename "rofsbuild.log", "rofs$i.log"
       
   519 		}
       
   520 }
       
   521 
       
   522 if ($rofs and $extension) {
       
   523 	for(my $i=0;$i<$extension;++$i) {
       
   524 		print "Executing $rofsbuilder on extension rofs\n" if !$quiet;
       
   525 		my $image="extension".$i.".oby";
       
   526 		system("$rofsbuilder $image");
       
   527 		if ($? != 0)
       
   528 			{
       
   529 			print "$rofsbuilder $image returned $?\n";
       
   530 			$rerrors++;
       
   531 			}
       
   532 		rename "rofsbuild.log", "extension$i.log"
       
   533 		}
       
   534 }
       
   535 
       
   536 if ($nerrors) {
       
   537 	print "\n\n Errors found during $builder!!\n\nLeaving tmp files\n";
       
   538 } elsif ($nwarnings) {
       
   539 	print "\n\n Warnings during $builder!!\n\nLeaving tmp files\n";
       
   540 } elsif ($rerrors) {
       
   541 	print "\n\n Errors during $rofsbuilder!!\n\nLeaving tmp files\n";
       
   542 } else {
       
   543 	unlink glob("*.tmp") if !$debug;
       
   544 }
       
   545 if ($opts{zip} or $zip{$opts{assp}}) {
       
   546 	my $zipname=$romname;
       
   547 	$zipname =~ s/\.(\w+)$/\.zip/i;
       
   548 	unlink $zipname;
       
   549 	system("zip $zipname $romname");
       
   550 }
       
   551 if ($opts{symbol}) {
       
   552 	my $logname=$romname;
       
   553 	$logname =~ s/\.(\w+)$/\.log/i;
       
   554 	my $obyname=$romname;
       
   555 	$obyname =~ s/\.(\w+)$/\.oby/i;
       
   556 	unlink $logname;
       
   557 	unlink $obyname;
       
   558 	system("rename rombuild.log $logname");
       
   559 	system("rename rom.oby $obyname");
       
   560 	system("maksym $logname");
       
   561 }
       
   562 
       
   563 #IMK if ($nerrors || $nwarnings || $rerrors) {
       
   564 #IMK	exit 4;
       
   565 #IMK}	
       
   566 if ($nerrors || $rerrors) {
       
   567 	exit 4;
       
   568 }	
       
   569 
       
   570 	
       
   571 exit 0;
       
   572 
       
   573 
       
   574 ################################ Subroutines  ##################################
       
   575 
       
   576 sub usage {
       
   577 	print <<EOT;
       
   578 
       
   579 rom <options>
       
   580 
       
   581 Generate a rom image for the specified target, along with a rom.oby file
       
   582 that can be fed to (a) rombuild to regenerate the image.
       
   583 
       
   584 The following options are required:
       
   585   --variant=<variant>         e.g. --variant=assabet
       
   586   --inst=<instruction set>    e.g. --inst=arm4
       
   587   --build=<build>             e.g. --build=udeb
       
   588   --type=<type of rom>  
       
   589          tshell for a text shell rom
       
   590          e32tests for a rom with e32tests
       
   591          f32tests for rom with f32tests
       
   592          alltests for all the tests
       
   593 
       
   594 The following are optional:
       
   595   --name=<image name>               Give image file specified name
       
   596   --noheader                        Pass -no-header option on to rombuild
       
   597   --help                            This help message.
       
   598   --clean                           Remove existing generated files first
       
   599   --quiet                           Be less verbose
       
   600   --modules=<comma separated list>  List of additional modules for this ROM
       
   601   --define=<comma separated list>   List of CPP macros to define
       
   602 
       
   603 Options may be specified as a short abbreviation 
       
   604 e.g. -b udeb instead of --build udeb
       
   605 
       
   606 EOT
       
   607 }
       
   608 
       
   609 sub rectify($$$) {
       
   610 	my ($in, $out, $k) = @_;
       
   611 	my $lastblank;
       
   612 	my $lineno = 0;
       
   613 	my $epocroot_pattern = $on_windows ? $epocroot . '\\\\' : $epocroot;
       
   614 
       
   615 	open(OUTPUT_FILE, "> $out") or die "Cannot open $out for output";
       
   616 	open(INPUT_FILE, "< $in") or die "Cannot open for $in input";
       
   617   
       
   618 	while ($line=<INPUT_FILE>) {
       
   619 		++$lineno;
       
   620 		if ($line =~ /^\/\// ) {} # Ignore c++ commented lines.
       
   621 		elsif ($line =~ /^\s*REM\s+/i) {} # Ignore REM commented lines.
       
   622 		elsif ($line =~ /^\s*$/) { # Compress blank lines down to one
       
   623 			if($lastblank) {
       
   624 				# Do nothing
       
   625 			}
       
   626 			else {
       
   627 				# This is the first blank line
       
   628 				$lastblank=1;
       
   629 				print OUTPUT_FILE $line;
       
   630 			}
       
   631 		}
       
   632 		else {
       
   633 			# Not blank
       
   634 			my $epoc32_line = 0;
       
   635 			$lastblank = 0;
       
   636 			$line =~ s|\#\#||g; # Delete "token-pasting" ops
       
   637 			$line =~ s|//.*$||g; # Delete trailing c++ comments
       
   638 			# prefix the epocroot dir to occurrences of 'epoc32' in all "KEYWORD=..." lines.
       
   639 			$line =~ s/(=\s*)[\\\/]epoc32/\1$epoc32path/i;
       
   640 			$epoc32_line = defined($1);
       
   641 			if (!$epoc32_line) {
       
   642 				$line =~ /(=.*$epocroot_pattern)/i;
       
   643 				$epoc32_line = defined($1);
       
   644 			}
       
   645 			if (!$epoc32_line) {
       
   646 				if ($k and $line=~/^\s*kerneltrace/i) {
       
   647 					$line = "kerneltrace $k\n";
       
   648 				}
       
   649 			}
       
   650 			elsif ($on_windows) {
       
   651 				$line =~ s|\/|\\|g;
       
   652 			}
       
   653 			elsif ($line =~ /(^bootbinary\s*=\s*${epocroot}epoc32)(\S+)$/) {
       
   654 				# unixify the bootbinary line
       
   655 				my $tail = $2;
       
   656 				$line =~ s|\\|\/|g;
       
   657 				$tail =~ s|\\|\/|g;
       
   658 				my $lc_tail = lc($tail);
       
   659 				$line =~ s|$tail|$lc_tail|;
       
   660 			}
       
   661 			elsif ($line =~ /^(\s*\S+\s*=\s*)(\S+)(\s*\S*)/) {
       
   662 				#unixify the lefthand sides of rom-mapping lines.
       
   663 				my $keyword_part = $1;
       
   664 				my $src = $2;
       
   665 				my $dest = $3;
       
   666 				$dest =~ s/^\s+//;
       
   667 				$dest =~ s/\s+$//;
       
   668 				$src =~ s|\\|\/|g;
       
   669 				if ($dest) {
       
   670 					my ($vol,$dir,$leaf) = File::Spec->splitpath($src);
       
   671 					my $lc_leaf = lc($leaf);
       
   672 					my $lc_dir = lc($dir);
       
   673 					$lc_dir =~ s/\/$//;
       
   674 					$lc_dir =~ s|^$lc_epocroot|$epocroot|;
       
   675 					my $fulldir = $lc_dir;	
       
   676 					$fulldir =~ s|//|/|g;
       
   677 					$dest =~ s|\/|\\|g;
       
   678 					$dest = '\\' . $dest, unless ($dest =~ /^\\/);
       
   679 					unless ( -d $fulldir ) {
       
   680 						chomp $line;
       
   681 						# Lower-cased source directory doesn't exist. Give up.
       
   682 						die "Guessed source directory \"$fulldir\" does not exist for line $lineno: \"$line\"\n";
       
   683 					}
       
   684 					if (($leaf eq $lc_leaf) or (-f "$fulldir\/$leaf")) { 
       
   685 						# Using source directory lowercase and source filename as input.
       
   686 						$line = "${keyword_part}${lc_dir}\/${leaf}\t${dest}\n";
       
   687 					}
       
   688 					elsif ( -f "$fulldir\/$lc_leaf") {
       
   689 						# Using source directory source filename both lowercase.
       
   690 						$line = "${keyword_part}${lc_dir}\/${lc_leaf}\t${dest}\n";
       
   691 					}
       
   692 					else { # Harder.
       
   693 						my @dirlist;
       
   694 						my $found = 0;
       
   695 						if (!defined($dir_listings{$fulldir})) {
       
   696 							# Haven't got a cached dir listing for the source directory.
       
   697 							# Make one now.
       
   698 							@dirlist = glob("$fulldir.*");
       
   699 							$dir_listings{$fulldir} = \@dirlist;
       
   700 						}	
       
   701 						@dirlist = @{dir_listings{$fulldir}}; # Get listing of source directory from cache.
       
   702 						foreach my $file (@dirlist) {
       
   703 							# See if any file in the source directory case-insensitively matches the input source file.
       
   704 							if ( (-f "$fulldir\/$file") and (lc($file) eq $lc_leaf)) {
       
   705 								$line = "${keyword_part}${lc_dir}\/${file}\t${dest}\n";
       
   706 								$found = 1;
       
   707 								last;
       
   708 							}
       
   709 						}
       
   710 						unless ($found) {
       
   711 							die "Cannot find any file case-insensitively matching \"$fulldir\/$leaf\" at line $lineno: \"$line\"\n";
       
   712 						}
       
   713 					}
       
   714 				}
       
   715 				else {
       
   716 					$line =~ s|\\|\/|g;
       
   717 				}								
       
   718 			}
       
   719 			print OUTPUT_FILE $line;
       
   720 		}
       
   721 	}
       
   722 	close(INPUT_FILE);
       
   723 	close(OUTPUT_FILE);
       
   724 }
       
   725 
       
   726 sub IsRVCTBuild($) {
       
   727     my ($build)=@_;
       
   728     return 1 if ($build =~ /^ARMV/i);
       
   729 	my @customizations = Plat_Customizations('ARMV5');
       
   730 	return 1 if (grep /$build/, @customizations);
       
   731 	return 0;
       
   732 }
       
   733 
       
   734 
       
   735 sub IsSmp($) {
       
   736 	my %SmpKernelDirs=(
       
   737 		'x86smp' => 1,
       
   738 		'x86gmp' => 1,
       
   739 		'arm4smp' => 1,
       
   740 		'armv4smp' => 1,
       
   741 		'armv5smp' => 1
       
   742 	);
       
   743 
       
   744 	my ($kdir) = @_;
       
   745 	return $SmpKernelDirs{lc $kdir};
       
   746 }
       
   747 
       
   748 sub checkopts {
       
   749 	unless($opts{variant}) { die "No Variant specified"; }
       
   750 	$opts{'build'}="UDEB" unless($opts{'build'});
       
   751 	$opts{'type'}="TSHELL" unless($opts{'type'});
       
   752 	$opts{'inst'}="ARM4" unless($opts{'inst'});
       
   753 
       
   754 	my $additional;
       
   755 	if ($opts{'modules'}) {
       
   756 		$additional="_".$opts{modules};
       
   757 		$additional=~ s/,/_/ig;
       
   758 	}
       
   759 	my $build=lc $opts{build};
       
   760 	my $inst=uc $opts{'inst'};
       
   761 	if ($inst eq "MARM") {
       
   762 		# Hackery to cope with old compiler
       
   763 		$main="MARM";
       
   764 		$euserdir="MARM";
       
   765 		$elocldir="MARM";
       
   766 	}
       
   767 	else {
       
   768 		$main=$inst;
       
   769 		if ($main eq "THUMB") {
       
   770 			$euserdir="ARMI";
       
   771 		} else {
       
   772 			$euserdir=$main;
       
   773 		}
       
   774 		if ($main eq "ARMI" or $main eq "THUMB") {
       
   775 			$elocldir="ARM4";
       
   776 		} else {
       
   777 			$elocldir=$main;
       
   778 		}
       
   779 	}
       
   780 	$kmain = $opts{'xabi'};
       
   781 	$kmain = $main unless ($kmain);
       
   782 	if (IsSmp($kmain)) {
       
   783 		$euserdir = $kmain;
       
   784 	}
       
   785 	if ($opts{name}) {
       
   786 		$romname=$opts{name};
       
   787 	} else {
       
   788 		$romname=uc($opts{variant}.$additional.$main);
       
   789 		if ($build=~/^\w*DEB$/i) {
       
   790 			$romname.='D';
       
   791 		}
       
   792 		$romname.='.IMG';
       
   793 	}
       
   794 }
       
   795 
       
   796 sub lookupFileInfo($$)
       
   797 {
       
   798 	my ($infile, $fullname) = @_;
       
   799 
       
   800 	my ($name, $ext) = $fullname =~ /^(.+)\.(\w+)$/ ? ($1, $2) : ($fullname, undef);
       
   801 
       
   802 	open TMP, $infile or die("Can't open $infile\n");
       
   803 	while(<TMP>)
       
   804 	{
       
   805 		$_ = lc;
       
   806 		if(/^\s*(\S+)\s*=\s*(\S+)\s+(\S+)/i)
       
   807 		{
       
   808 			my ($src, $dest) = ($2, $3);
       
   809 
       
   810 			my $destFullname = $dest =~ /^.*\\(.+)$/ ? $1 : $dest;
       
   811 			my ($destName, $destExt) = $destFullname =~ /^(.+?)\.(\w+)$/ ? ($1, $2) : ($destFullname, undef);
       
   812 
       
   813 			if ($destName eq $name && (!$ext || $ext eq $destExt))
       
   814 			{
       
   815 				close TMP;
       
   816 				return ($src, $dest);
       
   817 			}
       
   818 		}
       
   819 	}
       
   820 
       
   821 	die "patchdata: Can't find file $fullname\n";
       
   822 }
       
   823 
       
   824 sub lookupSymbolInfo($$)
       
   825 {
       
   826 	my ($file, $name) = @_;
       
   827 	open TMP, $file or die "Can't read $file\n";
       
   828 
       
   829 	# ignore local symbols.
       
   830 	while (<TMP>)
       
   831 	{
       
   832 		last if /Global Symbols|Linker script and memory map/;
       
   833 	}
       
   834 
       
   835   my @return_values = ();
       
   836   my $line;
       
   837 	while ($line = <TMP>)
       
   838 	{
       
   839 		next if (index($line, $name) < 0);		
       
   840 		
       
   841 		# RVCT 2.2
       
   842 		# 
       
   843 		#     KHeapMinCellSize  0x0004e38c  Data 4  mem.o(.constdata)
       
   844 		#
       
   845 		if ($line =~ /^\s*(\S+)\s+(\S+)\s+data\s+(\S+)/i)
       
   846 		{
       
   847 			my ($symbol, $addr, $size) = ($1, $2, $3);
       
   848 			if ($symbol eq $name)
       
   849 			{
       
   850 				@return_values = ($addr, $size);
       
   851 				last;
       
   852 			}
       
   853 		}
       
   854 
       
   855 		# This is a quick fix for RVCT 3.1, which uses the text "(EXPORTED)"
       
   856 		# in the map file. Here is an example:
       
   857 		#
       
   858 		# KHeapMinCellSize (EXPORTED) 0x0003d81c Data 4 mem.o(.constdata)
       
   859 		#
       
   860 		elsif ($line =~ /^\s*(\S+)\s+\(exported\)\s+(\S+)\s+data\s+(\S+)/i)
       
   861 		{
       
   862 			my ($symbol, $addr, $size) = ($1, $2, $3);
       
   863 			if ($symbol eq $name)
       
   864 			{
       
   865 				@return_values = ($addr, $size);
       
   866 				last;
       
   867 			}
       
   868 		}
       
   869 		
       
   870 		# GCC 4.x map files
       
   871 		#                 0x00114c68                KHeapMinCellSize
       
   872 		#                 0x00114c6c                KHeapShrinkHysRatio
       
   873 		#  .rodata        0x00115130      0x968 M:/epoc32/build/kernel/c_99481fddbd6c6f58/_omap3530_ekern_exe/armv5/udeb/heap_hybrid.o
       
   874 		#
       
   875 		elsif ($line =~ /^.+\s+(0x\S+)\s+(\S+)/i)
       
   876 		{
       
   877 			my ($addr, $symbol) = ($1, $2);
       
   878 			if ($symbol eq $name)
       
   879 			{
       
   880 				my $next_line = <TMP>;
       
   881 				if ($next_line =~ /^.+\s+(0x\S+)\s+(\S+)/i)
       
   882 				{
       
   883 					my $addr2 = $1;
       
   884 					
       
   885 					@return_values = ($addr, hex($addr2) - hex($addr));
       
   886 					last;
       
   887 				}
       
   888 			}
       
   889 		}
       
   890 
       
   891 	}
       
   892 	close TMP;
       
   893 
       
   894 	die "patchdata: Can't find symbol $name\n" if (scalar @return_values == 0);
       
   895 	return @return_values;
       
   896 }
       
   897 
       
   898 sub parsePatchData($$)
       
   899 {
       
   900 	my ($infile, $outfile) = @_;
       
   901 
       
   902 	open IN, $infile or die("Can't read $infile\n");
       
   903 	open OUT, ">$outfile" or die("Can't write $outfile\n");
       
   904 
       
   905 	my $line;
       
   906 	while($line = <IN>)
       
   907 	{
       
   908 		if ($line =~ /^\s*patchdata\s+(.+?)\s*$/i)
       
   909 		{
       
   910 			if ($1 !~ /(\S+)\s*@\s*(\S+)\s+(\S+)\s*$/)
       
   911 			{
       
   912 				die "Bad patchdata command: $line\n";
       
   913 			}
       
   914 
       
   915 			my ($file, $symbol, $value) = (lc $1, $2, $3);
       
   916 			my ($srcFile, $destFile) = lookupFileInfo($infile, $file);
       
   917 			my ($index, $elementSize) = (undef, undef);
       
   918 			if ($symbol =~ s/:(\d+)\[(\d+)\]$//)
       
   919 			{
       
   920 				($index, $elementSize) = ($2, $1);
       
   921 				$index = hex($index) if $index =~ /^0x/i;
       
   922 			}
       
   923 
       
   924 			if ($srcFile =~ /\\armv5(smp)?\\/i)
       
   925 			{
       
   926 				my ($symbolAddr, $symbolSize) = lookupSymbolInfo("$srcFile.map", $symbol);
       
   927 
       
   928 				my $max;
       
   929 				if (defined($index))
       
   930 				{
       
   931 					my $bytes;
       
   932 					$bytes = 1, $max = 0xff       if $elementSize ==  8;
       
   933 					$bytes = 2, $max = 0xffff     if $elementSize == 16;
       
   934 					$bytes = 4, $max = 0xffffffff if $elementSize == 32;
       
   935 					die("patchdata: invalid element size $elementSize: $line\n") unless defined($bytes);
       
   936 
       
   937 					if ($bytes > 1 && (($symbolSize & ($bytes-1)) != 0))
       
   938 					{
       
   939 						die("patchdata: unexpected symbol size $symbolSize for array $symbol ($elementSize-bit elements)\n");
       
   940 					}
       
   941 
       
   942 					if ($index >= int($symbolSize / $bytes))
       
   943 					{
       
   944 						die("patchdata: index $index out of bounds for $symbol of $symbolSize bytes ($elementSize-bit elements)\n");
       
   945 					}
       
   946 
       
   947 					$symbolAddr = hex($symbolAddr) if $symbolAddr =~ /^0x/i;
       
   948 					$symbolAddr += $index * $bytes;
       
   949 					$symbolAddr = sprintf("0x%x", $symbolAddr);
       
   950 
       
   951 					$symbolSize = $bytes;
       
   952 				}
       
   953 				elsif ($symbolSize == 1) { $max = 0xff; }
       
   954 				elsif ($symbolSize == 2) { $max = 0xffff; }
       
   955 				elsif ($symbolSize == 4) { $max = 0xffffffff; }
       
   956 				else { die "patchdata: Unexpected symbol size $symbolSize for $symbol\n"; }
       
   957 
       
   958 				$value = hex($value) if $value =~ /^0x/i;
       
   959 				if ($value > $max)
       
   960 				{
       
   961 					print("Warning:  Value overflow of $symbol\n");
       
   962 					$value &= $max;
       
   963 				}					
       
   964 				$value = sprintf("0x%08x", $value);
       
   965 
       
   966 				$line = "patchdata $destFile addr $symbolAddr $symbolSize $value\n";
       
   967 			}
       
   968 			else
       
   969 			{
       
   970 				$line = "";
       
   971 			}
       
   972 
       
   973 		}
       
   974 
       
   975 		print OUT $line;
       
   976 	}
       
   977 
       
   978 	close IN;
       
   979 	close OUT;
       
   980 }
       
   981 
       
   982 sub genfile {
       
   983 	my $count=0;
       
   984 	if($_[0] eq 'paged') {
       
   985 		my $file='gentestpaged.txt';
       
   986 		unlink $file;
       
   987 		open(OUTFILE, ">$file") or die "Can't open output file, $!";
       
   988 		for(my $i=0;$i<50000;++$i) {
       
   989 			if(($i >5) && ($i % 40 ==0)) {
       
   990 			print OUTFILE "\n";
       
   991 			$count++;
       
   992 			} 
       
   993 			if(($i+$count) % 5 ==0) {
       
   994 			print OUTFILE "SATOR ";
       
   995 			}
       
   996 			if(($i+$count) % 5 ==1) {
       
   997 			print OUTFILE "AREPO ";
       
   998 			}
       
   999 			if(($i+$count) % 5 ==2) {
       
  1000 			print OUTFILE "TENET ";
       
  1001 			}
       
  1002 			if(($i+$count) % 5 ==3) {
       
  1003 			print OUTFILE "OPERA ";
       
  1004 			}
       
  1005 			if(($i+$count) % 5 ==4) {
       
  1006 			print OUTFILE "ROTAS ";
       
  1007 			}
       
  1008 		}
       
  1009 	} else {
       
  1010 		my $file='gentestnonpaged.txt';
       
  1011 		unlink $file;
       
  1012 		open(OUTFILE, ">$file") or die "Can't open output file, $!";
       
  1013 		for(my $i=0;$i<20000;++$i) {
       
  1014 			if(($i >5) && ($i % 40 ==0)) {
       
  1015 			print OUTFILE "\n";
       
  1016 			$count++;
       
  1017 			} 
       
  1018 			if(($i+$count) % 4 ==0) {
       
  1019 			print OUTFILE "STEP ";
       
  1020 			}
       
  1021 			if(($i+$count) % 4 ==1) {
       
  1022 			print OUTFILE "TIME ";
       
  1023 			}
       
  1024 			if(($i+$count) % 4 ==2) {
       
  1025 			print OUTFILE "EMIT ";
       
  1026 			}
       
  1027 			if(($i+$count) % 4 ==3) {
       
  1028 			print OUTFILE "PETS ";
       
  1029 			}
       
  1030 		}
       
  1031 	}
       
  1032 }
       
  1033 
       
  1034 sub Variant_GetMacroHRHFile {
       
  1035 	my $cfgFile =  File::Spec->catfile($toolpath,"variant","variant.cfg"); # default location
       
  1036 	# save the volume, if any.
       
  1037 	my ($cfg_vol,$ignore1,$ignore2) = File::Spec->splitpath($cfgFile);    
       
  1038     my $file;
       
  1039     if(-e $cfgFile){
       
  1040 		open(FILE, $cfgFile) || die "\nCould not open for reading: " . $cfgFile ."\n";
       
  1041 		while (<FILE>) {
       
  1042 			# strip comments
       
  1043 			s/^([^#]*)#.*$/$1/o;
       
  1044 			# skip blank lines
       
  1045 			if (/^\s*$/o) {
       
  1046 				next;
       
  1047 			}
       
  1048 			# get the hrh file
       
  1049 			if($_ =~ /\.hrh/xi){
       
  1050 				$file = $_; 
       
  1051 				last;
       
  1052 			}
       
  1053 		}
       
  1054 		close FILE;
       
  1055 		die "\nERROR: No variant file specified in $cfgFile!\n" unless $file;
       
  1056 		$file =~ s/\s+//g;
       
  1057 		$file =~ s|\\|\/|g, unless($on_windows);
       
  1058 
       
  1059 		if ($on_windows) {
       
  1060 			if (File::Spec->file_name_is_absolute($file)) {
       
  1061 				my ($vol,$dir,$leaf) = File::Spec->splitpath($file);
       
  1062 				unless ( $vol) {
       
  1063 					$vol = substr $epocroot,0,2;
       
  1064 					$file = substr $file,1;                 
       
  1065 					$file = File::Spec->catfile($epocroot,$dir,$leaf);
       
  1066 				}
       
  1067 				die "\nERROR: Variant file specified in $cfgFile is not on the same volume as EPOCROOT\n", if (lc($vol) ne lc($cfg_vol));
       
  1068 			}
       
  1069 			else {
       
  1070 				$file = File::Spec->catfile($epoc32path,$file);
       
  1071 			}
       
  1072 		}
       
  1073 		elsif (File::Spec->file_name_is_absolute($file) && ! -e $file) {
       
  1074 			$file = File::Spec->catfile($epocroot,$file);
       
  1075 		} 
       
  1076 
       
  1077 		unless(-e $file) {
       
  1078 			die "\nERROR: $cfgFile specifies $file which doesn't exist!\n";
       
  1079 		}
       
  1080 
       
  1081 		$file =~ s/\//\\/g, if ($on_windows);
       
  1082     }
       
  1083     return $file;
       
  1084 }
       
  1085