######################################################################## # 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;