Subversion Repositories DevTools

Rev

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

# -*- mode: perl; tabs: 8; indent-width: 4; show-tabs: yes; -*-
#
# Module name   : GCC
# Module type   : Makefile system
# Compiler(s)   : ANSI C
# Environment(s): GCC
#
# Description:
#       GCC C/C++ toolset
#
#............................................................................#

use strict;
use warnings;

##############################################################################
#   Configuration information
#   Cross reference from CrossCompiler Alias to actual paths
#   Structure:
#   Hash reference: Array of toolchain information
#           Root of compiler
#           Path to gcc
#           Path to ar
#
#
my %ToolsetConfig = (
    #
    #   Preferred version of the embedded toolchain
    #
    'i386-unknown-linux-gnu' => ['/opt/crosstool/gcc-4.1.1-glibc-2.5/i586-unknown-linux-gnu',
                                 'bin/i586-unknown-linux-gnu-gcc' ],

    'arm-9tdmi-linux-gnu'    => ['/opt/crosstool/gcc-4.1.1-glibc-2.5/arm-9tdmi-linux-gnu/',
                                 'bin/arm-9tdmi-linux-gnu-gcc' ],

    #
    #   Old (not to be used) version of the embedded toolchain
    #   This was depricated in favor of gcc-4.1.1-glibc-2.5
    #   It is not possible to reproduce old packages using the old compiler
    #   This is a known issue
    #
    'i386-unknown-linux-gnu.glibc-2.3.2' => ['/opt/crosstool/gcc-4.1.0-glibc-2.3.2/i386-unknown-linux-gnu',
                                 'bin/i386-unknown-linux-gnu-gcc' ],

    'arm-9tdmi-linux-gnu.glibc-2.3.2'    => ['/opt/crosstool/gcc-4.1.0-glibc-2.3.2/arm-9tdmi-linux-gnu',
                                 'bin/arm-9tdmi-linux-gnu-gcc' ],

    #
    #   Not too sure where this is used
    #
    'armv4l-unknown-linux-gcc' => [ '/opt/host/armv4l',
                                    'bin/armv4l-unknown-linux-gcc' ],

    #
    #   The compiler for the current local machine
    #
    'i386-unknown-linux-gcc' => [ '/opt/host/i386',
                                  'bin/i386-unknown-linux-gcc' ],

    );

#
#   Cross reference from GCCTarget to GBE_MACHTYPE for which it can
#   build using the 'native gcc'. This is NOT the preferred mode of operation
#   as the compiler is not as controlled as the cross compilers.
#
my %NativeCompilers = (
    'Linux i386'       => 'linux_i386',
    );

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

ToolsetInit();

sub ToolsetInit
{
    my( $GCCTarget, @GCCToolchain, $GCCRoot, $GCCBin, $GCCAr );
    my( $arg_alias, $tools_found );

#.. Toolset configuration
#
    $::ScmToolsetVersion = "1.0.0";             # our version
    $::ScmToolsetGenerate = 0;                  # GEN generate optional
    $::ScmToolsetIFLAG3 = 1;                    # IFLAG3 supported
    $::ScmToolsetCompilerPath = 1;              # Exports Compiler path to makefile via SCM_COMPILERPATH

#.. Standard.rul requirements
#
    $::s = "asm";
    $::o = "o";
    $::so = "so";
    $::a = "a";
    $::exe = "";

#.. Parse arguments
#
    foreach $_ ( @::ScmToolsetArgs ) {
        if (/^--Target=(.*)/) {                 # OS Version
            $GCCTarget = "$1";

        } elsif (/^--CrossAlias=(.*)/) {        # CrossCompiler target-alias
            $arg_alias = $1;

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

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

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

    Error ("TOOLSET/gcc - Target undefined" )
        unless ($GCCTarget);

#.. Cross compile support
#
#   Toolchain=root,[bin]
#
    if ( $arg_alias )
    {
        if ( exists $ToolsetConfig{ $arg_alias } )
        {
            @GCCToolchain = @{$ToolsetConfig{ $arg_alias }};
            $tools_found = (-d $GCCToolchain[0]);
            Warning ("gcc toolset: CrossPlatform toolchain not found for: $arg_alias",
                     "Path: $GCCToolchain[0]" ) unless $tools_found;
        }
        else
        {
            Error("gcc toolset: CrossPlatform Alias not configured: $arg_alias");
        }
    }

    #
    #   If no Cross compiler toolchain is found (preferred method), then attempt
    #   to match a native compiler. Only known targets allow a native build
    #
    unless ( $tools_found )
    {
        if ( exists ( $NativeCompilers{$GCCTarget} ))
        {
            if ( $NativeCompilers{$GCCTarget} eq $::GBE_MACHTYPE )
            {
                $tools_found = 1;
                @GCCToolchain = ();
            }
        }
    }

    #
    #   Must have a toolset by now, either a cross compiler or Native
    #
    Error ("gcc toolset: Toolchain not found for: $GCCTarget" )
        unless ( $tools_found );


    if ( @GCCToolchain )
    {
        #
        #   Parse GCCToolchain. Potentially three parts
        #   [0] - GCCRoot - Location to find the effective /usr/include directory
        #   [1] - GCCBin  - Path to the gcc executable
        #                   If relative, then its relative to GCCRoot
        #   [2] - GCCAr   - Path to the ar executable
        #                   If relative, then its relative to GCCRoot
        #                   If not defined then its the same as GCCBin with gcc replaced with ar
        #
        $GCCRoot = $GCCToolchain[0];

        #   GCC_CC definition
        #
        if ( $GCCToolchain[1] )
        {                                           # user specification
            if ( substr($GCCToolchain[1],0,1) ne "/") {
                $GCCBin = $GCCToolchain[0].'/'.$GCCToolchain[1];
            } else {
                $GCCBin = $GCCToolchain[1];         # abs path
            }
        }
        else
        {                                           # default
            $GCCBin = $GCCToolchain[0] . '/bin/gcc';
        }

        #   GCC_AR definition
        #
        if ( defined($GCCToolchain[2]) && $GCCToolchain[2] )
        {                                           # user specification
            if ( substr($GCCToolchain[2],0,1) ne "/") {
                $GCCAr = $GCCToolchain[0].'/'.$GCCToolchain[2];
            } else {
                $GCCAr = $GCCToolchain[2];          # abs path
            }
        } 
        else 
        {                                           # default, base on GCCBin
            $GCCAr = substr($GCCBin,0,length($GCCBin)-3)."ar";
        }
    }
    else
    {
        $GCCRoot = "/usr";
        $GCCBin = "gcc";
        $GCCAr = "ar";
    }

#.. Define GCC environment
#
    PlatformDefine( "
#################################################
# GCC toolchain definitions 
#
#..");
    PlatformDefine( "GCC_TARGET\t".     ":=$GCCTarget" );
    PlatformDefine( "GCC_ROOT\t".       ":=$GCCRoot" );
    PlatformDefine( "GCC_CC\t\t".       ":=$GCCBin" );
    PlatformDefine( "GCC_AR\t\t".       ":=$GCCAr" );
    PlatformDefine( "" );

    #
    #   Required since this toolset advertises: ScmToolsetCompilerPath
    #
    PlatformDefine( "SCM_COMPILERPATH\t\t".       ":=$GCCBin" );


#.. Piece the world together
#
    Init( "gcc" );
    ToolsetDefines( "gcc.def" );
    ToolsetRules( "gcc.rul" );
    ToolsetRules( "standard.rul" );

#   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
        #
        'staticprogs'        => { 'STATIC_PROGS' , '1' },      # Progams link staticlly
        'no_staticprogs'     => { 'STATIC_PROGS' , undef },    # Default
    );

    #
    #   Set default options
    #
    $::ScmCompilerOpts{'STATIC_PROGS'} = undef;
}


###############################################################################
#   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
{
    my( $source, $obj, $pArgs ) = @_;
    my( $cflags, $file ) = "";

    foreach $_ ( @$pArgs ) {
        if (/--Shared$/) {                      # Building a 'shared' object
            $cflags  = "$cflags \$(SHCFLAGS)";
        } else {
            Message( "CC: unknown option $_ -- ignored\n" );
        }
    }
                   
    MakePrint( "\n\t\$(CC)\n" );
    if ( $cflags )
    {                                           # object specific CFLAGS
        MakePadded( 4, "\$(OBJDIR)/$obj.$::o:" );
        MakePrint( "\tCFLAGS +=$cflags\n" );
    }

    $file = StripExt( $obj );                   # Metric working file
    ToolsetGenerate( "\$(OBJDIR)/$file.met" );
}


###############################################################################
#   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
{
    my( $source, $obj, $pArgs ) = @_;
    my( $cflags, $file ) = "";

    foreach $_ ( @$pArgs ) {
        if (/--Shared$/) {                      # Building a 'shared' object
            $cflags  = "$cflags \$(SHCXXFLAGS)";
        } else {
            Message( "CXX: unknown option $_ -- ignored\n" );
        }
    }
                   
    MakePrint( "\n\t\$(CXX)\n" );
    if ( $cflags )
    {                                           # object specific CFLAGS
        MakePadded( 4, "\$(OBJDIR)/$obj.$::o:" );
        MakePrint( "\tCXXFLAGS +=$cflags\n" );
    }

    $file = StripExt( $obj );                   # Metric working file
    ToolsetGenerate( "\$(OBJDIR)/$file.met" );
}


###############################################################################
#   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() handles both CC and CXX source
}


###############################################################################
#   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:
#       n/a
#
#   Output:
#       $(BINDIR)/name$.${a}:   .... ]
#           $(AR)
#
#       name_ld += ...  Linker command file
#           :
#
#       name_dp += ...  Dependency list
#           :
#
###############################################################################

sub ToolsetAR
{
    my( $name, $pArgs, $pObjs ) = @_;

#.. Parse arguments
#
    foreach $_ ( @$pArgs )
    {
        Message( "AR: unknown option $_ -- ignored\n" );
    }

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

    MakeEntry( "\$(LIBDIR)/$name\$(GBE_TYPE).$::a:\t",
        "", "\\\n\t\t", ".$::o", @$pObjs );

#.. Build library rule (just append to standard rule)
#
    MakePrint( "\n\t\$(AR)\n\n" );
}


###############################################################################
#   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
{
    MakePrint( "\n\t\$(ARMERGE)\n\n" );
}


###############################################################################
#   ToolsetSHLD( $name, \@args, \@objs, \@libraries )
#       This subroutine takes the user options and builds the rules
#       required to link the program 'name'.
#
#   Arguments:
#   n/a
#
#   Output:
#       $(LIBDIR)/name:     $(LIBDIR)/shared
#           ln -s $shared $name
#
#       $(LIBDIR)/name.dep: $(GBE_OBJDIR)
#       $(LIBDIR)/name.dep: $(GBE_LIBDIR)
#       $(LIBDIR)/name.dep: $(GBE_PLATFORM).mk
#           $(SHLDDEPEND)
#
#       $(LIBDIR)/shared:   SHNAME=name
#       $(LIBDIR)/shared:   SHBASE=base
#       $(LIBDIR)/shared:   $(LIBDIR)/name.dep  \
#           $(OBJECTS)
#                           
#       ifneq "$(findstring $(IFLAG),23)" ""
#       -include            "$(LIBDIR)/name.dep"
#       endif
#
#       name_ld += ...
#           :
#
###############################################################################

sub ToolsetSHLD
{
    my( $name, $pArgs, $pObjs, $pLibs ) = @_;
    my( $shared, $def, $def_pref, $multi_scan );

#.. Parse arguments
#
    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);
            $def_pref = '';
            if ( $1 =~ m~\.def$~ ) {
                $def_pref = '--version-script='; # Old def file
            }
        } elsif ( /^--MultiScan/i ) {
            $multi_scan = 1;

        } elsif ( /^--NoMultiScan/i ) {
            $multi_scan = 0;

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

#.. Full name of shared library
#
    $shared = "$name\$(GBE_TYPE).$::so.$::SHLIB_VER{ $name }";

#.. Install and package the shared libraries that are generated
#
    PackageShlibAddFiles( $name, "\$(LIBDIR)/${name}\$(GBE_TYPE).$::so" );
    PackageShlibAddFiles( $name, "\$(LIBDIR)/$shared" );

#.. Cleanup rules
#
#   dep     Dependency file
#   map     Map file
#   ln      Link from LIBDIR to BINDIR
#
    ToolsetProg( "\$(LIBDIR)/${name}.dep" );
    ToolsetProg( "\$(LIBDIR)/${name}.map" );
    ToolsetProg( "\$(LIBDIR)/${shared}" );
    ToolsetProg( "\$(BINDIR)/${shared}" );

#.. Build rules
#
#   name        Base name
#   shared      Library name, includes GBE_TYPE specification
#
    my ($io) = ToolsetPrinter::New();

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

    $io->Prt( "\$(LIBDIR)/${name}\$(GBE_TYPE).$::so:\t\\\n" .
              "\t\t\$(GBE_BINDIR)\\\n" .
              "\t\t\$(LIBDIR)/${shared}\n" .
              "\t\@(rm -f \$@; ln -s ./$shared \$@)\n" .
              "\t\@(rm -f \$(BINDIR)/$shared; ln -s ../\$(LIBDIR)/$shared \$(BINDIR)/$shared)\n\n" );

    $io->SHLDDEPEND($name, $name, $shared);     # std SHLDDEPEND rules

    $io->Prt( "\$(LIBDIR)/${shared}:\tSHBASE=${name}\n" );
    $io->Prt( "\$(LIBDIR)/${shared}:\tSHNAME=${shared}\n" );
    $io->Entry( "\$(LIBDIR)/${shared}:\t", "", "\\\n\t\t", ".$::o", @$pObjs );
    $io->Prt( "\\\n\t\t$def" ) if($def);
    $io->Prt( "\\\n\t\t\$(LIBDIR)/${name}.dep\n" );
    $io->Prt( "\t\$(SHLD)\n\n" );


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

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

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

    ToolsetLibStd( $pLibs );                    # push standard libraries

    $io->Cmd( "-Wl,$def_pref$def" ) if ($def);

    $io->Cmd( "-Wl,--start-group" ) if ($multi_scan);
    $io->LibList( $name, $pLibs, \&ToolsetLibRecipe );
    $io->Cmd( "-Wl,--end-group" ) if ($multi_scan);

    $io->Newline();

#.. Dependency link,
#
#       Now piece together a variable $(name_dp) which ends up in
#       the command file building the application dependency list.
#
    $io->SetTag( "${name}_shdp" );              # command tag
    $io->SetTerm();

    $io->DepRules( $name, $pLibs,               # library depends rules
        \&ToolsetLibRecipe, "$shared" );

    $io->Newline();
}


###############################################################################
#   ToolsetLD( $name, \@args, \@objs, \@libraries )
#       This subroutine takes the user options and builds the rules
#       required to link the program 'name'.
#
#   Arguments:
#       n/a
#
#   Output:
#       $(BINDIR)/name:
#                       $(BINDIR)/name.dep
#           $(LD)
#                               
#       $(BINDIR)/name.dep:     $(GBE_BINDIR)
#       $(BINDIR)/name.dep:     $(GBE_PLATFORM).mk
#               $(LDDEPEND)
#
#       ifeq "$(IFLAG)" "3"
#       -include        "$(BINDIR)/name.dep"
#       endif
#
#       name_ld += ...
#           :
#
###############################################################################

sub ToolsetLD
{
    my( $name, $pArgs, $pObjs, $pLibs ) = @_;
    my $static = $::ScmCompilerOpts{'STATIC_PROGS'};
    my $multi_scan;

#.. Parse arguments
#
    foreach $_ ( @$pArgs )
    {
        if ( m/^--Static$/ ) {
            $static = 1;

        } elsif ( m/^--Shared/ ) {
            $static = 0;

        } elsif ( /^--MultiScan/i ) {
            $multi_scan = 1;

        } elsif ( /^--NoMultiScan/i ) {
            $multi_scan = 0;

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

#.. Cleanup rules
#
    ToolsetProg( "\$(BINDIR)/${name}.ld" );
    ToolsetProg( "\$(BINDIR)/${name}.dep" );
    ToolsetProg( "\$(BINDIR)/${name}.map" );

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

    $io->Prt( "\\\n\t\t\$(BINDIR)/${name}.dep\n" .
              "\t\$(LD)\n\n" );
    $io->LDDEPEND( $name );                     # standard LDDEPEND rules
    $io->Newline();

#.. Linker command file
#
#       Now the fun part... piecing together a variable $(name_ld)
#       which ends up in the command file.
#
    $io->SetTag( "${name}_ld" );                # macro tag
    $io->SetTerm( "\n" );

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

    $io->Cmd( "-static" ) if ($static);         # Link as a static program

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

    ToolsetLibStd( $pLibs );                    # push standard libraries

                                                # library list
    $io->Cmd( "-Wl,--start-group" ) if ($multi_scan);
    $io->LibList( $name, $pLibs, \&ToolsetLibRecipe );
    $io->Cmd( "-Wl,--end-group" ) if ($multi_scan);

    $io->Newline();

#.. Dependency link,
#
#       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->SetTerm();

    $io->DepRules( $name, $pLibs,               # library depends rules
        \&ToolsetLibRecipe, "\$(BINDIR)/${name}" );

    $io->Newline();
}


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

sub ToolsetLibStd
{
}


########################################################################
#
#   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( "\$(strip $obj).$::o" );
}


###############################################################################
#
#   Parse a linker lib list
#   This is a helper function used within this toolset
#
#   Arguments:
#       $target     Name of the target
#
#       $lib        Library specification
#
#       $tag        Tag (user specified)
#
#       $dp         If building a depend list, the full target name.
#
###############################################################################

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

    if ( ! defined($dp) ) {                     # linker
        $lib =~ s/^lib//;                       # .. remove leading 'lib'
        $io->Cmd( "-l$lib" );
    
    } else {                                    # depend
        $io->Cmd( "$dp:\t@(vlib2,$lib,GCC_LIB)" );

    }
}

#.. Successful termination
1;