Subversion Repositories DevTools

Rev

Rev 7009 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#
# Module name   : vcwce
# Module type   : Makefile system
# Compiler(s)   : ANSI C
# Environment(s): WCE
#
# Description:
#   Visual C/C++ for WCE
#
#............................................................................#

use strict;
use warnings;

#
#   Global data
#
my $pdb_file = "\$(GBE_PBASE)";
my $pdb_first_lib;
my $target_file_lib;
my $target_file_dll;
my $target_file_exe;
my $pdb_none;
my $toolset_name = 'vcwce';                           # Toolset name : Error reporting

##############################################################################
#   Toolchain information
#   Abstract out minor toolchain differences into a data structure
#
my $toolchain_info;
my %ToolChainData =
    (
        'EVC4'      =>  {  'def'        => 'vcwce.def' ,
                           'initDef'    => 'vcembedded',
                           'wceroot'    => 'Microsoft eMbedded C++ 4.0',
                           'buildcmd'   => 'evc =DSW= /make =TYPE= /use_env /CEConfig="=CEPLATFORM=" /out =LOG=',
                           'cleancmd'   => 'evc =DSW= /make =TYPE= /clean /use_env /CEConfig="=CEPLATFORM="',
                           'tmp'        => 'vc60',
                           'VSCOMPILER' => '1',
                           'def_targets' => [ 'ALL - RELEASE','ALL - DEBUG' ],
                           },


        'VS2005'    =>  {  'def'        => 'vcembedded2005.def' ,
                           'initDef'    => 'vcembedded',
                           'buildcmd'   => 'devenv =DSW= /build =TYPE= /useenv /out =LOG=' ,
                           'cleancmd'   => 'devenv =DSW= /clean =TYPE= /useenv' ,
                           'tmp'        => 'vc80',
                           'VSCOMPILER' => '2',

                           'wceroot'    => 'Microsoft Visual Studio 8/VC/ce',
                           'includes'   => [    '$(WCEROOT)/include',
                                                '$(WCEROOT)/atlmfc/include',
                                           ],
                           'libs'       => [    '$(WCEROOT)/lib/$(WCE_TARGETCPU)',
                                                '$(WCEROOT)/atlmfc/lib/$(WCE_TARGETCPU)',
                                           ],
                           'hex_WCEVersion' => 1,
                           },

        'VS2008'    =>  {  'def'       => 'vcembedded2008.def' ,
                          'initDef'    => 'vcembedded',
                          'buildcmd'   => 'devenv =DSW= /build =TYPE= /useenv /out =LOG=' ,
                          'cleancmd'   => 'devenv =DSW= /clean =TYPE= /useenv' ,
                          'tmp'        => 'vc80',
                          'VSCOMPILER' => '2',

                          'wceroot'    => 'Microsoft Visual Studio 9.0/VC/ce',
                          'includes'   => [    '$(WCEROOT)/include',
                                               '$(WCEROOT)/atlmfc/include',
                                          ],
                          'libs'       => [    '$(WCEROOT)/lib/$(WCE_TARGETCPU)',
                                               '$(WCEROOT)/atlmfc/lib/$(WCE_TARGETCPU)',
                                          ],
                          'hex_WCEVersion' => 1,
                          'calcEntryPoint' => 1,
                          },


    );


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

my( $WCEVersion,$WCEVersionTool ) = "";
my( $WCESubsystem )             = "";
my( $WCEPlatform )              = "";
my( $WCEPlatformDefine )        = "";
my( $WCEPlatformClean )         = "";
my( $WCETargetCPU )             = "";
my( $WCEHostCPU )               = "";
my( $WCEToolchain )             = "";
my( $WCEPlatformBase )          = "";

ToolsetInit();

sub ToolsetInit
{
    my( $wceroot, $sdkroot );
    my( $compiler, $linker, $vstool );
    my( @defines ) = ();
    my( @cflags, @cflags_debug, @cflags_prod ) = ();
    my( @libflags, @ldflags, @ldflags_debug, @ldflags_prod ) = ();
    my $is_vs2005;
    my $default_ehandling = undef;
    my @pDefines;
    my $stack = '0x10000,0x1000';
    my $findRc;

#.. 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
    $::ScmToolsetProperties{'LdFlagSpace'} = 1; # LdFlags support embedded spaces

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

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

    Debug( "$toolset_name(PlatformArgs=@::ScmPlatformArgs)" );

    foreach ( @::ScmPlatformArgs ) {
        if (/^--Version=(.*)/) {                # OS Version
            $WCEVersion     = $1;

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

        } elsif (/^--SdkBase=(.*)/) {           # SdkBase
            $WCEPlatformBase = $1;

        } elsif (/^--Target=(.*)/) {            # CPU
            $WCETargetCPU   = $1;

        } elsif (/^--Host=(.*)/) {              # Emulator host CPU
            $WCEHostCPU     = $1;

        } elsif (/^--Toolchain=(.*)/) {         # Toolchain
            $WCEToolchain   = $1;

        } elsif (/^--product=(.*)/) {           # GBE product

        } elsif (/^--NoDinkumware/) {           # Deprecated switch

        } elsif (/^--Define=(.*)/ ) {
            push @pDefines, '-D' . $1;

        } elsif (/^--FindRc/i ) {
            $findRc = 1;

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

#.. Select toolchain, based on targetCPU
#       1) EVC            - As provided via Embedded Visual C++
#       2) VS2005         - As provided via VS2005
#
    $toolchain_info = $ToolChainData{$WCEToolchain};
    Error( "Unknown Toolchain: $WCEToolchain" ) unless ( defined $toolchain_info );
    $is_vs2005 = ($toolchain_info->{'VSCOMPILER'} == 2);

#
#   The following table shows the processors that eMbedded Visual C++
#   currently supports.
#
#   ARM         ARMV4, ARMV4I, ARMV4T
#   MIPS        MIPSII, MIPSII_FP, MIPSIV, MIPSIV_FP, MIPS16
#   Hitachi     SH3, SH4
#   x86         x86, x86 emulation
#..
    Error ("TOOLSET/$toolset_name - Version undefined")
        if ($WCEVersion eq "");

    Error ("TOOLSET/$toolset_name - SDK undefined")
        if ($WCEPlatform eq "");

    Error ("TOOLSET/$toolset_name - TargetCPU undefined")
        if ($WCETargetCPU eq "");

    Error ("TOOLSET/$toolset_name - HostCPU undefined")
        if ($WCEPlatform eq "emulator" && $WCEHostCPU eq "");

    Error ("TOOLSET/$toolset_name - Toolchain undefined")
        unless ( $WCEToolchain );


# .. Generate CE Platform definition based on the selected SDK
#    The following is a list of known defintions for some SDKs
#    In the EVC studio these are $(CePlatform)
#..
    my %PlatformSDKDefinitions =
    (
        'H/PC 2000'         => 'WIN32_PLATFORM_HPC2000',
        'H/PC Pro 2.11'     => 'WIN32_PLATFORM_HPCPRO',
        'Pocket PC'         => 'WIN32_PLATFORM_PSPC',
        'Pocket PC 2002'    => 'WIN32_PLATFORM_PSPC=310',
        'POCKET PC 2003'    => 'WIN32_PLATFORM_PSPC=400',
        'Smartphone 2002'   => 'WIN32_PLATFORM_WFSP=100',
        'IT-3000'           => 'WCE_PLATFORM_PX780J_ARMV4I',
        'PCM7220'           => 'WCE_PLATFORM_SOCERXS',
        'ADVANTECH_X86_420' => 'WCE_PLATFORM_ADVANTECH_X86_420',
        'SOM_4450_2'        => 'WCE_PLATFORM_SOM_4450_2',
        'adv_som_4455_wlan' => 'WCE_PLATFORM_adv_som_4455_wlan',
        'PsionTeklogixCE420'=> 'WCE_PLATFORM_STANDARDSDK',
        'PsionTeklogixCE500'=> 'WCE_PLATFORM_STANDARDSDK',
        'PA961'             => 'WCE_PLATFORM_PA961',
        'PA962'             => 'WCE_PLATFORM_PA962',
        'PA962 WINCE 500'   => 'WCE_PLATFORM_PA962',
        'M81B_SDK'          => 'WCE_PLATFORM_M81B',                 # Just made this one up
        'VixArmv4iGeneric'  => 'WCE_PLATFORM_VIXARMV4I_GENERIC',    # Just made this one up
        'PocketPC'          => 'WIN32_PLATFORM_PSPC',
        'dc5000_som_4466_sdk' => 'WCE_PLATFORM_som_4466_sdk',       # Just made this one up
    );

    unless ( $WCEPlatform eq 'NONE' )
    {
        $WCEPlatformDefine = $PlatformSDKDefinitions{$WCEPlatform};

        Error ("TOOLSET/$toolset_name - SDK not defined. Extend table",
               "SDK: $WCEPlatform" )
            unless ( defined $WCEPlatformDefine );

        $WCEPlatformClean = $WCEPlatform;
        $WCEPlatformClean =~ s/\s/_/g;
    }
    else
    {
        $WCEPlatform = '.';
    }

    $WCESubsystem = "windowsce," . int($WCEVersion/100) . "." . $WCEVersion%100
        if ( !defined($WCESubsystem) || $WCESubsystem eq "" );

        push( @ldflags,     '-debug:full' ) unless ($is_vs2005);
        push( @ldflags,     '-debug' )      if ($is_vs2005);

#
#   VS2008 may nothave installed rc.exe correctly
#       May have to set up PATH to locate a copy
#       
if ($findRc) {
    my $rcPath;
    my $programFiles = $ENV{PROGRAMFILES};
    Error ('EnvVar PROGRAMFILES not defined') unless $programFiles;
    Error ('EnvVar PROGRAMFILES does not reference a directory') unless -d $programFiles;

    my @GuessList = (
        'Windows Kits/8.0/bin/x86',
        'Windows Kits/8.1/bin/x86/rc.exe',
        'Microsoft SDKs/Windows/v7.1A/Bin'
        );

    foreach my $testDir ( @GuessList) {
        my $testPath = CatPaths($programFiles, $testDir, 'rc.exe' );
        if (-f $testPath) {
            $rcPath = $testDir;
            last;
        }
    }
    Warning ('RC.EXE cannot be located') unless $rcPath;
    PlatformDefine ('RCPATH := $(PROGRAMFILES)/' . $rcPath )
    
}
        
#.. Select toolchain info , based on targetCPU

    if ( $WCETargetCPU eq "armv4" ) {
        $compiler           = "clarm";
        $linker             = "link";
        $vstool             = "x86_arm";
        $default_ehandling  = 1;

        @defines            = ( '-DARM', '-D_ARM_', '-DARMV4' );

        @cflags             = ( '-QRarch4' );
        @cflags             = ( '/GS-' )           if ($is_vs2005);
        @cflags_debug       = ( '-M$(CECrtDebug)' )unless ($is_vs2005);
        @cflags_prod        = ( '-M$(CECrtMT)' )   unless ($is_vs2005);

        push( @ldflags,     '-base:0x00010000' );
        push( @ldflags,     '-stack:' . $stack );
        push( @ldflags,     '-entry:WinMainCRTStartup' );
        push( @ldflags,     '$(CENoDefaultLib)' );
        push( @ldflags,     '-Subsystem:$(CESubsystem)' );
        push( @ldflags,     '-align:4096' );
        push( @ldflags,     '-MACHINE:ARM' );
        push( @ldflags,     'commctrl.lib' );
        push( @ldflags,     'coredll.lib' );
        push( @ldflags,     'aygshell.lib' );
        push( @ldflags,     '$(CEx86Corelibc)' ) if ($is_vs2005);

        push( @libflags,    '-MACHINE:ARM' );
        
    } elsif ( $WCETargetCPU eq "armv4i" ) {
        $compiler           = "clarm";
        $linker             = "link";
        $vstool             = "x86_arm";

        @defines            = ( '-DARM', '-D_ARM_', '-DARMV4I' );

        @cflags             = ( '/QRarch4T' );
        @cflags             = ( '/QRinterwork-return' );
        @cflags             = ( '/GS-' )           if ($is_vs2005);
        @cflags_debug       = ( '-M$(CECrtDebug)' )unless ($is_vs2005);
        @cflags_prod        = ( '-M$(CECrtMT)' )   unless ($is_vs2005);

        push( @ldflags,     '-base:0x00010000' );
        push( @ldflags,     '-stack:' . $stack );
        push( @ldflags,     '-entry:WinMainCRTStartup' );
        push( @ldflags,     '$(CENoDefaultLib)' );
        push( @ldflags,     '-nodefaultlib:oldnames.lib' ) if (1);
        push( @ldflags,     '-Subsystem:$(CESubsystem)' );
        push( @ldflags,     '-MACHINE:THUMB' );
        push( @ldflags,     'commctrl.lib' );
        push( @ldflags,     'coredll.lib' );
        push( @ldflags,     '$(CEx86Corelibc)' ) if ($is_vs2005);

        push( @libflags,    '-MACHINE:THUMB' );
        

    } elsif ( $WCETargetCPU eq 'armv5t' ) {
        Error ('armv5t only supported under VS2005') unless ( $is_vs2005 );
        $compiler           = 'cl';
        $linker             = 'link';
        $vstool             = 'x86_arm';
        $WCETargetCPU       = 'armv4i';

        push  (@defines,    '-DARM', '-D_ARM_', '-DARMV5T');

        push (@cflags,      '/QRarch5t' );
        push (@cflags,      '/GS-' );
        push (@cflags,      '/Zl' );

        #push( @ldflags,     '-base:0x00010000' );
        push( @ldflags,     '/Manifest:no' );
        push( @ldflags,     '-stack:' . $stack );
        push( @ldflags,     '-entry:WinMainCRTStartup' );
        push( @ldflags,     '$(CENoDefaultLib)' );
        push( @ldflags,     '-nodefaultlib:oldnames.lib' ) if (1);
        push( @ldflags,     '-Subsystem:$(CESubsystem)' );
        push( @ldflags,     '-MACHINE:THUMB' );
        push( @ldflags,     'commctrl.lib' );
        push( @ldflags,     'coredll.lib' );
        push( @ldflags,     '$(CEx86Corelibc)' );

        push( @libflags,    '-MACHINE:THUMB' );
        


    } elsif ( $WCETargetCPU eq "armv4t" ) {
        $compiler           = "clthumb";
        $linker             = "link";
        $vstool             = "x86_arm";

        @cflags             = ( '/QRarch4t' );
        @defines            = ( '-DARM', '-D_ARM_', '-DARMV4T' );

    } elsif ( $WCETargetCPU eq "mips16" ) {
        $compiler           = "clmips";
        $linker             = "link";
        $vstool             = "x86_mips";

        @cflags             = ( '/QMmips16' );
        @defines            = ( '-DMIPS', '-D_MIPS_' );

    } elsif ( $WCETargetCPU eq "mips16ii" ) {
        $compiler           = "clmips";
        $linker             = "link";
        $vstool             = "x86_mips";

        @cflags             = ( '/QMmips16' );
        @defines            = ( '-DMIPS', '-D_MIPS_' );

    } elsif ( $WCETargetCPU eq "mipsii_fp" ) {
        $compiler           = "clmips";
        $linker             = "link";

        @cflags             = ( '/QMFWCE' );
        @defines            = ( '-DMIPS', '-D_MIPS_' );

    } elsif ( $WCETargetCPU eq "mipsiv" ) {
        $compiler           = "clmips";
        $linker             = "link";
        $vstool             = "x86_mips";

        @defines            = ( '-DMIPS', '-D_MIPS_' );

    } elsif ( $WCETargetCPU eq "mipsiv_fp" ) {
        $compiler           = "clmips";
        $linker             = "link";

        @cflags             = ( '/QMFWCE' );
        @defines            = ( '-DMIPS', '-D_MIPS_' );

    } elsif ( $WCETargetCPU eq "sh3" ) {
        if ( $WCEVersion >= 400 ) {             # SDK specific
            $compiler       = "clsh";
        } else {
            $compiler       = "shcl";
        }
        $linker             = "link";
        $vstool             = "x86_sh";

        @cflags             = ( '-Qsh3' );
        @defines            = ( '-DSHx', '-DSH3', '-D_SH3_' );

    } elsif ( $WCETargetCPU eq "sh4" ) {
        if ( $WCEVersion >= 400 ) {             # SDK specific
            $compiler       = "clsh";
        } else {
            $compiler       = "shcl";
        }
        $linker             = "link";
        $vstool             = "x86_sh";

        @cflags             = ( '-Qsh4' );
        @defines            = ( '-DSHx', '-DSH4', '-D_SH4_' );

    } elsif ( $WCETargetCPU eq "x86" ) {
        $compiler           = "cl";
        $linker             = "link";
        $vstool             = "x86_cex86";

        @cflags             = ( '-Gs8192', '-GF' );
        @defines            = ( '-D_X86_', '-Dx86', '-D_i386_' );

        push( @ldflags, '-section:.shared,rws' );
        push( @ldflags, '-base:0x00100000' );
        push( @ldflags, '-stack:' . $stack );
        push( @ldflags, '-entry:WinMainCRTStartup' );
        push( @ldflags, '-Subsystem:$(CESubsystem)' );
        push( @ldflags, '-MACHINE:IX86' );
        push( @ldflags, '$(CENoDefaultLib)' );
        push( @ldflags, '-nodefaultlib:oldnames.lib' );
        push( @ldflags, '$(CEx86Corelibc)' );
        push( @ldflags, 'coredll.lib' );
        push( @ldflags, 'commctrl.lib' );
        push( @ldflags, 'aygshell.lib' );

        push( @libflags,'-MACHINE:IX86' );
        
    } elsif ( $WCETargetCPU eq "emulator" ) {

        if ( $WCEHostCPU eq "x86" ) {
            $compiler       = "cl";
            $linker         = "link";
            $vstool         = "x86_cex86";
            $default_ehandling  = 1;

            @defines        = ( '-D_X86_', '-Dx86', '-D_i386_' );

            @cflags         = ( '-Gs8192', '-GF' );

            push( @ldflags, '-base:0x00010000' );
            push( @ldflags, '-stack:' . $stack );
            push( @ldflags, '-entry:WinMainCRTStartup' );
            push( @ldflags, '-Subsystem:$(CESubsystem)' );
            push( @ldflags, '-MACHINE:IX86' );
            push( @ldflags, '$(CENoDefaultLib)' );
            push( @ldflags, '-nodefaultlib:oldnames.lib' );
            push( @ldflags, '$(CEx86Corelibc)' );
            push( @ldflags, 'commctrl.lib' );
            push( @ldflags, 'coredll.lib' );
            push( @ldflags, 'aygshell.lib' );

            push( @libflags,'-MACHINE:IX86' );
            
        } else {
            Error ("TOOLSET/$toolset_name - unknown HostCPU '$WCEHostCPU'");
        }

    } else {
        Error ("TOOLSET/$toolset_name - unknown TargetCPU '$WCETargetCPU'");
    }

    #
    #   Append any platform specific definitions
    #
    push (@defines,     '-D "_WINDOWS"', '-D "_WINCE"' ) if ($is_vs2005);
    push @defines, @pDefines;

#.. Define eMebbed C/C+ environment
#

    #
    #   Determine the toolchain root
    #   Currently these are within ProgramFiles
    #
    $wceroot = $toolchain_info->{'wceroot'};

    #
    #   The VS2005 toolchain uses a hex value for WCEVersion
    #
    $WCEVersionTool = $WCEVersion;
    $WCEVersionTool = '0X' . $WCEVersion if ( $toolchain_info->{'hex_WCEVersion'} );


    #
    #   Determine SDK root
    #   Currently these are well known
    #
    if ( $WCEPlatformBase )
    {
        $sdkroot = $WCEPlatformBase.'/'.$WCEPlatform;
    }
    else
    {
        $sdkroot = 'Windows CE Tools/wce'.$WCEVersion.'/'.$WCEPlatform;
    }
    
    Debug( "\twceroot           = $wceroot" );
    Debug( "\tsdkroot           = $sdkroot" );
    Debug( "\tWCEVersion        = $WCEVersion" );
    Debug( "\tWCESubsystem      = $WCESubsystem" );
    Debug( "\tWCEPlatform       = $WCEPlatform" );
    Debug( "\tWCEPlatformDefine = $WCEPlatformDefine" );
    Debug( "\tWCEPlatformClean  = $WCEPlatformClean" );
    Debug( "\tWCETargetCPU      = $WCETargetCPU" );
    Debug( "\tWCEHostCPU        = $WCEHostCPU" );
    Debug( "\tWCEToolchain      = $WCEToolchain" );

    PlatformDefine( "
#################################################
# Default paths, toolchain and flags
#
#..

PROGRAMFILES         ?= C:/Program Files

ifndef WCEROOT
WCEROOT              := \$(PROGRAMFILES)/" . $wceroot ."
export WCEROOT
endif

ifndef SDKROOT
SDKROOT              := \$(PROGRAMFILES)/" . $sdkroot ."
export SDKROOT
endif

WCE_VSTOOL           := $vstool
WCE_VERSION          := $WCEVersionTool
WCE_SUBSYSTEM        := $WCESubsystem
WCE_PLATFORM         := $WCEPlatform
WCE_PLATFORM_SDK_DEF := $WCEPlatformDefine
WCE_PLATFORM2        := $WCEPlatformClean
WCE_TARGETCPU        := $WCETargetCPU
WCE_HOSTCPU          := $WCEHostCPU

CESubsystem          := \$(WCE_SUBSYSTEM)
CEVersion            := \$(WCE_VERSION)
CEPlatform           := \$(WCE_PLATFORM)
");

if ( $WCEVersion < 201 ) {
    PlatformDefine( '
CECrtDebug      := Ld
CECrtMT         := T
CENoDefaultLib  := \
                -nodefaultlib:corelibc.lib
CEx86Corelibc   :=
');
} else {
    PlatformDefine( '
CECrtDebug      := C
CECrtMT         := C
CENoDefaultLib  := \\
                -nodefaultlib:libc.lib\
                -nodefaultlib:libcd.lib\
                -nodefaultlib:libcmt.lib\
                -nodefaultlib:libcmtd.lib\
                -nodefaultlib:msvcrt.lib\
                -nodefaultlib:msvcrtd.lib
CEx86Corelibc   := corelibc.lib
' );
}

if ( $is_vs2005 )
{
    PlatformDefine( '
CENoDefaultLib  += \\
                -nodefaultlib:secchk.lib\
                -nodefaultlib:ccrtrtti.lib
' );
}

#
#   WinCe development platform specifics
#       Encode Toolset paths as they contain spaces
#       These will be decoded later
#
PlatformEntry( "vc_includes\t=", "\n", "\\\n\t" . '$(call encodepath,', ')', @{$toolchain_info->{'includes'}} );
PlatformEntry( "vc_libs\t="    , "\n", "\\\n\t" . '$(call encodepath,', ')', @{$toolchain_info->{'libs'}} );

    PlatformDefine( "WCE_EMULATOR\t".   ":= 1" )
        if ( $WCETargetCPU eq "emulator" );

    PlatformEntry( "WCE_DEFINES\t=",    "\n", "\\\n\t", "", @defines )
        if ( scalar @defines );

    PlatformEntry( "WCE_CFLAGS\t=",     "\n", "\\\n\t", "", @cflags )
        if ( scalar @cflags );

    PlatformEntry( "WCE_CFLAGSD\t=",    "\n", "\\\n\t", "", @cflags_debug )
        if ( scalar @cflags_debug );

    PlatformEntry( "WCE_CFLAGSP\t=",    "\n", "\\\n\t", "", @cflags_prod )
        if ( scalar @cflags_prod );

    PlatformEntry( "WCE_LDFLAGS\t=",    "\n", "\\\n\t", "", @ldflags )
        if ( scalar @ldflags );

    PlatformEntry( "WCE_LIBFLAGS\t=",    "\n", "\\\n\t", "", @libflags )
        if ( scalar @libflags );
        
    PlatformEntry( "WCE_LDFLAGSD\t=",   "\n", "\\\n\t", "", @ldflags_debug )
        if ( scalar @ldflags_debug );

    PlatformEntry( "WCE_LDFLAGSP\t=",   "\n", "\\\n\t", "", @ldflags_prod )
        if ( scalar @ldflags_prod );

if ( $is_vs2005 )
{
    $compiler = 'cl';
    $linker = 'link';
}
    PlatformDefine( "
WCE_CC          := $compiler
WCE_LINK        := $linker
" );

    Init( $toolchain_info->{'initDef'} );
    ToolsetDefines( $toolchain_info->{'def'} );
    PlatformDefine ("VSCOMPILER\t= $toolchain_info->{'VSCOMPILER'}" );
    ToolsetRules( "vcwce.rul" );
    ToolsetRules( "standard.rul" );

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

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


#
#   The PDB files need to be compiled up with absolute paths to the source files
#   The easiest way to do this is with the makefile rules created with absolute
#   paths. Set a global flag to enable this option
#
    $::UseAbsObjects = 1;


#.. 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 =
    (
        'rtti'               => { 'USE_RTTI', 1 },
        'nopdb'              => { 'PDB_NONE', 1 },
        'pdb'                => { 'PDB_NONE', undef },
        'exceptions'         => { 'USE_HANDLING', 1 },
        'noexceptions'       => { 'USE_HANDLING', undef },
        'subsystem:windows'  => { 'ENTRYPOINT' , 'WinMainCRTStartup' },
        'subsystem:console'  => { 'ENTRYPOINT' , 'mainACRTStartup' },
    );

    #
    #   Set default options
    #       USE_HANDLING - not always the same default
    #
    $::ScmCompilerOpts{'USE_HANDLING'} = $default_ehandling;
}

##############################################################################
#   ToolsetPreprocess()
#       Process collected data before 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 created
#
##############################################################################
sub ToolsetPreprocess
{
    #
    #   Extract the current state of PDB_NONE
    #   Are PDB files to be constructed.
    #
    $pdb_none = $::ScmCompilerOpts{'PDB_NONE'};
}

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

    #
    #   Specify the name of the global PDB file. This is used for all
    #   compiles other than those associated with building a DLL
    #
    #   The name of the PDB will be based on either
    #       The name of base package
    #       The name of the first static library created
    #

MakePrint("
#
#   Export the name of the common PDB file
#   All compiler information will be placed in this file
#   The name of the file MUST be the same as the name of the output library
#
PDB             = \$(OBJDIR)/$pdb_file\$(GBE_TYPE).pdb
" );

    #
    #   Add values to the perl environment
    #   May be used by post processing tools to create Visual Studio Projects
    #
    $::TS_pdb_file = "\$(OBJDIR)/$pdb_file\$(GBE_TYPE).pdb" unless( $pdb_none );
    $::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;
        }
    }
}

###############################################################################
#   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, $pdb );

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

        } 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

    if ( $pdb && !$pdb_none )
    {
        #
        #   Determine the name of the PDB file
        #   If we are building a shared library then the name of the PDB
        #   MUST NOT be the same as the name of the library as there is
        #   some stange interaction with the linker ( 50% of the time )
        #   This is OK as the file will not be published
        #
        #   If building a static library then create a PDB of the same
        #   name as it may be published directly.
        #
        my $pdb_file;
        if ($cflags )
        {
            $pdb_file = "\$(OBJDIR)/${pdb}\$(GBE_TYPE)_shlib.pdb";
        }
        else
        {
            $pdb_file = "\$(OBJDIR)/${pdb}\$(GBE_TYPE).pdb";
        }    

        MakePadded( 4, "\$(OBJDIR)/$obj.$::o:", "\tPDB = $pdb_file\n" );
        ToolsetGenerate( $pdb_file );
        ToolsetGenerate( $pdb_file . ".tmp" );
    }

    #
    #   Remove possible Source Browser Files
    #
    ToolsetGenerate( "\$(OBJDIR)/$obj.sbr" );
    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
{
    ToolsetCCDepend();
}


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

#
#   To assist in debugging the static library it is nice to
#   keep the PDB file used to build the library, with the library.
#
#   If the library is being packaged or installed then add the PDB
#   file to the package / installation
#
#   NOTE: Due to the limitations of JATS/MicroSoft only one static
#   library can be built with a PDB file. The name of the PDB file
#   will be taken from the first static library encountered
#
    unless ( $pdb_first_lib )
    {
        $pdb_first_lib = $name;
        $pdb_file = $name;
    }
    else
    {
        Warning( "Multiple static libraries created with a common PDB file: $pdb_file, $name" )
            unless( $pdb_none );
    }

    PackageLibAddFiles( $name, "\$(OBJDIR)/$pdb_file\$(GBE_TYPE).pdb", "Class=debug" )
        unless( $pdb_none );
}


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

    #
    #   Package up the PDB's with the library
    #   Note: The PDBs will be found in the OBJDIR
    #
    unless( $pdb_none )
    {
        for ( @{$pLibs} )
        {
            s~\$\(LIBDIR\)~\$(OBJDIR)~;
            PackageLibAddFiles( $name, "$_\$(GBE_TYPE).pdb", "Class=debug" );
        }
    }
}


###############################################################################
#   ToolsetSHLD $name, \@args, \@objs, \@libraries, $ver )
#       This subroutine takes the user options and builds the rules
#       required to link a shared library
#
#   Arguments:
#       --Def=xxxx.def[,opts]           # Definition file
#           --MutualDll                 # SubOption: Generate a Mutual DLL
#       --MutualDll                     # Generate a Mutual DLL (requires --Def=xxx)
#       --StubOnly                      # Only generate the stub library (requires --Def=xxx)
#       --Resource=xxxx.rc              # Resource file
#       --ResourceOnly                  # Only resources in this DLL
#       --Implib                        # Alternate ruleset
#       --NoPDB                         # Do not package the PDB file
#       --NoImplib                      # Do not package the import library
#       --Entry=xxxxx                   # Entry point
#       --NoAddLibs                     # Do not add libraries
#
#   Output:
#
#       There is two supported rule sets differentiated by --Implib
#       The two are very similar and generated exportable files of:
#
#       --Implib
#           ${name}.lib         - Stub lib adresses the versioned DLL
#           ${name}.${ver}.dll
#
#       Default
#           ${name}.lib         - Stub lib addresses UN-versioned DLL
#           ${name}.dll
#           ${name}.${ver}.dll
#
#       Note: Each DLL has an associated PDB file
#
#       Generation is identical for both rulesets. The default form does
#       not export any stub library associated with the versioned DLL.
#
#   Implementation notes
#   The process of creating a DLL and associated import library (LIB) is
#
#           ${name}.${ver}.dep
#           ${name}.${ver}.pdb          - Exported
#           ${name}.${ver}.ilk
#           ${name}.${ver}.dll          - Exported
#           ${name}.${ver}.map
#           ${name}.lib                 - Exported + Optional
#           ${name}.exp
#
#       Where:    lib = name
#
#       #.. Rules ($lib)
#
#       $(LIBDIR)/${lib}.lib:               $(LIBDIR)/${lib}.${ver}.dll
#       $(LIBDIR)/${lib}.pdb:               $(LIBDIR)/${lib}.${ver}.dll
#       $(LIBDIR)/${lib}.${ver}.pdb:        $(LIBDIR)/${lib}.${ver}.dll
#
#       $(LIBDIR)/${lib}.${ver}.dep:        SHBASE=${name}
#       $(LIBDIR)/${lib}.${ver}.dep:        SHNAME=${lib}.${ver}
#       $(LIBDIR)/${lib}.${ver}.dep:        \$(LIBDIR)
#       $(LIBDIR)/${lib}.${ver}.dep:        Makefile
#           $(SHLDDEPEND)
#
#       $(LIBDIR)/${lib}.${ver}.${so}:      SHBASE=${name}
#       $(LIBDIR)/${lib}.${ver}.${so}:      SHNAME=${lib}.${ver}
#       $(LIBDIR)/${lib}.${ver}.${so}:      CFLAGS+=$(SHCFLAGS)
#       $(LIBDIR)/${lib}.${ver}.${so}:      CXXLAGS+=$(SHCXXFLAGS)
#       $(LIBDIR)/${lib}.${ver}.${so}:      ${def}
#       $(LIBDIR)/${lib}.${ver}.${so}:      $(OBJDIR)/${name} \
#                       object list ... \
#                       $(LIBDIR)/${lib}.${ver}.dep
#           $(SHLD)
#           @$(cp) -f $(LIBDIR)/${lib}.${ver}.pdb $(LIBDIR)/${lib}.pdb
#
#       ifneq "$(findstring $(IFLAG),23)" ""
#       -include        "$(LIBDIR)/${lib}.${ver}.dep"
#       endif
#
#       #.. Linker commands ($lib)
#
#       ${lib}_ld       += ...
#               standard flags                          \
#               -implib:$${lib}.lib
#
#       #.. Linker commands ($lib)
#
#       ${lib}_shdp     += ...
#
###############################################################################

sub ToolsetSHLD
{
    our( $name, $pArgs, $pObjs, $pLibs, $ver ) = @_;
    our( $def, $mutual_dll, $res, @reslist, $doimplib, $stub_only );
    our( $no_implib, $no_pdb, $resource_only );
    our( $entry, $entrySet, $noaddlibs );

#.. Parse arguments
#
    $def = "";                                  # options
    $doimplib = 0;
    $res = "";
    $no_pdb = $pdb_none;
    $entry = '_DllMainCRTStartup';

    foreach $_ ( @$pArgs ) {
        if (/^--Def=(.*?)(\,(.*))?$/) {         # Library definition
            #
            #   Locate the Def file.
            #   If it is a generate file so it will be in the SRCS hash
            #   Otherwise the user will have to use Src to locate the file
            #
            $def = MakeSrcResolve($1);

            #
            #   Process sub options to --Def
            #
            next unless ($2);
            if ( $3 =~ /^--MutualDll$/ ) {
                $mutual_dll = 1;
            } else {
                Message( "$toolset_name SHLD: unknown option $_ -- ignored\n" );
            }

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

        } elsif (/^--ResourceOnly/) {          # Resource definition
            $resource_only = 1;

        } elsif (/^--Implib$/) {
            $doimplib = 1;

        } elsif (/^--NoImplib$/) {
            $no_implib = 1;

        } elsif (/^--NoPDB$/) {
            $no_pdb = 1;

        } elsif (/^--Entry=(.*)/) {
            $entry = $1;
            $entrySet = 1;

        } elsif (/^--NoAddLib/) {
            $noaddlibs = 1;

        } elsif (/^--MutualDll$/) {
            $mutual_dll = 1;

        } elsif (/^--Stubonly/) {
            $stub_only = 1;

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

    #
    #   Sanity test
    #
    Error ("$toolset_name SHLD:Stubonly option requires --Def=file ")
        if ( $stub_only && ! $def );

    Error ("$toolset_name SHLD:MutualDll option requires --Def=file ")
        if ( $mutual_dll && ! $def );
        
    Error ("$toolset_name SHLD:--ResourceOnly and --Entry options are mutually exclusive")
        if ($entrySet && $resource_only);



#.. Build rules
#
#   base    -   Basic name of the DLL
#   name    -   Name of the Export library (Optional)
#   lib     -   Name of the DLL
#
    sub BuildSHLD
    {
        my ($base, $name, $lib) = @_;
        my $full = $lib.".$::so";
        my $link_with_def;

    #.. Cleanup rules
    #
    #   ld      Linker command file
    #   map     Map file
    #   pdb     Microsoft C/C++ program database
    #   ilk     Microsoft Linker Database
    #
        ToolsetGenerate( "\$(LIBDIR)/${lib}.ld" );
        ToolsetGenerate( "\$(LIBDIR)/${lib}.map" );
        ToolsetGenerate( "\$(LIBDIR)/${lib}.exp" );
        ToolsetGenerate( "\$(LIBDIR)/${lib}.ilk" );
        ToolsetGenerate( "\$(LIBDIR)/${full}" );

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

        my $import_lib;
        my $export_file;

        if ( $name && $def && ($mutual_dll || $stub_only ) )
        {
            #
            #   Creating an Export library from user .DEF file
            #   It is possible to create the stub library in the LIB phase
            #   which allows DLLs with mutual imports
            #
            $io->Label( "Import(stub) library for mutual exports", $name );
            $export_file = "\$(LIBDIR)/${name}.exp";

            #
            #   Rules and recipe to generate the stub library
            #
            $io->Prt( "\$(LIBDIR)/${name}.exp:\t\$(LIBDIR)/${name}.${a}\n" );
            $io->Prt( "\$(LIBDIR)/${name}.${a}:\tLIBDEF=$def\n" );
            $io->Prt( "\$(LIBDIR)/${name}.${a}:\tLIBNAME=$lib\n" );
            $io->Entry( "\$(LIBDIR)/${name}.${a}: \\\n\t\t\$(OBJDIR)/${base}",
                                            "", " \\\n\t\t", ".$::o", @$pObjs );
            $io->Prt( " \\\n\t\t$def" );
            $io->Prt( "\n\t\t\$(AR)\n" );
            $io->Newline();
            
            #
            #   Files to be cleanup up
            #
            ToolsetGenerate( "\$(LIBDIR)/${name}.exp" );
            ToolsetGenerate( "\$(LIBDIR)/${name}.${a}" );

            #
            #   If the DLL is being packaged/installed then add the static
            #   stub library to the packaging lists as a static library
            #   This will allow the stub library to be installed with the
            #   static libraries and thus allow DLL's with mutual imports
            #
            PackageShlibAddLibFiles ($base, "\$(LIBDIR)/${name}.${a}" )
                unless ($resource_only);

            #
            #   Add the stub library to the list of libraries being created
            #   Note: Don't do if not created with .DEF file
            #
            push @::LIBS, $base;

        }
        else
        {
            #
            #   The stub library is created as part of the DLL generation
            #   Whether we like it or not - so we need to control the name
            #   and location
            #
            my $slname = ($name) ? $name : $lib;
            $import_lib = "\$(LIBDIR)/${slname}.${a}";

            $io->Label( "Import(stub) library", $slname );
            $io->Prt( "$import_lib:\t\$(LIBDIR)/${full}\n" );
            $io->Newline();

            ToolsetGenerate( $import_lib );
            ToolsetGenerate( "\$(LIBDIR)/${slname}.exp" );

            #
            #   Package the generated stub library, if it is being
            #   created on request.
            #
            #   Package it with the shared libaries and not the static
            #   libraries as it will be created with the shared library
            #
            PackageShlibAddFiles ($base, $import_lib, 'Class=lib' )
                if ($name && ! $no_implib && ! $resource_only);

            #
            #   Indicate that we will be linking with a DEF file
            #
            $link_with_def = 1 if ( $def );
        }

        #
        #   If we are only creating a stub library, then the hard work has been
        #   done.
        #
        return
            if ($stub_only);

        $io->Label( "Shared library", $name );

        #
        #   The process of creating a DLL will generate PDB file
        #   Control the name of the PDB file
        #
        my $pdb_file = "\$(LIBDIR)/${lib}.pdb";
        unless( $no_pdb )
        {
            $io->Prt( "$pdb_file:\t\$(LIBDIR)/${full}\n" );
            ToolsetGenerate( $pdb_file );
        }

        #
        #   Package the PDB file up with the DLL
        #   Package the DLL - now that we know its proper name
        #
        PackageShlibAddFiles( $base, $pdb_file, 'Class=debug' ) unless $no_pdb ;
        PackageShlibAddFiles( $base, "\$(LIBDIR)/${full}" );

        #
        #   Generate Shared Library dependency information
        #
        my $dep = $io->SetShldTarget( $lib );

        #
        #   Generate rules and recipes to create the body of the shared
        #   library. Several build variables are overiden when creating
        #   a shared library.
        #
        $io->Prt( "\$(LIBDIR)/${full}:\tSHBASE=${lib}\n" );
        $io->Prt( "\$(LIBDIR)/${full}:\tSHNAME=${lib}\n" );
        $io->Prt( "\$(LIBDIR)/${full}:\tCFLAGS+=\$(SHCFLAGS)\n" );
        $io->Prt( "\$(LIBDIR)/${full}:\tCXXLAGS+=\$(SHCXXFLAGS)\n" );
        $io->Prt( "\$(LIBDIR)/${full}:\t$export_file\n" ) if ($export_file );
        $io->Prt( "\$(LIBDIR)/${full}:\t$res\n" ) if ( $res );

        $io->Entry( "\$(LIBDIR)/${full}: $dep \\\n\t\t\$(OBJDIR)/${base}",
            "", " \\\n\t\t", ".$::o", @$pObjs );

        $io->Prt( " \\\n\t\t$def" ) if ( $link_with_def );
        $io->Prt( "\n\t\$(SHLD)\n" );

        $io->Newline();

        #.. Linker command file
        #
        #       Now the fun part... piecing together a variable ${name}_shld
        #       which ends up in the command file.
        #
        $io->SetTag( "${lib}_shld" );          # command tag

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

        $io->Cmd( "-dll" );
        $io->Cmd( "-noentry" )if ($resource_only);
        $io->Cmd( "-def:$def" ) if ($link_with_def);
        $io->Cmd( "-out:\$(subst /,\\\\,\$(LIBDIR)/${full})" );
        $io->Cmd( "-implib:\$(subst /,\\\\,$import_lib)" ) if ($import_lib);
        $io->Cmd( "-pdb:\$(subst /,\\\\,$pdb_file)" ) unless ( $no_pdb );
        $io->Cmd( "-debug:none" )                     if ($no_pdb);
        $io->Cmd( "-pdb:none" )                       if ($no_pdb);
        $io->Cmd( "-entry:$entry" )                   unless ($resource_only);
        $io->Cmd( "-map:\$(subst /,\\\\,\$(LIBDIR)/${lib}).map" );
        $io->Cmd( "\$(subst /,\\\\,$res)" ) if ( $res );
        $io->Cmd( "\$(subst /,\\\\,$export_file)" ) if ( $export_file );

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

        $io->Newline();

        #.. Dependency link,
        #   Create a library dependency file
        #       Create command file to build applicaton dependency list
        #       from the list of dependent libraries
        #
        #       Create makefile directives to include the dependency
        #       list into the makefile.
        #
        $io->DepRules( $pLibs, \&ToolsetLibRecipe, "\$(LIBDIR)/${full}" );
        $io->SHLDDEPEND( $name, $lib );
    }

    ToolsetLibStd( $pLibs )                    # push standard libraries
        unless ( $noaddlibs );

    if ( $doimplib ) {
        #
        #   --Implib flavor will create
        #       a) Import library   $name$(GBE_TYPE).lib
        #       b) Versioned DLL    $name$(GBE_TYPE).xx.xx.xx.dll
        #
        $target_file_dll = "\$(LIBDIR)/$name\$(GBE_TYPE).$ver.$::so";
        BuildSHLD(
            "$name",                        # Base Name
            "$name\$(GBE_TYPE)",            # Name of Export Lib
            "$name\$(GBE_TYPE).$ver");      # Name of the DLL + PDB

    } else {
        #
        #   Original flavor will create
        #       a) Import library   $name$(GBE_TYPE).lib    ---+
        #       b) Unversioned DLL  $name$(GBE_TYPE).dll    <--+
        #       c) Versioned DLL    $name$(GBE_TYPE).xx.xx.xx.dll
        #
        MakePrint(
            "# .. Versioned image\n\n".
            "\$(LIBDIR)/${name}\$(GBE_TYPE).$::so:\t".
            "\$(LIBDIR)/${name}\$(GBE_TYPE).$ver.$::so\n".
            "\n" );

        $target_file_dll = "\$(LIBDIR)/$name\$(GBE_TYPE).$::so";
        BuildSHLD( "$name", "$name\$(GBE_TYPE)" , "$name\$(GBE_TYPE)" );
        BuildSHLD( "$name", ""                  , "$name\$(GBE_TYPE).$ver" );
    }

    #.. Resource File
    #
    ToolsetRCrecipe( $res, @reslist )
        if ( $res );
}


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

sub ToolsetSHLDLINT
{
    PCLintSHLIB( @_ );
}


###############################################################################
# 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 $no_pdb =$pdb_none;
    our( $entry, $noaddlibs );
    my $stack = '0x10000,0x1000';

    #
    #   Auto calc entry point - only in new WinCE
    #   Default is for subsystem:windows
    #   
    if ($toolchain_info->{'calcEntryPoint'}) {
        if (exists $::ScmCompilerOpts{'ENTRYPOINT'}) {
            $entry = $::ScmCompilerOpts{'ENTRYPOINT'}; 
        }
    }

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

        } elsif (/^--NoPDB$/) {
            $no_pdb = 1;

        } elsif (/^--Entry=(.*)/) {
            $entry = $1;

        } elsif (/^--NoAddLib/) {
            $noaddlibs = 1;

        } elsif (/^--Stack=(.*)/i) {            # Alternate stack.
            $stack   = $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 $pdb  = $base . '.pdb';


#.. Cleanup rules
#
#   ld      Linker command file
#   map     Map file
#   pdb     Microsoft C/C++ program database
#   ilk     Microsoft Linker Database
#   res     Compiled resource script
#
    ToolsetGenerate( $map );
    ToolsetGenerate( $pdb );
    ToolsetGenerate( $base . '.ld' );
    ToolsetGenerate( $base . '.ilk' );

#.. Toolset Printer
#
    my ($io) = ToolsetPrinter::New();
    my $dep = $io->SetLdTarget( $name );

#
#.. Linker command
#
    $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( "-out:\$(subst /,\\\\,$full)" );
    $io->Cmd( "-pdb:\$(subst /,\\\\,$pdb)" )        unless ($no_pdb);
    $io->Cmd( "-debug:none" )                       if ($no_pdb);
    $io->Cmd( "-pdb:none" )                         if ($no_pdb);
    $io->Cmd( "-entry:$entry" )                     if ($entry);
    $io->Cmd( "-stack:$stack" )                     if ($stack);
    $io->Cmd( "-map:\$(subst /,\\\\,$map)" );
    $io->Cmd( "\$(subst /,\\\\,$res)" )             if ( $res );

    ToolsetLibStd( $pLibs ) unless ( $noaddlibs );      # push standard libraries
    $io->ObjList( $name, $pObjs, \&ToolsetObjRecipe );  # object list
    $io->LibList( $name, $pLibs, \&ToolsetLibRecipe );  # library list
    $io->Newline();

    #.. Dependency link,
    #   Create a library dependency file
    #       Create command file to build applicaton dependency list
    #       from the list of dependent libraries
    #
    #       Create makefile directives to include the dependency
    #       list into the makefile.
    #
    $io->DepRules( $pLibs, \&ToolsetLibRecipe, $full );
    $io->LDDEPEND();

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

#.. Package up the PDB file with the program
#
    PackageProgAddFiles ( $name, $full );
    PackageProgAddFiles ( $name, $pdb, "Class=debug" ) unless ( $no_pdb );

#
#   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( @_ );
}


########################################################################
#
#   Push standard "system" libraries. This is a helper function
#   used within this toolset.
#
#   Arguments:
#       $plib       Reference to library array.
#
########################################################################

sub ToolsetLibStd
{
    my ($plib) = @_;

    #
    #   Only add libraries if required
    #
    return unless( $::ScmCompilerOpts{'ADDLINKLIBS'} );

}


########################################################################
#
#   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) = @_;

    return                                      # ignore (compat)
        if ( $lib eq "rt" ||        $lib eq "thread" ||
             $lib eq "pthread" ||   $lib eq "nsl" ||
             $lib eq "socket" );

    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( '\s*,\s*', $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 file
#
#   Arguments   : $name             - Base name of the project
#                 $project          - Path to the project file
#                 $pArgs            - Project specific options
#
########################################################################

my $project_defines_done = 0;
sub ToolsetPROJECT
{
    my( $name, $project, $pArgs ) = @_;
    my $buildcmd = $toolchain_info->{'buildcmd'};
    my $cleancmd = $toolchain_info->{'cleancmd'};
    my $release = ${$toolchain_info->{'def_targets'}}[0] || 'RELEASE';
    my $debug =   ${$toolchain_info->{'def_targets'}}[1] || 'DEBUG';

    #
    #   Process options
    #
    foreach ( @$pArgs ) {
        if ( m/^--TargetProd*=(.+)/ ) {
            $release = $1;

        } elsif ( m/^--TargetDebug=(.+)/ ) {
            $debug = $1;
            
        } else {
            Message( "$toolset_name PROJECT: unknown option $_ -- ignored\n" );
        }
    }

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

    #
    #   Setup toolset specific difinitions. Once
    #
    unless( $project_defines_done )
    {
        $project_defines_done = 1;
        $io->PrtLn( 'project_target = $(if $(findstring 1,$(DEBUG)),$2,$1)' );
        $io->Newline();
    }

    #
    #   Process the build and clean commands
    #       Substitute arguments
    #           =TYPE=
    #           =LOG=
    #           =DSW=
    #           =CEPLATFORM=
    #
    $buildcmd =~ s~=TYPE=~"\$(call project_target,$release,$debug)"~g;
    $buildcmd =~ s~=LOG=~$name\$(GBE_TYPE).log~g;
    $buildcmd =~ s~=DSW=~$project~g;
    $buildcmd =~ s~=CEPLATFORM=~\$(WCE_PLATFORM)~g;

    $cleancmd =~ s~=TYPE=~"\$(call project_target,$release,$debug)"~g;
    $cleancmd =~ s~=LOG=~$name\$(GBE_TYPE).log~g;
    $cleancmd =~ s~=DSW=~$project~g;
    $cleancmd =~ s~=CEPLATFORM=~\$(WCE_PLATFORM)~g;
    
    #
    #   Generate the recipe to create the project
    #
    $io->Label( "Build project", $name );
    $io->PrtLn( "Project_$name: $project" );
    $io->PrtLn( "\t\$(XX_PRE)( \$(rm) -f $name\$(GBE_TYPE).log; \\" );
    $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: $project" );
    $io->PrtLn( "\t-\$(XX_PRE)$cleancmd" );
    $io->PrtLn( "\t-\$(XX_PRE)\$(rm) -f $name\$(GBE_TYPE).log" );
    $io->Newline();

}


#.. Successful termination
1;