buildframework/helium/tools/compile/ec/sysdef2make.pl
changeset 1 be27ed110b50
child 179 d8ac696cc51f
equal deleted inserted replaced
0:044383f39525 1:be27ed110b50
       
     1 # This file is part of Nokia EC Tools release
       
     2 #
       
     3 #============================================================================ 
       
     4 #Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     5 #All rights reserved.
       
     6 #This component and the accompanying materials are made available
       
     7 #under the terms of the License "Eclipse Public License v1.0"
       
     8 #which accompanies this distribution, and is available
       
     9 #at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
    10 #
       
    11 #Initial Contributors:
       
    12 #Nokia Corporation - initial contribution.
       
    13 #
       
    14 #Contributors:
       
    15 #
       
    16 #Description: 
       
    17 # 
       
    18 #==============================================================================
       
    19 
       
    20 my $version=35;
       
    21 
       
    22 # 35 2008-09-26 jaakpaak:ou1tools#2679 Changed copyright symbol. Two days to go and I'm off to Atomia. Have fun.
       
    23 # 34 2008-09-23 jaakpaak:ou1tools#2677 Added command line options to revert to "make" instead of anything else for selected commands
       
    24 # 33 2008-09-19 jaakpaak:ou1tools#2673 Added copyright notice
       
    25 # 32 2008-09-11 jaakpaak:ou1tools#2661 Changed abld what and abld check targets to always use "make" in MAKE variable
       
    26 # 31 2008-09-03 jaakpaak:ou1tools#2627 Added creation of *-other-files.txt and *-other.zip
       
    27 # 30 2008-08-05 jaakpaak:ou1tools#2610 Add quoting of direct to file operator >
       
    28 # 29 2008-07-17 jaakpaak:ou1tools#2611 Get rid of symbian tool chain patching for emake
       
    29 # 28 2008-07-07 jaakpaak:ou1tools#2607 sysdef2make.pl to generate correct makefile independent of the location where the script is located
       
    30 # 27 2008-07-01 jaakpaak:ou1tools#2604 -n configuration option to sysdef2make to make it generate only configuration specific makefile
       
    31 # 26 2008-05-23 jaakpaak:ou1tools#2566 Improve output warnings and errors to be symbian compatible
       
    32 # 25 2008-03-26 jaakpaak:ou1tools#2531 Fix the output for log processor to be more compatible with EBS, increased quoting for special characters
       
    33 # 24 2008-03-13 jaakpaak:ou1tools#2522 Fix for last special instruction missing
       
    34 # 23 2008-03-07 jaakpaak:ou1tools#2516 Fix for buildLayer instructions which are executed twice
       
    35 # 22 2008-03-03 jaakpaak:ou1tools#2511 Targets for creating zip files from your workarea
       
    36 # 21 2008-02-29 jaakpaak:ou1tools#2510 Do not overwrite configuration-task targets targets with layer-task targets, printing of filters
       
    37 # 20 2008-02-28 jaakpaak:ou1tools#2495 Fix for specialInstruction dependencies and build time loggin dependencies
       
    38 # 19 2007-12-20 jaakpaak:ou1tools#2440 Fix for unitlists containing white spaces
       
    39 # 18 2007-12-17 jaakpaak:ou1tools#2432 Restructured variables, quoted echoing of command line
       
    40 # 17 2007-11-29 jaakpaak:ou1tools#2427 Fix to layer names containing white spaces, prefix also to specialInstructions
       
    41 # 16 2007-11-15 jaakpaak:ou1tools#2420 Fixed issue with multiple filters and empty unit lists
       
    42 # 15 2007-11-15 jaakpaak:ou1tools#2408 Added configuration-UNITS variable and optionless generic component rules
       
    43 # 14 2007-11-12 jaakpaak:ou1tools#2407 Added warning to layers not having any units
       
    44 # 13 2007-11-09 jaakpaak:ou1tools#2405 Fix to layers
       
    45 # 12 2007-10-31 jaakpaak:ou1tools#2402 Added -s option for path prefix and priorities
       
    46 # 11 2007-10-18 jaakpaak:ou1tools#2356 Fixed problems with filters and buildtime logging
       
    47 # 10 2007-10-18 jaakpaak:ou1tools#2356 Fixed dependency problems on EC, made everyting unit based (previously bld.inf based)
       
    48 # 09 2007-09-07 jaakpaak:ou1tools#2351 Added build time logging
       
    49 # 08 2007-09-01 jaakpaak:ou1tools#2340 Added error ignoring for selected commands and -v option
       
    50 # 07 2007-08-23 jaakpaak:ou1tools#2320 Submaked execution
       
    51 # 06 2007-08-15 jaakpaak:ou1tools#2311 Removed printing of empty unit lists, timestamp as perl script, makefiled unitlist/layernames
       
    52 # 05 2007-08-08 jaakpaak:ou1tools#2291 Added -filter option for user defined filters
       
    53 # 04 2007-08-07 jaakpaak:ou1tools#2290 Added tags for scanlog to specialInstructions also
       
    54 # 03 2007-07-04 jaakpaak:ou1tools#2275 htmlscanlog compatibility fixes
       
    55 # 02 2007-07-03 jaakpaak:ou1tools#2274 fixed specialInstructions handling
       
    56 # 01 2007-06-29 jaakpaak:ou1tools#2273 abldOption also valid for bldmake commands
       
    57 
       
    58 my $scriptDir=$0;
       
    59 # Strip the file from the path
       
    60 $scriptDir =~ s{[^\\\/]*$}{};
       
    61 
       
    62 use lib "$ENV{EPOCROOT}epoc32/tools/build/lib";
       
    63 use XML::DOM;
       
    64 
       
    65 my @userFilters = ();
       
    66 my @forceMakeCommands = ("abld.*\-(w|what|c|check)[^a-zA-Z0-9]");
       
    67 my $file = "";
       
    68 my $pathPrefix = "";
       
    69 
       
    70 my @userConfigurations = ();
       
    71 my @configurations = ();
       
    72 my $makefileName = "makefile";
       
    73 my $makefileOption = "";
       
    74 my $i=0;
       
    75 
       
    76 while ( $i < scalar (@ARGV) ) {
       
    77 	if ( $ARGV[$i] eq "-filter" ) {
       
    78 		push( @userFilters, $ARGV[$i+1] );
       
    79 		$i += 2;
       
    80 	} elsif ( $ARGV[$i] eq "-forcemake" ) {
       
    81 		push( @forceMakeCommands, $ARGV[$i+1] );
       
    82 		$i += 2;
       
    83 	} elsif ( $ARGV[$i] eq "-s" ) {
       
    84 		$pathPrefix = $ARGV[$i+1];
       
    85 		$i += 2;
       
    86 	} elsif ( $ARGV[$i] eq "-n" ) {
       
    87 		push( @configurations, $ARGV[$i+1] );
       
    88 		$i += 2;
       
    89 	} else {
       
    90 		$file = $ARGV[$i];
       
    91 		$i++;
       
    92 	}
       
    93 }
       
    94 my $otherCommandLineOptions;
       
    95 
       
    96 my $i=1;
       
    97 while ( $i < scalar(@forceMakeCommands) ) {
       
    98     $otherCommandLineOptions.="-forcemake \"".quoteCommandForEcho($forceMakeCommands[$i])."\" ";
       
    99     $i++;
       
   100 }
       
   101 
       
   102 
       
   103 if ( @configurations ) {
       
   104     push(@userConfigurations,@configurations);
       
   105     $makefileName = join("_",@configurations).".make";
       
   106 } 
       
   107 open(MAKEFILE,"> $makefileName");
       
   108 
       
   109 
       
   110 my $parser = XML::DOM::Parser->new();
       
   111 
       
   112 my $doc = $parser->parsefile($file);
       
   113 
       
   114 
       
   115 # Commands which' errors will be ignored 
       
   116 my %ignoreErrorCommands = ( "mkdir" => 1,
       
   117                             "md" => 1,
       
   118                             "del" => 1,
       
   119                             "rmdir" => 1,
       
   120                             "echo" => 1,
       
   121                             "rem" => 1,
       
   122                             "xcopy" => 1,
       
   123                             "dir" => 1 );
       
   124                             
       
   125 # Hash containing unitID's and bldFiles.
       
   126 # Keys are unitID's
       
   127 my %bldFiles;
       
   128 
       
   129 # Hash containing the units of each layer and unitlist
       
   130 # Key is the name of list, value is a list of unitId.s
       
   131 # The bldFile has to be obtained from unitIDs
       
   132 my %units;
       
   133 
       
   134 # Hash containing the actual abldTarget's of the command line. 
       
   135 # The key is the name of the target in System Definition xml
       
   136 my %targets;
       
   137 
       
   138 # Hash containing arrays of the real abldTarget's 
       
   139 # Key is the name defined in targetList in system definition xml
       
   140 my %targetLists;
       
   141 
       
   142 # Hash containing the default unitlists of each configuration
       
   143 # Key is the name of the configuration
       
   144 my %unitLists;
       
   145 
       
   146 # Hash containing contents of each specialInstruction
       
   147 # Key is the makefile target name of each specialInstruction
       
   148 # Value is the command line including cd part
       
   149 my %specialInstructions;
       
   150 
       
   151 # The bldfiles which are excluded from each configuration
       
   152 my %excludedUnits;
       
   153 
       
   154 # Hash containing the makefile targets for each task
       
   155 # Key is the task as a makefile target and values is a hash of buildlayer task
       
   156 my %buildLayerTasks;
       
   157 
       
   158 
       
   159 # So you cannot execute _any_ buildLayer command for _any_ unitList or layer
       
   160 # The combination must exist also in system definition xml
       
   161 
       
   162 # $unitId -> filterhash
       
   163 my %unitFilters;
       
   164 
       
   165 # List of all filters set in units
       
   166 my %filters;
       
   167 
       
   168 # Priorities of each unit
       
   169 # unitId -> priority
       
   170 my %unitPriorities;
       
   171 
       
   172 # Configuration makefile rules
       
   173 my %configurationTasks = ();
       
   174 
       
   175 my %optionNames;
       
   176 my %options;
       
   177 
       
   178 # Set verbose option on manually
       
   179 push( @{$options{abldOption}},"VERBOSE");
       
   180 push( @{$options{bldmakeOption}},"VERBOSE");
       
   181 $optionNames{"VERBOSE"} = "-v";
       
   182 
       
   183 # Loop through all the layers
       
   184 foreach my $layer ( $doc->getElementsByTagName('layer') ) {
       
   185     my $layerName = $layer->getAttribute('name');
       
   186 
       
   187     # Loop through all the units in the layer
       
   188     foreach my $unit ( $layer->getElementsByTagName('unit') ) {
       
   189         my $unitID = $unit->getAttribute('unitID');
       
   190         my $bldFile = $unit->getAttribute('bldFile');
       
   191         my $priority = $unit->getAttribute('priority');
       
   192 
       
   193         # Set the filter status
       
   194         $unitFilters{$unitID} = $unit->getAttribute('filter');
       
   195 
       
   196         # Set filters to global hash
       
   197         foreach my $word ( split(/,/,$unitFilters{$unitID}) ) {
       
   198             $word =~ s{^!}{};
       
   199             $filters{$word} = 1;
       
   200         }
       
   201         
       
   202         if ( $pathPrefix &&
       
   203              $bldFile !~ m{^\Q$pathPrefix\E}i ) {
       
   204             $bldFile = $pathPrefix.$bldFile;
       
   205         }
       
   206         # Set bldFile to the unitID
       
   207         $bldFiles{$unitID} = $bldFile ;
       
   208 
       
   209         # Set the default priority
       
   210         if ( ! $priority ) {
       
   211             $priority = 1000;
       
   212         }
       
   213         
       
   214         $unitPriorities{$unitID} = $priority;
       
   215         
       
   216         # Set the bldfile to the unitlist
       
   217         my $i = scalar(@{$units{$layerName}});
       
   218         while ( $i > 0 ) {
       
   219             my $prevUnit = $units{$layerName}[$i-1];
       
   220                 
       
   221             if ( $unitPriorities{$prevUnit} <= $unitPriorities{$unitID}  ) {
       
   222                 last;
       
   223             } else {
       
   224                 $i--;
       
   225             }           
       
   226         }
       
   227         # Insert init to slot $i
       
   228         splice( @{$units{$layerName}},$i,0,$unitID);
       
   229     }
       
   230 }
       
   231 
       
   232 # Loop through all unitLists
       
   233 foreach my $unitList ( $doc->getElementsByTagName('unitList') ) {
       
   234 	my $unitListName = $unitList->getAttribute('name');
       
   235 
       
   236 	# Loop through all unitRefs inside the unitLiss
       
   237 	foreach my $unitRef ( $unitList->getElementsByTagName('unitRef') ) {
       
   238 		my $unitID = $unitRef->getAttribute('unit');
       
   239 
       
   240 		# Set the bldfile to the unitlist
       
   241 		if ( $bldFiles{$unitID} ) {
       
   242 			
       
   243 			my $i = scalar(@{$units{$unitListName}});
       
   244 			while ( $i > 0 ) {
       
   245 				my $prevUnit = $units{$unitListName}[$i-1];
       
   246 				
       
   247 				if ( $unitPriorities{$prevUnit} <= $unitPriorities{$unitID}  ) {
       
   248 					last;
       
   249 				} else {
       
   250 					$i--;
       
   251 				}			
       
   252 			}
       
   253             # Insert init to slot $i
       
   254 			splice( @{$units{$unitListName}},$i,0,$unitID);
       
   255 		} else {
       
   256 			print(STDERR "ERROR: unitList by the name \"".$unitListName."\" has unitRef to \"".$unitID."\" which is not defined.\n");
       
   257 		}
       
   258 	}
       
   259 }
       
   260 
       
   261 # Get targets from the whole SystemDefinition.xml
       
   262 foreach my $target ( $doc->getElementsByTagName('target') ) {
       
   263 	my $targetName = $target->getAttribute('name');
       
   264 	my $abldTarget = $target->getAttribute('abldTarget');
       
   265 
       
   266 	$targets{$targetName} = $abldTarget;
       
   267 }
       
   268 
       
   269 
       
   270 # Get targetLists
       
   271 foreach my $targetList ( $doc->getElementsByTagName('targetList') ) {
       
   272 	my $name = $targetList->getAttribute('name');
       
   273 	my $targetString = $targetList->getAttribute('target');
       
   274 
       
   275 	foreach my $target ( split( /\s+/, $targetString ) ) {
       
   276 		push( @{$targetLists{$name}}, $targets{$target} )
       
   277 	}
       
   278 }
       
   279 
       
   280 # Get options
       
   281 foreach my $option ( $doc->getElementsByTagName('option') ) 
       
   282 # Loop through all option elements
       
   283 {
       
   284 	my $attributes = $option->getAttributes();
       
   285 	my $i = 0;
       
   286 
       
   287 	my %attributeHash;
       
   288 	
       
   289 	while ( $i < $attributes->getLength() ) 
       
   290 	# go through all attributes
       
   291 	{
       
   292 		my $item = $attributes->item($i);
       
   293 		# Get name and value for each item in option attributes
       
   294 		my $name = $item->getName();
       
   295 		my $value = $item->getValue();
       
   296 		
       
   297 		# Insert attribute value into hash by key as name
       
   298 		$attributeHash{$name} = $value;
       
   299 		$i++;
       
   300 	}
       
   301 
       
   302 	foreach my $key ( keys(%attributeHash) ) 
       
   303 	# Go through generated attribute hash
       
   304 	{
       
   305 		if ( $key =~ m{.*Option} && $attributeHash{'enable'} =~ m{y}i ) 
       
   306 		# Attribute key is somethingOption and it is enabled
       
   307 		{
       
   308 			# Set options hash
       
   309 			$optionNames{$attributeHash{"name"}} = $attributeHash{$key};
       
   310 			
       
   311 			push( @{$options{$key}}, $attributeHash{"name"} );
       
   312 
       
   313 			# abldOptions become bldmakeOptions
       
   314 			# bldMake only supports -keepgoing and -verbose options
       
   315 			if ( $key eq "abldOption" && 
       
   316 				 ( $attributeHash{$key} =~ /^\s*-k/i ||
       
   317 				   $attributeHash{$key} =~ /^\s*-v/i )) {
       
   318 				push( @{$options{bldmakeOption}}, $attributeHash{"name"} );
       
   319 			}
       
   320 		}
       
   321 	}
       
   322 }
       
   323 
       
   324 
       
   325 my @xmlConfigurations = ();
       
   326 # This loop digs out unitlists, layers and tasks from each configuration
       
   327 foreach my $xmlConfiguration ( $doc->getElementsByTagName('configuration') ) {
       
   328     my $configurationName = $xmlConfiguration->getAttribute('name');
       
   329 
       
   330     # Store all configurations to a list
       
   331     push( @xmlConfigurations, $configurationName );
       
   332 
       
   333     # Check we are not using configuration name which overlaps with unit list name
       
   334     foreach my $layer ( keys(%units)) {
       
   335         if ( lc($layer) eq lc($configurationName) ) {
       
   336             print(STDERR "ERROR: Configuration \"$configurationName\" is defined also as unitList/layer \"$layer\". Names MUST BE UNIQUE!\n");
       
   337             last;
       
   338         }
       
   339     }
       
   340     my $taskId=1;
       
   341 
       
   342     # Get the filters of the configuration
       
   343     my @configurationFilters = split( /,/, $xmlConfiguration->getAttribute('filter') );
       
   344 
       
   345     # Add user specified filters to current configuration
       
   346     push( @configurationFilters, @userFilters );
       
   347 
       
   348     # Get the first child of the configuration
       
   349     my $xmlElement = $xmlConfiguration->getFirstChild();
       
   350 
       
   351     # This variable keeps track when specialInstruction changes 
       
   352     # by storing the name of the current specialInstruction
       
   353     my %currentSpecialInstruction=();
       
   354 
       
   355     do { 
       
   356         my $tagName = $xmlElement->getNodeName();
       
   357 
       
   358         # Both unitListRef and layerRef end up to same place; unitLists hash
       
   359         # From makefile point of view they have no difference what so ever
       
   360         if ( $tagName eq "unitListRef" || 
       
   361             $tagName eq "layerRef" ) {
       
   362             my $unitList;
       
   363 
       
   364             if ( $tagName eq "unitListRef" ) {
       
   365                 $unitList = $xmlElement->getAttribute('unitList'); 
       
   366             } else {
       
   367                 $unitList = $xmlElement->getAttribute('layerName');
       
   368             }
       
   369 
       
   370             if ( scalar(@{$units{$unitList}}) == 0 ) {
       
   371                 print(STDERR "WARNING: unit list \"$unitList\" included to configuration \"$configurationName\" has no units.\n");
       
   372             } else {
       
   373                 # Go through bldfiles and check their filters
       
   374                 foreach my $unit ( @{$units{$unitList}} ) {
       
   375                     my $i = 0;
       
   376                     my $exclude = check_filter( $unitFilters{$unit}, \@configurationFilters);
       
   377                     
       
   378                        
       
   379                     if ( $exclude )
       
   380                     # If there was an exclusion filter, exclude
       
   381                     # If bldfile had filters set but include filter was not among them, exclude
       
   382                     {
       
   383                         push( @{$excludedUnits{$configurationName}}, $unit );
       
   384                     }
       
   385                 }
       
   386             }
       
   387             # Add the new unitlist to current configuration
       
   388             push( @{$unitLists{$configurationName}}, $unitList );
       
   389         }
       
   390 
       
   391         if ( $tagName eq "task" ) {
       
   392             # The unitlists applied for the current task
       
   393             my @taskUnitLists=();
       
   394 
       
   395             # First get possible task specific unitListRefs
       
   396             foreach my $xmlUnitListRef ( $xmlElement->getElementsByTagName('unitListRef') ) {
       
   397                 push( @taskUnitLists, $xmlUnitListRef->getAttribute('unitList') );
       
   398             }
       
   399 
       
   400             my $xmlTask = $xmlElement->getFirstChild();
       
   401             do {
       
   402                 my $taskType = $xmlTask->getNodeName();
       
   403 
       
   404                 # For specialInstructions we only need the name
       
   405                 # This is because the content in specialInstructions is determined later
       
   406                 if ( $taskType eq "specialInstructions" ) {
       
   407                     my $name = $xmlTask->getAttribute('name');
       
   408 
       
   409                     if ( $name ne $currentSpecialInstruction{specialInstruction} ) 
       
   410                     # The specialInstruction has just changed
       
   411                     {
       
   412                         if ( $currentSpecialInstruction{specialInstruction} ) 
       
   413                         # but it's not the first one
       
   414                         {
       
   415                             # Store the previous special instruction
       
   416                             my %configurationTask = %currentSpecialInstruction;
       
   417                             push( @{$configurationTasks{$configurationName}}, \%configurationTask );
       
   418 
       
   419                             # And clear up for next one
       
   420                             %currentSpecialInstruction = ();
       
   421                         }
       
   422                         $currentSpecialInstruction{specialInstruction} = $name;
       
   423                         $currentSpecialInstruction{taskId} = $taskId++;
       
   424                     } 
       
   425                      
       
   426                     my $cwd = $xmlTask->getAttribute('cwd');
       
   427                     my $command = quoteCommand($xmlTask->getAttribute('command'));
       
   428 
       
   429                     if ( $cwd ne "." ) {
       
   430                         $command = "cd ".$cwd." && ".$command." ";
       
   431                     }
       
   432 
       
   433                     if ( $ignoreErrorCommands{getExecutable($command)} ) 
       
   434                     # Command is listed as "ignore error" command
       
   435                     {
       
   436                         $command = "-".$command;
       
   437                     } 
       
   438                     push( @{$currentSpecialInstruction{commands}}, $command );
       
   439                 } 
       
   440 
       
   441                 if ( $taskType eq "buildLayer" ) {
       
   442                     if ( $currentSpecialInstruction{specialInstruction} ) 
       
   443                     # Last task was a specialInstruction
       
   444                     {
       
   445                         # Store the previous special instruction
       
   446                         my %configurationTask = %currentSpecialInstruction;
       
   447                         push( @{$configurationTasks{$configurationName}}, \%configurationTask );
       
   448                     }
       
   449                     # And clear up for next one
       
   450                     %currentSpecialInstruction = ();
       
   451 
       
   452                     # Set command and targets
       
   453                     my $targetList = $xmlTask->getAttribute('targetList');
       
   454                     my @targets = @{$targetLists{$targetList}};
       
   455                     my $command = $xmlTask->getAttribute('command');
       
   456                     my $executable = getExecutable($command);
       
   457 
       
   458                     my $option;
       
   459                     # abldOption specified, append makefile variable to command
       
   460                     # you can screw up what check and export by defining wrong options
       
   461 
       
   462                     # We are ignoring the fact that abld export doesnt work with all possible
       
   463                     # options. 
       
   464                     # It is more important to relay the -keepgoing to abld export
       
   465                     # than try to protect the environment from user who uses abldOption wrong
       
   466                     if ( @{$options{$executable.'Option'}} &&
       
   467                          $command !~ m{abld.*\-(w|what|c|check)\s}i ) {
       
   468                         $option =" \$(".$executable."Option)";
       
   469                     }
       
   470 
       
   471                     if ( ! @targets ) {
       
   472                         my %configurationTask;
       
   473                         $configurationTask{executable} = $executable;
       
   474                         $configurationTask{command} = quoteCommand($command);
       
   475                         $configurationTask{option} = $option;
       
   476 
       
   477                         if ( @taskUnitLists ) {
       
   478                             $configurationTask{unitLists} = \@taskUnitLists;
       
   479                         } else {
       
   480                             if ( ! @{$unitLists{$configurationName}} ) {
       
   481                                 print(STDERR "Warning: buildLayer task \"".$command."\" in configuration \"".$configurationName."\" does not contain any units.\n");
       
   482                             }
       
   483                         }
       
   484                         $configurationTask{taskId} = $taskId++;
       
   485 
       
   486                         push( @{$configurationTasks{$configurationName}},\%configurationTask );
       
   487 
       
   488                     } else {
       
   489                         foreach my $target ( @targets ) {
       
   490                             my %configurationTask;
       
   491 
       
   492                             # Append the target to the command
       
   493                             $configurationTask{executable} = $executable;
       
   494                             $configurationTask{command} = quoteCommand($command);
       
   495                             $configurationTask{option} = $option;
       
   496                             $configurationTask{target} = $target;
       
   497 
       
   498                             if ( @taskUnitLists ) {
       
   499                                 $configurationTask{unitLists} = \@taskUnitLists;
       
   500                             } elsif ( ! @{$unitLists{$configurationName}} ) {
       
   501                                 print(STDERR "Warning: buildLayer task \"".$command."\" in configuration \"".$configurationName."\" does not contain any units.\n");
       
   502                             }
       
   503                             $configurationTask{taskId} = $taskId++;
       
   504 
       
   505                             push( @{$configurationTasks{$configurationName}},\%configurationTask );
       
   506                         }
       
   507                     }
       
   508                 }
       
   509             } while ( $xmlTask = $xmlTask->getNextSibling() ) ;
       
   510         }
       
   511     } while ( $xmlElement = $xmlElement->getNextSibling() ) ;
       
   512 
       
   513     if ( $currentSpecialInstruction{specialInstruction} ) 
       
   514     # Last task was a specialInstruction
       
   515     {
       
   516         # Store the previous special instruction
       
   517         my %configurationTask = %currentSpecialInstruction;
       
   518         push( @{$configurationTasks{$configurationName}}, \%configurationTask );
       
   519     }
       
   520     # And clear up for next one
       
   521     %currentSpecialInstruction = ();
       
   522 }
       
   523 
       
   524 
       
   525 # If no configuration specified on command line, use all configurations collected from xml
       
   526 if ( ! @configurations ) {
       
   527     push(@configurations,@xmlConfigurations);
       
   528 }
       
   529 
       
   530 # Print help
       
   531 
       
   532 print(MAKEFILE "\# Set the script directory\n");
       
   533 print(MAKEFILE "\# The directory is trailed with a space to\n");
       
   534 print(MAKEFILE "\# prevent continuing line side effects of trailing backslash\n");
       
   535 print(MAKEFILE "\# We need strip to remove the trailing space.\n");
       
   536 print(MAKEFILE "SCRIPTDIR:=$scriptDir \n\n");
       
   537 print(MAKEFILE "SCRIPTDIR:=\$(strip \$(SCRIPTDIR))\n\n");
       
   538 print(MAKEFILE "# Export MAKE variable in order to abld.pl to see it\n");
       
   539 print(MAKEFILE "export MAKE\n\n");
       
   540 
       
   541 print(MAKEFILE "SYSTEMDEFINITIONXML:=".$file."\n\n");
       
   542 
       
   543 if ( @userFilters ) {
       
   544     print(MAKEFILE "FILTERS:=".join(" ",@userFilters)."\n\n");
       
   545 }
       
   546 
       
   547 if ( @userConfigurations )
       
   548 # User configuration was set on command line
       
   549 {
       
   550     print(MAKEFILE "CONFIGURATION=$userConfigurations[0]\n\n");
       
   551     print(MAKEFILE "export CONFIGURATION\n\n");
       
   552     # Set the configuration as default target
       
   553     print(MAKEFILE "\$(CONFIGURATION):\n\n");
       
   554 }
       
   555 
       
   556 # Print out options
       
   557 print(MAKEFILE "# Option names\n");
       
   558 
       
   559 foreach my $optionName ( keys(%optionNames) ) {
       
   560 	print(MAKEFILE "$optionName := ".$optionNames{$optionName}." \n");
       
   561 }
       
   562 print(MAKEFILE "\n");
       
   563 
       
   564 print(MAKEFILE "# command options\n");
       
   565 foreach my $cmdOption ( keys(%options)) {
       
   566 	print(MAKEFILE $cmdOption." := ");
       
   567 	foreach my $optionName ( @{$options{$cmdOption}} ) {
       
   568 		print(MAKEFILE "\$\($optionName\) ");
       
   569 	}
       
   570 	print(MAKEFILE "\n");
       
   571 }
       
   572 print(MAKEFILE "\n");
       
   573 
       
   574 if ( $makefileName ne "makefile" ) {
       
   575     print(MAKEFILE "CURRENT_MAKEFILE:=$makefileName\n");
       
   576 }
       
   577 
       
   578 if ( $otherCommandLineOptions ) {
       
   579     print(MAKEFILE "SYSDEF2MAKEFLAGS:=$otherCommandLineOptions\n\n");
       
   580 }
       
   581 
       
   582 print(MAKEFILE ".PHONY : help\n");
       
   583 print(MAKEFILE "help:\n");
       
   584 print(MAKEFILE "\t\@cmd /c echo.\n");
       
   585 print(MAKEFILE "\t\@echo This is a makefile \$(CURRENT_MAKEFILE) created by sysdef2make.pl version $version with command line:\n");
       
   586 print(MAKEFILE "\t\@echo  perl \$(SCRIPTDIR)sysdef2make.pl \$(addprefix -filter ,\$(FILTERS)) \$(addprefix -n ,\$(CONFIGURATION)) \$(SYSDEF2MAKEFLAGS) \$(SYSTEMDEFINITIONXML)\n");
       
   587 print(MAKEFILE "\t\@cmd /c echo.\n");
       
   588 if ( scalar(@userFilters) ) {
       
   589 	print(MAKEFILE "\t\@echo User defined filters added to all configurations: ".join(" ",@userFilters)."\n\n");
       
   590 }
       
   591 print(MAKEFILE "\t\@cmd /c echo.\n");
       
   592 print(MAKEFILE "\t\@echo To start up (hopefully) helpful web page, type:\n");
       
   593 print(MAKEFILE "\t\@echo  make \$(addprefix -f ,\$(CURRENT_MAKEFILE)) nethelp\n");
       
   594 print(MAKEFILE "\t\@cmd /c echo.\n");
       
   595 print(MAKEFILE "\t\@echo To get a list of all the buildable configurations:\n");
       
   596 print(MAKEFILE "\t\@echo  make \$(addprefix -f ,\$(CURRENT_MAKEFILE)) configurations\n");
       
   597 print(MAKEFILE "\t\@cmd /c echo.\n");
       
   598 print(MAKEFILE "\t\@echo To get a list of all the executable special instructions:\n");
       
   599 print(MAKEFILE "\t\@echo  make \$(addprefix -f ,\$(CURRENT_MAKEFILE)) specialInstructions\n");
       
   600 print(MAKEFILE "\t\@cmd /c echo.\n");
       
   601 print(MAKEFILE "\t\@echo Any of the previous configurations or specialInstructions\n");
       
   602 print(MAKEFILE "\t\@echo can be executed as they are by adding the name after make.\n");
       
   603 print(MAKEFILE "\t\@cmd /c echo.\n");
       
   604 print(MAKEFILE "\t\@echo To get a list of tasks executable for any component\n");
       
   605 print(MAKEFILE "\t\@echo  make \$(addprefix -f ,\$(CURRENT_MAKEFILE)) tasks\n");
       
   606 print(MAKEFILE "\t\@cmd /c echo.\n");
       
   607 print(MAKEFILE "\t\@echo Components and tasks are combined with\n");
       
   608 print(MAKEFILE "\t\@echo  make \$(addprefix -f ,\$(CURRENT_MAKEFILE)) \[component\]-\[task\]\n");
       
   609 print(MAKEFILE "\t\@cmd /c echo.\n");
       
   610 print(MAKEFILE "\t\@echo For instance:\n");
       
   611 print(MAKEFILE "\t\@echo  make s60\\yourcomponent\\group-task\n");
       
   612 print(MAKEFILE "\t\@cmd /c echo.\n");
       
   613 print(MAKEFILE "\t\@cmd /c echo.\n");
       
   614 print(MAKEFILE "\t\@echo Any amount of configurations, special instructions and\n");
       
   615 print(MAKEFILE "\t\@echo component-task combinations can be combined on one command line.\n");
       
   616 print(MAKEFILE "\t\@cmd /c echo.\n");
       
   617 print(MAKEFILE "\t\@echo Instead of make you can use any gnu make compatible framework like emake.\n");
       
   618 print(MAKEFILE "\t\@cmd /c echo.\n");
       
   619 print(MAKEFILE "\t\@echo To get more information about the gnu make options google \"gnu make manual\"\n");
       
   620 print(MAKEFILE "\t\@echo or type \"make --help\"\n\n");
       
   621 
       
   622 print(MAKEFILE ".PHONY : nethelp\n\n");
       
   623 print(MAKEFILE "nethelp : \n");
       
   624 print(MAKEFILE "\tcmd /c \"start http://s60wiki/S60Wiki/Sysdef2make\"\n\n");
       
   625 
       
   626 print(MAKEFILE "# Printing out messsages\n");
       
   627 print(MAKEFILE ".PHONY : \%-print\n\n");
       
   628 print(MAKEFILE "\%-print : \n\t\@echo \$\*\n\n");
       
   629 
       
   630 print(MAKEFILE "\n");
       
   631 print(MAKEFILE "\%.html : \%.log\n");
       
   632 print(MAKEFILE "\t\@-del \$\@\n");
       
   633 print(MAKEFILE "\tperl -S htmlscanlog.pl -l \$\< -o \$\@ -v -v\n\n");
       
   634 
       
   635 print(MAKEFILE "define STARTTASK\n");
       
   636 print(MAKEFILE "\@echo === \$(CONFIGURATION) == \$\*\n");
       
   637 print(MAKEFILE "\t\@echo -- \$\(1\) \n");
       
   638 print(MAKEFILE "\t-\@perl -e \"print '++ Started at '.localtime().\\\"\\n\\\"\"\n");
       
   639 print(MAKEFILE "\t-\@perl -e \"use Time::HiRes; print '+++ HiRes Start '.Time::HiRes::time().\\\"\\n\\\";\"\n");
       
   640 print(MAKEFILE "endef\n\n");
       
   641 
       
   642 
       
   643 print(MAKEFILE "define ENDTASK\n");
       
   644 print(MAKEFILE "\t\-\@perl -e \"use Time::HiRes; print '+++ HiRes End '.Time::HiRes::time().\\\"\\n\\\";\"\n");
       
   645 print(MAKEFILE "\t-\@perl -e \"print '++ Finished at '.localtime().\\\"\\n\\\"\"\n");
       
   646 print(MAKEFILE "endef\n\n");
       
   647 
       
   648 print(MAKEFILE "# Rule for starting up a configuration\n");
       
   649 print(MAKEFILE ".PHONY : timestart.txt\n\n");
       
   650 print(MAKEFILE "timestart.txt \:\n");
       
   651 print(MAKEFILE "\t\@echo ===-------------------------------------------------\n");
       
   652 print(MAKEFILE "\t\@echo === \$\(CONFIGURATION)\n");
       
   653 print(MAKEFILE "\t\@echo ===-------------------------------------------------\n");
       
   654 print(MAKEFILE "\t\@\-perl -e \"print '=== \$(CONFIGURATION) started '.localtime().\\\"\\n\\\"\"\n");
       
   655 print(MAKEFILE "\t\@\-perl -e \"print time\" \> \$\@\n");
       
   656 print(MAKEFILE "\n\n");
       
   657 
       
   658 print(MAKEFILE "define LOGBUILDTIME\n");
       
   659 print(MAKEFILE "\-\(echo \$(CONFIGURATION)\$(CONFIGURATIONSUFFIX) \& type \$\< \) \| perl \$(SCRIPTDIR)send_data.pl\n");
       
   660 print(MAKEFILE "endef\n\n");
       
   661 
       
   662 print(MAKEFILE "# Do not delete generated \*-files.txt files afterwards\n");
       
   663 print(MAKEFILE ".PRECIOUS : \%-files.txt\n\n");
       
   664 
       
   665 print(MAKEFILE "# ... unless there was an error generating \*-files.txt file, the delete it\n");
       
   666 print(MAKEFILE ".DELETE_ON_ERROR : \%-files.txt\n\n");
       
   667 
       
   668 
       
   669 print(MAKEFILE "\%-otherfiles.txt : %-files.txt\n");
       
   670 print(MAKEFILE "\tperl \$(SCRIPTDIR)filter-out.pl \$\< \$(filter-out \$\<,\$(wildcard \$(\*)\*-files.txt)) > \$\@\n");
       
   671 
       
   672 print(MAKEFILE "\%-files.txt  : \n");
       
   673 print(MAKEFILE "\tperl \$(SCRIPTDIR)find.pl \$\(subst \_,\/,\$\*\) \> \$\@\n\n");
       
   674 
       
   675 print(MAKEFILE "\%others.zip : \%-otherfiles.txt\n");
       
   676 print(MAKEFILE "\ttype \$\< \| zip \-\@ \$\@\n\n");
       
   677 
       
   678 print(MAKEFILE "\%.zip : \%-files.txt\n");
       
   679 print(MAKEFILE "\ttype \$\< \| zip \-\@ \$\@\n\n");
       
   680 
       
   681 
       
   682 
       
   683 print(MAKEFILE "# Creating cmd file for configuration using ebs tools\n");
       
   684 print(MAKEFILE "\%\-ebs.xml : \$(SYSTEMDEFINITIONXML)\n");
       
   685 print(MAKEFILE "\tperl \$(EPOCROOT)epoc32/tools/build/genxml.pl -o \$\@ -s \"\\\" -n \$\* -x \$\<\n");
       
   686 print(MAKEFILE "\n");
       
   687 
       
   688 print(MAKEFILE "\%.cmd : \%-ebs.xml\n");
       
   689 print(MAKEFILE "\tperl \$(SCRIPTDIR)getEbsCommands.pl -d \$\< \> \$\@\n");
       
   690 print(MAKEFILE "\n");
       
   691 
       
   692 print(MAKEFILE "# Automatic dependencies\n");
       
   693 print(MAKEFILE "\%\/abld.bat : \%\/bld.inf\n");
       
   694 print(MAKEFILE "\t\$(call STARTTASK,bldmake bldfiles -v -k)\n");
       
   695 print(MAKEFILE "\t\@echo Error 42 abld command issued when bldmake was not done first\n");
       
   696 print(MAKEFILE "\t\@echo Error 42 This is a serious error in your build configuration and must be fixed.\n");
       
   697 print(MAKEFILE "\t\@echo Error 42 In this build the error has been fixed automatically.\n");
       
   698 print(MAKEFILE "\tcd \$* && bldmake bldfiles -v -k\n");
       
   699 print(MAKEFILE "\t\$(ENDTASK)\n\n");
       
   700 print(MAKEFILE "\n");
       
   701 
       
   702 print(MAKEFILE "# If we are working on EC \"patched\" system\n");
       
   703 print(MAKEFILE "ifeq (\$(strip \$(MAKE)),emake)\n");
       
   704 print(MAKEFILE " \# We assume this to be Electric Cloud build\n");
       
   705 print(MAKEFILE " CONFIGURATIONSUFFIX=-ECBS\n");
       
   706 print(MAKEFILE "endif\n\n");
       
   707 	
       
   708 
       
   709 print(MAKEFILE "# Configurations\n");
       
   710 print(MAKEFILE "CONFIGURATIONS:=");
       
   711 foreach my $configurationName (sort(keys(%configurationTasks))) {
       
   712 	print(MAKEFILE " \\\n ".makefileTargetName($configurationName));
       
   713 }
       
   714 print(MAKEFILE "\n\n");
       
   715 
       
   716 
       
   717 
       
   718 print(MAKEFILE "# Printing out the configurations\n");
       
   719 print(MAKEFILE "configurations : \$(addsuffix -print,\$(CONFIGURATIONS))\n\n");
       
   720 
       
   721 # Filter current makefile out of this rule in order to avoid trying to regenerate current makefile
       
   722 # in situations where for one reason or another system definition xml file is not present.
       
   723 print(MAKEFILE "\$(filter-out \$(CURRENT_MAKEFILE),\$(addsuffix .make,\$(CONFIGURATIONS))) : \%.make : \$(SYSTEMDEFINITIONXML) ");
       
   724 
       
   725 # If this is the root level makefile, add this makefile to dependencies also
       
   726 # to avoid configuration specific sub makefiles and main level makefile 
       
   727 # incompatibilities for instance with filters.
       
   728 if ( $makefileName eq "makefile" ) {
       
   729     print(MAKEFILE "makefile");
       
   730 }
       
   731 print(MAKEFILE "\n");
       
   732 print(MAKEFILE "\tperl \$(SCRIPTDIR)sysdef2make.pl \$(addprefix -filter ,\$(FILTERS)) -n \$\* \$(SYSDEF2MAKEFLAGS) \$\<\n\n");
       
   733 
       
   734 print(MAKEFILE "\$(filter-out \$(CONFIGURATION),\$(CONFIGURATIONS)) : \% : \%.make\n");
       
   735 print(MAKEFILE "\t\$(MAKE) -f \$\< \$\@\n\n");
       
   736 
       
   737 
       
   738 
       
   739 # Build up buildlayertasks
       
   740 foreach my $configurationName ( @configurations ) {
       
   741     my $configurationTargetName = makefileTargetName( $configurationName );
       
   742     foreach my $looptask ( @{$configurationTasks{$configurationName}} ) {
       
   743         my %task = %{$looptask};
       
   744         my $taskId = $task{taskId};
       
   745         if ( ! $task{specialInstruction} ) {
       
   746             my $command = makefileTargetName( $task{command} );
       
   747             my $target = makefileTargetName( $task{target} );
       
   748             $taskTargetName = makefileTargetName( $task{command},$task{target} );
       
   749 
       
   750             # Add task to list of tasks
       
   751             $buildLayerTasks{$taskTargetName} = $looptask;
       
   752         }
       
   753     }
       
   754 }
       
   755 
       
   756 
       
   757 # Process buildLayer tasks and derive commands which do not have options incorporated with them
       
   758 foreach my $taskTarget ( sort(keys(%buildLayerTasks)) ) {
       
   759     my %task = %{$buildLayerTasks{$taskTarget}};
       
   760     
       
   761     my %newTask;
       
   762     $newTask{command} = $task{command};
       
   763 
       
   764     # Strip any " -XXX" from command
       
   765     $newTask{command} =~ s{\s-[^\s]*}{}g;
       
   766     
       
   767     $newTask{target} = $task{target};
       
   768 
       
   769     # Strip leading "-XXX" from target
       
   770     $newTask{target} =~ s{^-[^\s]*}{}g;
       
   771 
       
   772     # Strip any " -XXX" from target
       
   773     $newTask{target} =~ s{\s-[^\s]*}{}g;
       
   774     
       
   775     my $newTaskTargetName = makefileTargetName( $newTask{command}, $newTask{target} );
       
   776     if ( ! exists($buildLayerTasks{$newTaskTargetName}) ) {
       
   777         $newTask{option} = $task{option};
       
   778         $newTask{executable} = $task{executable};
       
   779         $buildLayerTasks{$newTaskTargetName} = \%newTask;
       
   780     }
       
   781 }
       
   782 
       
   783 
       
   784 
       
   785 # Here we determine the content for each special instruction
       
   786 my $i = 0;
       
   787 my @specialInstructionList = @{ $doc->getElementsByTagName('specialInstructions') };
       
   788 my @currentArray = ();
       
   789 my $name;
       
   790 while ( $i < scalar(@specialInstructionList) ) 
       
   791 # There are more specialInstructions
       
   792 {
       
   793 	# Set name and specialInstruction to list
       
   794 	my $specialInstruction = $specialInstructionList[$i];
       
   795 	$name = $specialInstruction->getAttribute('name');
       
   796 	my $command = quoteCommand($specialInstruction->getAttribute('command'));
       
   797 	my $cwd = $specialInstruction->getAttribute('cwd');
       
   798 
       
   799 	if ( $ignoreErrorCommands{getExecutable($command)} ) 
       
   800 	# Command is listed as "ignore error" command
       
   801 	{
       
   802 		$command = "-cd ".$cwd." && ".$command." ";
       
   803 	} else {
       
   804 		$command = "cd ".$cwd." && ".$command." ";
       
   805 	}
       
   806 
       
   807 	push( @currentArray, $command );
       
   808 	
       
   809 	# Get next element and advance list
       
   810 	my $prevSpecialInstruction = $specialInstruction;
       
   811 	$specialInstruction = $specialInstruction->getNextSibling();
       
   812 
       
   813 	if ( ! $specialInstruction ) 
       
   814 	# No next sibling. Get first child of parents next sibling
       
   815 	{
       
   816 		my $nextParent = $prevSpecialInstruction->getParentNode();
       
   817 		do {
       
   818 			$nextParent = $nextParent->getNextSibling();
       
   819 	 	} while ( $nextParent && $nextParent->getNodeName() =~ m{^\#.*} );
       
   820  
       
   821 		if ( $nextParent ) {
       
   822 			$specialInstruction = $nextParent->getFirstChild();
       
   823 		}
       
   824 	}
       
   825 	$i++;
       
   826 
       
   827 	if ( ! $specialInstruction ||
       
   828            $specialInstruction->getNodeName() ne "specialInstructions" ||
       
   829            $specialInstruction->getAttribute('name') ne $name )
       
   830 	# Element is not part of same specialInstruction group
       
   831 	{
       
   832 		checkRegisterSpecialInstruction( $name, @currentArray );
       
   833 		# reset tasks
       
   834 		@currentArray = ();
       
   835 		$name = ();
       
   836 	}
       
   837 }
       
   838 
       
   839 if ( $name && @currentArray ) {
       
   840 	checkRegisterSpecialInstruction( $name, @currentArray );
       
   841 }
       
   842 
       
   843 
       
   844 sub checkRegisterSpecialInstruction($@) {
       
   845 	my ($name,@currentArray) = @_;
       
   846 
       
   847 	if ( $specialInstructions{$name} ) 
       
   848 	# Same specialInstruction name has been registered
       
   849 	{ 
       
   850 		if ( scalar(@{$specialInstructions{$name}}) != scalar(@currentArray) ) 
       
   851 		# Different amount of tasks
       
   852 		{
       
   853 			print(STDERR "ERROR: specialInstruction $name is defined in several places but with different contents.\n");
       
   854 
       
   855 			if ( scalar(@currentArray) > scalar(@{$specialInstructions{$name}}) ) 
       
   856 			# The latter instance has more instances
       
   857 			{
       
   858 				# Use that one 
       
   859 				@{$specialInstructions{$name}} = @currentArray;
       
   860 			}
       
   861 		} else 
       
   862 		# Same amount of tasks
       
   863 		{
       
   864 			my @registeredTasks = @{$specialInstructions{$name}};
       
   865 			my $j=0;
       
   866 			while ( $j < scalar(@currentArray) && 
       
   867 					$currentArray[$j] eq $registeredTasks[$j] ) {
       
   868 				$j++;
       
   869 			}
       
   870 			if ( $currentArray[$j] ne $registeredTasks[$j] ) {
       
   871 				print(STDERR "ERROR: specialInstruction $name is defined several places but with different contents.\n");
       
   872 			}
       
   873 		}
       
   874 	} else 
       
   875 	# Not registered before, this is first time
       
   876 	{
       
   877 		push( @{$specialInstructions{$name}}, @currentArray );
       
   878 	}
       
   879 }
       
   880 
       
   881 
       
   882 # Print out component specific rules resulting from buildLayer tasks
       
   883 print(MAKEFILE "# buildLayer component (group/bld.inf) specific rules\n");
       
   884 foreach my $makefileTarget ( keys(%buildLayerTasks) ) {
       
   885     my %task = %{$buildLayerTasks{$makefileTarget}};
       
   886     my $cmdLine = $task{command}." ".$task{option}." ".$task{target};
       
   887 
       
   888     # buildLayer tasks end up to pattern rules where pattern is the component directory
       
   889     my $match=0;
       
   890     foreach my $regexp (@forceMakeCommands) {
       
   891         if ( $cmdLine =~ m{$regexp}i ) {
       
   892             $match=1;
       
   893             last;
       
   894         }
       
   895     }
       
   896     if ( $match ) {
       
   897         # Its command matching "force make on this command" regexp
       
   898        
       
   899         # Make variable must contain standard gnu make, nothing else
       
   900         print(MAKEFILE "\%-".$makefileTarget.": MAKE=make\n");
       
   901     }
       
   902     if ( $task{executable} =~ /^abld/i ) {
       
   903         print(MAKEFILE "\%-".$makefileTarget.": %/abld.bat\n");
       
   904     } else {
       
   905         print(MAKEFILE "\%-".$makefileTarget.": %/bld.inf\n");
       
   906     }
       
   907     print(MAKEFILE "\t\$(call STARTTASK,".quoteCommandSeparators($task{command}).")\n");
       
   908     print(MAKEFILE "\t");
       
   909     if ( $ignoreErrorCommands{$task{executable}} ) {
       
   910         print(MAKEFILE "-");
       
   911     }
       
   912     print(MAKEFILE "cd \$* && $cmdLine\n");
       
   913     print(MAKEFILE "\t\$(ENDTASK)\n\n");
       
   914 }
       
   915 
       
   916 
       
   917 # Print out the contents of specialInstructions
       
   918 print(MAKEFILE "# specialInstructions\n");
       
   919 foreach my $specialInstruction ( keys(%specialInstructions) ) {
       
   920     my $simpleTarget = makefileTargetName($specialInstruction);
       
   921     my $commands = join(" \n\t",@{$specialInstructions{$specialInstruction}});
       
   922     
       
   923     # buildLayer tasks end up to pattern rules where pattern is the component directory
       
   924     my $match=0;
       
   925     foreach my $regexp (@forceMakeCommands) {
       
   926         if ( $commands =~ m{$regexp}i ) {
       
   927             $match=1;
       
   928             last;
       
   929         }
       
   930     }
       
   931     if ( $match ) {
       
   932         # Its command matching "force make on this command" regexp
       
   933        
       
   934         # Make variable must contain standard gnu make, nothing else
       
   935         print(MAKEFILE $simpleTarget.": MAKE=make\n");
       
   936     }
       
   937     print(MAKEFILE "$simpleTarget:\n");
       
   938     print(MAKEFILE "\t\$(call STARTTASK,\$\@)\n");
       
   939     print(MAKEFILE "\t$commands \n");
       
   940     print(MAKEFILE "\t\$(ENDTASK)\n\n");
       
   941 }
       
   942 
       
   943 # Print out the unitlists 
       
   944 # Note that this will print unitlists several times if they are in several configurations
       
   945 print(MAKEFILE "# Component lists based on contents of layers and unitlists\n");
       
   946 foreach my $configuration ( @userConfigurations ) {
       
   947     foreach my $unitList ( @{$unitLists{$configuration}} ) {
       
   948         print(MAKEFILE "\n\n");
       
   949         print(MAKEFILE makefileTargetName($unitList)." := ");
       
   950         foreach my $unit ( @{$units{$unitList}} ) {
       
   951             print(MAKEFILE " \\\n ".$bldFiles{$unit});
       
   952         }
       
   953 
       
   954     }
       
   955 }
       
   956 print(MAKEFILE "\n\n");
       
   957 
       
   958 print(MAKEFILE "# Rules for layers and unitLists\n");
       
   959 foreach my $configuration ( @userConfigurations) {
       
   960     foreach my $unitList ( @{$unitLists{$configuration}} ) {
       
   961         # Check there's no matching configuration name
       
   962         my $unitListTarget = makefileTargetName($unitList);
       
   963         my $matchingLayer=0;
       
   964         foreach my $configurationName ( keys(%unitLists) ) {
       
   965             if ( makefileTargetName(lc($configurationName)) eq lc($unitListTarget) ) {
       
   966                 $matchingLayer = 1;
       
   967                 last;
       
   968             }
       
   969         }
       
   970     
       
   971         # Print unitlist-task rule only if it there is no matching configuration-task rule existing anywhere
       
   972         if ( ! $matchingLayer ) {
       
   973             foreach my $task ( keys(%buildLayerTasks) ) {
       
   974                 print(MAKEFILE "\n\n".makefileTargetName($unitList)."-$task : \$(addsuffix -$task , \$(filter-out \$(\$(CONFIGURATION)-EXCLUDE),\$(".makefileTargetName($unitList).")))");
       
   975             }
       
   976         }
       
   977     }
       
   978 }
       
   979 print(MAKEFILE "\n\n");
       
   980 
       
   981 foreach my $configurationName ( @userConfigurations ) {
       
   982     my $configurationTargetName = makefileTargetName( $configurationName );
       
   983 
       
   984     print(MAKEFILE "$configurationTargetName-UNITS := ");
       
   985     foreach my $unitList ( @{$unitLists{$configurationName}} ) {
       
   986         print(MAKEFILE "\$(".makefileTargetName($unitList).") ");
       
   987     }
       
   988     print(MAKEFILE "\n\n");
       
   989 
       
   990     my @excludedUnits = @{$excludedUnits{$configurationName}};
       
   991     
       
   992     print(MAKEFILE "# Excluded components in $configurationName\n");
       
   993     print(MAKEFILE "$configurationTargetName-EXCLUDE := ");
       
   994     foreach my $unit ( @excludedUnits ) {
       
   995         print(MAKEFILE " \\\n".$bldFiles{$unit});
       
   996     }
       
   997     print(MAKEFILE "\n\n");
       
   998 
       
   999     my %targetDependencies;
       
  1000     my %targetCommands;
       
  1001 
       
  1002     push( @{$targetDependencies{$configurationTargetName}}, "timestart.txt" );    
       
  1003     foreach my $looptask ( @{$configurationTasks{$configurationName}} ) {
       
  1004         # Build up configuration depencencies list
       
  1005         my %task = %{$looptask};
       
  1006         my $taskId = $task{taskId};
       
  1007         if ( $task{specialInstruction} ) {
       
  1008             my $taskTargetName = makefileTargetName( $task{specialInstruction} );
       
  1009             my $target = "$configurationTargetName-$taskTargetName-$taskId";
       
  1010             push( @{$targetDependencies{$configurationTargetName}}, $target );
       
  1011             # TODO set the correct file name for the following
       
  1012             $cmdString = "\$(MAKE) \$(addprefix -f ,\$(CURRENT_MAKEFILE)) $taskTargetName";
       
  1013             push( @{$targetCommands{$target}}, $cmdString );
       
  1014 
       
  1015         } else {
       
  1016             my $command = makefileTargetName( $task{command} );
       
  1017             my $target = makefileTargetName( $task{target} );
       
  1018             $taskTargetName = makefileTargetName( $task{command},$task{target} );
       
  1019 
       
  1020             # Set unitlist or configuration as a prefix to task rule
       
  1021             if ( @{$task{unitLists}} ) 
       
  1022             # Task specific unitlist defined
       
  1023             {
       
  1024                 $taskTargetName = "\$(addsuffix -".$taskTargetName.",".join(" ",@{$task{unitLists}}).")";
       
  1025             } else {
       
  1026                 # Prefix the targetname to current dependencies
       
  1027                 $taskTargetName = $configurationTargetName."-".$taskTargetName;
       
  1028             }
       
  1029             my $target = "$configurationTargetName-$taskTargetName-$taskId";
       
  1030             push( @{$targetDependencies{$configurationTargetName}}, $target );
       
  1031             # TODO set the correct file name for the following
       
  1032             $cmdString = "\$(MAKE) \$(addprefix -f ,\$(CURRENT_MAKEFILE)) $taskTargetName";
       
  1033             push( @{$targetCommands{$target}}, $cmdString );
       
  1034         }
       
  1035     }
       
  1036 
       
  1037     print(MAKEFILE "$configurationTargetName: CONFIGURATION:=$configurationTargetName\n");
       
  1038     print(MAKEFILE "$configurationTargetName: ".join(" \\\n  ".(" " x length($configurationTargetName)), @{$targetDependencies{$configurationTargetName}})."\n");
       
  1039 
       
  1040     print(MAKEFILE "\t\@\-perl -e \"print '=== \$(CONFIGURATION) finished '.localtime().\\\"\\n\\\"\"\n");
       
  1041     print(MAKEFILE "\t\$\(LOGBUILDTIME\)\n");
       
  1042     print(MAKEFILE "\t\@\-perl -e \"print time\" \> timestop.txt\n");
       
  1043     print(MAKEFILE "\n\n");
       
  1044 
       
  1045     print(MAKEFILE "# Dependencies between individual tasks\n");
       
  1046 
       
  1047     # Makefile target name for current task 
       
  1048     # buildLayer tasks: unitlist/configuration-command[-target]
       
  1049 
       
  1050     my $i=1;
       
  1051     while ( $i < scalar( @{$targetDependencies{$configurationTargetName}} ) ) {
       
  1052         my $target = $targetDependencies{$configurationTargetName}[$i];
       
  1053         print(MAKEFILE "$target: ".$targetDependencies{$configurationTargetName}[$i-1]."\n");
       
  1054         print(MAKEFILE "\t".join(" \n\t",@{$targetCommands{$target}})."\n");
       
  1055         print(MAKEFILE "\n");
       
  1056         $i++;
       
  1057     }
       
  1058 }   
       
  1059 
       
  1060 
       
  1061 
       
  1062 foreach my $configurationName ( @userConfigurations ) {
       
  1063     print(MAKEFILE getConfigurationTaskRules($configurationName) );
       
  1064 }
       
  1065 
       
  1066 sub getConfigurationTaskRules($) {
       
  1067     my ($configurationName) = @_;
       
  1068 	my $configurationTargetName = makefileTargetName( $configurationName );
       
  1069     my $output = "# configuration -> unitlists rules for $configurationName\n";
       
  1070 
       
  1071 	foreach my $task ( keys(%buildLayerTasks) ) {
       
  1072 		$output.="$configurationTargetName-$task : \$(addsuffix -$task,\$(filter-out \$($configurationTargetName-EXCLUDE),\$($configurationTargetName-UNITS)))\n";
       
  1073 		$output.="\n\n";
       
  1074 	}
       
  1075 	return($output);
       
  1076 }
       
  1077 
       
  1078 
       
  1079 
       
  1080 
       
  1081 print(MAKEFILE "# Printing out the tasks for layers unitlists and bld.inf\n");
       
  1082 print(MAKEFILE "tasks : \$(foreach TASK,");
       
  1083 foreach my $command (sort(keys(%buildLayerTasks))) {
       
  1084 	print(MAKEFILE " \\\n  ".quoteCommandForEcho($command));
       
  1085 }
       
  1086 print(MAKEFILE ",-\$(TASK)-print)\n\n");
       
  1087 
       
  1088 print(MAKEFILE "# Printing out special instructions\n");
       
  1089 print(MAKEFILE "specialInstructions:\n");
       
  1090 foreach my $specialInstruction (sort(keys(%specialInstructions))) {
       
  1091 	print(MAKEFILE "\t\@echo ".makefileTargetName($specialInstruction)."\n");
       
  1092 }
       
  1093 print(MAKEFILE "\n\n");
       
  1094 
       
  1095 
       
  1096 
       
  1097 print(MAKEFILE "# Printing out layers\n");
       
  1098 print(MAKEFILE "layers:\n");
       
  1099 foreach my $layer (sort(keys(%units))) {
       
  1100 	print(MAKEFILE "\t\@echo $layer\n");
       
  1101 }
       
  1102 print(MAKEFILE "\n\n");
       
  1103 
       
  1104 print(MAKEFILE "# Printing out filters\n");
       
  1105 print(MAKEFILE "filters:\n");
       
  1106 foreach my $filter (keys(%filters)) {
       
  1107     print(MAKEFILE "\t\@echo $filter\n");
       
  1108 }
       
  1109 print(MAKEFILE "\n\n");
       
  1110 
       
  1111 close(MAKEFILE);
       
  1112 
       
  1113 # Creates a valid makefile target string from name,command and target
       
  1114 sub makefileTargetName {
       
  1115 	my @arguments=@_;
       
  1116 
       
  1117 	if ( ! @arguments ) {
       
  1118 		return("");
       
  1119 	}
       
  1120 	my $result=shift(@arguments);
       
  1121 	$result =~ s{[\s\.\%\&\|\;\"\<\>]}{_}g;
       
  1122 	$result =~ s{\\}{/}g;
       
  1123 	$result =~ s{_+}{_}g;
       
  1124 
       
  1125 
       
  1126 	my $rest = makefileTargetName(@arguments);
       
  1127 	if ( $rest ) {
       
  1128 		$result.="-".$rest;
       
  1129 	}
       
  1130 
       
  1131 	$result =~ s{_-}{-}g;
       
  1132 	return $result;
       
  1133 }
       
  1134 
       
  1135 sub quoteCommandSeparators($) {
       
  1136     my ($string) = @_;
       
  1137     $string =~ s{([\&\|\;\"])}{_}g;
       
  1138     return($string);
       
  1139 }
       
  1140 
       
  1141 sub getExecutable($) {
       
  1142 	my ($command) = @_;
       
  1143 	$command =~ s{^\s*([^\s]+).*}{\1};
       
  1144 	return $command;
       
  1145 }
       
  1146 
       
  1147 # Add quoting for echoing commands which have command control characters in them
       
  1148 sub quoteCommandForEcho($) {
       
  1149 	my ($command) = @_;
       
  1150 	$command =~ s{([\%\|\&\<\>])}{\^\1}g;
       
  1151 	return $command;
       
  1152 }
       
  1153 
       
  1154 # Add quoting for commands to make them print out in makefile
       
  1155 sub quoteCommand($) {
       
  1156 	my ($command) = @_;
       
  1157 	$command =~ s{\$}{\$\$}g;
       
  1158 	return $command;
       
  1159 }
       
  1160 
       
  1161 # check_filter
       
  1162 #
       
  1163 # Inputs
       
  1164 # $item_filter - filter specification (comma-separated list of words)
       
  1165 # $configspec - configuration specification (reference to list of words)
       
  1166 #
       
  1167 # Outputs
       
  1168 # $failed - filter item which did not agree with the configuration (if any)
       
  1169 #           An empty string is returned if the configspec passed the filter
       
  1170 #
       
  1171 # Description
       
  1172 # This function checks the configspec list of words against the words in the
       
  1173 # filter. If a word is present in the filter, then it must also be present in
       
  1174 # the configspec. If "!word" is present in the filter, then "word" must not
       
  1175 # be present in the configspec.
       
  1176 sub check_filter($$) {
       
  1177     my ($item_filter, $configspec) = @_;
       
  1178     my $failed = "";
       
  1179 
       
  1180     foreach my $word (split /,/,$item_filter) {
       
  1181         if ($word =~ /^!/) {
       
  1182             # word must NOT be present in configuration filter list
       
  1183 
       
  1184             my $notword = substr($word, 1);
       
  1185             if ( grep(/^$notword$/, @$configspec) ) {
       
  1186                 $failed = $word;
       
  1187             }
       
  1188         } else {
       
  1189             # word must be present in configuration filter list
       
  1190             $failed = $word unless grep(/^$word$/, @$configspec);
       
  1191         }
       
  1192     }
       
  1193     return $failed;
       
  1194 }
       
  1195