sbsv1/abld/e32util/featurevariantmap.pm
changeset 599 fa7a3cc6effd
equal deleted inserted replaced
596:9f25be3da657 599:fa7a3cc6effd
       
     1 # Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 # All rights reserved.
       
     3 # This component and the accompanying materials are made available
       
     4 # under the terms of "Eclipse Public License v1.0"
       
     5 # which accompanies this distribution, and is available
       
     6 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 #
       
     8 # Initial Contributors:
       
     9 # Nokia Corporation - initial contribution.
       
    10 #
       
    11 # Contributors:
       
    12 #
       
    13 # Description:
       
    14 #
       
    15 
       
    16 # modified start: makefile improvement 
       
    17 use Cwd;
       
    18 # modified end: makefile improvement 
       
    19 use Digest::MD5;
       
    20 use File::Basename;
       
    21 
       
    22 package featurevariantmap;
       
    23 our $verbose = 0;
       
    24 
       
    25 my $featureListDir = "$ENV{EPOCROOT}epoc32\\include\\variant\\featurelists";
       
    26 
       
    27 sub LoadFeatureList
       
    28 	{
       
    29 	my %featurehash;
       
    30 	
       
    31 	# Try and find the feature master list folder
       
    32 	if (!opendir DIR, $featureListDir)
       
    33 		{
       
    34 		print "\nERROR: Failed to open feature list directory $featureListDir: $!";
       
    35 		return \%featurehash;
       
    36 		}
       
    37 		
       
    38 	# Load the list of features from each file
       
    39 	foreach my $file ( grep(/\.txt$/i, readdir DIR) )
       
    40 		{
       
    41 		$file = "$featureListDir\\$file";
       
    42 		print "Reading feature list from $file\n" if ($verbose);
       
    43 
       
    44 		if (!open IN, $file)
       
    45 			{
       
    46 			print "\nERROR: Failed to read feature list $file: $!";
       
    47 			}
       
    48 		else
       
    49 			{
       
    50 			while(my $line = <IN>)
       
    51 				{
       
    52 				$line =~ s/\/\/.+$//; # Get rid of c++ style comments
       
    53 				if ($line =~ /(\S+)/)
       
    54 					{
       
    55 					$featurehash{$1} = $file;
       
    56 					}
       
    57 				}
       
    58 			close IN;
       
    59 			}
       
    60 			
       
    61 		}
       
    62 	closedir DIR;
       
    63 	return \%featurehash;
       
    64 	}
       
    65 	
       
    66 sub ValidFeature
       
    67 {
       
    68 	our $featurelist;
       
    69 	my $name = shift;
       
    70 	
       
    71 	$featurelist = LoadFeatureList() if !$featurelist;
       
    72 	return exists $featurelist->{$name};
       
    73 # modified start: makefile improvement 
       
    74 }
       
    75 sub GetVariantListFromVmap
       
    76 {
       
    77 	my $obj = shift;
       
    78 	my $vmapfile = shift;
       
    79 	if(open(VMAP, "<$vmapfile"))
       
    80 	{
       
    81 		my @varlist;
       
    82 		while(<VMAP>)
       
    83 		{
       
    84 			if(/^\w{32}\s+(\w+)/)
       
    85 			{
       
    86 				push @varlist, $1;
       
    87 			}
       
    88 
       
    89 		}
       
    90 		close(VMAP);
       
    91 		return @varlist;
       
    92 	}
       
    93 	close(VMAP);
       
    94 	return;
       
    95 	
       
    96 }
       
    97 sub CheckOldVmapFile
       
    98 {
       
    99 	my $thisObj = shift;
       
   100 	my $vmapfile = shift;
       
   101 	my $varRef = shift;
       
   102 	my $buildincludes = $$varRef{BUILD_INCLUDES};
       
   103 	my $parents = $$varRef{PARENTS};
       
   104 	my $children = $$varRef{CHILDREN};
       
   105 	my $varianthrh = $$varRef{VARIANT_HRH};
       
   106 	my %variantMacrolist;
       
   107 	my $Options = "-dM -undef -nostdinc -+";
       
   108 	my $Drive = $1 if (Cwd->cwd =~ /^(.:)/);
       
   109 	if($buildincludes)
       
   110 	{
       
   111 		foreach (@$buildincludes)
       
   112 		{
       
   113 			$Options .= " -I \"".$Drive.$_."\"";
       
   114 		}
       
   115 	}
       
   116 	if($varianthrh)
       
   117 	{
       
   118 		$Options .= " \"".$Drive.$varianthrh."\"";
       
   119 	}
       
   120 	if(open(CPP, "cpp $Options 2>&1 |"))
       
   121 	{
       
   122 		while(<CPP>)
       
   123 		{
       
   124 			my ( $key, $value );
       
   125 			if (/^#define (\w+(?:\([^\)]*\))?)(?:\s(\S.*?))?\s*$/)
       
   126 			{
       
   127 				my $tmpKey = $1;
       
   128 				my $tmpValue = $2;
       
   129 				$tmpValue =~ s/,/\\,/g;
       
   130 				($key, $value ) = ( $tmpKey, $tmpValue ? "\'$tmpValue\'" : 'defined' );
       
   131 			}
       
   132 			if ($key && ValidFeature($key))
       
   133 			{
       
   134 				$variantMacrolist{$key} = $value;
       
   135 			}
       
   136 		}
       
   137 		if(!close(CPP))
       
   138 		{
       
   139 			print "Incomplete pre-precess of $varianthrh \n";
       
   140 		}
       
   141 	}
       
   142 	my $findReusedKey = 1;
       
   143 	my %vmapfeatureinfo;
       
   144 	my $keyhash;
       
   145 	my $macroList;
       
   146 	if(open(VMAP, "<$vmapfile"))
       
   147 	{
       
   148 		while(<VMAP>)
       
   149 		{
       
   150 			if(/^\w{32}\s+(\w+)/)
       
   151 			{
       
   152 				$findReusedKey = 1;
       
   153 				s/(^\w{32})\s+\w+\s+//;
       
   154 				$keyhash = $1;
       
   155 				my @feature = split(/(?<=[^\\]),/, $_);
       
   156 				foreach my $value (@feature)
       
   157 				{
       
   158 					if($value =~ /([^\s]*)\s*=\s*(.*)/)
       
   159 					{
       
   160 						$vmapfeatureinfo{$1} = $2;
       
   161 					}
       
   162 				}
       
   163 				foreach my $key (sort keys %vmapfeatureinfo)
       
   164 				{
       
   165 					
       
   166 					if(($vmapfeatureinfo{$key} eq "undefined") && (not(exists($variantMacrolist{$key}))))
       
   167 					{
       
   168 						$findReusedKey = 1;
       
   169 					}
       
   170 					elsif($vmapfeatureinfo{$key} eq $variantMacrolist{$key})
       
   171 					{
       
   172 						$findReusedKey = 1;
       
   173 					}else
       
   174 					{
       
   175 						$findReusedKey = 0;
       
   176 						last;
       
   177 					}
       
   178 				}
       
   179 				if( $findReusedKey == 1)
       
   180 				{
       
   181 					$macroList = $_;
       
   182 					last;
       
   183 				}
       
   184 				undef(%vmapfeatureinfor);
       
   185 				undef($keyhash);
       
   186 			}
       
   187 		}
       
   188 	}
       
   189 	if($findReusedKey == 1)
       
   190 	{
       
   191     	return ($keyhash, $macroList);
       
   192 	}
       
   193 	else
       
   194 	{
       
   195 		return;
       
   196 	}
       
   197 }
       
   198 # modified end: makefile improvement 
       
   199 	
       
   200 # Usage:	featurevariantmap->Hash(\@sources, \%var)
       
   201 #
       
   202 # Generate a hash value from the source files for a target using the
       
   203 # given feature variant data.
       
   204 #
       
   205 # \@sources	- list of source files (full path)
       
   206 # \%var		- variant data (from featurevariantparser->GetVariant)
       
   207 #
       
   208 # returns the hash value, or "" if an error occurs.
       
   209 	
       
   210 sub Hash
       
   211 {
       
   212 	my $thisObj = shift;
       
   213 	my @result = $thisObj->HashAndFeatures(@_);
       
   214 	return $result[0];
       
   215 }
       
   216 
       
   217 # Usage:	featurevariantmap->HashAndFeatures(\@sources, \%var)
       
   218 #
       
   219 # Generate a hash value from the source files for a target using the
       
   220 # given feature variant data.
       
   221 #
       
   222 # \@sources	- list of source files (full path)
       
   223 # \%var		- variant data (from featurevariantparser->GetVariant)
       
   224 #
       
   225 # returns a list of two entries [0] the hash value, or "" if an error occurs [1] A string of macros tested or affecting the code
       
   226 
       
   227 sub HashAndFeatures
       
   228 {
       
   229 	my $thisObj = shift;
       
   230 	my $srcRef = shift;
       
   231 	my $varRef = shift;
       
   232 
       
   233 	return "" if (!$srcRef || !$varRef);
       
   234 	return "" if (!$$varRef{'VALID'});
       
   235 
       
   236 	# get the pre-processing options
       
   237 	my $pre = $$varRef{'PREINCLUDE'};
       
   238 	my $inc = $$varRef{'BUILD_INCLUDES'};
       
   239 	my $mac = $$varRef{'MACROS'};
       
   240 
       
   241 	# Pass -dU option to get list of macros affecting the code
       
   242 	my $options = "-dU -undef -nostdinc -+";
       
   243 
       
   244 	if ($pre)	# pre-include file
       
   245 	{
       
   246 		$options .= " -include \"$pre\"";
       
   247 	}
       
   248 
       
   249 	if ($inc)	# include directories
       
   250 	{
       
   251 		foreach (@$inc)
       
   252 		{
       
   253 			$options .= " -I \"$_\"";
       
   254 		}
       
   255 	}
       
   256 
       
   257 	if ($mac)	# macro definitions
       
   258 	{
       
   259 		foreach (@$mac)
       
   260 		{
       
   261 			$options .= " -D$_";
       
   262 		}
       
   263 	}
       
   264 
       
   265 	my %testedMacrosHash;
       
   266 	
       
   267 	# Macros that affect the mmp file also affect the variant - so add them to the list
       
   268 	foreach my $key ( keys %{ $$varRef{MMPTESTED} } )
       
   269 		{
       
   270 		$testedMacrosHash{$key} = $$varRef{MMPTESTED}->{$key} if (ValidFeature($key));
       
   271 		}
       
   272 		
       
   273 	foreach my $src (@$srcRef)
       
   274 	{
       
   275 		my $options = "-I " . File::Basename::dirname($src) . " $options";
       
   276 
       
   277 		print "cpp $options $src\n" if ($verbose);
       
   278 
       
   279 		if (open(CPP, "cpp $options $src 2>&1 |"))
       
   280 		{
       
   281 			while (<CPP>)
       
   282 			{
       
   283 				print $_ if ($verbose && /No such file/);
       
   284 
       
   285 				# Scan for #define or #undef generated for -dU
       
   286 				my ( $key, $value );
       
   287 				if (/^#define (\w+(?:\([^\)]*\))?)(?:\s(\S.*?))?\s*$/)
       
   288 				{
       
   289 # modified start: makefile improvement 
       
   290 					my $tmpKey = $1;
       
   291 					my $tmpValue = $2;
       
   292 					$tmpValue =~ s/,/\\,/g;
       
   293 					( $key, $value ) = ( $tmpKey, $tmpValue ? "\'$tmpValue\'" : 'defined' );
       
   294 # modified end: makefile improvement 
       
   295 				}
       
   296 				elsif (/^#undef (.+)$/)
       
   297 				{
       
   298 					( $key, $value ) = ( $1, 'undefined' );
       
   299 				}
       
   300 				
       
   301 				if ($key && ValidFeature($key))
       
   302 				{
       
   303 					# Warn the user if a macro appears to have changed value - shouldn't really happen
       
   304 					# Feature macros should only be set in platform HRH files and not in the code
       
   305 					if (exists $testedMacrosHash{$key} && $testedMacrosHash{$key} ne $value)
       
   306 					{
       
   307 						print "WARNING: Feature macro $key redefined from $testedMacrosHash{$key} to $value\n";
       
   308 					}
       
   309 					
       
   310 					# Store the macro details
       
   311 					$testedMacrosHash{$key} = $value;
       
   312 				}
       
   313 			}
       
   314 			if (!close(CPP))
       
   315 			{
       
   316 				# this probably means that a rsg file was included
       
   317 				# that hasn't been generated yet.
       
   318 				print "Incomplete pre-process of $src\n" if ($verbose);
       
   319 			}
       
   320 		}
       
   321 		else
       
   322 		{
       
   323 			print "ERROR: Could not pre-process $src\n";
       
   324 			return "";
       
   325 		}
       
   326 	}
       
   327 
       
   328 	# Now generate the tested macros string
       
   329 	my $testedMacros = '';
       
   330 	foreach my $key ( sort keys %testedMacrosHash )
       
   331 	{
       
   332 		$testedMacros .= ',' if $testedMacros;
       
   333 		$testedMacros .= "$key=$testedMacrosHash{$key}";
       
   334 	}
       
   335 	
       
   336 	print "Tested feature list: $testedMacros\n" if $verbose;
       
   337 	return ( Digest::MD5::md5_hex($testedMacros), $testedMacros );
       
   338 }
       
   339 
       
   340 # Usage:	featurevariantmap->Save("my.dll", "1234", "myvar", \@hints)
       
   341 #
       
   342 # Write a hash value for a target into the target.vmap file along
       
   343 # with some optional hints data.
       
   344 #
       
   345 # "my.dll"	- the target (full path)
       
   346 # "1234"	- the hash value (32 character hex number)
       
   347 # "myvar"	- the feature variant name
       
   348 # \@hints	- optional list of extra strings (eg. "FEATUREVARIANT")
       
   349 #
       
   350 # returns 0 if OK and non-zero if an error occurs.
       
   351 
       
   352 sub Save
       
   353 {
       
   354 	my $thisObj = shift;
       
   355 	my $binName = shift;
       
   356 	my $keyValue = shift;
       
   357 	my $varName = shift;
       
   358 	my $features = shift;
       
   359 	my $hintRef = shift;
       
   360 
       
   361 	# read the current data first if the .vmap file already exists
       
   362 # modified by SV start: makefile improvement 
       
   363 	my $vmapFile = "$binName.$varName.vmap";
       
   364 	my @lines;
       
   365 	my $tmpinfo = "$keyValue $varName";
       
   366 	$tmpinfo .= " $features" if $features;
       
   367 	if (open(VMAP, $vmapFile))
       
   368 	{
       
   369 		my @tmp=<VMAP>;
       
   370 		if (grep (/$tmpinfo/, @tmp)){
       
   371 			close(VMAP);
       
   372 			return 0;
       
   373 		}
       
   374 		else {
       
   375 			foreach  (@tmp)
       
   376 			{
       
   377 				if (/^\w{32}\s+(\w+)/)
       
   378 				{
       
   379 					push(@lines, $_) unless (uc($1) eq uc($varName));
       
   380 				}
       
   381 			}
       
   382 			close(VMAP);
       
   383 		}
       
   384 	}
       
   385 # modified by SV end: makefile improvement 
       
   386 
       
   387 	# write the new data to the .vmap file
       
   388 	if (!open(VMAP, ">$vmapFile"))
       
   389 	{
       
   390 		print "ERROR: Could not write VMAP to $vmapFile\n";
       
   391 		return 1;
       
   392 	}
       
   393 
       
   394 	# put the hints at the beginning
       
   395 	if ($hintRef)
       
   396 	{
       
   397 		foreach (@$hintRef)
       
   398 		{
       
   399 			print VMAP "$_\n";
       
   400 		}
       
   401 	}
       
   402 
       
   403 	# then the "key var" pairs
       
   404 	foreach (@lines)
       
   405 	{
       
   406 		print VMAP $_;
       
   407 	}
       
   408 	print VMAP "$keyValue $varName";
       
   409 	print VMAP " $features" if $features;
       
   410 	print VMAP "\n";
       
   411 	
       
   412 	close(VMAP);
       
   413 	return 0;
       
   414 }
       
   415 
       
   416 # Usage:    featurevariantmap->Find("my.dll", "myvar")
       
   417 #
       
   418 # Look for a binary using its "final" name. We will use the feature
       
   419 # variant map and the feature variant name to deduce the "variant"
       
   420 # binary name and test for its existence.
       
   421 #
       
   422 # "my.dll"	- the final target (full path)
       
   423 # "myvar"	- the feature variant name
       
   424 #
       
   425 # returns the file name if found, or "" otherwise.
       
   426 
       
   427 sub Find
       
   428 {
       
   429 	my $thisObj = shift;
       
   430 	my $binName = shift;
       
   431 	my $varName = shift;
       
   432 
       
   433 	# look for the vmap file
       
   434 # modified by SV start: makefile improvement 
       
   435 	my $vmapFile = "$binName.$varName.vmap";
       
   436 # modified by SV end: makefile improvement 
       
   437 
       
   438 	if (-e $vmapFile)
       
   439 	{
       
   440 		my $key = $thisObj->GetKeyFromVMAP($varName, $vmapFile);
       
   441 
       
   442 		if ($key)
       
   443 		{
       
   444 			$binName =~ /^(.*)\.([^\.]*)$/;
       
   445 			$binName = "$1.$key.$2";
       
   446 		}
       
   447 		else
       
   448 		{
       
   449 			print "ERROR: No \'$varName\' variant for $binName in $vmapFile\n";
       
   450 			return "";	# file not found
       
   451 		}
       
   452 	}
       
   453 
       
   454 	# check that the actual binary exists
       
   455 	if (-e $binName)
       
   456 	{
       
   457 		return $binName;
       
   458 	}
       
   459 	return "";	# file not found
       
   460 }
       
   461 
       
   462 # internal functions
       
   463 
       
   464 sub GetKeyFromVMAP
       
   465 	{
       
   466 	my $thisObj = shift;
       
   467 	my @res = $thisObj->GetDataFromVMAP(@_);
       
   468 	return $res[0];
       
   469 	}
       
   470 	
       
   471 # Usage:    featurevariantmap->GetDataFromVMAP("myvar", "mydll.vmap")
       
   472 #
       
   473 # Opens the vmap file indicated and returns the data for the requested variant
       
   474 #
       
   475 # "myvar"	- the feature variant name
       
   476 # "my.vmap"	- the final target vmap file (full path)
       
   477 #
       
   478 # Returns a list ( hash, features ) for the variant in the vmap or undef if not found
       
   479 
       
   480 sub GetDataFromVMAP
       
   481 {
       
   482 	my $thisObj = shift;
       
   483 	my $varName = shift;
       
   484 	my $fileName = shift;
       
   485 
       
   486 	if (!open(VMAP, $fileName))
       
   487 	{
       
   488 		print "ERROR: Could not read VMAP from $fileName\n";
       
   489 		return "";
       
   490 	}
       
   491 	while (<VMAP>)
       
   492 	{
       
   493 		chomp;
       
   494 		if (/(\w{32})\s+$varName\s+(.*)$/i or /(\w{32})\s+$varName$/i)
       
   495 		{
       
   496 			my ( $hash, $features ) = ( $1, $2 ? $2 : '' );
       
   497 			close(VMAP);
       
   498 			return ( $hash, $features );
       
   499 		}
       
   500 	}
       
   501 	close(VMAP);
       
   502 	return;
       
   503 }
       
   504 
       
   505 1;