<?xml version="1.0" encoding="UTF-8"?>
<!--
============================================================================
Name        : compile.ant.xml
Part of     : Helium

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:

============================================================================
-->
<!--* @package compile -->
<project name="compile" xmlns:hlm="http://www.nokia.com/helium">
    <description>
        Targets related to compile stage. It includes cmaker,
        ec, ebs, sbs, sbs-ec build system.
    </description>
    
    <!--* @property sysdef.configurations.list
    Comma-separated list of System Definition configuration names to be built in the compile-main stage.
    @type string
    @editable required
    @scope public
    -->

    <!-- Property declaration -->
    <!-- Suffix used in genxml related output files. This value is added into file names to show that they are genxml related. Used in log files, genxml output files and component list for EE images. Normally does not need to be set.
    @type string
    @scope private
    -->
    <property name="genxml.output.file.suffix" value="genxml" />
    <!-- Path of sysdef dtd
    @type string
    -->
    <property name="compile.sysdef.dtd.stub" location="${helium.dir}/tools/common/dtd/sysdef_dtd_1_4_0.xml" />
    <!-- Name of the signal input to be able to override the compile-main target.
    @type string
    @scope private
    -->
    <property name="compile.signal.input" value="compileSignalInput" />
    <!-- Compilation summary file for diamonds.
    @type string
    @scope private
    -->
    <property name="diamonds.compile.summary" location="${compile.log.dir}/${build.id}_compile_diamonds.xml" />
    
    <!-- including common compilation macros -->
    <hlm:typedef file="${helium.dir}/tools/compile/compile.antlib.xml" uri="http://www.nokia.com/helium"/>
    <import file="cmaker.ant.xml" />
    <import file="ec/ec.ant.xml" />
    <import file="ebs/ebs.ant.xml" />
    <import file="sbs/sbs.ant.xml" />
    <import file="sis.ant.xml" />
    <import file="qt/qt.ant.xml" />
    <import file="coverity.ant.xml" />

    <!-- A few basic steps (directory creation) that are needed before starting compilation. -->
    <target name="prebuild">
        <!-- Needed for the emulator to work. -->
        <mkdir dir="${build.drive}/epoc32/winscw/d"/>
        <!-- Build from source workaround as Symbian release is not completely unzipped. -->
        <mkdir dir="${build.drive}/epoc32/release/winscw/udeb/z/resource/fonts"/>
        <mkdir dir="${build.drive}/epoc32/release/winscw/urel/z/resource/fonts"/>
        <mkdir dir="${build.drive}/epoc32/include/osextensions"/>
    </target>

    <!-- Does all the necessary steps before starting the component build -->
    <target name="precompile" depends="record-compile-start-time,create-canonical-sysdef-file,precompile-ec,run-coverity-configure"/>

    <!-- post operation for EC builds, submits the compile time and lists all the built components-->
    <target name="postcompile" depends="postcompile-ec,render-build-duplicates,post-coverity" unless="env.HLM_SUBCON">
        <runtarget target="submit-compile-time"/>
    </target>
    
    
    <!-- Pre-processes all System Definition input files.

    Any Ant properties used in the files will be replaced by their values.
    Also the Symbian System Definition files needs to have \src inserted
    in front of the paths of the units.
    -->
    <target name="preprocess-sysdef-files">
        <mkdir dir="${build.output.dir}/build/input"/>
        <delete verbose="true">
            <fileset dir="${build.output.dir}/build/input/" includes="**"/>
        </delete>

        <fail message="No sysdef files found">
            <condition>
                <resourcecount refid="system.definition.files" when="equal" count="0" />
            </condition>
        </fail>

        <for param="file">
            <resources refid="system.definition.files"/>
            <sequential>
                <copy todir="${build.output.dir}/build/input" verbose="true">
                    <fileset file="@{file}"/>
                    <filterchain>
                        <replaceregex pattern="bldFile=&quot;common" replace="bldFile=&quot;src\\\\common" flags="gi"/>
                        <replaceregex pattern="mrp=&quot;common" replace="mrp=&quot;src\\\\common" flags="gi"/>
                        <replaceregex pattern="bldFile=&quot;cedar" replace="bldFile=&quot;src\\\\cedar" flags="gi"/>
                        <replaceregex pattern="mrp=&quot;cedar" replace="mrp=&quot;src\\\\cedar" flags="gi"/>
                        <expandproperties/>
                    </filterchain>
                    <mapper>
                        <scriptmapper language="jython">
<![CDATA[
import os
(drive, _) = os.path.splitdrive(r'@{file}')
path = r'@{file}'.replace(drive + os.sep, "", 1)
self.addMappedName(path)
]]>
                        </scriptmapper>
                    </mapper>
                </copy>
            </sequential>
        </for>
    </target>


    <!-- Merges all preprocessed System Definition files into one combined file. -->
    <target name="create-canonical-sysdef-file" depends="preprocess-sysdef-files">
        <mkdir dir="${compile.log.dir}" />
        <if>
            <istrue value="${schema.new}" />
            <then>
                <echo message="system model file: ${system.model.file}" />
                <copy file="${system.model.file}" tofile="${build.drive}/sf/os/deviceplatformrelease/foundation_system/system_model/system_model.xml"/> 
                <hlm:joinSysdef epocroot="${build.drive}" srcfile="${build.drive}/sf/os/deviceplatformrelease/foundation_system/system_model/system_model.xml" 
                    destfile="${canonical.sysdef.file}.join.xml" />
                <!-- <hlm:mergeSysdef epocroot="${epocroot}" destfile="${canonical.sysdef.file}" srcfile="${canonical.sysdef.file}.join.xml" downstreamfile="${epocroot}/layer2.sysdef.xml" /> -->
                <hlm:downgradeSysdef epocroot="${build.drive}" srcfile="${canonical.sysdef.file}.join.xml" 
                    destfile="${canonical.sysdef.file}"/>
            </then>
            <else>
                <pathconvert pathsep=" " property="system.definition.files.list">
                    <fileset dir="${build.output.dir}/build/input/" includes="**"/>
                    <chainedmapper>
                        <globmapper from="*" to="-x '*'" casesensitive="no"/>
                    </chainedmapper>
                </pathconvert>
                <hlm:compileGenxmlMergeMacro input="-x ${compile.sysdef.dtd.stub} ${system.definition.files.list}"
                                            output="${canonical.sysdef.file}" logfile="${compile.log.dir}/${build.id}.sysdef_GenxmlMerge.log"/>
            </else>
        </if>
    </target>

    <!-- Supports a cleaning of binaries before starting compilation, based on a SysDef configuration.
    @deprecated Please consider using ido-prep-clean target.
    -->
    <target name="compile-clean" depends="create-canonical-sysdef-file"
      if="sysdef.clean.configuration">
        <antcall target="compile-configuration" inheritRefs="true">
            <param name="sysdef.configuration" value="${sysdef.clean.configuration}"/>
            <param name="compile.signal.input" value="compileCleanSignalInput"/>
            <param name="compile.discard.result" value="true"/>
        </antcall>
    </target>


    <!-- Creates a input file for EBS using Symbian genxml tool. -->
    <target name="genxml">
        <if>
            <or>
                <isset property="build.system.ebs"/>
                <isset property="build.system.ebs-ant"/>
            </or>
            <then>
                <hlm:compileGenxmlMacro input="-x ${canonical.sysdef.file}"
                                        configuration="${sysdef.configuration}"
                                        output="${genxml.output.file}"
                                        log="${compile.log.dir}/${build.id}.${sysdef.configuration}_${genxml.output.file.suffix}.log" />
            </then>
        </if>
    </target>


    <!-- Postprocess genxml generated file by prefixing all commands with echos.

    Reads in the genxml generated command file (ready to be fed to EBS) and
    replaces all the command strings in the Execute statements with strings
    prefixed with echos.  For example, this target changes the following
    Execute statement:
    <pre>
      '<Execute ID="123" CommandLine="bldmake bldfiles -k"/>

    to:

      '<Execute ID="123" CommandLine="echo bldmake bldfiles -k"/>
    </pre>
    Properties:

      ebs.dry-run         When set, echo will be added to commands.
      genxml.output.file  The XML file with commands to be executed (by EBS).

    -->
    <target name="postprocess-genxml" if="ebs.dry-run">
      <!-- The 'echo' prefix will be added to the command even though it might
    already exist there. This is due to a problem with a regular expression;
    for some reason negative lookbehind assertion did not work due to syntax
    not being correct (python expression with less-than character within a
    python string within XML data; sounds messy and it was). -->
        <hlm:python>
import fileinput
import re

COMMANDLINE_RE = r'CommandLine="(.*?)"'
ECHO_REPLACEMENT = r'CommandLine="echo \1"'

for line in fileinput.input(["${genxml.output.file}"], inplace=True):
    print re.sub(COMMANDLINE_RE, ECHO_REPLACEMENT, line).rstrip()
        </hlm:python>
    </target>


    <!-- Takes a specific timestamp at the start of the compilation stage.

    This is used at the end of compilation to log the compile time to the GTI
    database.
    -->
    <target name="record-compile-start-time">
        <preset.exec executable="perl" outputproperty="build.main.start.time">
            <arg value="-e"/>
            <arg value="print time"/>
        </preset.exec>
    </target>

  <!-- Runs the Symbian scanlog and HTMLscanlog tools, as well as a Helium tool, for
  scanning the compilation log. -->
    <target name="compile-scanlog">
        <if>
            <!-- Only run is SBS is in use and sbs.hlm.scanlog is defined -->
            <or>
                <isset property="build.system.sbs"/>
                <isset property="build.system.sbs-ec"/>
            </or>
            <then>
                <if>
                    <not>
                        <isfalse value="${compile.discard.result}"/>
                    </not>
                    <then>
                        <delete file="${compile.log.dir}/${build.id}.${sysdef.configuration}_compile.log.xml" failonerror="false"/>
                    </then>
                </if>
            </then>
            <else>
                <exec executable="perl" dir="${build.drive}/" output="${compile.log.dir}/${build.id}.${sysdef.configuration}_scan1.log" failonerror="${failonerror}">
                    <arg value="${epocroot}epoc32/tools/scanlog.pl"/>
                    <arg file="${compile.log.dir}/${build.id}.${sysdef.configuration}_compile.log"/>
                </exec>
                <exec executable="perl" dir="${build.drive}/" failonerror="${failonerror}">
                    <arg value="${epocroot}epoc32/tools/htmlscanlog.pl"/>
                    <arg value="-v"/>
                    <arg value="-v"/>
                    <arg value="-l"/>
                    <arg file="${compile.log.dir}/${build.id}.${sysdef.configuration}_compile.log"/>
                    <arg value="-o"/>
                    <arg file="${build.log.dir}/${build.id}.${sysdef.configuration}_scan2.html"/>
                </exec>
                <hlm:assertFileExists file="${build.log.dir}/${build.id}.${sysdef.configuration}_scan2.html"/>
                <if>
                    <!--
                      Only generate the log.xml if we want the results to be included in the final results
                      or get them used by the signaling mechanism.
                    -->
                    <isfalse value="${compile.discard.result}"/>
                    <then>
                        <hlm:metadatarecord database="${metadata.dbfile}">
                            <hlm:abldmetadatainput>
                                <fileset casesensitive="false" file="${compile.log.dir}/${build.id}.${sysdef.configuration}_compile.log" />
                                <metadatafilterset refid="filterset.compile" />
                            </hlm:abldmetadatainput>
                        </hlm:metadatarecord>
                        <hlm:compileLogSignalMacro compile.summary.file="${build.id}.${sysdef.configuration}_compile.log" 
                            error.limit="${build.errors.limit}" phase="compile"/>
                        <!-- Todo: metadata: insert assertions for metadata parsing here -->
                    </then>
                </if>
            </else>
        </if>
    </target>

  <!-- Compiles one System Definition configuration.

  Certain properties must be defined to call this. It is intended to be called using
  an antcall from within a loop.
  -->
    <target name="compile-configuration" depends="run-qmake,genxml,postprocess-genxml,compile-ebs,compile-genxml-ec,
                        compile-ec-helium,compile-ebs-ant,compile-sbs,compile-scanlog"/>

  <!-- Executes each of the System Definition configurations in turn. -->
    <target name="do-compile-main">
        <propertyregex property="sysdef.configurations.list" input="${sysdef.configurations.list}"
                       regexp="\s*(\S+?)\s*,\s*(\S+?)\s*" replace="\1,\2" global="true" casesensitive="false"
                       override="true" defaultValue="${sysdef.configurations.list}"/>

        <for list="${sysdef.configurations.list}" delimiter="," param="sysdef.config">
            <sequential>
                <antcall target="compile-configuration" inheritRefs="true">
                    <param name="sysdef.configuration" value="@{sysdef.config}"/>
                    <param name="genxml.output.file" location="${temp.build.dir}/${build.id}.@{sysdef.config}_${genxml.output.file.suffix}.xml" />
                </antcall>
            </sequential>
        </for>
    </target>
    <var name="build.errors.total" value="" unset="true"/>

    <!-- Starts the actual compilation  phase of a build -->
    <target name="compile-main" depends="precompile,do-compile-main,postcompile"/>

    <!-- Macro to preprocess build information -->
    <scriptdef name="diamondsSummaryMacro" language="jython" uri="http://www.nokia.com/helium">
        <attribute name="output"/>
    <![CDATA[
from xml.sax.handler import ContentHandler
from xml.sax import make_parser
from xml.sax.saxutils import quoteattr

class DiamondsSummary(ContentHandler):
    def __init__(self):
        ContentHandler.__init__(self)
        self.scanLog = False
        self.components = {}
        self.component = None
        self.level = 0
        self.total = {'error':0, 'critical':0, 'warning':0}

    def startElement(self, name, attrs):
        if name == 'log' and attrs.get('filename', None) != None and attrs.get('filename', '').endswith('_compile.log'):
            self.scanLog = True
        elif self.scanLog and name == "task":
            self.level += 1

        if self.scanLog and name == "task" and self.level == 2 and attrs.get('name', None) != None:
            self.component = attrs.get('name', None)
            if self.component not in self.components:
                self.components[self.component] = {'error':0, 'critical':0, 'warning':0}

        if self.scanLog and name == "message" and attrs.get('priority', None) != None:
            if attrs.get('priority') in self.total:
                self.total[attrs.get('priority')] += 1

        if self.scanLog and name == "message" and self.level > 1 and self.component != None and attrs.get('priority', None) != None:
            if attrs.get('priority') in self.components[self.component]:
                self.components[self.component][attrs.get('priority')] += 1

    def endElement(self, name):
        if name == 'log':
            self.scanLog = False
            self.level = 0
            self.component = None
        elif name == 'task':
            self.level = self.level - 1


parser = make_parser()
diamondsSummary = DiamondsSummary()
parser.setContentHandler(diamondsSummary)
parser.parse(open(str(project.getProperty('build.summary.file'))))

output = '<?xml version="1.0"?>\n<compile>\n'
output += '<components>\n'
for name in diamondsSummary.components:
    xname = quoteattr(name)
    output += '<component name=%s error="%d" critical="%d" warning="%d" />\n' % (xname, diamondsSummary.components[name]['error'], diamondsSummary.components[name]['critical'], diamondsSummary.components[name]['warning'])
    #print name + " ==> %d" % diamondsSummary.components[name]['error']
output += '</components>\n'
output += '<total error="%d" critical="%d" warning="%d" />\n' % (diamondsSummary.total['error'], diamondsSummary.total['critical'], diamondsSummary.total['warning'])
output += '</compile>\n'
self.log(str("Writing %s" % str(attributes.get('output'))))
f = open(str(attributes.get('output')), 'w+')
f.write(output)
    ]]></scriptdef>

    <!-- Creates a .csv log of the sizes of all the binaries created in the build. -->
    <target name="binary-sizes-log" if="binary.sizes.output">
        <hlm:startSpecificLogMacro name="${compile.log.dir}/${build.id}_binary_sizes.log" phase="compile"/>
        <!-- File containing data related to flash image size
        @type string
        @scope private
        -->
        <property name="binary.sizes.output.file" location="${build.log.dir}/${build.id}_flash_image_size_data.csv"/>
        <pathconvert pathsep=";" property="build.logs.list">
            <fileset dir="${compile.log.dir}" includes="*_build.log" excludes="*ant_build.log;*_zipup_build.log"/>
        </pathconvert>
        <pathconvert pathsep=";" property="binary.sizes.rom.logs.list">
            <fileset refid="binary.sizes.rom.logs"/>
        </pathconvert>
        <hlm:python>
import logging
import compilation
import sysdef.api
#logging.basicConfig(level=logging.DEBUG)
logging.basicConfig(level=logging.INFO)

logging.info('Reading the System Sefinition information')
sysDef = sysdef.api.SystemDefinition(r'${canonical.sysdef.file}')

bnsizelogger = compilation.BinarySizeLogger(sysDef)
# Read in the output binaries of each unit
bnsizelogger.read_output_binaries_per_unit(r'${build.logs.list}'.split(';'))

# Read in the binary sizes listed in the ROM output logs
bnsizelogger.read_binary_sizes_in_rom_output_logs(r'${binary.sizes.rom.logs.list}'.split(';'))

# Write out a .csv file containing
bnsizelogger.write2csvfile(r'${binary.sizes.output.file}', r'${sysdef.configurations.list}'.split(','))
        </hlm:python>
        <hlm:assertFileExists file="${binary.sizes.output.file}"/>
        <hlm:stopSpecificLogMacro name="${compile.log.dir}/${build.id}_binary_sizes.log" phase="compile"/>
    </target>


    <!-- Run codescanner to perform analysis on source code.
    Logs will be created under ${build.log.dir}/codescanner/
    Property ${codescanner.path} needs to be set to indicate what code to analyse.
    -->
    <target name="codescanner">
        <mkdir dir="${build.log.dir}"/>
        <mkdir dir="${build.log.dir}/codescanner"/>
        <hlm:codescanner dest="${build.log.dir}/codescanner" format="${codescanner.format}" configuration="${codescanner.config}" auto="${codescanner.log.unique}" >
            <path refid="codescanner.path"/>
        </hlm:codescanner>
        <move todir="${build.log.dir}/codescanner" includeemptydirs="false">
            <fileset dir="${build.log.dir}/codescanner" includes="*.*"/>
            <mapper type="glob" from="*" to="${build.id}_*"/>
        </move>
    </target>


    <!-- Updates the UAProf header.

    TODO: Is this still needed? -->
    <target name="update-uaprof-header">
        <property name="uaprof.cenrep.file" value="${build.drive}/epoc32/data/Z/private/10202be9/101F8731.txt"/>
        <copy file="${uaprof.cenrep.file}" tofile="${uaprof.cenrep.file}.original"/>
        <replace file="${uaprof.cenrep.file}" token="@version@" value="${build.version}" encoding="UTF-16LE" summary="true"/>
    </target>


  <!-- Runs a number of postbuild steps that must be run after compilation is complete,
  but before ROM images and zipping are started. -->
    <target name="postbuild" depends="update-uaprof-header,sisfiles" unless="env.HLM_SUBCON">
        <antcall target="security-checker"/>
        <antcall target="dump-swicertstore"/>
        <antcall target="check-stub-sis"/>
    </target>
</project>
