sbsv1/abld/e32util/featurevariantmap.pm
changeset 599 fa7a3cc6effd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sbsv1/abld/e32util/featurevariantmap.pm	Fri Jun 25 17:29:25 2010 +0800
@@ -0,0 +1,505 @@
+# Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description:
+#
+
+# modified start: makefile improvement 
+use Cwd;
+# modified end: makefile improvement 
+use Digest::MD5;
+use File::Basename;
+
+package featurevariantmap;
+our $verbose = 0;
+
+my $featureListDir = "$ENV{EPOCROOT}epoc32\\include\\variant\\featurelists";
+
+sub LoadFeatureList
+	{
+	my %featurehash;
+	
+	# Try and find the feature master list folder
+	if (!opendir DIR, $featureListDir)
+		{
+		print "\nERROR: Failed to open feature list directory $featureListDir: $!";
+		return \%featurehash;
+		}
+		
+	# Load the list of features from each file
+	foreach my $file ( grep(/\.txt$/i, readdir DIR) )
+		{
+		$file = "$featureListDir\\$file";
+		print "Reading feature list from $file\n" if ($verbose);
+
+		if (!open IN, $file)
+			{
+			print "\nERROR: Failed to read feature list $file: $!";
+			}
+		else
+			{
+			while(my $line = <IN>)
+				{
+				$line =~ s/\/\/.+$//; # Get rid of c++ style comments
+				if ($line =~ /(\S+)/)
+					{
+					$featurehash{$1} = $file;
+					}
+				}
+			close IN;
+			}
+			
+		}
+	closedir DIR;
+	return \%featurehash;
+	}
+	
+sub ValidFeature
+{
+	our $featurelist;
+	my $name = shift;
+	
+	$featurelist = LoadFeatureList() if !$featurelist;
+	return exists $featurelist->{$name};
+# modified start: makefile improvement 
+}
+sub GetVariantListFromVmap
+{
+	my $obj = shift;
+	my $vmapfile = shift;
+	if(open(VMAP, "<$vmapfile"))
+	{
+		my @varlist;
+		while(<VMAP>)
+		{
+			if(/^\w{32}\s+(\w+)/)
+			{
+				push @varlist, $1;
+			}
+
+		}
+		close(VMAP);
+		return @varlist;
+	}
+	close(VMAP);
+	return;
+	
+}
+sub CheckOldVmapFile
+{
+	my $thisObj = shift;
+	my $vmapfile = shift;
+	my $varRef = shift;
+	my $buildincludes = $$varRef{BUILD_INCLUDES};
+	my $parents = $$varRef{PARENTS};
+	my $children = $$varRef{CHILDREN};
+	my $varianthrh = $$varRef{VARIANT_HRH};
+	my %variantMacrolist;
+	my $Options = "-dM -undef -nostdinc -+";
+	my $Drive = $1 if (Cwd->cwd =~ /^(.:)/);
+	if($buildincludes)
+	{
+		foreach (@$buildincludes)
+		{
+			$Options .= " -I \"".$Drive.$_."\"";
+		}
+	}
+	if($varianthrh)
+	{
+		$Options .= " \"".$Drive.$varianthrh."\"";
+	}
+	if(open(CPP, "cpp $Options 2>&1 |"))
+	{
+		while(<CPP>)
+		{
+			my ( $key, $value );
+			if (/^#define (\w+(?:\([^\)]*\))?)(?:\s(\S.*?))?\s*$/)
+			{
+				my $tmpKey = $1;
+				my $tmpValue = $2;
+				$tmpValue =~ s/,/\\,/g;
+				($key, $value ) = ( $tmpKey, $tmpValue ? "\'$tmpValue\'" : 'defined' );
+			}
+			if ($key && ValidFeature($key))
+			{
+				$variantMacrolist{$key} = $value;
+			}
+		}
+		if(!close(CPP))
+		{
+			print "Incomplete pre-precess of $varianthrh \n";
+		}
+	}
+	my $findReusedKey = 1;
+	my %vmapfeatureinfo;
+	my $keyhash;
+	my $macroList;
+	if(open(VMAP, "<$vmapfile"))
+	{
+		while(<VMAP>)
+		{
+			if(/^\w{32}\s+(\w+)/)
+			{
+				$findReusedKey = 1;
+				s/(^\w{32})\s+\w+\s+//;
+				$keyhash = $1;
+				my @feature = split(/(?<=[^\\]),/, $_);
+				foreach my $value (@feature)
+				{
+					if($value =~ /([^\s]*)\s*=\s*(.*)/)
+					{
+						$vmapfeatureinfo{$1} = $2;
+					}
+				}
+				foreach my $key (sort keys %vmapfeatureinfo)
+				{
+					
+					if(($vmapfeatureinfo{$key} eq "undefined") && (not(exists($variantMacrolist{$key}))))
+					{
+						$findReusedKey = 1;
+					}
+					elsif($vmapfeatureinfo{$key} eq $variantMacrolist{$key})
+					{
+						$findReusedKey = 1;
+					}else
+					{
+						$findReusedKey = 0;
+						last;
+					}
+				}
+				if( $findReusedKey == 1)
+				{
+					$macroList = $_;
+					last;
+				}
+				undef(%vmapfeatureinfor);
+				undef($keyhash);
+			}
+		}
+	}
+	if($findReusedKey == 1)
+	{
+    	return ($keyhash, $macroList);
+	}
+	else
+	{
+		return;
+	}
+}
+# modified end: makefile improvement 
+	
+# Usage:	featurevariantmap->Hash(\@sources, \%var)
+#
+# Generate a hash value from the source files for a target using the
+# given feature variant data.
+#
+# \@sources	- list of source files (full path)
+# \%var		- variant data (from featurevariantparser->GetVariant)
+#
+# returns the hash value, or "" if an error occurs.
+	
+sub Hash
+{
+	my $thisObj = shift;
+	my @result = $thisObj->HashAndFeatures(@_);
+	return $result[0];
+}
+
+# Usage:	featurevariantmap->HashAndFeatures(\@sources, \%var)
+#
+# Generate a hash value from the source files for a target using the
+# given feature variant data.
+#
+# \@sources	- list of source files (full path)
+# \%var		- variant data (from featurevariantparser->GetVariant)
+#
+# 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
+
+sub HashAndFeatures
+{
+	my $thisObj = shift;
+	my $srcRef = shift;
+	my $varRef = shift;
+
+	return "" if (!$srcRef || !$varRef);
+	return "" if (!$$varRef{'VALID'});
+
+	# get the pre-processing options
+	my $pre = $$varRef{'PREINCLUDE'};
+	my $inc = $$varRef{'BUILD_INCLUDES'};
+	my $mac = $$varRef{'MACROS'};
+
+	# Pass -dU option to get list of macros affecting the code
+	my $options = "-dU -undef -nostdinc -+";
+
+	if ($pre)	# pre-include file
+	{
+		$options .= " -include \"$pre\"";
+	}
+
+	if ($inc)	# include directories
+	{
+		foreach (@$inc)
+		{
+			$options .= " -I \"$_\"";
+		}
+	}
+
+	if ($mac)	# macro definitions
+	{
+		foreach (@$mac)
+		{
+			$options .= " -D$_";
+		}
+	}
+
+	my %testedMacrosHash;
+	
+	# Macros that affect the mmp file also affect the variant - so add them to the list
+	foreach my $key ( keys %{ $$varRef{MMPTESTED} } )
+		{
+		$testedMacrosHash{$key} = $$varRef{MMPTESTED}->{$key} if (ValidFeature($key));
+		}
+		
+	foreach my $src (@$srcRef)
+	{
+		my $options = "-I " . File::Basename::dirname($src) . " $options";
+
+		print "cpp $options $src\n" if ($verbose);
+
+		if (open(CPP, "cpp $options $src 2>&1 |"))
+		{
+			while (<CPP>)
+			{
+				print $_ if ($verbose && /No such file/);
+
+				# Scan for #define or #undef generated for -dU
+				my ( $key, $value );
+				if (/^#define (\w+(?:\([^\)]*\))?)(?:\s(\S.*?))?\s*$/)
+				{
+# modified start: makefile improvement 
+					my $tmpKey = $1;
+					my $tmpValue = $2;
+					$tmpValue =~ s/,/\\,/g;
+					( $key, $value ) = ( $tmpKey, $tmpValue ? "\'$tmpValue\'" : 'defined' );
+# modified end: makefile improvement 
+				}
+				elsif (/^#undef (.+)$/)
+				{
+					( $key, $value ) = ( $1, 'undefined' );
+				}
+				
+				if ($key && ValidFeature($key))
+				{
+					# Warn the user if a macro appears to have changed value - shouldn't really happen
+					# Feature macros should only be set in platform HRH files and not in the code
+					if (exists $testedMacrosHash{$key} && $testedMacrosHash{$key} ne $value)
+					{
+						print "WARNING: Feature macro $key redefined from $testedMacrosHash{$key} to $value\n";
+					}
+					
+					# Store the macro details
+					$testedMacrosHash{$key} = $value;
+				}
+			}
+			if (!close(CPP))
+			{
+				# this probably means that a rsg file was included
+				# that hasn't been generated yet.
+				print "Incomplete pre-process of $src\n" if ($verbose);
+			}
+		}
+		else
+		{
+			print "ERROR: Could not pre-process $src\n";
+			return "";
+		}
+	}
+
+	# Now generate the tested macros string
+	my $testedMacros = '';
+	foreach my $key ( sort keys %testedMacrosHash )
+	{
+		$testedMacros .= ',' if $testedMacros;
+		$testedMacros .= "$key=$testedMacrosHash{$key}";
+	}
+	
+	print "Tested feature list: $testedMacros\n" if $verbose;
+	return ( Digest::MD5::md5_hex($testedMacros), $testedMacros );
+}
+
+# Usage:	featurevariantmap->Save("my.dll", "1234", "myvar", \@hints)
+#
+# Write a hash value for a target into the target.vmap file along
+# with some optional hints data.
+#
+# "my.dll"	- the target (full path)
+# "1234"	- the hash value (32 character hex number)
+# "myvar"	- the feature variant name
+# \@hints	- optional list of extra strings (eg. "FEATUREVARIANT")
+#
+# returns 0 if OK and non-zero if an error occurs.
+
+sub Save
+{
+	my $thisObj = shift;
+	my $binName = shift;
+	my $keyValue = shift;
+	my $varName = shift;
+	my $features = shift;
+	my $hintRef = shift;
+
+	# read the current data first if the .vmap file already exists
+# modified by SV start: makefile improvement 
+	my $vmapFile = "$binName.$varName.vmap";
+	my @lines;
+	my $tmpinfo = "$keyValue $varName";
+	$tmpinfo .= " $features" if $features;
+	if (open(VMAP, $vmapFile))
+	{
+		my @tmp=<VMAP>;
+		if (grep (/$tmpinfo/, @tmp)){
+			close(VMAP);
+			return 0;
+		}
+		else {
+			foreach  (@tmp)
+			{
+				if (/^\w{32}\s+(\w+)/)
+				{
+					push(@lines, $_) unless (uc($1) eq uc($varName));
+				}
+			}
+			close(VMAP);
+		}
+	}
+# modified by SV end: makefile improvement 
+
+	# write the new data to the .vmap file
+	if (!open(VMAP, ">$vmapFile"))
+	{
+		print "ERROR: Could not write VMAP to $vmapFile\n";
+		return 1;
+	}
+
+	# put the hints at the beginning
+	if ($hintRef)
+	{
+		foreach (@$hintRef)
+		{
+			print VMAP "$_\n";
+		}
+	}
+
+	# then the "key var" pairs
+	foreach (@lines)
+	{
+		print VMAP $_;
+	}
+	print VMAP "$keyValue $varName";
+	print VMAP " $features" if $features;
+	print VMAP "\n";
+	
+	close(VMAP);
+	return 0;
+}
+
+# Usage:    featurevariantmap->Find("my.dll", "myvar")
+#
+# Look for a binary using its "final" name. We will use the feature
+# variant map and the feature variant name to deduce the "variant"
+# binary name and test for its existence.
+#
+# "my.dll"	- the final target (full path)
+# "myvar"	- the feature variant name
+#
+# returns the file name if found, or "" otherwise.
+
+sub Find
+{
+	my $thisObj = shift;
+	my $binName = shift;
+	my $varName = shift;
+
+	# look for the vmap file
+# modified by SV start: makefile improvement 
+	my $vmapFile = "$binName.$varName.vmap";
+# modified by SV end: makefile improvement 
+
+	if (-e $vmapFile)
+	{
+		my $key = $thisObj->GetKeyFromVMAP($varName, $vmapFile);
+
+		if ($key)
+		{
+			$binName =~ /^(.*)\.([^\.]*)$/;
+			$binName = "$1.$key.$2";
+		}
+		else
+		{
+			print "ERROR: No \'$varName\' variant for $binName in $vmapFile\n";
+			return "";	# file not found
+		}
+	}
+
+	# check that the actual binary exists
+	if (-e $binName)
+	{
+		return $binName;
+	}
+	return "";	# file not found
+}
+
+# internal functions
+
+sub GetKeyFromVMAP
+	{
+	my $thisObj = shift;
+	my @res = $thisObj->GetDataFromVMAP(@_);
+	return $res[0];
+	}
+	
+# Usage:    featurevariantmap->GetDataFromVMAP("myvar", "mydll.vmap")
+#
+# Opens the vmap file indicated and returns the data for the requested variant
+#
+# "myvar"	- the feature variant name
+# "my.vmap"	- the final target vmap file (full path)
+#
+# Returns a list ( hash, features ) for the variant in the vmap or undef if not found
+
+sub GetDataFromVMAP
+{
+	my $thisObj = shift;
+	my $varName = shift;
+	my $fileName = shift;
+
+	if (!open(VMAP, $fileName))
+	{
+		print "ERROR: Could not read VMAP from $fileName\n";
+		return "";
+	}
+	while (<VMAP>)
+	{
+		chomp;
+		if (/(\w{32})\s+$varName\s+(.*)$/i or /(\w{32})\s+$varName$/i)
+		{
+			my ( $hash, $features ) = ( $1, $2 ? $2 : '' );
+			close(VMAP);
+			return ( $hash, $features );
+		}
+	}
+	close(VMAP);
+	return;
+}
+
+1;