diff -r 044383f39525 -r be27ed110b50 buildframework/helium/tools/compile/ec/sysdef2make.pl --- /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; +} +