Subversion Repositories DevTools

Rev

Rev 5709 | Blame | Compare with Previous | Last modification | View Log | RSS feed

########################################################################
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
#
# Module name   : ToolsetPrinter.pm
# Module type   : Perl Module
# Compiler(s)   : Perl
# Environment(s): jats
#
# Description   : Common toolset utils
#                 Toolset I/O stream for creating makefile rules and recipes
# Usage:
#
#       New         Create a new stream
#
#       Prt         Print a raw line
#
#       PrtLn       Print a raw line and a new line
#
#       PrtPart     Print a raw line that will be extended. Contains continuation charaters and a new line
#
#       Newline     Print a single new line
#
#       Tag         Tagged line print.
#
#       Cmd         Command line print, tagged with meta quoted and terminates.
#
#       SetTag      Set the "tag", default none.
#
#       SetTerm     Set the command line "terminator", default "\\n\n".
#
#       Label       Print generalised label
#
#       StartDef    Create a Definition
#       Def         Accumulate
#       EndDef      Print it out
#
#       ObjList     Generate a object list, using the specified recipe.
#
#       LibList     Generate a library list, using the specified recipe.
#
#       DepRules    Generate library dependency rules
#
###############################################################################

use strict;
use warnings;


package ToolsetPrinter;

sub New
{
    my ($tag, $cmdterm) = @_;

    $tag = "" if ( !defined($tag) );            # default tag
    $cmdterm = "\\n\n"                          # and terminator
        if ( !defined($cmdterm) );

    my ($self) = {
            TAG         => $tag,
            CMDTERM     => $cmdterm
        };
    return bless $self, __PACKAGE__;
}

sub Reset
{
    my ($self) = shift;
    delete $self->{DEPEND_target};
    delete $self->{DEPEND_list};
    delete $self->{DEPEND_dir};
    delete $self->{DEPEND_file};
}

sub Prt
{
    my ($self) = shift;
    ::MakePrint ("@_");
}

sub PrtLn
{
    my ($self) = shift;
    ::MakePrint ("@_\n");
}

sub PrtPart
{
    my ($self) = shift;
    ::MakePrint ("@_ \\\n");
}

sub Entry
{
    my ($self) = shift;
    ::MakeEntry( @_ );
}


sub Newline
{
    my ($self) = shift;
    ::MakePrint ("\n");
}


sub SetTag
{
    my ($self) = shift;
    my ($tag) = @_;

    $tag = "" if ( !defined($tag) );
    $self->{TAG} = $tag;
}


sub SetTerm
{
    my ($self) = shift;
    my ($cmdterm) = @_;

    $cmdterm = "\\n\n"                          # default terminator
        if ( !defined($cmdterm) );
    $self->{CMDTERM} = $cmdterm;
}


sub Cmd
{
    my ($self) = shift;
    ::MakeQuote ("$self->{TAG}\t+=@_$self->{CMDTERM}");
}


sub Tag
{
    my ($self) = shift;
    ::MakePrint ("$self->{TAG}\t+=@_\n");
}


sub Label
{
    my ($self) = shift;
    my ($desc, $target) = @_;

    $self->Prt( "#.. $desc ($target)\n\n" );
}


sub ObjList
{
    my ($self) = shift;
    my ($target, $objs, $genrecipe, @uargs) = @_;

    foreach (@$objs)
    {
        &$genrecipe( $self, $target, $_, @uargs );
    }
}

sub StartDef
{
    my ($self) = shift;
    my ($tag) = @_;

    $tag = "" if ( !defined($tag) );
    $self->{DEF} = $tag;
    $self->{DEFS} = [];
}

sub Def
{
    my ($self) = shift;
    push @{$self->{DEFS}}, "@_";
}

sub EndDef
{
    my ($self) = shift;
    ::MakeDefEntry ( $self->{DEF}, '=' , $self->{DEFS} );
    delete $self->{DEFS};
}


#private
sub CondParse
{
    my ($target, $cond) = @_;

    if ($cond =~ /^--ifdef=(.*)/) {             # .. ifdef XXX
        $cond = "ifdef $1";

    } elsif ($cond =~ /^--ifndef=(.*)/) {       # .. ifndef XXX
        $cond = "ifndef $1";

    } elsif ($cond =~ /^--ifdebug$/) {          # .. if DEBUG
        $cond = "ifeq \"\$(DEBUG)\" \"1\"";

    } elsif ($cond =~ /^--ifprod$/) {           # .. if PRODUCTION
        $cond = "ifeq \"\$(DEBUG)\" \"0\"";

    } elsif ($cond =~ /^--ifeq=(.*):(.*)$/) {   # .. ifeq XXXX:YYYY
        $cond = "ifeq \"\$($1)\" \"$2\"";

    } elsif ($cond =~ /^--ifneq=(.*):(.*)$/) {  # .. ifneq XXXX:YYYY
        $cond = "ifneq \"\$($1)\" \"$2\"";

    } else {                                    # .. unknown
        ::Error( "$target: unknown conditional construct '$cond'" );
        $cond = "";
    }
    return $cond;
}


#private
sub CondOpen
{
    my ($self) = shift;

    @{$self->{CONDSTACK}} = ();
}


#private
sub CondModify
{
    my ($self) = shift;
    my ($newstack) = @_;
    my ($oldstack) = \@{$self->{CONDSTACK}};
    my ($idx, $cond);

#   Diff the two stacks
#
    $idx = 0;
    while ( $idx <= $#$newstack &&
            $idx <= $#$oldstack &&
            $$newstack[$idx] eq $$oldstack[$idx] ) {
        $idx++;
    }

#   Pop diff
#
    while ($idx <= $#$oldstack) {
        $cond = pop @$oldstack;
        $self->Prt( "  " x ($#$oldstack+1) . "endif\n" );
    }

#   Push diff
#
    while ($idx <= $#$newstack) {
        $self->Prt( "  " x $idx . "$$newstack[$idx]\n" );
        $idx++;
    }

    @{$self->{CONDSTACK}} = @$newstack;
}


#private
sub CondClose
{
    my ($self) = shift;
    my (@newstack) = ();

    $self->CondModify( \@newstack );            # pop any stacked conditionals
}


sub LibList
{
    my ($self) = shift;
    my ($target, $libs, $genrecipe, @uargs) = @_;
    my (@cond, $t_cond) = ();

    $self->CondOpen();                          # open a conditional session

    foreach (@$libs)
    {
        if (/^--if/)                            # inlined conditionals
        {
            push @cond, $t_cond
                if (($t_cond = CondParse( $target, $_ )) ne "");
        }
        elsif (/^--/)                           # arguments
        {
            &$genrecipe( $self, $target, $_, @uargs );
        }
        else                                    # library
        {
            my (@args) = split( "\n\t\t", $_ ); # see makeif.pl
            my ($lib) = shift @args;

            #   Associated conditionals (if any)
            #
            foreach (@args) {
                push @cond, $t_cond
                    if (($t_cond = CondParse( $target, $_ )) ne "");
            }
            $self->CondModify( \@cond );        # modify
            @cond = ();

            #   Generate recipe
            #
            &$genrecipe( $self, $target, $lib, @uargs );
        }
    }
    $self->CondClose();                         # close session
}

#-------------------------------------------------------------------------------
# Function        : SetShldTarget
#
# Description     : Set up the Shared Library target information
#                   Main function is to calculate the name of the
#                   dependency file so that it can be used
#
#                   Must be called before SHLDDEPEND or DepRules
#
# Inputs          : $self
#                   $target         - Name of the target library
#                                     May or may not have $(GBE_TYPE)
#                   $dir            - Optional alternate directory
#                                     Default: LIBDIR
#
# Returns         : Full name of the dependency file
#

sub SetShldTarget
{
    my ($self, $target, $dir ) = @_;
    ::Warning("Internal: SetShldTarget already specified") if ( defined $self->{DEPEND_target} );

    #   Create a 'tag' to be used within the makefile
    #
    $self->{DEPEND_target} = $target;
    $self->{DEPEND_list} = $target . '_shdp';

    #
    #   Set up the name of the dependency file
    #
    $dir = 'LIBDIR' unless ( defined $dir );
    $self->{DEPEND_dir} = $dir;

    my $depfile = "\$($dir)/${target}";
    $depfile .= '$(GBE_TYPE)' unless ( $depfile =~ m~\$\(GBE_TYPE\)~ );
    $depfile .= '.dep';
    $self->{DEPEND_file} = $depfile;

    ::Verbose3("SetShldTarget",
                "DepDir:  $self->{DEPEND_dir}",
                "DepFile: $self->{DEPEND_file}",
                "DepList: $self->{DEPEND_list}" );

    return $depfile;
}

#-------------------------------------------------------------------------------
# Function        : SHLDDEPEND
#
# Description     : Create a set of rules and recipes to handle the creation
#                   of dependency files used in the creation of shared
#                   libraries
#
#
# Inputs          : $self
#                   $base       - SHBASE: Defines the shared library name (eg: lib)
#                   $name       - SHNAME: Defines the base library name (eg: lib.so.1.1)
#
sub SHLDDEPEND
{
    my ($self) = shift;
    my ($base, $name) = @_;

    #
    #   Sanity test: The name of the list must have been setup
    #
    my $depfile = $self->{DEPEND_file} || ::Error ("Internal error: SetShldTarget not called before SHLDDEPEND");

    $self->Newline();
    $self->Label( "Include Shared Library Dependency Rules", $self->{DEPEND_target} );

    $self->Prt(
"${depfile}:\tSHBASE=${base}
${depfile}:\tSHNAME=${name}
${depfile}:\tDPLIST=$self->{DEPEND_list}
${depfile}:\t\$(GBE_$self->{DEPEND_dir}) \$(SCM_MAKEFILE)
        \$(SHLDDEPEND)

ifneq \"\$(findstring \$(IFLAG),23)\" \"\"
-include\t${depfile}
endif

" );

    #   Mark file as generated by the toolset
    #
    ::ToolsetGenerate( $depfile );
}

#-------------------------------------------------------------------------------
# Function        : SetLdTarget
#
# Description     : Set up the Program target information
#                   Main function is to calculate the name of the
#                   dependency file so that it can be used
#
#                   Must be called before LDDEPEND or DepRules
#
# Inputs          : $self
#                   $target         - Name of the target program
#                   $dir            - Optional alternate directory
#                                     Default: BINDIR
#
# Returns         : Full name of the dependency file
#
sub SetLdTarget
{
    my ($self, $target, $dir ) = @_;
    ::Warning("Internal: SetLdTarget already specified") if ( defined $self->{DEPEND_target} );

    #   Create a 'tag' to be used within the makefile
    #
    $self->{DEPEND_target} = $target;
    $self->{DEPEND_list} = $target . '_dp';

    #
    #   Set up the name of the dependency file
    #
    $dir = 'BINDIR' unless ( defined $dir );
    $self->{DEPEND_dir} = $dir;
    
    my $depfile = "\$($dir)/${target}.dep";
    $self->{DEPEND_file} = $depfile;

    ::Verbose3("SetLdTarget",
                "DepDir:  $self->{DEPEND_dir}",
                "DepFile: $self->{DEPEND_file}",
                "DepList: $self->{DEPEND_list}" );
    
    return $depfile;
}

#-------------------------------------------------------------------------------
# Function        : LDDEPEND
#
# Description     : Create a set of rules and recipes to handle the creation
#                   of dependency files used in the creation of a program
#
#
# Inputs          : $self
#
sub LDDEPEND
{
    my ($self) = shift;

    #
    #   Sanity test: The name of the list must have been setup
    #
    my $depfile = $self->{DEPEND_file} || ::Error ("Internal error: SetLdTarget not called before LDDEPEND");
    
    $self->Newline();
    $self->Label( "Include Library Dependency Rules", $self->{DEPEND_target} );

    $self->Prt(
"${depfile}:\tDPLIST=$self->{DEPEND_list}
${depfile}:\t\$(GBE_$self->{DEPEND_dir}) \$(SCM_MAKEFILE)
        \$(LDDEPEND)

ifeq \"\$(IFLAG)\" \"3\"
-include\t${depfile}
endif

" );

    #   Mark file as generated by the toolset
    #
    ::ToolsetGenerate( $depfile );
}

#-------------------------------------------------------------------------------
# Function        : DepRules
#
# Description     : Create the list of dependency rules used
#                   within the dependency include file
#
# Inputs          : $libs       - Ref to a list of libraries
#                   $librecipe  - Ref to code to create the library recipe
#                   @uargs      - User arguments, passed to the librecipe function
#
# Returns         : Nothing
#
sub DepRules
{
    my ($self) = shift;
    my ( $libs, $librecipe, @uargs) = @_;

    #
    #   Sanity test: The name of the list must have been setup
    #
    my $target = $self->{DEPEND_target} || ::Error ("Internal error: SetShldTarget/SetLdTarget not called before DepRules");
    
    $self->SetTag( $self->{DEPEND_list});                   # command tag
    $self->SetTerm();
    unless ( $self->{DepRulesHeaderDone}{$target} )
    {
        $self->{DepRulesHeaderDone}{$target} = 1;

        $self->Label( "Linker Dependencies", $target );    # label
                                                           # library depends
        $self->Tag( "\\# DO NOT REMOVE - dependencies\\\\n" );
        $self->Tag( "\\#\\\\n" );
    }

    $self->LibList( $target, $libs, $librecipe, @uargs );
}

1;