sbsv1/abld/e32util/checksource.pm
changeset 607 378360dbbdba
parent 599 fa7a3cc6effd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sbsv1/abld/e32util/checksource.pm	Wed Jun 30 11:35:58 2010 +0800
@@ -0,0 +1,471 @@
+# Copyright (c) 2005-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:
+# Routines involved in checking that source matches various filename policy constraints
+# 
+#
+
+
+package CheckSource;
+
+require Exporter;
+@ISA=qw(Exporter);
+
+# Exported for clarity in calling scripts and modules
+our $CheckSource_PhysicalCheck = 1;
+our $CheckSource_NoUserSystemDistinction = 1;
+
+@EXPORT=qw(
+	CheckSource_MetaData
+	CheckSource_Includes
+	CheckSource_ExportedIncludes
+	CheckSource_MakefileOutput
+	CheckSource_UnixSlash
+	CheckSource_Lowercase
+	CheckSource_Physical
+	$CheckSource_PhysicalCheck
+	$CheckSource_NoUserSystemDistinction
+);
+
+use Cwd;
+use Pathutl;
+use Win32;
+
+my $exclusionsFile = $ENV{EPOCROOT}."epoc32\\tools\\filenamepolicyexclusions.txt";
+
+my $makefileWarningPrefix = "\@echo ";
+my $checksourcePrefix = "\@perl -S checksource.pl";
+my $releaseLocationRoot = quotemeta ($ENV{EPOCROOT}."epoc32");
+
+
+sub CheckSource_MetaData (\%$$$$;$;$)
+	{
+	my ($actionHash, $sourceFile, $item, $reference, $lineNumber, $physical, $offset) = @_;
+
+	return if ($reference =~ /^(\.|\.\.)$/);
+
+	my $checksourceCall = "$checksourcePrefix --metadata \"$sourceFile\" \"$item\" \"$reference\" $lineNumber";
+	$checksourceCall .= " $physical" if ($physical);
+	$checksourceCall .= " \"$offset\"" if ($offset);
+	$$actionHash{$checksourceCall} = 1;
+	}
+
+
+sub CheckSource_UnixSlash (\%$$$$;$)
+	{
+	my ($actionHash, $sourceFile, $item, $reference, $lineNumber, $verbose) = @_;
+
+	$sourceFile =~ s/^[a-zA-Z]{1}://;
+	$item =~ s/PRJ_EXPORTS \(NO DESTINATION\)/PRJ_EXPORTS/;
+
+	print "Checking - Unix slash : $sourceFile ($lineNumber) - $item:$reference\n" if ($verbose);
+
+	if ($reference =~/\\/)
+		{	
+		$$actionHash{constructWarning ($sourceFile, $lineNumber, $item, "Incorrect slash in", $reference)} = 1;
+		}
+	}
+
+
+sub CheckSource_Lowercase (\%$$$;$;$)
+	{
+	my ($actionHash, $sourceFile, $item, $reference, $lineNumber, $verbose) = @_;
+
+	return if ($reference =~ /^[\/|\\]epoc32[\/|\\]tools[\/|\\].*$/);
+
+	$sourceFile =~ s/^[a-zA-Z]{1}://;
+
+	print "Checking - lowercase  : $sourceFile ($lineNumber) - $item:$reference\n" if ($verbose);
+
+	my $exclusion = lowercaseExclusionCheck ($reference);
+
+	if ($exclusion eq "UNLISTED")
+		{
+		if ($reference =~ /[A-Z]/)
+			{			
+			$$actionHash{constructWarning ($sourceFile, $lineNumber, $item, "Incorrect case for epoc32 tree in", $reference)} = 1;
+			}
+		}
+	elsif ($exclusion !~ /(OK|ERROR)/)
+		{
+		$$actionHash{constructWarning($sourceFile, $lineNumber, $item, "Incorrect case versus exclusion list in", $reference, " vs. $exclusion")} = 1;		
+		}
+	}
+
+
+sub CheckSource_Physical (\%$$$$;$;$)
+	{
+	my ($actionHash, $sourceFile, $item, $reference, $lineNumber, $path, $verbose) = @_;
+	
+	print "Checking - physical   : $sourceFile ($lineNumber) - $item:$reference:$path\n" if ($verbose);
+
+	my $physicalCheck;
+	my $searchText;
+
+	my $examineDefaultExportDestination = ($item =~ s/PRJ_EXPORTS \(NO DESTINATION\)/PRJ_EXPORTS/) ? 1 : 0;
+
+	if ($item eq "#include")
+		{
+		# In the case of #includes, the path passed in is already the fully pathed physical file
+		# that needs to be checked (as obtained from the parsed output of CPP)
+		$searchText = $reference;
+		$physicalCheck = $path;
+		}
+	else
+		{
+		my $physicalReference;
+		if (($item =~ /^PRJ_(TEST)?MMPFILES MMP/) && ($reference !~ /\.\w+$/i))
+			{
+			$physicalReference = $reference."\.mmp";
+			$searchText = $reference."\.*";
+			}
+		elsif ($item =~ /^DEFFILE/)
+			{
+			# The full path for DEFFILE entries is always passed in, so we just
+			# need to concentrate on sorting out the oddities for the search
+			# text and then just take the final file bit as the physical
+			# reference
+
+			$searchText = $reference;			
+			$searchText .= "?\.*" if ($reference !~ /(\.def|[\\|\/])$/i);
+			$searchText =~ s/(\.def)/\?$1/i if ($item !~ /NOSTRICTDEF/);
+			$searchText =~ s/\~/\*/;			
+			$physicalReference = $searchText;
+			$physicalReference =~ s/\//\\/g;
+			$physicalReference =~ s/\?/u/;
+			$physicalReference =~ s/\.\w+$/\.def/;
+			$physicalReference = &Path_Split ('File', $physicalReference);			
+			}
+		else
+			{
+			$searchText = $reference;
+			$physicalReference = $searchText;
+			}
+
+		my $physicalLocation;
+		if ($path)
+			{
+			$physicalLocation = $path;
+			}
+		elsif ($reference =~ /^(\\|\/)/)
+			{
+			$physicalLocation = $ENV{EPOCROOT};
+			}
+		elsif ($reference =~ /^\+/)
+			{
+			$physicalLocation = $ENV{EPOCROOT}."epoc32\\";
+			}
+		elsif ($item =~ /EXTENSIONS/)
+			{
+			$physicalLocation = $ENV{EPOCROOT}."epoc32\\tools\\makefile_templates\\";
+			}
+		else
+			{
+			$physicalLocation = &Path_Split ('Path', $sourceFile);
+			}
+		$physicalReference =~ s/^[\\|\/]//;
+		$physicalCheck = $physicalLocation.$physicalReference;
+		}
+
+	$physicalCheck =~ s/\//\\/g;
+	$physicalCheck = &Path_Strip ($physicalCheck);
+
+	# If a file reference is actually under \epoc32, we just need to confirm that it's lowercase
+	if ($physicalCheck =~ /^$releaseLocationRoot/i)
+		{
+		CheckSource_Lowercase (%$actionHash, $sourceFile, $item, $reference, $lineNumber, $verbose);
+		return;
+		}
+
+	# Massage search text to provide something we can compare with a physical check on the filesystem
+	$searchText =~ s/\//\\/g;
+	$searchText =~ s/\.\.\\//g;
+	$searchText =~ s/\.\\//g;
+	$searchText =~ s/\\\\/\\/g;
+
+	my $warningSearchText = $searchText;	# Record a more intelligible version of the search text for warning purposes
+	
+	$searchText = quotemeta ($searchText);
+	$searchText =~ s/\\\*/\\w\+/g;			# * -> \w+
+	$searchText =~ s/\\\?/\\w\{1\}/g;		# ? -> \w{1}
+
+	my $physicalReality = getPhysical ($physicalCheck);
+
+	my $warningSuffix = "";
+
+	if (!$physicalReality)
+		{
+		$$actionHash{constructWarning($sourceFile, $lineNumber, $item, "Can\'t find physical file match for", $reference, " on filesystem")} = 1;
+		}
+	elsif ($physicalReality !~ /^.*$searchText$/)
+		{
+		if ($physicalReality !~ /^.*$searchText$/i)
+			{
+			# Doesn't just differ in case...something's gone wrong
+			$$actionHash{constructWarning($sourceFile, $lineNumber, $item, "Can\'t find physical file match for", $reference, " - match was attempted against $physicalReality")} = 1;		
+			}
+		else
+			{
+			if (($item =~ /^DEFFILE/ || $item =~ /^PRJ_(TEST)?MMPFILES MMP/) && ($reference !~ /$searchText$/))
+				{
+				$warningSuffix .= " (actual test \'$warningSearchText\')"
+				}
+
+			$warningSuffix .= " vs. $physicalReality";
+			$$actionHash{constructWarning($sourceFile, $lineNumber, $item, "Incorrect case versus filesystem in", $reference, $warningSuffix)} = 1;
+			}
+		}
+
+	# Special case - PRJ_EXPORTS source lines with no destination must be normalised via a new destination compliant
+	# with the filename policy.  FIXSOURCE will do this, but it needs a warning to work on
+
+	if ($examineDefaultExportDestination)
+		{
+		$physicalReality =~ /^.*($searchText)$/i;
+		my $defaultExportReference = $1;
+		
+		my $exclusion = lowercaseExclusionCheck ($defaultExportReference);
+
+		if ($defaultExportReference =~ /[A-Z]/)
+			{
+			$$actionHash{constructWarning ($sourceFile, $lineNumber, $item, "Incorrect case for epoc32 tree from default export in", $reference, $warningSuffix)} = 1;
+			}
+		}
+
+	}
+	
+
+sub CheckSource_Includes ($\%$\@;\@;\@;$)
+	{
+	# References are used for array arguments only so that they can be distinguished within the subroutine
+	my ($sourceFile, $actionHash, $preInclude, $macros, $userIncludesRef, $systemIncludesRef, $noUserSystemDistinction) = @_;
+	my (@userIncludes, @systemIncludes);
+
+	@userIncludes = @$userIncludesRef if ($userIncludesRef);
+	@systemIncludes = @$systemIncludesRef if ($systemIncludesRef);
+
+	my $call = "$checksourcePrefix --preprocess -- ";
+
+	if (($sourceFile !~ /\.inf$/i) && ($sourceFile !~ /\.mmp/i))
+		{
+		push @$macros, "__SUPPORT_CPP_EXCEPTIONS__";
+		}
+
+	my $platformPreInclude = "";
+
+	foreach my $macro (@$macros)
+		{
+		$call .= "-D$macro ";
+
+		if ($macro =~ /__ARMCC_2_2__/)
+			{
+			$platformPreInclude = $ENV{EPOCROOT}."epoc32\\include\\rvct2_2\\rvct2_2.h";
+
+			if (($sourceFile =~ /BASE\\E32\\compsupp\\/i) && $ENV{RVCT22INC})
+				{					
+				# Need some way to deal with ARMINC from the front-end...
+				my $rvctIncDir = $ENV{RVCT22INC};
+				push @systemIncludes, $rvctIncDir;
+				}
+			}
+		elsif ($macro =~ /__GCCE__/)
+			{
+			$platformPreInclude = $ENV{EPOCROOT}."epoc32\\include\\GCCE\\GCCE.h";
+
+			my $GCCEinstall = Cl_bpabi::getConfigVariable('COMPILER_INSTALL_PATH');
+			
+			push @systemIncludes, "\"\\\"$GCCEinstall\\..\\lib\\gcc\\arm-none-symbianelf\\3.4.3\\include\\\"\"";
+			}
+		}
+
+	if ($preInclude ne "")
+		{
+		$call .= "-include ".getDrive().$preInclude." ";
+		push @systemIncludes, &Path_Split ('Path', getDrive().$preInclude);
+		}		
+
+	if ($platformPreInclude ne "")
+		{
+		$call .= "-include ".getDrive().$platformPreInclude." ";
+		push @systemIncludes, &Path_Split ('Path', getDrive().$platformPreInclude);
+		}	
+
+	# Enforce user and system includes in checksource processing.
+
+	foreach my $include (@userIncludes)
+		{
+		$include =~ s/\\$//;
+		$include = getDrive().$include if (($include !~ /^[a-zA-Z]:/) && ($include !~ /^[\"|\.]/));
+		$call .= "-I $include ";
+		}
+
+	$call .= "-I- " unless $noUserSystemDistinction;
+
+	foreach my $include (@systemIncludes)
+		{
+		$include =~ s/\\$//;
+		$include = getDrive().$include if (($include !~ /^[a-zA-Z]:/) && ($include !~ /^[\"|\.]/));
+		$call .= "-I $include ";
+		}
+
+	$sourceFile =~ s/\//\\/g;
+	$sourceFile = &Path_Strip ($sourceFile);
+	$sourceFile = getDrive().$sourceFile;
+
+	$call .= $sourceFile;
+
+	$$actionHash{$call} = 1;
+
+	return $call;
+	}
+
+
+sub CheckSource_ExportedIncludes ($$\%)
+	{
+	my ($sourceFile, $destinationFile, $actionHash) = @_;
+
+	# Exclude exported files as appropriate
+	if ($destinationFile)
+		{
+		my $epoc32Include = quotemeta ($ENV{EPOCROOT})."epoc32\\\\include";
+		return if ($destinationFile !~ /^$epoc32Include/i);
+		return if ($destinationFile =~ /\.def$/i);
+		}
+
+	$$actionHash{"$checksourcePrefix --parsefile -- $sourceFile"} = 1;
+	}
+
+
+sub CheckSource_MakefileOutput(%)
+	{
+	my (%actionHash) = @_;
+
+	return "\t\@rem\n" if !(keys (%actionHash));
+
+	my $output = "";
+
+	foreach (keys (%actionHash))
+		{
+		$output .= "\t$_\n";
+		}
+
+	return $output;
+	}
+	
+
+sub getDrive
+	{
+    if(cwd =~ /^([a-zA-Z]:)/)
+    	{
+		return $1;
+    	}
+
+	return "";
+	}
+
+
+sub getPhysical ($)
+	{
+	my ($physicalReference) = @_;
+	
+	my $physicalReality = Win32::GetLongPathName($physicalReference);
+
+	if ($physicalReality)
+		{			
+		$physicalReality =~ s/^.*://;
+		$physicalReality = &Path_Strip ($physicalReality);		
+		}
+
+	return $physicalReality;
+	}
+
+
+sub constructWarning ($$$$$;$)
+	{
+	my ($sourceFile, $lineNumber, $item, $warningText, $reference, $suffix) = @_;
+
+	$sourceFile =~ s/\//\\/g;
+	$sourceFile = Win32::GetLongPathName($sourceFile);
+	$sourceFile =~ s/^[a-zA-Z]{1}://;
+	$sourceFile = &Path_Strip ($sourceFile);
+
+	my $warning = "";
+	$warning .= $sourceFile.":".$lineNumber.": ".$warningText." $item - \'".$reference."\'";
+	$warning .= $suffix if ($suffix);
+	$warning .= ".";		
+
+	return $warning;
+	}
+
+
+sub lowercaseExclusionCheck ($)
+	{
+	my ($reference) = @_;
+
+	# An exclusions file isn't mandatory
+	return "UNLISTED" if (! -e $exclusionsFile);
+
+	my $EXCLUSIONS;
+
+	if (!(open EXCLUSIONS, "< $exclusionsFile"))
+			{
+			print ("ERROR: Can't open $exclusionsFile in checksource processing.\n");
+			return "ERROR";
+			}
+
+	my $referenceDOSSlash = $reference;
+	$referenceDOSSlash =~ s/\//\\/g;
+
+	my $exclusionCheck = "UNLISTED";
+
+	while (my $exclusion = <EXCLUSIONS>)
+		{
+		next if ($exclusion =~ /^\s*$/);
+
+		$exclusion =~ s/^\s+//;
+		$exclusion =~ s/\s+$//;
+		$exclusion =~ s/\//\\/g;
+		my $quotemetaExclusion = quotemeta ($exclusion);
+
+		if ($referenceDOSSlash =~ /^$quotemetaExclusion$/i)
+			{				
+			if ($referenceDOSSlash !~ /^$quotemetaExclusion$/)
+				{
+				$exclusionCheck = $exclusion;
+				}
+			else
+				{
+				$exclusionCheck = "OK";
+				}
+			last;
+			}
+			elsif($referenceDOSSlash =~ /\\$quotemetaExclusion$/i)
+			{				
+			if ($referenceDOSSlash !~ /\\$quotemetaExclusion$/)
+				{
+				$exclusionCheck = $exclusion;
+				}
+			else
+				{
+				$exclusionCheck = "OK";
+				}
+			last;
+			}
+		}
+
+	close EXCLUSIONS;
+
+	return $exclusionCheck;
+	}
+
+1;