buildframework/helium/tools/compile/ec/sysdef2make.pl
changeset 1 be27ed110b50
child 179 d8ac696cc51f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/buildframework/helium/tools/compile/ec/sysdef2make.pl	Wed Oct 28 14:39:48 2009 +0000
@@ -0,0 +1,1195 @@
+# This file is part of Nokia EC Tools release
+#
+#============================================================================ 
+#Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+#All rights reserved.
+#This component and the accompanying materials are made available
+#under the terms of the License "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: 
+# 
+#==============================================================================
+
+my $version=35;
+
+# 35 2008-09-26 jaakpaak:ou1tools#2679 Changed copyright symbol. Two days to go and I'm off to Atomia. Have fun.
+# 34 2008-09-23 jaakpaak:ou1tools#2677 Added command line options to revert to "make" instead of anything else for selected commands
+# 33 2008-09-19 jaakpaak:ou1tools#2673 Added copyright notice
+# 32 2008-09-11 jaakpaak:ou1tools#2661 Changed abld what and abld check targets to always use "make" in MAKE variable
+# 31 2008-09-03 jaakpaak:ou1tools#2627 Added creation of *-other-files.txt and *-other.zip
+# 30 2008-08-05 jaakpaak:ou1tools#2610 Add quoting of direct to file operator >
+# 29 2008-07-17 jaakpaak:ou1tools#2611 Get rid of symbian tool chain patching for emake
+# 28 2008-07-07 jaakpaak:ou1tools#2607 sysdef2make.pl to generate correct makefile independent of the location where the script is located
+# 27 2008-07-01 jaakpaak:ou1tools#2604 -n configuration option to sysdef2make to make it generate only configuration specific makefile
+# 26 2008-05-23 jaakpaak:ou1tools#2566 Improve output warnings and errors to be symbian compatible
+# 25 2008-03-26 jaakpaak:ou1tools#2531 Fix the output for log processor to be more compatible with EBS, increased quoting for special characters
+# 24 2008-03-13 jaakpaak:ou1tools#2522 Fix for last special instruction missing
+# 23 2008-03-07 jaakpaak:ou1tools#2516 Fix for buildLayer instructions which are executed twice
+# 22 2008-03-03 jaakpaak:ou1tools#2511 Targets for creating zip files from your workarea
+# 21 2008-02-29 jaakpaak:ou1tools#2510 Do not overwrite configuration-task targets targets with layer-task targets, printing of filters
+# 20 2008-02-28 jaakpaak:ou1tools#2495 Fix for specialInstruction dependencies and build time loggin dependencies
+# 19 2007-12-20 jaakpaak:ou1tools#2440 Fix for unitlists containing white spaces
+# 18 2007-12-17 jaakpaak:ou1tools#2432 Restructured variables, quoted echoing of command line
+# 17 2007-11-29 jaakpaak:ou1tools#2427 Fix to layer names containing white spaces, prefix also to specialInstructions
+# 16 2007-11-15 jaakpaak:ou1tools#2420 Fixed issue with multiple filters and empty unit lists
+# 15 2007-11-15 jaakpaak:ou1tools#2408 Added configuration-UNITS variable and optionless generic component rules
+# 14 2007-11-12 jaakpaak:ou1tools#2407 Added warning to layers not having any units
+# 13 2007-11-09 jaakpaak:ou1tools#2405 Fix to layers
+# 12 2007-10-31 jaakpaak:ou1tools#2402 Added -s option for path prefix and priorities
+# 11 2007-10-18 jaakpaak:ou1tools#2356 Fixed problems with filters and buildtime logging
+# 10 2007-10-18 jaakpaak:ou1tools#2356 Fixed dependency problems on EC, made everyting unit based (previously bld.inf based)
+# 09 2007-09-07 jaakpaak:ou1tools#2351 Added build time logging
+# 08 2007-09-01 jaakpaak:ou1tools#2340 Added error ignoring for selected commands and -v option
+# 07 2007-08-23 jaakpaak:ou1tools#2320 Submaked execution
+# 06 2007-08-15 jaakpaak:ou1tools#2311 Removed printing of empty unit lists, timestamp as perl script, makefiled unitlist/layernames
+# 05 2007-08-08 jaakpaak:ou1tools#2291 Added -filter option for user defined filters
+# 04 2007-08-07 jaakpaak:ou1tools#2290 Added tags for scanlog to specialInstructions also
+# 03 2007-07-04 jaakpaak:ou1tools#2275 htmlscanlog compatibility fixes
+# 02 2007-07-03 jaakpaak:ou1tools#2274 fixed specialInstructions handling
+# 01 2007-06-29 jaakpaak:ou1tools#2273 abldOption also valid for bldmake commands
+
+my $scriptDir=$0;
+# Strip the file from the path
+$scriptDir =~ s{[^\\\/]*$}{};
+
+use lib "$ENV{EPOCROOT}epoc32/tools/build/lib";
+use XML::DOM;
+
+my @userFilters = ();
+my @forceMakeCommands = ("abld.*\-(w|what|c|check)[^a-zA-Z0-9]");
+my $file = "";
+my $pathPrefix = "";
+
+my @userConfigurations = ();
+my @configurations = ();
+my $makefileName = "makefile";
+my $makefileOption = "";
+my $i=0;
+
+while ( $i < scalar (@ARGV) ) {
+	if ( $ARGV[$i] eq "-filter" ) {
+		push( @userFilters, $ARGV[$i+1] );
+		$i += 2;
+	} elsif ( $ARGV[$i] eq "-forcemake" ) {
+		push( @forceMakeCommands, $ARGV[$i+1] );
+		$i += 2;
+	} elsif ( $ARGV[$i] eq "-s" ) {
+		$pathPrefix = $ARGV[$i+1];
+		$i += 2;
+	} elsif ( $ARGV[$i] eq "-n" ) {
+		push( @configurations, $ARGV[$i+1] );
+		$i += 2;
+	} else {
+		$file = $ARGV[$i];
+		$i++;
+	}
+}
+my $otherCommandLineOptions;
+
+my $i=1;
+while ( $i < scalar(@forceMakeCommands) ) {
+    $otherCommandLineOptions.="-forcemake \"".quoteCommandForEcho($forceMakeCommands[$i])."\" ";
+    $i++;
+}
+
+
+if ( @configurations ) {
+    push(@userConfigurations,@configurations);
+    $makefileName = join("_",@configurations).".make";
+} 
+open(MAKEFILE,"> $makefileName");
+
+
+my $parser = XML::DOM::Parser->new();
+
+my $doc = $parser->parsefile($file);
+
+
+# Commands which' errors will be ignored 
+my %ignoreErrorCommands = ( "mkdir" => 1,
+                            "md" => 1,
+                            "del" => 1,
+                            "rmdir" => 1,
+                            "echo" => 1,
+                            "rem" => 1,
+                            "xcopy" => 1,
+                            "dir" => 1 );
+                            
+# Hash containing unitID's and bldFiles.
+# Keys are unitID's
+my %bldFiles;
+
+# Hash containing the units of each layer and unitlist
+# Key is the name of list, value is a list of unitId.s
+# The bldFile has to be obtained from unitIDs
+my %units;
+
+# Hash containing the actual abldTarget's of the command line. 
+# The key is the name of the target in System Definition xml
+my %targets;
+
+# Hash containing arrays of the real abldTarget's 
+# Key is the name defined in targetList in system definition xml
+my %targetLists;
+
+# Hash containing the default unitlists of each configuration
+# Key is the name of the configuration
+my %unitLists;
+
+# Hash containing contents of each specialInstruction
+# Key is the makefile target name of each specialInstruction
+# Value is the command line including cd part
+my %specialInstructions;
+
+# The bldfiles which are excluded from each configuration
+my %excludedUnits;
+
+# Hash containing the makefile targets for each task
+# Key is the task as a makefile target and values is a hash of buildlayer task
+my %buildLayerTasks;
+
+
+# So you cannot execute _any_ buildLayer command for _any_ unitList or layer
+# The combination must exist also in system definition xml
+
+# $unitId -> filterhash
+my %unitFilters;
+
+# List of all filters set in units
+my %filters;
+
+# Priorities of each unit
+# unitId -> priority
+my %unitPriorities;
+
+# Configuration makefile rules
+my %configurationTasks = ();
+
+my %optionNames;
+my %options;
+
+# Set verbose option on manually
+push( @{$options{abldOption}},"VERBOSE");
+push( @{$options{bldmakeOption}},"VERBOSE");
+$optionNames{"VERBOSE"} = "-v";
+
+# Loop through all the layers
+foreach my $layer ( $doc->getElementsByTagName('layer') ) {
+    my $layerName = $layer->getAttribute('name');
+
+    # Loop through all the units in the layer
+    foreach my $unit ( $layer->getElementsByTagName('unit') ) {
+        my $unitID = $unit->getAttribute('unitID');
+        my $bldFile = $unit->getAttribute('bldFile');
+        my $priority = $unit->getAttribute('priority');
+
+        # Set the filter status
+        $unitFilters{$unitID} = $unit->getAttribute('filter');
+
+        # Set filters to global hash
+        foreach my $word ( split(/,/,$unitFilters{$unitID}) ) {
+            $word =~ s{^!}{};
+            $filters{$word} = 1;
+        }
+        
+        if ( $pathPrefix &&
+             $bldFile !~ m{^\Q$pathPrefix\E}i ) {
+            $bldFile = $pathPrefix.$bldFile;
+        }
+        # Set bldFile to the unitID
+        $bldFiles{$unitID} = $bldFile ;
+
+        # Set the default priority
+        if ( ! $priority ) {
+            $priority = 1000;
+        }
+        
+        $unitPriorities{$unitID} = $priority;
+        
+        # Set the bldfile to the unitlist
+        my $i = scalar(@{$units{$layerName}});
+        while ( $i > 0 ) {
+            my $prevUnit = $units{$layerName}[$i-1];
+                
+            if ( $unitPriorities{$prevUnit} <= $unitPriorities{$unitID}  ) {
+                last;
+            } else {
+                $i--;
+            }           
+        }
+        # Insert init to slot $i
+        splice( @{$units{$layerName}},$i,0,$unitID);
+    }
+}
+
+# Loop through all unitLists
+foreach my $unitList ( $doc->getElementsByTagName('unitList') ) {
+	my $unitListName = $unitList->getAttribute('name');
+
+	# Loop through all unitRefs inside the unitLiss
+	foreach my $unitRef ( $unitList->getElementsByTagName('unitRef') ) {
+		my $unitID = $unitRef->getAttribute('unit');
+
+		# Set the bldfile to the unitlist
+		if ( $bldFiles{$unitID} ) {
+			
+			my $i = scalar(@{$units{$unitListName}});
+			while ( $i > 0 ) {
+				my $prevUnit = $units{$unitListName}[$i-1];
+				
+				if ( $unitPriorities{$prevUnit} <= $unitPriorities{$unitID}  ) {
+					last;
+				} else {
+					$i--;
+				}			
+			}
+            # Insert init to slot $i
+			splice( @{$units{$unitListName}},$i,0,$unitID);
+		} else {
+			print(STDERR "ERROR: unitList by the name \"".$unitListName."\" has unitRef to \"".$unitID."\" which is not defined.\n");
+		}
+	}
+}
+
+# Get targets from the whole SystemDefinition.xml
+foreach my $target ( $doc->getElementsByTagName('target') ) {
+	my $targetName = $target->getAttribute('name');
+	my $abldTarget = $target->getAttribute('abldTarget');
+
+	$targets{$targetName} = $abldTarget;
+}
+
+
+# Get targetLists
+foreach my $targetList ( $doc->getElementsByTagName('targetList') ) {
+	my $name = $targetList->getAttribute('name');
+	my $targetString = $targetList->getAttribute('target');
+
+	foreach my $target ( split( /\s+/, $targetString ) ) {
+		push( @{$targetLists{$name}}, $targets{$target} )
+	}
+}
+
+# Get options
+foreach my $option ( $doc->getElementsByTagName('option') ) 
+# Loop through all option elements
+{
+	my $attributes = $option->getAttributes();
+	my $i = 0;
+
+	my %attributeHash;
+	
+	while ( $i < $attributes->getLength() ) 
+	# go through all attributes
+	{
+		my $item = $attributes->item($i);
+		# Get name and value for each item in option attributes
+		my $name = $item->getName();
+		my $value = $item->getValue();
+		
+		# Insert attribute value into hash by key as name
+		$attributeHash{$name} = $value;
+		$i++;
+	}
+
+	foreach my $key ( keys(%attributeHash) ) 
+	# Go through generated attribute hash
+	{
+		if ( $key =~ m{.*Option} && $attributeHash{'enable'} =~ m{y}i ) 
+		# Attribute key is somethingOption and it is enabled
+		{
+			# Set options hash
+			$optionNames{$attributeHash{"name"}} = $attributeHash{$key};
+			
+			push( @{$options{$key}}, $attributeHash{"name"} );
+
+			# abldOptions become bldmakeOptions
+			# bldMake only supports -keepgoing and -verbose options
+			if ( $key eq "abldOption" && 
+				 ( $attributeHash{$key} =~ /^\s*-k/i ||
+				   $attributeHash{$key} =~ /^\s*-v/i )) {
+				push( @{$options{bldmakeOption}}, $attributeHash{"name"} );
+			}
+		}
+	}
+}
+
+
+my @xmlConfigurations = ();
+# This loop digs out unitlists, layers and tasks from each configuration
+foreach my $xmlConfiguration ( $doc->getElementsByTagName('configuration') ) {
+    my $configurationName = $xmlConfiguration->getAttribute('name');
+
+    # Store all configurations to a list
+    push( @xmlConfigurations, $configurationName );
+
+    # Check we are not using configuration name which overlaps with unit list name
+    foreach my $layer ( keys(%units)) {
+        if ( lc($layer) eq lc($configurationName) ) {
+            print(STDERR "ERROR: Configuration \"$configurationName\" is defined also as unitList/layer \"$layer\". Names MUST BE UNIQUE!\n");
+            last;
+        }
+    }
+    my $taskId=1;
+
+    # Get the filters of the configuration
+    my @configurationFilters = split( /,/, $xmlConfiguration->getAttribute('filter') );
+
+    # Add user specified filters to current configuration
+    push( @configurationFilters, @userFilters );
+
+    # Get the first child of the configuration
+    my $xmlElement = $xmlConfiguration->getFirstChild();
+
+    # This variable keeps track when specialInstruction changes 
+    # by storing the name of the current specialInstruction
+    my %currentSpecialInstruction=();
+
+    do { 
+        my $tagName = $xmlElement->getNodeName();
+
+        # Both unitListRef and layerRef end up to same place; unitLists hash
+        # From makefile point of view they have no difference what so ever
+        if ( $tagName eq "unitListRef" || 
+            $tagName eq "layerRef" ) {
+            my $unitList;
+
+            if ( $tagName eq "unitListRef" ) {
+                $unitList = $xmlElement->getAttribute('unitList'); 
+            } else {
+                $unitList = $xmlElement->getAttribute('layerName');
+            }
+
+            if ( scalar(@{$units{$unitList}}) == 0 ) {
+                print(STDERR "WARNING: unit list \"$unitList\" included to configuration \"$configurationName\" has no units.\n");
+            } else {
+                # Go through bldfiles and check their filters
+                foreach my $unit ( @{$units{$unitList}} ) {
+                    my $i = 0;
+                    my $exclude = check_filter( $unitFilters{$unit}, \@configurationFilters);
+                    
+                       
+                    if ( $exclude )
+                    # If there was an exclusion filter, exclude
+                    # If bldfile had filters set but include filter was not among them, exclude
+                    {
+                        push( @{$excludedUnits{$configurationName}}, $unit );
+                    }
+                }
+            }
+            # Add the new unitlist to current configuration
+            push( @{$unitLists{$configurationName}}, $unitList );
+        }
+
+        if ( $tagName eq "task" ) {
+            # The unitlists applied for the current task
+            my @taskUnitLists=();
+
+            # First get possible task specific unitListRefs
+            foreach my $xmlUnitListRef ( $xmlElement->getElementsByTagName('unitListRef') ) {
+                push( @taskUnitLists, $xmlUnitListRef->getAttribute('unitList') );
+            }
+
+            my $xmlTask = $xmlElement->getFirstChild();
+            do {
+                my $taskType = $xmlTask->getNodeName();
+
+                # For specialInstructions we only need the name
+                # This is because the content in specialInstructions is determined later
+                if ( $taskType eq "specialInstructions" ) {
+                    my $name = $xmlTask->getAttribute('name');
+
+                    if ( $name ne $currentSpecialInstruction{specialInstruction} ) 
+                    # The specialInstruction has just changed
+                    {
+                        if ( $currentSpecialInstruction{specialInstruction} ) 
+                        # but it's not the first one
+                        {
+                            # Store the previous special instruction
+                            my %configurationTask = %currentSpecialInstruction;
+                            push( @{$configurationTasks{$configurationName}}, \%configurationTask );
+
+                            # And clear up for next one
+                            %currentSpecialInstruction = ();
+                        }
+                        $currentSpecialInstruction{specialInstruction} = $name;
+                        $currentSpecialInstruction{taskId} = $taskId++;
+                    } 
+                     
+                    my $cwd = $xmlTask->getAttribute('cwd');
+                    my $command = quoteCommand($xmlTask->getAttribute('command'));
+
+                    if ( $cwd ne "." ) {
+                        $command = "cd ".$cwd." && ".$command." ";
+                    }
+
+                    if ( $ignoreErrorCommands{getExecutable($command)} ) 
+                    # Command is listed as "ignore error" command
+                    {
+                        $command = "-".$command;
+                    } 
+                    push( @{$currentSpecialInstruction{commands}}, $command );
+                } 
+
+                if ( $taskType eq "buildLayer" ) {
+                    if ( $currentSpecialInstruction{specialInstruction} ) 
+                    # Last task was a specialInstruction
+                    {
+                        # Store the previous special instruction
+                        my %configurationTask = %currentSpecialInstruction;
+                        push( @{$configurationTasks{$configurationName}}, \%configurationTask );
+                    }
+                    # And clear up for next one
+                    %currentSpecialInstruction = ();
+
+                    # Set command and targets
+                    my $targetList = $xmlTask->getAttribute('targetList');
+                    my @targets = @{$targetLists{$targetList}};
+                    my $command = $xmlTask->getAttribute('command');
+                    my $executable = getExecutable($command);
+
+                    my $option;
+                    # abldOption specified, append makefile variable to command
+                    # you can screw up what check and export by defining wrong options
+
+                    # We are ignoring the fact that abld export doesnt work with all possible
+                    # options. 
+                    # It is more important to relay the -keepgoing to abld export
+                    # than try to protect the environment from user who uses abldOption wrong
+                    if ( @{$options{$executable.'Option'}} &&
+                         $command !~ m{abld.*\-(w|what|c|check)\s}i ) {
+                        $option =" \$(".$executable."Option)";
+                    }
+
+                    if ( ! @targets ) {
+                        my %configurationTask;
+                        $configurationTask{executable} = $executable;
+                        $configurationTask{command} = quoteCommand($command);
+                        $configurationTask{option} = $option;
+
+                        if ( @taskUnitLists ) {
+                            $configurationTask{unitLists} = \@taskUnitLists;
+                        } else {
+                            if ( ! @{$unitLists{$configurationName}} ) {
+                                print(STDERR "Warning: buildLayer task \"".$command."\" in configuration \"".$configurationName."\" does not contain any units.\n");
+                            }
+                        }
+                        $configurationTask{taskId} = $taskId++;
+
+                        push( @{$configurationTasks{$configurationName}},\%configurationTask );
+
+                    } else {
+                        foreach my $target ( @targets ) {
+                            my %configurationTask;
+
+                            # Append the target to the command
+                            $configurationTask{executable} = $executable;
+                            $configurationTask{command} = quoteCommand($command);
+                            $configurationTask{option} = $option;
+                            $configurationTask{target} = $target;
+
+                            if ( @taskUnitLists ) {
+                                $configurationTask{unitLists} = \@taskUnitLists;
+                            } elsif ( ! @{$unitLists{$configurationName}} ) {
+                                print(STDERR "Warning: buildLayer task \"".$command."\" in configuration \"".$configurationName."\" does not contain any units.\n");
+                            }
+                            $configurationTask{taskId} = $taskId++;
+
+                            push( @{$configurationTasks{$configurationName}},\%configurationTask );
+                        }
+                    }
+                }
+            } while ( $xmlTask = $xmlTask->getNextSibling() ) ;
+        }
+    } while ( $xmlElement = $xmlElement->getNextSibling() ) ;
+
+    if ( $currentSpecialInstruction{specialInstruction} ) 
+    # Last task was a specialInstruction
+    {
+        # Store the previous special instruction
+        my %configurationTask = %currentSpecialInstruction;
+        push( @{$configurationTasks{$configurationName}}, \%configurationTask );
+    }
+    # And clear up for next one
+    %currentSpecialInstruction = ();
+}
+
+
+# If no configuration specified on command line, use all configurations collected from xml
+if ( ! @configurations ) {
+    push(@configurations,@xmlConfigurations);
+}
+
+# Print help
+
+print(MAKEFILE "\# Set the script directory\n");
+print(MAKEFILE "\# The directory is trailed with a space to\n");
+print(MAKEFILE "\# prevent continuing line side effects of trailing backslash\n");
+print(MAKEFILE "\# We need strip to remove the trailing space.\n");
+print(MAKEFILE "SCRIPTDIR:=$scriptDir \n\n");
+print(MAKEFILE "SCRIPTDIR:=\$(strip \$(SCRIPTDIR))\n\n");
+print(MAKEFILE "# Export MAKE variable in order to abld.pl to see it\n");
+print(MAKEFILE "export MAKE\n\n");
+
+print(MAKEFILE "SYSTEMDEFINITIONXML:=".$file."\n\n");
+
+if ( @userFilters ) {
+    print(MAKEFILE "FILTERS:=".join(" ",@userFilters)."\n\n");
+}
+
+if ( @userConfigurations )
+# User configuration was set on command line
+{
+    print(MAKEFILE "CONFIGURATION=$userConfigurations[0]\n\n");
+    print(MAKEFILE "export CONFIGURATION\n\n");
+    # Set the configuration as default target
+    print(MAKEFILE "\$(CONFIGURATION):\n\n");
+}
+
+# Print out options
+print(MAKEFILE "# Option names\n");
+
+foreach my $optionName ( keys(%optionNames) ) {
+	print(MAKEFILE "$optionName := ".$optionNames{$optionName}." \n");
+}
+print(MAKEFILE "\n");
+
+print(MAKEFILE "# command options\n");
+foreach my $cmdOption ( keys(%options)) {
+	print(MAKEFILE $cmdOption." := ");
+	foreach my $optionName ( @{$options{$cmdOption}} ) {
+		print(MAKEFILE "\$\($optionName\) ");
+	}
+	print(MAKEFILE "\n");
+}
+print(MAKEFILE "\n");
+
+if ( $makefileName ne "makefile" ) {
+    print(MAKEFILE "CURRENT_MAKEFILE:=$makefileName\n");
+}
+
+if ( $otherCommandLineOptions ) {
+    print(MAKEFILE "SYSDEF2MAKEFLAGS:=$otherCommandLineOptions\n\n");
+}
+
+print(MAKEFILE ".PHONY : help\n");
+print(MAKEFILE "help:\n");
+print(MAKEFILE "\t\@cmd /c echo.\n");
+print(MAKEFILE "\t\@echo This is a makefile \$(CURRENT_MAKEFILE) created by sysdef2make.pl version $version with command line:\n");
+print(MAKEFILE "\t\@echo  perl \$(SCRIPTDIR)sysdef2make.pl \$(addprefix -filter ,\$(FILTERS)) \$(addprefix -n ,\$(CONFIGURATION)) \$(SYSDEF2MAKEFLAGS) \$(SYSTEMDEFINITIONXML)\n");
+print(MAKEFILE "\t\@cmd /c echo.\n");
+if ( scalar(@userFilters) ) {
+	print(MAKEFILE "\t\@echo User defined filters added to all configurations: ".join(" ",@userFilters)."\n\n");
+}
+print(MAKEFILE "\t\@cmd /c echo.\n");
+print(MAKEFILE "\t\@echo To start up (hopefully) helpful web page, type:\n");
+print(MAKEFILE "\t\@echo  make \$(addprefix -f ,\$(CURRENT_MAKEFILE)) nethelp\n");
+print(MAKEFILE "\t\@cmd /c echo.\n");
+print(MAKEFILE "\t\@echo To get a list of all the buildable configurations:\n");
+print(MAKEFILE "\t\@echo  make \$(addprefix -f ,\$(CURRENT_MAKEFILE)) configurations\n");
+print(MAKEFILE "\t\@cmd /c echo.\n");
+print(MAKEFILE "\t\@echo To get a list of all the executable special instructions:\n");
+print(MAKEFILE "\t\@echo  make \$(addprefix -f ,\$(CURRENT_MAKEFILE)) specialInstructions\n");
+print(MAKEFILE "\t\@cmd /c echo.\n");
+print(MAKEFILE "\t\@echo Any of the previous configurations or specialInstructions\n");
+print(MAKEFILE "\t\@echo can be executed as they are by adding the name after make.\n");
+print(MAKEFILE "\t\@cmd /c echo.\n");
+print(MAKEFILE "\t\@echo To get a list of tasks executable for any component\n");
+print(MAKEFILE "\t\@echo  make \$(addprefix -f ,\$(CURRENT_MAKEFILE)) tasks\n");
+print(MAKEFILE "\t\@cmd /c echo.\n");
+print(MAKEFILE "\t\@echo Components and tasks are combined with\n");
+print(MAKEFILE "\t\@echo  make \$(addprefix -f ,\$(CURRENT_MAKEFILE)) \[component\]-\[task\]\n");
+print(MAKEFILE "\t\@cmd /c echo.\n");
+print(MAKEFILE "\t\@echo For instance:\n");
+print(MAKEFILE "\t\@echo  make s60\\yourcomponent\\group-task\n");
+print(MAKEFILE "\t\@cmd /c echo.\n");
+print(MAKEFILE "\t\@cmd /c echo.\n");
+print(MAKEFILE "\t\@echo Any amount of configurations, special instructions and\n");
+print(MAKEFILE "\t\@echo component-task combinations can be combined on one command line.\n");
+print(MAKEFILE "\t\@cmd /c echo.\n");
+print(MAKEFILE "\t\@echo Instead of make you can use any gnu make compatible framework like emake.\n");
+print(MAKEFILE "\t\@cmd /c echo.\n");
+print(MAKEFILE "\t\@echo To get more information about the gnu make options google \"gnu make manual\"\n");
+print(MAKEFILE "\t\@echo or type \"make --help\"\n\n");
+
+print(MAKEFILE ".PHONY : nethelp\n\n");
+print(MAKEFILE "nethelp : \n");
+print(MAKEFILE "\tcmd /c \"start http://s60wiki/S60Wiki/Sysdef2make\"\n\n");
+
+print(MAKEFILE "# Printing out messsages\n");
+print(MAKEFILE ".PHONY : \%-print\n\n");
+print(MAKEFILE "\%-print : \n\t\@echo \$\*\n\n");
+
+print(MAKEFILE "\n");
+print(MAKEFILE "\%.html : \%.log\n");
+print(MAKEFILE "\t\@-del \$\@\n");
+print(MAKEFILE "\tperl -S htmlscanlog.pl -l \$\< -o \$\@ -v -v\n\n");
+
+print(MAKEFILE "define STARTTASK\n");
+print(MAKEFILE "\@echo === \$(CONFIGURATION) == \$\*\n");
+print(MAKEFILE "\t\@echo -- \$\(1\) \n");
+print(MAKEFILE "\t-\@perl -e \"print '++ Started at '.localtime().\\\"\\n\\\"\"\n");
+print(MAKEFILE "\t-\@perl -e \"use Time::HiRes; print '+++ HiRes Start '.Time::HiRes::time().\\\"\\n\\\";\"\n");
+print(MAKEFILE "endef\n\n");
+
+
+print(MAKEFILE "define ENDTASK\n");
+print(MAKEFILE "\t\-\@perl -e \"use Time::HiRes; print '+++ HiRes End '.Time::HiRes::time().\\\"\\n\\\";\"\n");
+print(MAKEFILE "\t-\@perl -e \"print '++ Finished at '.localtime().\\\"\\n\\\"\"\n");
+print(MAKEFILE "endef\n\n");
+
+print(MAKEFILE "# Rule for starting up a configuration\n");
+print(MAKEFILE ".PHONY : timestart.txt\n\n");
+print(MAKEFILE "timestart.txt \:\n");
+print(MAKEFILE "\t\@echo ===-------------------------------------------------\n");
+print(MAKEFILE "\t\@echo === \$\(CONFIGURATION)\n");
+print(MAKEFILE "\t\@echo ===-------------------------------------------------\n");
+print(MAKEFILE "\t\@\-perl -e \"print '=== \$(CONFIGURATION) started '.localtime().\\\"\\n\\\"\"\n");
+print(MAKEFILE "\t\@\-perl -e \"print time\" \> \$\@\n");
+print(MAKEFILE "\n\n");
+
+print(MAKEFILE "define LOGBUILDTIME\n");
+print(MAKEFILE "\-\(echo \$(CONFIGURATION)\$(CONFIGURATIONSUFFIX) \& type \$\< \) \| perl \$(SCRIPTDIR)send_data.pl\n");
+print(MAKEFILE "endef\n\n");
+
+print(MAKEFILE "# Do not delete generated \*-files.txt files afterwards\n");
+print(MAKEFILE ".PRECIOUS : \%-files.txt\n\n");
+
+print(MAKEFILE "# ... unless there was an error generating \*-files.txt file, the delete it\n");
+print(MAKEFILE ".DELETE_ON_ERROR : \%-files.txt\n\n");
+
+
+print(MAKEFILE "\%-otherfiles.txt : %-files.txt\n");
+print(MAKEFILE "\tperl \$(SCRIPTDIR)filter-out.pl \$\< \$(filter-out \$\<,\$(wildcard \$(\*)\*-files.txt)) > \$\@\n");
+
+print(MAKEFILE "\%-files.txt  : \n");
+print(MAKEFILE "\tperl \$(SCRIPTDIR)find.pl \$\(subst \_,\/,\$\*\) \> \$\@\n\n");
+
+print(MAKEFILE "\%others.zip : \%-otherfiles.txt\n");
+print(MAKEFILE "\ttype \$\< \| zip \-\@ \$\@\n\n");
+
+print(MAKEFILE "\%.zip : \%-files.txt\n");
+print(MAKEFILE "\ttype \$\< \| zip \-\@ \$\@\n\n");
+
+
+
+print(MAKEFILE "# Creating cmd file for configuration using ebs tools\n");
+print(MAKEFILE "\%\-ebs.xml : \$(SYSTEMDEFINITIONXML)\n");
+print(MAKEFILE "\tperl \$(EPOCROOT)epoc32/tools/build/genxml.pl -o \$\@ -s \"\\\" -n \$\* -x \$\<\n");
+print(MAKEFILE "\n");
+
+print(MAKEFILE "\%.cmd : \%-ebs.xml\n");
+print(MAKEFILE "\tperl \$(SCRIPTDIR)getEbsCommands.pl -d \$\< \> \$\@\n");
+print(MAKEFILE "\n");
+
+print(MAKEFILE "# Automatic dependencies\n");
+print(MAKEFILE "\%\/abld.bat : \%\/bld.inf\n");
+print(MAKEFILE "\t\$(call STARTTASK,bldmake bldfiles -v -k)\n");
+print(MAKEFILE "\t\@echo Error 42 abld command issued when bldmake was not done first\n");
+print(MAKEFILE "\t\@echo Error 42 This is a serious error in your build configuration and must be fixed.\n");
+print(MAKEFILE "\t\@echo Error 42 In this build the error has been fixed automatically.\n");
+print(MAKEFILE "\tcd \$* && bldmake bldfiles -v -k\n");
+print(MAKEFILE "\t\$(ENDTASK)\n\n");
+print(MAKEFILE "\n");
+
+print(MAKEFILE "# If we are working on EC \"patched\" system\n");
+print(MAKEFILE "ifeq (\$(strip \$(MAKE)),emake)\n");
+print(MAKEFILE " \# We assume this to be Electric Cloud build\n");
+print(MAKEFILE " CONFIGURATIONSUFFIX=-ECBS\n");
+print(MAKEFILE "endif\n\n");
+	
+
+print(MAKEFILE "# Configurations\n");
+print(MAKEFILE "CONFIGURATIONS:=");
+foreach my $configurationName (sort(keys(%configurationTasks))) {
+	print(MAKEFILE " \\\n ".makefileTargetName($configurationName));
+}
+print(MAKEFILE "\n\n");
+
+
+
+print(MAKEFILE "# Printing out the configurations\n");
+print(MAKEFILE "configurations : \$(addsuffix -print,\$(CONFIGURATIONS))\n\n");
+
+# Filter current makefile out of this rule in order to avoid trying to regenerate current makefile
+# in situations where for one reason or another system definition xml file is not present.
+print(MAKEFILE "\$(filter-out \$(CURRENT_MAKEFILE),\$(addsuffix .make,\$(CONFIGURATIONS))) : \%.make : \$(SYSTEMDEFINITIONXML) ");
+
+# If this is the root level makefile, add this makefile to dependencies also
+# to avoid configuration specific sub makefiles and main level makefile 
+# incompatibilities for instance with filters.
+if ( $makefileName eq "makefile" ) {
+    print(MAKEFILE "makefile");
+}
+print(MAKEFILE "\n");
+print(MAKEFILE "\tperl \$(SCRIPTDIR)sysdef2make.pl \$(addprefix -filter ,\$(FILTERS)) -n \$\* \$(SYSDEF2MAKEFLAGS) \$\<\n\n");
+
+print(MAKEFILE "\$(filter-out \$(CONFIGURATION),\$(CONFIGURATIONS)) : \% : \%.make\n");
+print(MAKEFILE "\t\$(MAKE) -f \$\< \$\@\n\n");
+
+
+
+# Build up buildlayertasks
+foreach my $configurationName ( @configurations ) {
+    my $configurationTargetName = makefileTargetName( $configurationName );
+    foreach my $looptask ( @{$configurationTasks{$configurationName}} ) {
+        my %task = %{$looptask};
+        my $taskId = $task{taskId};
+        if ( ! $task{specialInstruction} ) {
+            my $command = makefileTargetName( $task{command} );
+            my $target = makefileTargetName( $task{target} );
+            $taskTargetName = makefileTargetName( $task{command},$task{target} );
+
+            # Add task to list of tasks
+            $buildLayerTasks{$taskTargetName} = $looptask;
+        }
+    }
+}
+
+
+# Process buildLayer tasks and derive commands which do not have options incorporated with them
+foreach my $taskTarget ( sort(keys(%buildLayerTasks)) ) {
+    my %task = %{$buildLayerTasks{$taskTarget}};
+    
+    my %newTask;
+    $newTask{command} = $task{command};
+
+    # Strip any " -XXX" from command
+    $newTask{command} =~ s{\s-[^\s]*}{}g;
+    
+    $newTask{target} = $task{target};
+
+    # Strip leading "-XXX" from target
+    $newTask{target} =~ s{^-[^\s]*}{}g;
+
+    # Strip any " -XXX" from target
+    $newTask{target} =~ s{\s-[^\s]*}{}g;
+    
+    my $newTaskTargetName = makefileTargetName( $newTask{command}, $newTask{target} );
+    if ( ! exists($buildLayerTasks{$newTaskTargetName}) ) {
+        $newTask{option} = $task{option};
+        $newTask{executable} = $task{executable};
+        $buildLayerTasks{$newTaskTargetName} = \%newTask;
+    }
+}
+
+
+
+# Here we determine the content for each special instruction
+my $i = 0;
+my @specialInstructionList = @{ $doc->getElementsByTagName('specialInstructions') };
+my @currentArray = ();
+my $name;
+while ( $i < scalar(@specialInstructionList) ) 
+# There are more specialInstructions
+{
+	# Set name and specialInstruction to list
+	my $specialInstruction = $specialInstructionList[$i];
+	$name = $specialInstruction->getAttribute('name');
+	my $command = quoteCommand($specialInstruction->getAttribute('command'));
+	my $cwd = $specialInstruction->getAttribute('cwd');
+
+	if ( $ignoreErrorCommands{getExecutable($command)} ) 
+	# Command is listed as "ignore error" command
+	{
+		$command = "-cd ".$cwd." && ".$command." ";
+	} else {
+		$command = "cd ".$cwd." && ".$command." ";
+	}
+
+	push( @currentArray, $command );
+	
+	# Get next element and advance list
+	my $prevSpecialInstruction = $specialInstruction;
+	$specialInstruction = $specialInstruction->getNextSibling();
+
+	if ( ! $specialInstruction ) 
+	# No next sibling. Get first child of parents next sibling
+	{
+		my $nextParent = $prevSpecialInstruction->getParentNode();
+		do {
+			$nextParent = $nextParent->getNextSibling();
+	 	} while ( $nextParent && $nextParent->getNodeName() =~ m{^\#.*} );
+ 
+		if ( $nextParent ) {
+			$specialInstruction = $nextParent->getFirstChild();
+		}
+	}
+	$i++;
+
+	if ( ! $specialInstruction ||
+           $specialInstruction->getNodeName() ne "specialInstructions" ||
+           $specialInstruction->getAttribute('name') ne $name )
+	# Element is not part of same specialInstruction group
+	{
+		checkRegisterSpecialInstruction( $name, @currentArray );
+		# reset tasks
+		@currentArray = ();
+		$name = ();
+	}
+}
+
+if ( $name && @currentArray ) {
+	checkRegisterSpecialInstruction( $name, @currentArray );
+}
+
+
+sub checkRegisterSpecialInstruction($@) {
+	my ($name,@currentArray) = @_;
+
+	if ( $specialInstructions{$name} ) 
+	# Same specialInstruction name has been registered
+	{ 
+		if ( scalar(@{$specialInstructions{$name}}) != scalar(@currentArray) ) 
+		# Different amount of tasks
+		{
+			print(STDERR "ERROR: specialInstruction $name is defined in several places but with different contents.\n");
+
+			if ( scalar(@currentArray) > scalar(@{$specialInstructions{$name}}) ) 
+			# The latter instance has more instances
+			{
+				# Use that one 
+				@{$specialInstructions{$name}} = @currentArray;
+			}
+		} else 
+		# Same amount of tasks
+		{
+			my @registeredTasks = @{$specialInstructions{$name}};
+			my $j=0;
+			while ( $j < scalar(@currentArray) && 
+					$currentArray[$j] eq $registeredTasks[$j] ) {
+				$j++;
+			}
+			if ( $currentArray[$j] ne $registeredTasks[$j] ) {
+				print(STDERR "ERROR: specialInstruction $name is defined several places but with different contents.\n");
+			}
+		}
+	} else 
+	# Not registered before, this is first time
+	{
+		push( @{$specialInstructions{$name}}, @currentArray );
+	}
+}
+
+
+# Print out component specific rules resulting from buildLayer tasks
+print(MAKEFILE "# buildLayer component (group/bld.inf) specific rules\n");
+foreach my $makefileTarget ( keys(%buildLayerTasks) ) {
+    my %task = %{$buildLayerTasks{$makefileTarget}};
+    my $cmdLine = $task{command}." ".$task{option}." ".$task{target};
+
+    # buildLayer tasks end up to pattern rules where pattern is the component directory
+    my $match=0;
+    foreach my $regexp (@forceMakeCommands) {
+        if ( $cmdLine =~ m{$regexp}i ) {
+            $match=1;
+            last;
+        }
+    }
+    if ( $match ) {
+        # Its command matching "force make on this command" regexp
+       
+        # Make variable must contain standard gnu make, nothing else
+        print(MAKEFILE "\%-".$makefileTarget.": MAKE=make\n");
+    }
+    if ( $task{executable} =~ /^abld/i ) {
+        print(MAKEFILE "\%-".$makefileTarget.": %/abld.bat\n");
+    } else {
+        print(MAKEFILE "\%-".$makefileTarget.": %/bld.inf\n");
+    }
+    print(MAKEFILE "\t\$(call STARTTASK,".quoteCommandSeparators($task{command}).")\n");
+    print(MAKEFILE "\t");
+    if ( $ignoreErrorCommands{$task{executable}} ) {
+        print(MAKEFILE "-");
+    }
+    print(MAKEFILE "cd \$* && $cmdLine\n");
+    print(MAKEFILE "\t\$(ENDTASK)\n\n");
+}
+
+
+# Print out the contents of specialInstructions
+print(MAKEFILE "# specialInstructions\n");
+foreach my $specialInstruction ( keys(%specialInstructions) ) {
+    my $simpleTarget = makefileTargetName($specialInstruction);
+    my $commands = join(" \n\t",@{$specialInstructions{$specialInstruction}});
+    
+    # buildLayer tasks end up to pattern rules where pattern is the component directory
+    my $match=0;
+    foreach my $regexp (@forceMakeCommands) {
+        if ( $commands =~ m{$regexp}i ) {
+            $match=1;
+            last;
+        }
+    }
+    if ( $match ) {
+        # Its command matching "force make on this command" regexp
+       
+        # Make variable must contain standard gnu make, nothing else
+        print(MAKEFILE $simpleTarget.": MAKE=make\n");
+    }
+    print(MAKEFILE "$simpleTarget:\n");
+    print(MAKEFILE "\t\$(call STARTTASK,\$\@)\n");
+    print(MAKEFILE "\t$commands \n");
+    print(MAKEFILE "\t\$(ENDTASK)\n\n");
+}
+
+# Print out the unitlists 
+# Note that this will print unitlists several times if they are in several configurations
+print(MAKEFILE "# Component lists based on contents of layers and unitlists\n");
+foreach my $configuration ( @userConfigurations ) {
+    foreach my $unitList ( @{$unitLists{$configuration}} ) {
+        print(MAKEFILE "\n\n");
+        print(MAKEFILE makefileTargetName($unitList)." := ");
+        foreach my $unit ( @{$units{$unitList}} ) {
+            print(MAKEFILE " \\\n ".$bldFiles{$unit});
+        }
+
+    }
+}
+print(MAKEFILE "\n\n");
+
+print(MAKEFILE "# Rules for layers and unitLists\n");
+foreach my $configuration ( @userConfigurations) {
+    foreach my $unitList ( @{$unitLists{$configuration}} ) {
+        # Check there's no matching configuration name
+        my $unitListTarget = makefileTargetName($unitList);
+        my $matchingLayer=0;
+        foreach my $configurationName ( keys(%unitLists) ) {
+            if ( makefileTargetName(lc($configurationName)) eq lc($unitListTarget) ) {
+                $matchingLayer = 1;
+                last;
+            }
+        }
+    
+        # Print unitlist-task rule only if it there is no matching configuration-task rule existing anywhere
+        if ( ! $matchingLayer ) {
+            foreach my $task ( keys(%buildLayerTasks) ) {
+                print(MAKEFILE "\n\n".makefileTargetName($unitList)."-$task : \$(addsuffix -$task , \$(filter-out \$(\$(CONFIGURATION)-EXCLUDE),\$(".makefileTargetName($unitList).")))");
+            }
+        }
+    }
+}
+print(MAKEFILE "\n\n");
+
+foreach my $configurationName ( @userConfigurations ) {
+    my $configurationTargetName = makefileTargetName( $configurationName );
+
+    print(MAKEFILE "$configurationTargetName-UNITS := ");
+    foreach my $unitList ( @{$unitLists{$configurationName}} ) {
+        print(MAKEFILE "\$(".makefileTargetName($unitList).") ");
+    }
+    print(MAKEFILE "\n\n");
+
+    my @excludedUnits = @{$excludedUnits{$configurationName}};
+    
+    print(MAKEFILE "# Excluded components in $configurationName\n");
+    print(MAKEFILE "$configurationTargetName-EXCLUDE := ");
+    foreach my $unit ( @excludedUnits ) {
+        print(MAKEFILE " \\\n".$bldFiles{$unit});
+    }
+    print(MAKEFILE "\n\n");
+
+    my %targetDependencies;
+    my %targetCommands;
+
+    push( @{$targetDependencies{$configurationTargetName}}, "timestart.txt" );    
+    foreach my $looptask ( @{$configurationTasks{$configurationName}} ) {
+        # Build up configuration depencencies list
+        my %task = %{$looptask};
+        my $taskId = $task{taskId};
+        if ( $task{specialInstruction} ) {
+            my $taskTargetName = makefileTargetName( $task{specialInstruction} );
+            my $target = "$configurationTargetName-$taskTargetName-$taskId";
+            push( @{$targetDependencies{$configurationTargetName}}, $target );
+            # TODO set the correct file name for the following
+            $cmdString = "\$(MAKE) \$(addprefix -f ,\$(CURRENT_MAKEFILE)) $taskTargetName";
+            push( @{$targetCommands{$target}}, $cmdString );
+
+        } else {
+            my $command = makefileTargetName( $task{command} );
+            my $target = makefileTargetName( $task{target} );
+            $taskTargetName = makefileTargetName( $task{command},$task{target} );
+
+            # Set unitlist or configuration as a prefix to task rule
+            if ( @{$task{unitLists}} ) 
+            # Task specific unitlist defined
+            {
+                $taskTargetName = "\$(addsuffix -".$taskTargetName.",".join(" ",@{$task{unitLists}}).")";
+            } else {
+                # Prefix the targetname to current dependencies
+                $taskTargetName = $configurationTargetName."-".$taskTargetName;
+            }
+            my $target = "$configurationTargetName-$taskTargetName-$taskId";
+            push( @{$targetDependencies{$configurationTargetName}}, $target );
+            # TODO set the correct file name for the following
+            $cmdString = "\$(MAKE) \$(addprefix -f ,\$(CURRENT_MAKEFILE)) $taskTargetName";
+            push( @{$targetCommands{$target}}, $cmdString );
+        }
+    }
+
+    print(MAKEFILE "$configurationTargetName: CONFIGURATION:=$configurationTargetName\n");
+    print(MAKEFILE "$configurationTargetName: ".join(" \\\n  ".(" " x length($configurationTargetName)), @{$targetDependencies{$configurationTargetName}})."\n");
+
+    print(MAKEFILE "\t\@\-perl -e \"print '=== \$(CONFIGURATION) finished '.localtime().\\\"\\n\\\"\"\n");
+    print(MAKEFILE "\t\$\(LOGBUILDTIME\)\n");
+    print(MAKEFILE "\t\@\-perl -e \"print time\" \> timestop.txt\n");
+    print(MAKEFILE "\n\n");
+
+    print(MAKEFILE "# Dependencies between individual tasks\n");
+
+    # Makefile target name for current task 
+    # buildLayer tasks: unitlist/configuration-command[-target]
+
+    my $i=1;
+    while ( $i < scalar( @{$targetDependencies{$configurationTargetName}} ) ) {
+        my $target = $targetDependencies{$configurationTargetName}[$i];
+        print(MAKEFILE "$target: ".$targetDependencies{$configurationTargetName}[$i-1]."\n");
+        print(MAKEFILE "\t".join(" \n\t",@{$targetCommands{$target}})."\n");
+        print(MAKEFILE "\n");
+        $i++;
+    }
+}   
+
+
+
+foreach my $configurationName ( @userConfigurations ) {
+    print(MAKEFILE getConfigurationTaskRules($configurationName) );
+}
+
+sub getConfigurationTaskRules($) {
+    my ($configurationName) = @_;
+	my $configurationTargetName = makefileTargetName( $configurationName );
+    my $output = "# configuration -> unitlists rules for $configurationName\n";
+
+	foreach my $task ( keys(%buildLayerTasks) ) {
+		$output.="$configurationTargetName-$task : \$(addsuffix -$task,\$(filter-out \$($configurationTargetName-EXCLUDE),\$($configurationTargetName-UNITS)))\n";
+		$output.="\n\n";
+	}
+	return($output);
+}
+
+
+
+
+print(MAKEFILE "# Printing out the tasks for layers unitlists and bld.inf\n");
+print(MAKEFILE "tasks : \$(foreach TASK,");
+foreach my $command (sort(keys(%buildLayerTasks))) {
+	print(MAKEFILE " \\\n  ".quoteCommandForEcho($command));
+}
+print(MAKEFILE ",-\$(TASK)-print)\n\n");
+
+print(MAKEFILE "# Printing out special instructions\n");
+print(MAKEFILE "specialInstructions:\n");
+foreach my $specialInstruction (sort(keys(%specialInstructions))) {
+	print(MAKEFILE "\t\@echo ".makefileTargetName($specialInstruction)."\n");
+}
+print(MAKEFILE "\n\n");
+
+
+
+print(MAKEFILE "# Printing out layers\n");
+print(MAKEFILE "layers:\n");
+foreach my $layer (sort(keys(%units))) {
+	print(MAKEFILE "\t\@echo $layer\n");
+}
+print(MAKEFILE "\n\n");
+
+print(MAKEFILE "# Printing out filters\n");
+print(MAKEFILE "filters:\n");
+foreach my $filter (keys(%filters)) {
+    print(MAKEFILE "\t\@echo $filter\n");
+}
+print(MAKEFILE "\n\n");
+
+close(MAKEFILE);
+
+# Creates a valid makefile target string from name,command and target
+sub makefileTargetName {
+	my @arguments=@_;
+
+	if ( ! @arguments ) {
+		return("");
+	}
+	my $result=shift(@arguments);
+	$result =~ s{[\s\.\%\&\|\;\"\<\>]}{_}g;
+	$result =~ s{\\}{/}g;
+	$result =~ s{_+}{_}g;
+
+
+	my $rest = makefileTargetName(@arguments);
+	if ( $rest ) {
+		$result.="-".$rest;
+	}
+
+	$result =~ s{_-}{-}g;
+	return $result;
+}
+
+sub quoteCommandSeparators($) {
+    my ($string) = @_;
+    $string =~ s{([\&\|\;\"])}{_}g;
+    return($string);
+}
+
+sub getExecutable($) {
+	my ($command) = @_;
+	$command =~ s{^\s*([^\s]+).*}{\1};
+	return $command;
+}
+
+# Add quoting for echoing commands which have command control characters in them
+sub quoteCommandForEcho($) {
+	my ($command) = @_;
+	$command =~ s{([\%\|\&\<\>])}{\^\1}g;
+	return $command;
+}
+
+# Add quoting for commands to make them print out in makefile
+sub quoteCommand($) {
+	my ($command) = @_;
+	$command =~ s{\$}{\$\$}g;
+	return $command;
+}
+
+# check_filter
+#
+# Inputs
+# $item_filter - filter specification (comma-separated list of words)
+# $configspec - configuration specification (reference to list of words)
+#
+# Outputs
+# $failed - filter item which did not agree with the configuration (if any)
+#           An empty string is returned if the configspec passed the filter
+#
+# Description
+# This function checks the configspec list of words against the words in the
+# filter. If a word is present in the filter, then it must also be present in
+# the configspec. If "!word" is present in the filter, then "word" must not
+# be present in the configspec.
+sub check_filter($$) {
+    my ($item_filter, $configspec) = @_;
+    my $failed = "";
+
+    foreach my $word (split /,/,$item_filter) {
+        if ($word =~ /^!/) {
+            # word must NOT be present in configuration filter list
+
+            my $notword = substr($word, 1);
+            if ( grep(/^$notword$/, @$configspec) ) {
+                $failed = $word;
+            }
+        } else {
+            # word must be present in configuration filter list
+            $failed = $word unless grep(/^$word$/, @$configspec);
+        }
+    }
+    return $failed;
+}
+