Subversion Repositories DevTools

Rev

Rev 227 | Blame | Last modification | View Log | RSS feed

########################################################################
# Copyright (C) 2008 ERG Limited, All rights reserved
#
# Module name   : makeif.pl
# Module type   : JATS Internal
# Compiler(s)   : Perl
# Environment(s): JATS
#
# Description   : This modules builds the interface object
#
#                       *** DO NOT DETAB ***
#
#......................................................................#

use strict;
use warnings;

#
#   System Globals
#   Declared to avoid compile errors
#
our $ScmVersion;
our $ScmTargetHost;
our @TESTPROJECT_TO_ARUN;
our @TESTPROJECT_TO_URUN;
our $ToolsetPROJECT_type;

###############################################################################
#   MakeInterface ---
#       Interface framework
#
#   Push                Push a package into the interface stack.
#   Factory             Build a interface.
#   Load                Loads the specified interface
#...

package MakeIf;

use strict;
use warnings;

our (@IfStack)              = ();               # interface stack


sub Push
{
    ::Debug( "MakeIf::Push( @_ )" );
    push (@IfStack, @_);                        # push onto stack
}


sub Factory
{
    sub Unroll
    {
        my ($stack) = @_;                       # current
        my ($package, $base, $self);

        $package = shift(@$stack);              # base class
        ::Error( "Interface -- base-class $package cannot Spawn." )
            unless( $package->can( "Spawn" ));

        $self = $package->Spawn();

        while (scalar(@$stack))
        {                                       # child
            my ($has_constructor);

            $base = $package;
            $package = shift(@$stack);

            no strict 'refs';

            ::Warning( "Interface --- base package $base is empty." )
                unless (%{"$base\::"});

            $has_constructor = $package->can( "Constructor" );

            push @{"$package\::ISA"}, $base;    # inherit class(es)
            bless ($self, $package);            # consecrate

            $self->Constructor()                # 'local' constructor
                if ($has_constructor);
        }

        return ($self);
    }

    my (@stack) = @IfStack;                     # clone stack
    my ($self);

    ::Error( "Interface -- object stack empty." )
        if ( ! scalar (@stack) );
    $self = Unroll( \@stack) ||
        ::Error( "Interface --- cannot build interface object." );
    return $self;
}


sub Load
{
    my ($dpackage, $dir, $root, $project) = @_;
    my ($package, $template, $cfgfile, $pkgfile, $code);

    #
    #   The code will not work if dpackage has a "-" in it
    #   Replace nasty characters with nice ones
    #
    $project = '' unless ( $project );
    $dpackage =~ s~-~_~g;
    $package = $dpackage . "_" . $project . "_DPACKAGE";
    $pkgfile = $dir . "/DPACKAGE";
    $cfgfile = $dir . "/DPACKAGE.CFG";

    $template = (<< '__END_OF_DPACKAGE_TEMPLATE__');
########################################################################
#
#   DPACKAGE Template -- version (1.x)
#
#       Version         State interface version requirements.
#       Using           Using statement.
#       Needs           Pre-req
#       Interface       Push onto the interface stack.
#       Self            Our reference.
#       Package         Package name.
#       Name            Name of perl package.
#       Root            Root directory of our installation.
#       Debug           General purpose debug output.
#..
package __PACKAGE__;

use strict;
use warnings;

our $VERSION='1.00';                            # Template version
our $SelfReference;

DPACKAGE_Initialise();

sub DPACKAGE_Initialise {
    my $self = {
            PACKAGE     => "__DPACKAGE__",
            NAME        => "__PACKAGE__",
            ROOT        => "__ROOT__"
        };
    $SelfReference = bless $self, "__PACKAGE__";
}

sub Self                { return $SelfReference; }
sub Package             { $SelfReference->{PACKAGE}; }
sub Name                { $SelfReference->{NAME}; }
sub Root                { $SelfReference->{ROOT}; }
sub Interface           { MakeIf::Push( "__PACKAGE__" ); }
sub Debug               { ::Debug @_; }
sub Debug2              { ::Debug2 @_; }
sub Debug3              { ::Debug3 @_; }


sub Version
{
    my ($major, $minor) = @_;

    ::Error( "DPACKAGE $SelfReference->{PACKAGE} requires Version($major,$minor)" )
        if ($major != 1 || $minor != 0);
}


sub Using
{
    my ($using) = @_;
    $SelfReference->{USING} = $using;
}


sub Needs
{
    my ($name, $version) = @_;

    #   TODO - statement of DPACKAGE prereqs.
    #
    #   name                Package name
    #
    #   Version [optional]
    #       =xx.xx.xx       Absolute
    #       >=xx.xx.xx      Greater or equal.  Where xx respresents
    #                       either, * or missing.
    #...
}


sub IncDir
{
    #TODO
}


sub LibDir
{
    #TODO
}


sub Libraries
{
    my ($caller, $file, $line) = caller();

    ::Error( "$SelfReference->{PACKAGE} ($line) requires Using()" )
        if ( ! defined( $SelfReference->{USING} ) );

    MakeIf::Libaries( $SelfReference->{USING}, @_ );
}

###########################################################################
#   -END-
#
__END_OF_DPACKAGE_TEMPLATE__

    $template =~ s/__PACKAGE__/$package/g;      # preprocess template
    $template =~ s/__DPACKAGE__/$dpackage/g;
    $template =~ s/__ROOT__/$root/g;

    if ( -e $cfgfile )
    {
        open(CFGFILE, $cfgfile) ||
            ::Error( "cannot open '$cfgfile'" );
        $code .= "# line 1 ".$cfgfile."\n";     # name the image
        while (<CFGFILE>) {
            $code .= $_;                        # slurp text
        }
        close (CFGFILE);
    }

    open(PKGFILE, $pkgfile) ||
        ::Error( "cannot open '$pkgfile'" );
    $code .= "# line 1 ".$pkgfile."\n";         # name the image
    while (<PKGFILE>) {
        $code .= $_;                            # slurp text
    }
    close (PKGFILE);

    eval "# line 1 \"DPACKAGE_TEMPLATE\"\n".    # name the image
         "$template";                           # .. template code
    die $@ if ($@);

    eval "package $package;\n".
         "use strict;\n".
         "use warnings;\n".
         "$code";                               # .. user code
    die $@ if ($@);
}


###############################################################################
#   DPACKAGE Interface
#
#       PackageLoad     Load the DPACKAGES for soecified platform(s).
#
#       PackageDirs     Retrieve the search path for package configuration.
#
#       LibUsing        Processing Using(XXX) library recipes
#
#       LibProcess      Apply library ordering rules.
#
#       ExportDepend    Export a local package dependency list.
#..

our (@IfPkgLibaries)        = ();
our (%IfPkgOrdering)        =
        (
            'User'      => '0',                 # User (default)

            'App'       => '3',                 # Application common
            'App2'      => '3a',
            'App3'      => '3b',
            'App4'      => '3c',

            'If'        => '5',                 # Interface
            'If2'       => '5a',
            'If3'       => '5b',
            'If4'       => '5c',

            'Kern'      => '7',                 # Kernel (ie MOS, LMOS)
            'Kern2'     => '7a',
            'Kern3'     => '7b',
            'Kern4'     => '7c',

            'Sys'       => '9',                 # System (ie WIN32, Linux)
            'Sys2'      => '9a',
            'Sys3'      => '9b',
            'Sys4'      => '9c'
        );

#
#   Provide reverse lookup of the %IfPkgOrdering for error reporting purposes
#   It may be slow, but its not used (Often).
#
sub ClassNumToText
{
    my (@classes) = @_;
    my @result;

    foreach my $class ( @classes )
    {
        my $result = "Unknown Class($class)";
        foreach ( keys %IfPkgOrdering )
        {
            if ( $IfPkgOrdering{$_} eq $class )
            {
                $result = $_;
                last;
            }
        }
        push @result, $result;
    }
    return @result;
}


sub PackageLoad
{
    my ($platform) = @_;

    return if ( !defined(%::ScmBuildPkgRules) );# configuration available

    my $pPlatform = $::ScmBuildPkgRules{$platform};

    foreach my $package ( @{$pPlatform} )
    {
        if ( defined( $package->{'CFGDIR'} ) )
        {
            my ($dir) = $package->{'ROOT'}.$package->{'CFGDIR'};

            if ( -e "$dir/DPACKAGE" )
            {                                   # .. load interface
                ::Debug( "Loading $dir/DPACKAGE ($package->{'NAME'}) ..." );

                MakeIf::Load( $package->{'NAME'}, $dir, $package->{'ROOT'}, $package->{'DPROJ'} );
            }
        }
    }
}

#-------------------------------------------------------------------------------
# Function        : PackageDirs
#
# Description     : Extend an array of 'search' directories to include
#                   'gbe' extension directories located with external toolsets
#
#                   Scan the package information held in ScmBuildPkgRules
#                   and locate 'gbe' directories.
#
# Inputs          : $dirs       - Ref to an array to extend
#                   @platforms  - A list of platforms to scan
#
# Returns         : Nothing
#
sub PackageDirs
{
    my ($dirs, @platforms) = @_;

    if ( defined(%::ScmBuildPkgRules) )
    {
        for my $platform (@platforms)
        {
            my $pPlatform = $::ScmBuildPkgRules{$platform};

            foreach my $package ( @$pPlatform )
            {
                push @$dirs, $package->{'ROOT'}.$package->{'CFGDIR'}
                    if ( defined( $package->{'CFGDIR'} ) );
            }
        }
    }
}


sub Libaries
{
    my ($using, $platforms, @libs) = @_;
    my ($recipe) =
        {
            USING   => "$using",
            LIBS    => [ @libs ],
        };

    ::Debug2( "Makeif::Libraries($using, $platforms, @libs)" );

    return if ( ! ::ActivePlatform($platforms) );

    push @IfPkgLibaries, $recipe;
}


#private
sub LibUsing
{
    my ($caller, $args, $libs) = @_;
    my ($using, @args) = split( ',', $args );

    ::Debug2( "Makeif::LibUsing($caller->$args)" );

# Global arguments (if any)
#
#   ie. --Using(XXX)[,--NoWarn][,--ifdef USING_XXX]
#
    my ($x_nowarn, $x_conds) = (0, 0);

    foreach (@args) {
        if ( /^--NoWarn$/ ) {                   # .. disable warnings
            $x_nowarn = 1;

        } elsif ( /^--if(.*)$/ ) {              # .. conditional(s)
            $x_conds .= "," if ($x_conds);
            $x_conds .= $_;

        } else {
            ::Warning( "$caller->Using($using), unknown option '$_'" );
        }
    }

# Library list
#
    my ($found) = 0;

    foreach my $recipe (@IfPkgLibaries)
    {
        if ( $recipe->{USING} eq $using )
        {
            my ($arg, $deforder, $defallowdup, $defnowarn, @defconds);

        # Record matchs and then stop any loop conditions
            $found++;

            if ( $recipe->{COOKED} ) {
                ::Warning( "$caller->Using($using) causes loop, ignored" );
                next;
            }

        # Parse Using arguments
            $deforder = "User";                 # default "class"
            $defallowdup = 0;
            $defnowarn = 0;

            foreach (@{$recipe->{LIBS}})
            {
            # Locally processed switches (global/default settings)
            #
                if ( /^--DefOrder=(.*)$/ ) {
                    $deforder = $1;             # Sort using name
                    next;
                }
                if ( /^--DefAllowDup$/ ) {
                    $defallowdup = 1;
                    next;
                }
                if ( /^--DefNoWarn$/ ) {
                    $defnowarn = 1;
                    next;
                }

                if ( /^--DefCond\((.*)\)$/ ) {
                    my (@conds) = split( ',', $1 );

                    @defconds = ();
                    foreach (@conds) {
                        Error( "Invalid --DeCond argument '$_' " )
                            if ( ! /^--if/ );
                        push @defconds, $_;
                    }
                    next;
                }

            # Handle indirections
            #
                if ( /^--Using\((.*)\)(.*)$/ )
                {                               # recurse
                    my ($x_using);

                    $x_using  = "$1";
                    $x_using .= ",$x_conds"     if ( $x_conds );
                    $x_using .= "$2";

                    $recipe->{COOKED}++;
                    LibUsing( $using, $x_using, $libs );
                    $recipe->{COOKED}--;
                    next;
                }

            # Libraries and arguments
            #
                if ( /^-[lL].*/ )
                {                               # Library
                    my ($order, $allowdup, $nowarn, @conds) =
                        ($deforder, $defallowdup, $defnowarn, @defconds);
                    my (@args) = split( ',', $_ );

                    foreach (@args) {
                        if ( /^-([lL])(.*)/ ) {
                            $arg = $_;
                        } elsif ( /^--Order=(.*)/ ) {
                            $order = $1;
                        } elsif ( /^--AllowDup$/ ) {
                            $allowdup = 1;
                        } elsif ( /^--NoAllowDup$/ ) {
                            $allowdup = 0;
                        } elsif ( /^--NoWarn$/ ) {
                            $nowarn = 1;
                        } elsif ( /^--Warn$/ ) {
                            $nowarn = 0;
                        } elsif ( /^--if/ ) {
                            push @conds, $_;
                        } else {
                            $arg .= $_;         # unknown
                        }
                    }

                    $arg .= ",--Order=$order"       if ( $order );
                    $arg .= ",--NoWarn"             if ( $nowarn );
                    $arg .= ",--AllowDup"           if ( $allowdup );
                    $arg .= ",$x_conds"             if ( $x_conds );
                    $arg .= ",". join(',', @conds)  if ( @conds );
                }
                else
                {                               # other options etc
                    $arg = $_;
                }

                push @$libs, $arg;              # push cooked argument
            }
        }
    }

    ::Warning( "$caller->Using($using), module not found" )
        unless ( $found || $x_nowarn );
}


sub LibProcess
{
    my ($libs) = @_;
    my (@newlibs, @ordered_newlibs);
    my ($order, @cond, %librecipes, %libstatus);

    #
    #   Only process the library specification if arguments/attributes
    #   are encountered .. compat with older makefile's.
    #
    my ($attrs) = 0;

    #   use Data::Dumper;
    #   $Data::Dumper::Purity = 1;
    #   ::Debug "# Uncooked library list";
    #   ::Debug Dumper( $libs );

    $order = 1;                                 # physical order start @ 1
    @cond = ();

    foreach (@$libs)
    {
        my ($libname, $class, $fdup, $fnowarn, @params);

        $libname = "";                          # library name and class
        $class = "User";                        # deafult class
        $fdup = 0;                              # default, remove duplicates
        $fnowarn = 0;

        if ( /^--if(.*)/ )
        {                                       # Conditional (for next)
            ::Warning( "Stray --if '$1' within library specification -- ignored" )
                if ( @cond );
            @cond = ( $_ );
            $attrs++;
            next;
        }

        if ( /^-[lL].*/ )
        {                                       # Library
            my (@args) = split( ',', $_ );      # split specification

            foreach (@args) {
                if ( /^-([lL])(.*)/ ) {         # Library
                    if ( $::ScmTargetHost eq "Unix" ) {
                        $libname = "lib$2";     # .. prefix lib
                        $libname =~ s/^liblib/lib/;
                    } else {
                        $libname = $2;          # .. just stripped name
                    }
                    $libname .= "\$(GBE_TYPE)"  # .. append GBE_TYPE
                        if ( $1 eq "l" );

                    push @params, $libname;

                } else {                        # Attribute/options
                    if ( /^--Order=(.*)/ ) {    # .. sort using 'class'
                        if ( exists $IfPkgOrdering{$1} )
                        {
                            $class = $1;
                        }
                        else
                        {
                            ::Warning( "Lib '$libname' has unknown class '$1'" );
                        }


                    } elsif ( /^--AllowDup$/ ) {# .. allow duplicate images
                        $fdup = 1;

                    } elsif ( /^--NoWarn$/ ) {  # .. disable warnings
                        $fnowarn = 1;

                    } elsif ( /^--if(.*)/ ) {   # .. conditional(s)
                        push @cond, $_;

                    } else {                    # .. other "parameters"
                        push @params, $_;
                    }

                    $attrs++;
                }
            }

            #
            #   Convert text class name to an ordered number to assist in sorting
            #
            $class = $IfPkgOrdering{ $class };
        }
        else
        {                                       # Anything else
            push @params, $_;
        }

        my ($recipe) = {
                CLASS   => $class,              # logical class, prim key
                ORDER   => $order,              # physical order, 2nd key
                LIBNAME => $libname,            # library name (if any)
                FDUP    => $fdup,               # duplicate flag
                FNOWARN => $fnowarn,            # no-warning flag
                CONDS   => [ @cond ],           # optional conditional(s)
                PARAMS  => [ @params ],         # parameters
            };

        push @newlibs, $recipe;                 # push recipe
        push @{$librecipes{$libname}}, $recipe  # plus index using $name
            if ( $libname ne "" );

        @cond = ();
        $order++;
    }

    #   ::Debug3 "# Cooked library list";
    #   ::Debug3 Dumper( @newlibs );

#   Parse the library list and determine the status and correct
#   handling of any duplicate images.
#..
    foreach my $name (keys %librecipes)
    {
        if ( scalar( @{$librecipes{$name}} ) > 1 )
        {
            my ($class, $classerr, $dup, $nowarn);

            foreach my $recipe (@{$librecipes{$name}})
            {
                $classerr = 1                   # test for conflicts
                    if ( defined($class) && $class ne $recipe->{CLASS} );

                $class = $recipe->{CLASS};

                $dup = $recipe->{FDUP}          # accumulate
                    if ( !defined($dup) || $recipe->{FDUP} );

                $nowarn = $recipe->{FNOWARN}    # accumulate
                    if ( !defined($nowarn) || $recipe->{FNOWARN} );
            }

            my ($stat) = {};

            $stat->{SEEN} = 0;
            $stat->{DUP} = $dup;
            $stat->{NOWARN} = $nowarn;
            $stat->{CLASSERR} = 1 if (defined($classerr));
            $libstatus{$name} = $stat;
        }
    }

#   Sort the library list
#
    @ordered_newlibs =                          # sort by class/order
        sort {
            ($a->{CLASS} ne "" && $b->{CLASS} ne "" &&
                    $a->{CLASS} cmp $b->{CLASS}) ||
            $a->{ORDER} <=> $b->{ORDER}
        } @newlibs;

    #   ::Debug3 "# Sorted library list";
    #   ::Debug3 Dumper( @ordered_newlibs );

#   Now built the final list, removing duplicates (if required)
#
    @$libs = ();                                # zap libraries

    foreach my $newlib (@ordered_newlibs)
    {
        my ($name) = $newlib->{LIBNAME};

        if ($attrs && defined($libstatus{$name}))
        {                                       # two or more entries
            my ($stat) = $libstatus{$name};

            if ( $stat->{SEEN}++ == 0 )
            {                                   # first image
                if ( ! $stat->{NOWARN} )
                {                               # .. warnings ?
                    if ( defined($stat->{CLASSERR}) )
                    {                           # .. class conflict
                        my (@classes);

                        foreach my $recipe (@{$librecipes{$name}}) {
                            ::UniquePush( \@classes, $recipe->{CLASS} );
                        }
                        ::Warning( "Lib '$name' has multiple classes\n\t" .
                            ::CommifySeries( ClassNumToText(@classes) ) );
                    }

                    my ($count) = scalar( @{$librecipes{$name}} );

                    ::Warning( "Lib '$name' appeared $count times, ".
                               "duplicate" . ($count > 2 ? "s":""). " removed" )
                        if ($stat->{DUP} == 0);
                }
            }
            else
            {                                   # remove duplicate(s) ?
                next if ($stat->{DUP} == 0);
            }
        }

        my ($spec);

        $spec = join( ',', @{$newlib->{PARAMS}} );
        $spec .= "\n\t\t" . join( "\n\t\t", @{$newlib->{CONDS}} )
            if ( @{$newlib->{CONDS}} );

        push @$libs, $spec;
    }

    #   ::Debug "# Final library list";
    #   ::Debug Dumper( $libs );
}


sub ExportDepend
{
    #
    #   Create the dependancy data structure
    #   Its easier to dump a complete structure
    #
    my %ScmBuildPkgDepend;
    foreach my $platform ( keys %::ScmBuildPkgRules )
    {
        foreach my $package ( @{$::ScmBuildPkgRules{$platform}} )
        {
            my %entry;
            $entry{NAME}        = $package->{'NAME'};
            $entry{VERSION}     = $package->{'VERSION'};
            $entry{DNAME}       = $package->{'DNAME'};
            $entry{DVERSION}    = $package->{'DVERSION'};
            $entry{DPROJ}       = $package->{'DPROJ'};

            push @{$ScmBuildPkgDepend{$platform}}, \%entry;
        }
    }


    my $fh = ::ConfigurationFile::New( "DPACKAGE.CFG" );
    $fh->Header( "makelib (Version $::ScmVersion)",
                                "DPACKAGE configuration file" );
    $fh->DumpData(
        "# Dependancy list.\n#\n",
        "ScmBuildPkgDepend", \%ScmBuildPkgDepend );

    $fh->Close(1);
}


###############################################################################
#   BASE_Toolset ---
#       Default interface.
#
#..

package BASE_Toolset;

MakeIf::Push( "BASE_Toolset" );                 # root of object stack

sub Spawn
{
    my ($obclass) = shift;
    my ($class) = ref($obclass) || $obclass;
    my ($self) = {};

    ::Debug2( "\tBASE_Toolset->Spawn()" );
    bless($self, $class);
    return ($self);
}


sub Preprocess
{
    my ($self) = shift;

    ::Debug2( "BASE_Toolset->Preprocess()" );
    ::ToolsetPreprocess()                       # optional toolset interface
        if ( defined &::ToolsetPreprocess );
}


sub Postprocess
{
    my ($self) = shift;

    ::Debug2( "BASE_Toolset->Postprocess()" );
    ::ToolsetPostprocess()                      # optional toolset interface
        if ( defined &::ToolsetPostprocess );
}


sub CTAGS
{
    ::ToolsetCTAGS()                            # optional toolset interface
        if ( defined &::ToolsetCTAGS );
}


sub CCDepend
{
    my ($self) = shift;

    ::Debug2( "BASE_Toolset->CCDepend()" );
    ::Error ("BASE_Toolset does not support C file dependency generation" )
        unless ( defined &::ToolsetCCDepend );
    ::ToolsetCCDepend( @_ );                    # toolset
}


sub CXXDepend
{
    my ($self) = shift;

    ::Debug2( "BASE_Toolset->CXXDepend()" );
    ::Error ("BASE_Toolset does not support C++ dependency generation" )
        unless ( defined &::ToolsetCXXDepend );
    ::ToolsetCXXDepend( @_ );                   # toolset
}


sub CC
{
    my ($self) = shift;
    my ($source, $obj, $pArgs) = @_;

    ::Debug2( "BASE_Toolset->CC($source)" );
    ::Error ("BASE_Toolset does not support C compilation" )
        unless ( defined &::ToolsetCC );
    ::ToolsetCC( @_ );                          # toolset
}


sub CXX
{
    my ($self) = shift;
    my ($source, $obj, $pArgs) = @_;

    ::Debug2( "BASE_Toolset->CXX($source)" );
    ::Error ("BASE_Toolset does not support C++ compilation" )
        unless ( defined &::ToolsetCXX );
    ::ToolsetCXX( @_ );                         # toolset
}


sub AS
{
    my ($self) = shift;
    my ($source, $obj, $pArgs) = @_;

    ::Debug2( "BASE_Toolset->AS($source)" );
    ::Error ("BASE_Toolset does not support assembler files" )
        unless ( defined &::ToolsetAS );
    ::ToolsetAS( @_ );                          # toolset
}


sub EXT
{
    my ($self) = shift;

    ::Debug2( "BASE_Toolset->EXT()" );
    return ::ToolsetEXT( @_ )                   # optional toolset interface
        if ( defined &::ToolsetEXT );
    return 0;                                   # default not supppored
}


sub AR
{
    my ($self) = shift;
    my ($name, $pArgs, $pObjs) = @_;

    ::Debug2( "BASE_Toolset->AR($name)" );
    ::Error ("BASE_Toolset does not support library files" )
        unless ( defined &::ToolsetAR );

    ProcessArgs ( "", @_ );                     # Proccess arguments
    ::ToolsetAR( @_ );                          # toolset
}


sub ARLINT
{
    my ($self) = shift;
    my ($name, $pArgs, $pObjs) = @_;

    my ($lname) = "\$(LIBDIR)/$name\$(GBE_TYPE)";
    my ($ltarget) = "lib_$name\_lint";
    my (@LIBCSRC, @LIBCXXSRC) = ();
    my ($srcfile) = "";

    ::Debug2( "BASE_Toolset->ARLINT($name)" );
    ::Error ("BASE_Toolset does not support library files" )
        unless ( defined &::ToolsetAR );

    foreach (@$pObjs) {
        $_ =~ s/^\$\(OBJDIR\)\///g;             # remmove OBJDIR

        if ( ($srcfile = $::OBJSOURCE{ $_ }) )
        {
            my( $quoted_srcfile ) = quotemeta( $srcfile );

            if ( grep /^$quoted_srcfile$/, @::CSRCS ) {
                push( @LIBCSRC, $srcfile );

            } elsif ( grep /^$quoted_srcfile$/, @::CXXSRC ) {
                push( @LIBCXXSRC, $srcfile );

            }
        }
    }

    ::MakePrint(  "
#.. Lint library ($name)

.PHONY:         $ltarget
$ltarget:       LIBBASE = $name
$ltarget:       LIBNAME = $lname
" );

    ::MakeDefEntry ( "$ltarget:","LIBCSRC =", \@LIBCSRC );
    ::MakeDefEntry ( "$ltarget:","LIBCXXSRC =", \@LIBCXXSRC );

    if ( defined ( &::ToolsetARLINT ) ) {
        ::MakePrint( "$ltarget:" );
        ::ToolsetARLINT( $name, $pArgs, $pObjs, $ltarget, \@LIBCSRC, \@LIBCXXSRC );

    } else {
        ::MakePrint( "$ltarget: \
        \@echo [\$(LIBNAME)] linting not supported..\n" );
    }

    ::MakePrint( "\n" );
}


sub ARMerge
{
    my ($self) = shift;
    my ($name, $pArgs, $pLibs) = @_;

    ::Debug2( "BASE_Toolset->ARMERGE($name)" );
    ::Error ("BASE_Toolset does not support library file merging" )
        unless ( defined &::ToolsetARMerge );
    ::ToolsetARMerge( @_ );                     # toolset
}


sub SHLD
{
    my ($self) = shift;
    my ($name, $pArgs, $pObjs, $pLibs) = @_;
    my ($i);

    ::Debug2( "BASE_Toolset->SHLD($name)" );
    ::Error ("BASE_Toolset does not support shared libraries" )
        unless ( defined &::ToolsetSHLD );

    ProcessArgs ( 'Using', @_ );                # Proccess arguments

    MakeIf::LibProcess( $pLibs );               # cook libraries

    ::Debug3( " args: @$pArgs" );
    ::Debug3( " objs: @$pObjs" );
    ::Debug3( " libs: @$pLibs" );

    ::ToolsetSHLD( @_ );                        # toolset
}


sub SHLDLINT
{
    my ($self) = shift;
    my ($name, $pArgs, $pObjs, $pLibs) = @_;

    my ($lname) = "\$(LIBDIR)/$name\$(GBE_TYPE)";
    my ($ltarget) = "shlib_$name\_lint";
    my (@SHLIBCSRC, @SHLIBCXXSRC) = ();
    my ($srcfile) = "";

    ::Debug2( "BASE_Toolset->SHLDLINT($name)" );
    ::Error ("BASE_Toolset does not support shared libraries" )
        unless ( defined &::ToolsetSHLD );

    foreach (@$pObjs) {
        $_ =~ s/^\$\(OBJDIR\)\///g;             # remmove OBJDIR

        if ( ($srcfile = $::OBJSOURCE{ $_ }) )
        {
            my( $quoted_srcfile ) = quotemeta( $srcfile );

            if ( grep /^$quoted_srcfile$/, @::CSRCS ) {
                push( @SHLIBCSRC, $srcfile );

            } elsif ( grep /^$quoted_srcfile$/, @::CXXSRC ) {
                push( @SHLIBCXXSRC, $srcfile );

            }
        }
    }

    ::MakePrint(  "
#.. Lint shared library ($name)

.PHONY:         $ltarget
$ltarget:       SHLIBBASE = $name
$ltarget:       SHLIBNAME = $lname
" );

    ::MakeDefEntry ( "$ltarget:","SHLIBCSRC =", \@SHLIBCSRC );
    ::MakeDefEntry ( "$ltarget:","SHLIBCXXSRC =", \@SHLIBCXXSRC );

    if ( defined ( &::ToolsetSHLDLINT ) ) {
        ::MakePrint( "$ltarget:" );
        ::ToolsetSHLDLINT( $name, $pArgs, $pObjs, $pLibs, $ltarget, \@SHLIBCSRC, \@SHLIBCXXSRC );

    } else {
        ::MakePrint( "$ltarget: \
        \@echo [\$(SHLIBNAME)] linting not supported..\n" );
    }

    ::MakePrint( "\n" );
}


sub LD
{
    my ($self) = shift;
    my ($name, $pArgs, $pObjs, $pLibs) = @_;
    my ($i);

    ::Debug2( "BASE_Toolset->LD($name)" );
    ::Error ("BASE_Toolset does not support program generation" )
        unless ( defined &::ToolsetLD );

    ProcessArgs ( 'Using', @_ );                 # Proccess arguments

    MakeIf::LibProcess( $pLibs );               # cook libraries

    ::Debug3( " args: @$pArgs" );
    ::Debug3( " objs: @$pObjs" );
    ::Debug3( " libs: @$pLibs" );

    ::ToolsetLD( @_ );                          # toolset
}


sub LDLINT
{
    my ($self) = shift;
    my ($name, $pArgs, $pObjs, $pLibs) = @_;

    my ($pname) = "\$(BINDIR)/$name";
    my ($ptarget) = "prog_$name\_lint";
    my (@PROGCSRC, @PROGCXXSRC) = ();
    my ($srcfile) = "";

    ::Debug2( "BASE_Toolset->LDLINT($name)" );
    ::Error ("BASE_Toolset does not support program generation" )
        unless ( defined &::ToolsetLD );

    foreach (@$pObjs) {
        $_ =~ s/^\$\(OBJDIR\)\///g;             # remmove OBJDIR

        if ( ($srcfile = $::OBJSOURCE{ $_ }) )
        {
            my( $quoted_srcfile ) = quotemeta( $srcfile );

            if ( grep /^$quoted_srcfile$/, @::CSRCS ) {
                push( @PROGCSRC, $srcfile );

            } elsif ( grep /^$quoted_srcfile$/, @::CXXSRC ) {
                push( @PROGCXXSRC, $srcfile );

            }
        }
    }

    ::MakePrint(  "
#.. Lint program ($name)

.PHONY:         $ptarget
$ptarget:       PROGBASE = $name
$ptarget:       PROGNAME = $pname
" );

    ::MakeDefEntry ( "$ptarget:","PROGCSRC =", \@PROGCSRC );
    ::MakeDefEntry ( "$ptarget:","PROGCXXSRC =", \@PROGCXXSRC );

    if ( defined ( &::ToolsetLDLINT ) ) {
        ::MakePrint( "$ptarget:" );
        ::ToolsetLDLINT( $name, $pArgs, $pObjs, $pLibs, $ptarget, \@PROGCSRC, \@PROGCXXSRC );

    } else {
        ::MakePrint( "$ptarget: \
        \@echo [\$(PROGNAME)] linting not supported..\n" );
    }

    ::MakePrint( "\n" );
}

#-------------------------------------------------------------------------------
# Function        : PROJECT
#
# Description     : Invoke the underlying toolset functions to construct a
#                   project
#
# Inputs          : $pProject       - Reference to the project data
#
# Returns         :
#
sub PROJECT
{
    my( $self, $pProject) = @_;
    my $name = $pProject->{name};

    ::Debug2( "BASE_Toolset->PROJECT($name)" );
    ::Error ("BASE_Toolset does not support Project generation" )
        unless ( defined &::ToolsetPROJECT );

    #
    #   Sanity test the Toolset PROJECT
    #   Only the JAVA toolset will handle ANT projects
    #
    my $ptype = $pProject->{type} ;
    if ( $ptype )
    {
        my $type = $::ToolsetPROJECT_type || '';
        ::Error ("BASE_Toolset does not support Project generation of type: $ptype " )
            unless ( $type eq $ptype );
    }

    #
    #   Generate Phony target names
    #   The toolset MUST provide the targets
    #
    ::MakePrint( "PHONY:\tProjectClean_$name\n" );
    ::MakePrint( "PHONY:\tProject_$name\n" );
    ::MakePrint( "PHONY:\tProjectATest_$name\n" ) if ($pProject->{'autotest'});
    ::MakePrint( "PHONY:\tProjectUTest_$name\n" ) if ($pProject->{'unittest'});
    ::MakePrint( "\n" );

    #
    #   Projects may be specific to debug or production
    #
    my $conditional;
    $conditional = 'ifeq'  if ($pProject->{'Debug'});
    $conditional = 'ifneq' if ($pProject->{'Prod'});
    if ( $conditional )
    {
        ::MakePrint( "$conditional \"\$(DEBUG)\" \"1\"\n" );
    }

    #
    #   Invoke toolset specific function to create the desired targets
    #
    ::ToolsetPROJECT( $pProject->{name},
                      $pProject->{project},
                      $pProject->{options},
                      $pProject->{'autotest'},
                      $pProject->{'unittest'},
                      $pProject->{'generated'}
                       );

    #
    #   Complete any conditional process
    #
    if ( $conditional )
    {
        ::MakePrint( "else\n\n" );
        ::MakePrint( "ProjectClean_$name:\n" );
        ::MakePrint( "Project_$name:\n" );
        ::MakePrint( "ProjectATest_$name:\n" ) if ($pProject->{'autotest'});
        ::MakePrint( "ProjectUTest_$name:\n" ) if ($pProject->{'unittest'});
        ::MakePrint( "\nendif\n" );
    }

    #
    #   If this project does contain a unit test, then the name of the target
    #   that will run the unit test must be added to a list
    #
    push @::TESTPROJECT_TO_ARUN, "ProjectATest_$name" if ($pProject->{'autotest'});
    push @::TESTPROJECT_TO_URUN, "ProjectUTest_$name" if ($pProject->{'unittest'});
}


#-------------------------------------------------------------------------------
# Function        : TESTFRAMEWORK
#
# Description     : Invoke the underlying toolset functions to construct a
#                   Test Frame Work
#
#                   Done by manipulating entries in the HASH that is passed
#                   into the FrameWork Support functionn
#
# Inputs          : $pEntry       - Reference to the test data
#
# Returns         :
#
sub TESTFRAMEWORK
{
    my( $self, $pEntry, @args) = @_;
    my $name = $pEntry->{framework};
    my $fnc = 'ToolsetTESTFRAMEWORK_'. uc($name);
    my $fref = UNIVERSAL::can ( '::main', $fnc );
    ::Debug2( "BASE_Toolset->TestFrameWork($name)" );
    ::Error ("BASE_Toolset does not support Test Frame Work generation: $name" )
        unless ( $fref );

    &$fref( $pEntry, @args );          # Invoke the Function
}

#sub LDUsing
#{
#    my ($self) = shift;
#    my ($using, $name, $isshared, $pObjs, $pLibs) = @_;
#
#    ::Debug2( "BASE_Toolset->LDUsing($using, $isshared, $name)" );
#
#    MakeIf::LibUsing( $name, $using, $pLibs );
#}

#-------------------------------------------------------------------------------
# Function        : ProcessArgs
#
# Description     : Process arguments for the program and library building commands
#                   Processes options:
#                       --Using(XXX),[options]
#                       --Exclude(XXX,XXX,XXX)
#                       --ExcludeLIB(XXX,XXX,XXX)
#
# Inputs          : $mode       - Using == Allow 'Using'
#                   $name       - Name of the program/library
#                   $pArgs      - Ref to an array of arguments
#                   $pObjs      - Ref to an array of objects
#                   $pLibs      - Ref to an array of libraries (Optional)
#
#                   Note: Argument order to assist caller
#
# Returns         : Nothing directly
#                   Massages arrays directly
#
sub ProcessArgs
{
    my ($mode, $name, $pArgs, $pObjs, $pLibs) = @_;
    ::Debug2( "BASE_Toolset->ProcessArgs(@$pArgs)" );

    my @rArgs;

    my $i;
    for ($i = 0; $i < scalar @$pArgs; $i++)
    {
        $_ = $pArgs->[$i];

        if ( $mode && /^--Using\((.*)\)(.*)$/)  # --Using(XXX)[,options]
        {
            MakeIf::LibUsing( $name, "$1$2", $pLibs );

#::DebugDumpData("IfPkgLibaries",\@IfPkgLibaries );
#::DebugDumpData("pLibs",\$pLibs );
        }
        elsif (/^--Exclude\((.*)\)$/)           # --Exclude(Obj,Obj...)
        {
            #
            #   Exclude specified object files
            #   Note: Maintain the order of the object files
            #
            my %exclude;
            my @retain = ();

            @exclude{split( ',', $1 )} = ();

            foreach (@$pObjs)
            {
                (my $objfile = $_) =~ s~.*/~~;  # Remove Shared lib object directory

                push @retain, $_
                    unless (exists $exclude{$objfile} );
            }
            @$pObjs = @retain;
            ::Debug3( "BASE_Toolset->ProcessArgs. OBJS: @retain)" );
        }
        elsif (/^--ExcludeLib\((.*)\)$/)        # --ExcludeLib(Lib,Lib...)
        {
            #
            #   Exclude specified library files
            #   Note: Maintain the order of the library files
            #
            my %exclude;
            my @retain_libs = ();

            @exclude{split( ',', $1 )} = ();

            foreach (@$pLibs)
            {
                m~-[Ll]([^,]*)~;                # Extract library name
                my $libfile = $1;
                push @retain_libs, $_
                    unless (exists $exclude{$libfile} );
            }
            @$pLibs = @retain_libs;
            ::Debug3( "BASE_Toolset->ProcessArgs. LIBS: @retain_libs)" );
        }
        else
        {
            #
            #   Unknown option
            #   Retain to be processed later
            #
            push @rArgs, $_;
        }
    }

    #
    #   Pass unprocessed arguments back to the user
    #
    @$pArgs = @rArgs;
}

1;