Subversion Repositories DevTools

Rev

Blame | Last modification | View Log | RSS feed

########################################################################
# Copyright (C) 2008 ERG Limited, All rights reserved
#
# Module name   : PHARLAP.PL
# Module type   : JATS TOOLSET
# Compiler(s)   : Perl
# Environment(s): JATS
#
# Description   : PharLap (and VC6) for PHARLAP
#
#                 Based on the WIN32 toolset
#                 Pharlap uses the MS V6 compiler
#                 but provides its own linker
#
# Notes         : The Pharlap linker does not support PDB files
#
#                 Shared Library (DLL) support has not bee implemented
#                 Not currently needed
#
#                 Building via Visual Studio Project is to be discouraged.
#                 The linker intrerface requires:
#                   1) Great care
#                   2) Hacking of the Visual Studio install
#
#......................................................................#

use strict;
use warnings;

#
#   Global data
#
my $target_file_lib;                        # Last library built
my $target_file_dll;                        # Last dll built
my $target_file_exe;                        # Last program built

my $toolset_name = 'pharlap';               # Toolset name : Error reporting

##############################################################################
#   Version information
#
my $toolset_info;
my $toolset_version = 'PHARLAP.10.1';
my %ToolsetVersion =
    (
        'PHARLAP.10.1' => { 'def'        => 'PHARLAP.def' ,
                            'buildcmd'   => 'msdev =DSW= /make "ALL - =TYPE=" /useenv /out =LOG=' ,
                            'cleancmd'   => 'msdev =DSW= /make "ALL - =TYPE=" /clean /useenv' ,
                            'tmp'        => 'vc60',
                            'VSCOMPILER' => '1',
                          },
    );


##############################################################################
#   ToolsetInit()
#       Runtime initialisation
#
##############################################################################

ToolsetInit();

sub ToolsetInit
{

#.. Parse arguments (Toolset arguments)
#
    Debug( "$toolset_name(@::ScmToolsetArgs)" );

    foreach $_ ( @::ScmToolsetArgs ) {
        if (/^--Version=(.*)/) {           # MS SDK Version
            $toolset_version = $1;

        } else {
            Message( "$toolset_name toolset: unknown option $_ -- ignored\n" );
        }
    }

#.. Parse arguments (platform arguments)
#
    Debug( "$toolset_name(@::ScmPlatformArgs)" );

    foreach $_ ( @::ScmPlatformArgs ) {
        if (/^--product=(.*)/) {                # GBE product

        } elsif (/^--Version=(.*)/) {           # MS SDK Version
            $toolset_version = $1;

        } else {
            Message( "$toolset_name toolset: unknown platform argument $_ -- ignored\n" );
        }
    }

#.. Validate SDK version
#   Currently only one version is supported
#       1) PHARLAP.10.1     - As provided via Visual Studio and PharLap 10.1
#
    $toolset_info = $ToolsetVersion{$toolset_version};
    Error( "toolset_name: Unknown version: $toolset_version" ) unless ( defined $toolset_info );


#.. Standard.rul requirements
#
    $::s = 'asm';
    $::o = 'obj';
    $::a = 'lib';
    $::so = 'dll';
    $::exe = '.exe';

#.. Toolset configuration
#
    $::ScmToolsetVersion = "1.0.0";             # our version
    $::ScmToolsetGenerate = 0;                  # generate optional
    $::ScmToolsetProgDependancies = 0;          # handle Prog dependancies myself

#.. define Visual C/C+ environment
    Init( "visualc" );
    ToolsetDefines( $toolset_info->{'def'} );
    PlatformDefine ("VSCOMPILER\t= $toolset_info->{'VSCOMPILER'}" );
    ToolsetRequire( "exctags" );                # and Exuberant Ctags
    ToolsetRules( "pharlap.rul" );
    ToolsetRules( "standard.rul" );

#.. define PCLint envrionment
    ToolsetRequire( "pclint" );                 # using pclint
    PlatformDefine ("LINT_COFILE\t= co-msc60.lnt");
    PlatformDefine ("LINT_PRJ_FILE\t=lint.visualc");

#.. Cleanup rules
#
    ToolsetGenerate( "\$(OBJDIR)/$toolset_info->{'tmp'}.idb" );     # vc60.idb
    ToolsetGenerate( "\$(OBJDIR)/$toolset_info->{'tmp'}.pch" );
    ToolsetGenerate( "\$(OBJDIR)/$toolset_info->{'tmp'}.pdb" );



#.. Extend the CompilerOption directive
#   Create a standard data structure
#   This is a hash of hashes
#       The first hash is keyed by CompileOption keyword
#       The second hash contains pairs of values to set or remove
#
    %::ScmToolsetCompilerOptions =
    (
        #
        #   Control the thread model to use
        #   This will affect the compiler options and the linker options
        #
    );

    #
    #   Set default options
    #
}

##############################################################################
#   ToolsetPostprocess
#       Process collected data as the makefile is generated
#       This, optional, routine is called from within MakefileGenerate()
#       It allows the toolset to massage any of the collected data before
#       the makefile is finally closed created
#
##############################################################################

sub ToolsetPostprocess
{
    MakeHeader('Toolset Postprocessed Information');

    #
    #   Add values to the perl environment
    #   May be used by post processing tools to create Visual Studio Projects
    #
    $::TS_sbr_support = 1;

    #
    #   Prioritorise target: EXE, DLL, LIB
    #
    for my $tgt ( $target_file_exe, $target_file_dll, $target_file_lib  )
    {
        if ( $tgt )
        {
            $::TS_target_file = $tgt;
            last;
        }
    }
}


###############################################################################
#   ToolsetCTAGS()
#       This subroutine takes the user options and builds the rules
#       required to build the CTAGS database.
#
#   Arguments:
#       --xxx                   No arguments currently defined
#
#   Output:
#       [ctags:]
#           $(EXCTAGS)
#
###############################################################################

sub ToolsetCTAGS
{
    EXCTAGS( @_ );
}


###############################################################################
#   ToolsetCC( $source, $obj, \@args )
#       This subroutine takes the user options and builds the rule(s)
#       required to compile the source file 'source' to 'obj'
#
###############################################################################

sub ToolsetCC
{
    ToolsetCC_common( "CC", @_ );
}

sub ToolsetCC_common
{
    my( $name, $source, $obj, $pArgs ) = @_;
    my( $cflags );

    foreach $_ ( @$pArgs ) {
        if (/--Shared$/) {                      # Building a 'shared' object
            $cflags = "$cflags \$(SHCFLAGS)";

        } else {
            Message( "$toolset_name $name: unknown option $_ -- ignored\n" );
        }
    }

    MakePrint( "\n\t\$($name)\n" );
    MakePadded( 4, "\$(OBJDIR)/$obj.$::o:", "\tCFLAGS +=$cflags\n" )
        if ( $cflags );                         # object specific CFLAGS

    #
    #   Remove possible Source Browser Files and source file
    #
    ToolsetGenerate( "\$(OBJDIR)/$obj.sbr" );
    ToolsetGenerate( "\$(OBJDIR)/$obj.src" );
    MakePrint( "\n" );
}


###############################################################################
#   ToolsetCCDepend( $depend, \@sources )
#       This subroutine takes the user options and builds the
#       rule(s) required to build the dependencies for the source
#       files 'sources' to 'depend'.
#
###############################################################################

sub ToolsetCCDepend
{
    MakePrint( "\t\$(CCDEPEND)\n" );
}


###############################################################################
#   ToolsetCXX( $source, $obj, \@args )
#       This subroutine takes the user options and builds the rule(s)
#       required to compile the source file 'source' to 'obj'
#
###############################################################################

sub ToolsetCXX
{
    ToolsetCC_common( "CXX", @_ );
}

###############################################################################
#   ToolsetCXXDepend( $depend, \@sources )
#       This subroutine takes the user options and builds the
#       rule(s) required to build the dependencies for the source
#       files 'sources' to 'depend'.
#
###############################################################################

sub ToolsetCXXDepend
{
    MakePrint( "\t\$(CCDEPEND)\n" );
}


###############################################################################
#   ToolsetAS( $source, $obj, \@args )
#       This subroutine takes the user options and builds the rule(s)
#       required to compile the source file 'source' to 'obj'
#
###############################################################################

sub ToolsetAS
{
    MakePrint( "\n\t\$(AS)\n" );
}

sub ToolsetASDepend
{
}

###############################################################################
#   ToolsetAR( $name, \@args, \@objs )
#       This subroutine takes the user options and builds the rules
#       required to build the library 'name'.
#
#   Arguments:
#       --Def=name              Library definition module
#
#   Output:
#       [ $(LIBDIR)/name$.${a}:   .... ]
#           $(AR)
#
###############################################################################

sub ToolsetAR
{
    my( $name, $pArgs, $pObjs ) = @_;
    my( $def );
    my ( $res, @reslist );
    my $lib_base = "\$(LIBDIR)/${name}\$(GBE_TYPE)";
    my $lib_name = "$lib_base.${a}";


#.. Parse arguments
#
    $def = "";                                  # options
    $res = "";

    foreach $_ ( @$pArgs ) {
        if (/^--Def=(.*)/) {                    # library definition
            $def = "$1";

        } elsif (/^--Resource=(.*)/) {          # Resource definition
            ($res, @reslist) = ToolsetRClist( "$name", $1 );

        } else {                                # unknown
            Message( "$toolset_name AR: unknown option $_ -- ignored\n" );
        }
    }

#.. Resource Creation
#
    MakePrint( "#.. Library Resource ($name)\n\n" );
    ToolsetRCrecipe( $res, @reslist )
        if ( $res );

#.. Target
#
    MakePrint( "#.. Library ($name)\n\n" );     # label

    MakePrint( "$lib_name:\tLIBDEF=$def\n" ) if ($def);
    MakeEntry( "$lib_name:\t", "", "\\\n\t\t", ".$::o", @$pObjs );
    MakePrint( "\\\n\t\t$def" ) if ($def);
    MakePrint( "\\\n\t\t$res" ) if ($res);
    MakePrint( "\n\t\$(AR)" );

#
#   Track the name of the possible target file
#   Used when creating Visual Studio projects
#
    $target_file_lib = $lib_name;

}


###############################################################################
#   ToolsetARLINT( $name, \@args, \@objs )
#       This subroutine takes the user options and builds the rules
#       required to build the library 'name'.
#
#   Arguments:
#       --xxx                   No arguments currently defined
#
#   Output:
#       [ $(LIBDIR)/name$_lint:   .... ]
#           $(ARLINT)
#
###############################################################################

sub ToolsetARLINT
{
    PCLintAR( @_ );
}


###############################################################################
#   ToolsetARMerge( $name, \@args, \@libs )
#       This subroutine takes the user options and builds the rules
#       required to build the library 'name' by merging the specified
#       libaries
#
#   Arguments:
#       --xxx                   No arguments currently defined
#
#   Output:
#       [ $(LIBDIR)/name$.${a}:   .... ]
#           ...
#
###############################################################################

sub ToolsetARMerge
{
    my ($name, $pArgs, $pLibs) = @_;
    MakePrint( "\n\t\$(ARMERGE)\n\n" );
}

###############################################################################
# Function        : ToolsetLD
#
# Description     : Takes the user options and builds the rules required to
#                   link the program 'name'.
#
# Inputs          : $name           - base name of the program
#                   $pArgs          - Ref to program arguments
#                   $pObjs          - Ref to program objects
#                   $pLibs          - Ref to program library list
#
# Returns         : Nothing
#
# Output:         : Rules and recipes to create a program
#                       Create program rules and recipes
#                       Create linker input script
#                       Create library dependency list
#                       Include library dependency information
#
sub ToolsetLD
{
    my ( $name, $pArgs, $pObjs, $pLibs ) = @_;
    my ( $res, @reslist );
    my @cmd_files;

#.. Parse arguments
#
    foreach ( @$pArgs ) {
        if (/^--Resource=(.*)/) {               # Resource definition
            ($res, @reslist) = ToolsetRClist( $name, $1 );

        } elsif (/^--CmdFile=(.+)/) {
            push @cmd_files, MakeSrcResolve($1);

        } else {
            Message( "$toolset_name LD: unknown option $_ -- ignored\n" );

        }
    }

#.. Names of important files
#
    my $base = "\$(BINDIR)/${name}";
    my $full = $base . $::exe;
    my $map  = $base . '.map';
    my $dep  = $base . '.dep';


#.. Cleanup rules
#
#   dep             Dependency file
#   ld              Linker command file
#   map             Map file
#   ilk             Microsoft Linker Database
#   res             Compiled resource script
#
    ToolsetGenerate( $dep );
    ToolsetGenerate( $map );
    ToolsetGenerate( $base . '.ld' );
    ToolsetGenerate( $base . '.ilk' );

#.. Linker command
#
    my ($io) = ToolsetPrinter::New();

    $io->Prt( "$full : $dep " );
    $io->Entry( "", "", "\\\n\t", ".$::o ", @$pObjs );
    $io->Prt( "\\\n\t$res " ) if ( $res );
    $io->Prt( "\n\t\$(LD)\n\n" );


#.. Linker command file
#
#       Now piece together a variable $(name_ld) which ends up in
#       the command file linking the application.
#
    $io->SetTag( "${name}_ld" );                # macro tag

    $io->Label( "Linker commands", $name );     # label

    $io->Cmd( "\@\$(subst /,\\\\,$_)" ) foreach (@cmd_files);
    $io->Cmd( "-exe \$(subst /,\\\\,$full)" );
    $io->Cmd( "-cvsymbols" );
    $io->Cmd( "-map \$(subst /,\\\\,$map)" );
    $io->Cmd( "\$(subst /,\\\\,$res)" )             if ( $res );

    $io->ObjList( $name, $pObjs, \&ToolsetObjRecipe );  # object list
    $io->LibList( $name, $pLibs, \&ToolsetLibRecipe );  # library list
    $io->Newline();

#.. Library dependency information
#   Rules to include a .dep file when required
#
    $io->LDDEPEND( $name );

#.. Dependencies
#
#       Now piece together a variable $(name_dp) which ends up in
#       the command file building the application dependency list.
#
    $io->SetTag( "${name}_dp" );                                # macro tag
    $io->DepRules( $name, $pLibs, \&ToolsetLibRecipe, $full );  # library depends rules
    $io->Newline();

#.. Compile up the resource file
#
    ToolsetRCrecipe( $res, @reslist )
        if ( $res );

#.. Package up the program
#
    PackageProgAddFiles ( $name, $full );

#
#   Track the name of the possible target file
#   Used when creating Visual Studio projects
#
    $target_file_exe = $full;
}


###############################################################################
#   ToolsetLD( $name, \@args, \@objs, \@libraries, \@csrc, \@cxxsrc )
#       This subroutine takes the user options and builds the rules
#       required to lint the program 'name'.
#
#   Arguments:
#       (none)
#
#   Output:
#       [ $(BINDIR)/$name_lint:   .... ]
#           $(LDLINT)
#
###############################################################################

sub ToolsetLDLINT
{
    PCLintLD( @_ );
}


########################################################################
#
#   Generate a linker object recipe.  This is a helper function used 
#   within this toolset.
#
#   Arguments:
#       $io         I/O stream
#
#       $target     Name of the target
#
#       $obj        Library specification
#
########################################################################

sub ToolsetObjRecipe
{
    my ($io, $target, $obj) = @_;

    $io->Cmd( "\$(subst /,\\\\,\$(strip $obj)).$::o" );
}


########################################################################
#
#   Generate a linker/depend library recipe.  This is a helper function
#   used within this toolset.
#
#   Arguments:
#       $io         I/O stream
#
#       $target     Name of the target
#
#       $lib        Library specification
#
#       $dp         If building a depend list, the full target name.
#
########################################################################

sub ToolsetLibRecipe
{
    my ($io, $target, $lib, $dp) = @_;

    if ( !defined($dp) ) {                      # linker
        $io->Cmd( "\$(subst /,\\\\,\$(strip $lib)).$::a" );

    } else {                                    # depend
        $io->Cmd( "$dp:\t@(vlib2,$lib,LIB)" );
    }
}


########################################################################
#
#   Parse resource file data
#   This is a helper function used within this toolset
#
#   Arguments   : $1  BaseName
#                 $2  The users resource list
#                     This is a list of comma seperated files
#                     The first file is the main resource script
#
#   Returns     : An array of resource files with full pathnames
#                 [0] = The output file
#                 [1] = The input file
#                 [..] = Other input files
#
########################################################################

sub ToolsetRClist
{
    my ($name, $files) = @_;
    my @result;

    #
    #   Generate the name of the output file
    #
    push @result, "\$(OBJDIR)/$name.res";

    #
    #   Process each user file
    #
    for (split( ',', $files ))
    {
        #
        #   Locate the file.
        #   If it is a generate file so it will be in the SRCS hash
        #   Other wise the use will have to use Src to locate the file
        #
        push @result, MakeSrcResolve($_);
    }

    #
    #   Return the array to the user
    #
    return @result;
}


########################################################################
#
#   Generate a resource file recipe
#   This is a helper function used within this tool
#
#   Arguments   : $1  Output resource file
#                 ..  Input resource files
#
########################################################################

sub ToolsetRCrecipe
{
    my ($out, @in) = @_;

    #
    #   Cleanup
    #
    ToolsetGenerate( $out );

    #
    #   Recipe
    #
    MakePrint( "\n#.. Compile Resource file: $out\n\n" );
    MakePrint( "$out:\t\$(GBE_PLATFORM).mk\n" );
    MakeEntry( "$out:\t", "", "\\\n\t\t", " ", @in );
    MakePrint( "\n\t\$(RC)\n" );
    MakePrint( "\n" );
}

########################################################################
#
#   Generate a project from the provided project solution file
#   This is aimed at .NET work
#
#   Arguments   : $name             - Base name of the project
#                 $solution         - Path to the solutionn file
#                 $pArgs            - Project specific options
#
########################################################################

my $project_defines_done = 0;
sub ToolsetPROJECT
{
    my( $name, $solution ,$pArgs ) = @_;
    my $buildcmd = $toolset_info->{'buildcmd'};
    my $cleancmd = $toolset_info->{'cleancmd'};

    #
    #   Process options
    #
    foreach ( @$pArgs ) {
        Message( "$toolset_name PROJECT: unknown option $_ -- ignored\n" );
    }

    my ($io) = ToolsetPrinter::New();

    #
    #   Setup toolset pecific difinitions. Once
    #
    unless( $project_defines_done )
    {
        $project_defines_done = 1;
        $io->PrtLn( "ifeq \"\$(DEBUG)\" \"1\"");
        $io->PrtLn( "PROJECT_CMD\t:= DEBUG");
        $io->PrtLn( "else");
        $io->PrtLn( "PROJECT_CMD\t:= RELEASE");
        $io->PrtLn( "endif");
        $io->Newline();
    }

    #
    #   Process the build and clean commands
    #       Substitute arguments
    #           =TYPE=
    #           =LOG=
    #           =DSW=
    #
    $buildcmd =~ s~=TYPE=~\$\(PROJECT_CMD)~g;
    $buildcmd =~ s~=LOG=~$name\$(GBE_TYPE).log~g;
    $buildcmd =~ s~=DSW=~$solution~g;

    $cleancmd =~ s~=TYPE=~\$\(PROJECT_CMD)~g;
    $cleancmd =~ s~=LOG=~$name\$(GBE_TYPE).log~g;
    $cleancmd =~ s~=DSW=~$solution~g;
    
    #
    #   Generate the recipe to create the project
    #   Use the set_WIN32.sh file to extend the DLL search path
    #
    $io->Label( "Build project", $name );
    $io->PrtLn( "Project_$name: $solution \$(INTERFACEDIR)/set_$::ScmPlatform.sh" );

    $io->PrtLn( "\t\$(XX_PRE)( \$(rm) -f $name\$(GBE_TYPE).log; \\" );
    $io->PrtLn( "\t. \$(INTERFACEDIR)/set_$::ScmPlatform.sh; \\" );
    $io->PrtLn( "\t\$(show_environment); \\" );
    $io->PrtLn( "\t$buildcmd; \\" );
    $io->PrtLn( "\tret=\$\$?; \\" );
    $io->PrtLn( "\t\$(GBE_BIN)/cat $name\$(GBE_TYPE).log; \\" );
    $io->PrtLn( "\texit \$\$ret )" );
    $io->Newline();

    #
    #   Generate the recipe to clean the project
    #
    $io->Label( "Clean project", $name );
    $io->PrtLn( "ProjectClean_$name: $solution" );
    $io->PrtLn( "\t-\$(XX_PRE)$cleancmd" );
    $io->PrtLn( "\t-\$(XX_PRE)\$(rm) -f $name\$(GBE_TYPE).log" );
    $io->Newline();

}


#.. Successful termination
1;