sbsv1/abld/e32util/checksource.pm
changeset 599 fa7a3cc6effd
equal deleted inserted replaced
596:9f25be3da657 599:fa7a3cc6effd
       
     1 # Copyright (c) 2005-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 # Routines involved in checking that source matches various filename policy constraints
       
    15 # 
       
    16 #
       
    17 
       
    18 
       
    19 package CheckSource;
       
    20 
       
    21 require Exporter;
       
    22 @ISA=qw(Exporter);
       
    23 
       
    24 # Exported for clarity in calling scripts and modules
       
    25 our $CheckSource_PhysicalCheck = 1;
       
    26 our $CheckSource_NoUserSystemDistinction = 1;
       
    27 
       
    28 @EXPORT=qw(
       
    29 	CheckSource_MetaData
       
    30 	CheckSource_Includes
       
    31 	CheckSource_ExportedIncludes
       
    32 	CheckSource_MakefileOutput
       
    33 	CheckSource_UnixSlash
       
    34 	CheckSource_Lowercase
       
    35 	CheckSource_Physical
       
    36 	$CheckSource_PhysicalCheck
       
    37 	$CheckSource_NoUserSystemDistinction
       
    38 );
       
    39 
       
    40 use Cwd;
       
    41 use Pathutl;
       
    42 use Win32;
       
    43 
       
    44 my $exclusionsFile = $ENV{EPOCROOT}."epoc32\\tools\\filenamepolicyexclusions.txt";
       
    45 
       
    46 my $makefileWarningPrefix = "\@echo ";
       
    47 my $checksourcePrefix = "\@perl -S checksource.pl";
       
    48 my $releaseLocationRoot = quotemeta ($ENV{EPOCROOT}."epoc32");
       
    49 
       
    50 
       
    51 sub CheckSource_MetaData (\%$$$$;$;$)
       
    52 	{
       
    53 	my ($actionHash, $sourceFile, $item, $reference, $lineNumber, $physical, $offset) = @_;
       
    54 
       
    55 	return if ($reference =~ /^(\.|\.\.)$/);
       
    56 
       
    57 	my $checksourceCall = "$checksourcePrefix --metadata \"$sourceFile\" \"$item\" \"$reference\" $lineNumber";
       
    58 	$checksourceCall .= " $physical" if ($physical);
       
    59 	$checksourceCall .= " \"$offset\"" if ($offset);
       
    60 	$$actionHash{$checksourceCall} = 1;
       
    61 	}
       
    62 
       
    63 
       
    64 sub CheckSource_UnixSlash (\%$$$$;$)
       
    65 	{
       
    66 	my ($actionHash, $sourceFile, $item, $reference, $lineNumber, $verbose) = @_;
       
    67 
       
    68 	$sourceFile =~ s/^[a-zA-Z]{1}://;
       
    69 	$item =~ s/PRJ_EXPORTS \(NO DESTINATION\)/PRJ_EXPORTS/;
       
    70 
       
    71 	print "Checking - Unix slash : $sourceFile ($lineNumber) - $item:$reference\n" if ($verbose);
       
    72 
       
    73 	if ($reference =~/\\/)
       
    74 		{	
       
    75 		$$actionHash{constructWarning ($sourceFile, $lineNumber, $item, "Incorrect slash in", $reference)} = 1;
       
    76 		}
       
    77 	}
       
    78 
       
    79 
       
    80 sub CheckSource_Lowercase (\%$$$;$;$)
       
    81 	{
       
    82 	my ($actionHash, $sourceFile, $item, $reference, $lineNumber, $verbose) = @_;
       
    83 
       
    84 	return if ($reference =~ /^[\/|\\]epoc32[\/|\\]tools[\/|\\].*$/);
       
    85 
       
    86 	$sourceFile =~ s/^[a-zA-Z]{1}://;
       
    87 
       
    88 	print "Checking - lowercase  : $sourceFile ($lineNumber) - $item:$reference\n" if ($verbose);
       
    89 
       
    90 	my $exclusion = lowercaseExclusionCheck ($reference);
       
    91 
       
    92 	if ($exclusion eq "UNLISTED")
       
    93 		{
       
    94 		if ($reference =~ /[A-Z]/)
       
    95 			{			
       
    96 			$$actionHash{constructWarning ($sourceFile, $lineNumber, $item, "Incorrect case for epoc32 tree in", $reference)} = 1;
       
    97 			}
       
    98 		}
       
    99 	elsif ($exclusion !~ /(OK|ERROR)/)
       
   100 		{
       
   101 		$$actionHash{constructWarning($sourceFile, $lineNumber, $item, "Incorrect case versus exclusion list in", $reference, " vs. $exclusion")} = 1;		
       
   102 		}
       
   103 	}
       
   104 
       
   105 
       
   106 sub CheckSource_Physical (\%$$$$;$;$)
       
   107 	{
       
   108 	my ($actionHash, $sourceFile, $item, $reference, $lineNumber, $path, $verbose) = @_;
       
   109 	
       
   110 	print "Checking - physical   : $sourceFile ($lineNumber) - $item:$reference:$path\n" if ($verbose);
       
   111 
       
   112 	my $physicalCheck;
       
   113 	my $searchText;
       
   114 
       
   115 	my $examineDefaultExportDestination = ($item =~ s/PRJ_EXPORTS \(NO DESTINATION\)/PRJ_EXPORTS/) ? 1 : 0;
       
   116 
       
   117 	if ($item eq "#include")
       
   118 		{
       
   119 		# In the case of #includes, the path passed in is already the fully pathed physical file
       
   120 		# that needs to be checked (as obtained from the parsed output of CPP)
       
   121 		$searchText = $reference;
       
   122 		$physicalCheck = $path;
       
   123 		}
       
   124 	else
       
   125 		{
       
   126 		my $physicalReference;
       
   127 		if (($item =~ /^PRJ_(TEST)?MMPFILES MMP/) && ($reference !~ /\.\w+$/i))
       
   128 			{
       
   129 			$physicalReference = $reference."\.mmp";
       
   130 			$searchText = $reference."\.*";
       
   131 			}
       
   132 		elsif ($item =~ /^DEFFILE/)
       
   133 			{
       
   134 			# The full path for DEFFILE entries is always passed in, so we just
       
   135 			# need to concentrate on sorting out the oddities for the search
       
   136 			# text and then just take the final file bit as the physical
       
   137 			# reference
       
   138 
       
   139 			$searchText = $reference;			
       
   140 			$searchText .= "?\.*" if ($reference !~ /(\.def|[\\|\/])$/i);
       
   141 			$searchText =~ s/(\.def)/\?$1/i if ($item !~ /NOSTRICTDEF/);
       
   142 			$searchText =~ s/\~/\*/;			
       
   143 			$physicalReference = $searchText;
       
   144 			$physicalReference =~ s/\//\\/g;
       
   145 			$physicalReference =~ s/\?/u/;
       
   146 			$physicalReference =~ s/\.\w+$/\.def/;
       
   147 			$physicalReference = &Path_Split ('File', $physicalReference);			
       
   148 			}
       
   149 		else
       
   150 			{
       
   151 			$searchText = $reference;
       
   152 			$physicalReference = $searchText;
       
   153 			}
       
   154 
       
   155 		my $physicalLocation;
       
   156 		if ($path)
       
   157 			{
       
   158 			$physicalLocation = $path;
       
   159 			}
       
   160 		elsif ($reference =~ /^(\\|\/)/)
       
   161 			{
       
   162 			$physicalLocation = $ENV{EPOCROOT};
       
   163 			}
       
   164 		elsif ($reference =~ /^\+/)
       
   165 			{
       
   166 			$physicalLocation = $ENV{EPOCROOT}."epoc32\\";
       
   167 			}
       
   168 		elsif ($item =~ /EXTENSIONS/)
       
   169 			{
       
   170 			$physicalLocation = $ENV{EPOCROOT}."epoc32\\tools\\makefile_templates\\";
       
   171 			}
       
   172 		else
       
   173 			{
       
   174 			$physicalLocation = &Path_Split ('Path', $sourceFile);
       
   175 			}
       
   176 		$physicalReference =~ s/^[\\|\/]//;
       
   177 		$physicalCheck = $physicalLocation.$physicalReference;
       
   178 		}
       
   179 
       
   180 	$physicalCheck =~ s/\//\\/g;
       
   181 	$physicalCheck = &Path_Strip ($physicalCheck);
       
   182 
       
   183 	# If a file reference is actually under \epoc32, we just need to confirm that it's lowercase
       
   184 	if ($physicalCheck =~ /^$releaseLocationRoot/i)
       
   185 		{
       
   186 		CheckSource_Lowercase (%$actionHash, $sourceFile, $item, $reference, $lineNumber, $verbose);
       
   187 		return;
       
   188 		}
       
   189 
       
   190 	# Massage search text to provide something we can compare with a physical check on the filesystem
       
   191 	$searchText =~ s/\//\\/g;
       
   192 	$searchText =~ s/\.\.\\//g;
       
   193 	$searchText =~ s/\.\\//g;
       
   194 	$searchText =~ s/\\\\/\\/g;
       
   195 
       
   196 	my $warningSearchText = $searchText;	# Record a more intelligible version of the search text for warning purposes
       
   197 	
       
   198 	$searchText = quotemeta ($searchText);
       
   199 	$searchText =~ s/\\\*/\\w\+/g;			# * -> \w+
       
   200 	$searchText =~ s/\\\?/\\w\{1\}/g;		# ? -> \w{1}
       
   201 
       
   202 	my $physicalReality = getPhysical ($physicalCheck);
       
   203 
       
   204 	my $warningSuffix = "";
       
   205 
       
   206 	if (!$physicalReality)
       
   207 		{
       
   208 		$$actionHash{constructWarning($sourceFile, $lineNumber, $item, "Can\'t find physical file match for", $reference, " on filesystem")} = 1;
       
   209 		}
       
   210 	elsif ($physicalReality !~ /^.*$searchText$/)
       
   211 		{
       
   212 		if ($physicalReality !~ /^.*$searchText$/i)
       
   213 			{
       
   214 			# Doesn't just differ in case...something's gone wrong
       
   215 			$$actionHash{constructWarning($sourceFile, $lineNumber, $item, "Can\'t find physical file match for", $reference, " - match was attempted against $physicalReality")} = 1;		
       
   216 			}
       
   217 		else
       
   218 			{
       
   219 			if (($item =~ /^DEFFILE/ || $item =~ /^PRJ_(TEST)?MMPFILES MMP/) && ($reference !~ /$searchText$/))
       
   220 				{
       
   221 				$warningSuffix .= " (actual test \'$warningSearchText\')"
       
   222 				}
       
   223 
       
   224 			$warningSuffix .= " vs. $physicalReality";
       
   225 			$$actionHash{constructWarning($sourceFile, $lineNumber, $item, "Incorrect case versus filesystem in", $reference, $warningSuffix)} = 1;
       
   226 			}
       
   227 		}
       
   228 
       
   229 	# Special case - PRJ_EXPORTS source lines with no destination must be normalised via a new destination compliant
       
   230 	# with the filename policy.  FIXSOURCE will do this, but it needs a warning to work on
       
   231 
       
   232 	if ($examineDefaultExportDestination)
       
   233 		{
       
   234 		$physicalReality =~ /^.*($searchText)$/i;
       
   235 		my $defaultExportReference = $1;
       
   236 		
       
   237 		my $exclusion = lowercaseExclusionCheck ($defaultExportReference);
       
   238 
       
   239 		if ($defaultExportReference =~ /[A-Z]/)
       
   240 			{
       
   241 			$$actionHash{constructWarning ($sourceFile, $lineNumber, $item, "Incorrect case for epoc32 tree from default export in", $reference, $warningSuffix)} = 1;
       
   242 			}
       
   243 		}
       
   244 
       
   245 	}
       
   246 	
       
   247 
       
   248 sub CheckSource_Includes ($\%$\@;\@;\@;$)
       
   249 	{
       
   250 	# References are used for array arguments only so that they can be distinguished within the subroutine
       
   251 	my ($sourceFile, $actionHash, $preInclude, $macros, $userIncludesRef, $systemIncludesRef, $noUserSystemDistinction) = @_;
       
   252 	my (@userIncludes, @systemIncludes);
       
   253 
       
   254 	@userIncludes = @$userIncludesRef if ($userIncludesRef);
       
   255 	@systemIncludes = @$systemIncludesRef if ($systemIncludesRef);
       
   256 
       
   257 	my $call = "$checksourcePrefix --preprocess -- ";
       
   258 
       
   259 	if (($sourceFile !~ /\.inf$/i) && ($sourceFile !~ /\.mmp/i))
       
   260 		{
       
   261 		push @$macros, "__SUPPORT_CPP_EXCEPTIONS__";
       
   262 		}
       
   263 
       
   264 	my $platformPreInclude = "";
       
   265 
       
   266 	foreach my $macro (@$macros)
       
   267 		{
       
   268 		$call .= "-D$macro ";
       
   269 
       
   270 		if ($macro =~ /__ARMCC_2_2__/)
       
   271 			{
       
   272 			$platformPreInclude = $ENV{EPOCROOT}."epoc32\\include\\rvct2_2\\rvct2_2.h";
       
   273 
       
   274 			if (($sourceFile =~ /BASE\\E32\\compsupp\\/i) && $ENV{RVCT22INC})
       
   275 				{					
       
   276 				# Need some way to deal with ARMINC from the front-end...
       
   277 				my $rvctIncDir = $ENV{RVCT22INC};
       
   278 				push @systemIncludes, $rvctIncDir;
       
   279 				}
       
   280 			}
       
   281 		elsif ($macro =~ /__GCCE__/)
       
   282 			{
       
   283 			$platformPreInclude = $ENV{EPOCROOT}."epoc32\\include\\GCCE\\GCCE.h";
       
   284 
       
   285 			my $GCCEinstall = Cl_bpabi::getConfigVariable('COMPILER_INSTALL_PATH');
       
   286 			
       
   287 			push @systemIncludes, "\"\\\"$GCCEinstall\\..\\lib\\gcc\\arm-none-symbianelf\\3.4.3\\include\\\"\"";
       
   288 			}
       
   289 		}
       
   290 
       
   291 	if ($preInclude ne "")
       
   292 		{
       
   293 		$call .= "-include ".getDrive().$preInclude." ";
       
   294 		push @systemIncludes, &Path_Split ('Path', getDrive().$preInclude);
       
   295 		}		
       
   296 
       
   297 	if ($platformPreInclude ne "")
       
   298 		{
       
   299 		$call .= "-include ".getDrive().$platformPreInclude." ";
       
   300 		push @systemIncludes, &Path_Split ('Path', getDrive().$platformPreInclude);
       
   301 		}	
       
   302 
       
   303 	# Enforce user and system includes in checksource processing.
       
   304 
       
   305 	foreach my $include (@userIncludes)
       
   306 		{
       
   307 		$include =~ s/\\$//;
       
   308 		$include = getDrive().$include if (($include !~ /^[a-zA-Z]:/) && ($include !~ /^[\"|\.]/));
       
   309 		$call .= "-I $include ";
       
   310 		}
       
   311 
       
   312 	$call .= "-I- " unless $noUserSystemDistinction;
       
   313 
       
   314 	foreach my $include (@systemIncludes)
       
   315 		{
       
   316 		$include =~ s/\\$//;
       
   317 		$include = getDrive().$include if (($include !~ /^[a-zA-Z]:/) && ($include !~ /^[\"|\.]/));
       
   318 		$call .= "-I $include ";
       
   319 		}
       
   320 
       
   321 	$sourceFile =~ s/\//\\/g;
       
   322 	$sourceFile = &Path_Strip ($sourceFile);
       
   323 	$sourceFile = getDrive().$sourceFile;
       
   324 
       
   325 	$call .= $sourceFile;
       
   326 
       
   327 	$$actionHash{$call} = 1;
       
   328 
       
   329 	return $call;
       
   330 	}
       
   331 
       
   332 
       
   333 sub CheckSource_ExportedIncludes ($$\%)
       
   334 	{
       
   335 	my ($sourceFile, $destinationFile, $actionHash) = @_;
       
   336 
       
   337 	# Exclude exported files as appropriate
       
   338 	if ($destinationFile)
       
   339 		{
       
   340 		my $epoc32Include = quotemeta ($ENV{EPOCROOT})."epoc32\\\\include";
       
   341 		return if ($destinationFile !~ /^$epoc32Include/i);
       
   342 		return if ($destinationFile =~ /\.def$/i);
       
   343 		}
       
   344 
       
   345 	$$actionHash{"$checksourcePrefix --parsefile -- $sourceFile"} = 1;
       
   346 	}
       
   347 
       
   348 
       
   349 sub CheckSource_MakefileOutput(%)
       
   350 	{
       
   351 	my (%actionHash) = @_;
       
   352 
       
   353 	return "\t\@rem\n" if !(keys (%actionHash));
       
   354 
       
   355 	my $output = "";
       
   356 
       
   357 	foreach (keys (%actionHash))
       
   358 		{
       
   359 		$output .= "\t$_\n";
       
   360 		}
       
   361 
       
   362 	return $output;
       
   363 	}
       
   364 	
       
   365 
       
   366 sub getDrive
       
   367 	{
       
   368     if(cwd =~ /^([a-zA-Z]:)/)
       
   369     	{
       
   370 		return $1;
       
   371     	}
       
   372 
       
   373 	return "";
       
   374 	}
       
   375 
       
   376 
       
   377 sub getPhysical ($)
       
   378 	{
       
   379 	my ($physicalReference) = @_;
       
   380 	
       
   381 	my $physicalReality = Win32::GetLongPathName($physicalReference);
       
   382 
       
   383 	if ($physicalReality)
       
   384 		{			
       
   385 		$physicalReality =~ s/^.*://;
       
   386 		$physicalReality = &Path_Strip ($physicalReality);		
       
   387 		}
       
   388 
       
   389 	return $physicalReality;
       
   390 	}
       
   391 
       
   392 
       
   393 sub constructWarning ($$$$$;$)
       
   394 	{
       
   395 	my ($sourceFile, $lineNumber, $item, $warningText, $reference, $suffix) = @_;
       
   396 
       
   397 	$sourceFile =~ s/\//\\/g;
       
   398 	$sourceFile = Win32::GetLongPathName($sourceFile);
       
   399 	$sourceFile =~ s/^[a-zA-Z]{1}://;
       
   400 	$sourceFile = &Path_Strip ($sourceFile);
       
   401 
       
   402 	my $warning = "";
       
   403 	$warning .= $sourceFile.":".$lineNumber.": ".$warningText." $item - \'".$reference."\'";
       
   404 	$warning .= $suffix if ($suffix);
       
   405 	$warning .= ".";		
       
   406 
       
   407 	return $warning;
       
   408 	}
       
   409 
       
   410 
       
   411 sub lowercaseExclusionCheck ($)
       
   412 	{
       
   413 	my ($reference) = @_;
       
   414 
       
   415 	# An exclusions file isn't mandatory
       
   416 	return "UNLISTED" if (! -e $exclusionsFile);
       
   417 
       
   418 	my $EXCLUSIONS;
       
   419 
       
   420 	if (!(open EXCLUSIONS, "< $exclusionsFile"))
       
   421 			{
       
   422 			print ("ERROR: Can't open $exclusionsFile in checksource processing.\n");
       
   423 			return "ERROR";
       
   424 			}
       
   425 
       
   426 	my $referenceDOSSlash = $reference;
       
   427 	$referenceDOSSlash =~ s/\//\\/g;
       
   428 
       
   429 	my $exclusionCheck = "UNLISTED";
       
   430 
       
   431 	while (my $exclusion = <EXCLUSIONS>)
       
   432 		{
       
   433 		next if ($exclusion =~ /^\s*$/);
       
   434 
       
   435 		$exclusion =~ s/^\s+//;
       
   436 		$exclusion =~ s/\s+$//;
       
   437 		$exclusion =~ s/\//\\/g;
       
   438 		my $quotemetaExclusion = quotemeta ($exclusion);
       
   439 
       
   440 		if ($referenceDOSSlash =~ /^$quotemetaExclusion$/i)
       
   441 			{				
       
   442 			if ($referenceDOSSlash !~ /^$quotemetaExclusion$/)
       
   443 				{
       
   444 				$exclusionCheck = $exclusion;
       
   445 				}
       
   446 			else
       
   447 				{
       
   448 				$exclusionCheck = "OK";
       
   449 				}
       
   450 			last;
       
   451 			}
       
   452 			elsif($referenceDOSSlash =~ /\\$quotemetaExclusion$/i)
       
   453 			{				
       
   454 			if ($referenceDOSSlash !~ /\\$quotemetaExclusion$/)
       
   455 				{
       
   456 				$exclusionCheck = $exclusion;
       
   457 				}
       
   458 			else
       
   459 				{
       
   460 				$exclusionCheck = "OK";
       
   461 				}
       
   462 			last;
       
   463 			}
       
   464 		}
       
   465 
       
   466 	close EXCLUSIONS;
       
   467 
       
   468 	return $exclusionCheck;
       
   469 	}
       
   470 
       
   471 1;