Subversion Repositories DevTools

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
# -*- mode: perl; tabs: 8; indent-width: 4; show-tabs: yes; -*-
2
# Copyright 1995-2004 ERG Transit Systems, All Rights Reserved
3
#
4
# Module name   : buildlib.pl
5
# Module type   : Makefile system
6
# Compiler(s)   : ANSI C
7
# Environment(s): n/a
8
#
9
# Description:
10
#       This is the standard bootstrap script for sandboxs.
11
#
12
# Notes:
13
#
14
#                       *** DO NOT DETAB ***
15
#
16
#       Beware the use of space v's tab characters within the
17
#       makefile generation sessions.
18
#
19
#.........................................................................
20
#
21
 
22
use strict;
23
use warnings;
24
 
25
use BuildVersion;
26
use BuildName;
27
use PackageEntry;
28
use JatsEnv;
29
use JatsSystem;
30
use JatsVersionUtils;
31
use FileUtils;
32
use Pod::Usage;
261 dpurdie 33
use Getopt::Long;
227 dpurdie 34
 
35
our $BuildVersion           = "2.1.0";
36
 
37
#.. Switchs
38
#
39
our $ScmBuildlib            = 0;
40
our $ScmBuildSrc            = "";
41
 
42
our $CmdSwitch              = "";
43
our $CmdParm                = "";
44
our $Clobber                = 0;
45
our $Archive                = 0;
46
our $Interface              = 0;
47
our $RootOnly               = 0;
48
our $Perms                  = 0;
49
our $Expert                 = 0;
50
our $All                    = 0;
51
our $Nolog                  = 0;
52
our $Cache                  = 0;
53
our $FullJats               = 0;
261 dpurdie 54
our $NoPackageError         = 0;
227 dpurdie 55
our $ForceBuildPkg          = 0;
56
our $Srcdir                 = "";               # default source root
57
 
58
#.. Public symbols, referenced by many build.pl implementations
59
#
60
our $BUILDPREVIOUSVERSION   = "0.0.0";          # BuildPreviousVersion()
61
our @BUILDPLATFORMS         = ();               # BuildPlatforms()
62
our %BUILDINFO              = ();               # BuildInfo
63
our @DEFBUILDPLATFORMS      = ();
64
our %BUILDPLATFORMARGS      = ();
65
our @BUILD_ACTIVEPLATFORMS  = ();
66
our @BUILDSUBDIRS           = ();               # BuildSubDir()
67
our @BUILDSETENV            = ();               # BuildSetenv()
68
our $BUILDINTERFACE         = "";               # BuildInterface()
69
our $BUILDLOCAL             = "";               # BuildInterface()
70
our $BUILDDIRTREE           = "";               # BuildDirTree()
71
our $BUILDLPA_CLEAN_DONE    = 0;                # LinkPkgArchive initialisation done
241 dpurdie 72
our @BUILD_BADNAME          = ();               # Unknown platforms
227 dpurdie 73
 
74
our $BUILDNAME              = "";               # BuildName()
75
our $BUILDVERSION           = "";               # BuildName()
76
our $BUILDNAME_PACKAGE;                         # Name
77
our $BUILDNAME_VERSION;                         # Version
78
our $BUILDNAME_PROJECT;                         # Project(optional)
79
our $DEPLOY_PATCH           = 0;                # Deplyment patch number
80
 
81
our %BUILDALIAS_DELAY       = ();               # Delayed aliases
82
our %BUILDALIAS_TARGETS     = ();               # BuildAlias from --Targets
83
our %BUILDALIAS             = ();               # BuildAlias
84
our %BUILDPRODUCT           = ();               # BuildProduct
85
our %BUILDPRODUCT_PARTS     = ();               # BuildProduct parts
86
our %PKGRULES               = ();               # Package include and link rules
87
our @BUILDTOOLS             = ();               # Extended tool path
88
our $BUILDPHASE             = 0;                # In Build Phase
89
our @CLOBBERDIRS            = ();               # Directories to clobber
90
our @CLOBBERFILES           = ();               # Files to clobber
247 dpurdie 91
our %BUILD_KNOWNFILES       = ();               # Files that will be known
227 dpurdie 92
 
93
our $Makelib                = "";
94
 
263 dpurdie 95
our $GBE_CORE;                                  # Root of JATS
96
our $MAKELIB_PL;                                # Name of the makelib file
97
our $InterfaceVersion;                          # Interface directory format version
98
our $ScmInterface;                              # Interface directory
227 dpurdie 99
 
263 dpurdie 100
 
101
 
227 dpurdie 102
my  $DeleteDPACKAGE         = 0;                # Must clobber DPACKAGE
103
my  $opt_help               = 0;
104
 
105
BuildLibInit();
106
 
107
sub BuildLibInit
108
{
109
 
110
#.. Set environment
111
#
112
    EnvImport( "GBE_VERSION" );
113
    EnvImport( "GBE_BIN" );
114
    EnvImport( "GBE_CORE" );
115
    EnvImport( "GBE_PERL" );
116
    EnvImport( "GBE_TOOLS" );
117
    EnvImport( "GBE_CONFIG" );
118
    EnvImport( "GBE_DPKG" );
119
    EnvImport( "GBE_MACHTYPE" );
120
    EnvImport( "USER" );
121
    EnvImport( "GBE_DRV" )
122
        if ( $ScmHost ne "Unix" );            # DOS or WIN special
123
 
124
    EnvImportOptional ( 'GBE_DPKG_STORE','' );
125
    EnvImportOptional ( 'GBE_DPKG_CACHE','' );
126
    EnvImportOptional ( 'GBE_DPKG_LOCAL','' );
127
    EnvImportOptional ( 'GBE_DPKG_SBOX' ,'' );
128
 
129
    EnvImportOptional ( 'GBE_PLATFORM' );           # optional PLATFORM filter
130
    EnvImportOptional ( 'GBE_BUILDFILTER' );        # optional BUILD filter       
131
    EnvImportOptional ( 'GBE_ABT' );                # optional ABT flags          
132
 
133
#.. Common stuff
134
#
135
    require "$::GBE_TOOLS/common.pl";
136
    CommonInit( "buildlib" );
137
    Debug( "Version:   $BuildVersion" );
138
 
139
#.. Parse command line
140
#
141
    $ScmBuildSrc = $0;                          # Name of the build file
142
    ($Cwd, $Makelib) = @ARGV;
143
    $Cwd =~ tr~\\/~/~s;;                        # Need / in path, Remove doubles
144
 
145
    Debug( "Host:      $ScmHost" );
146
    Debug( "Cwd:       $Cwd" );
147
    Debug( "Makelib:   $Makelib" );
148
    Debug( "BuildFile: $ScmBuildSrc" );
149
 
261 dpurdie 150
    Verbose ("Command Line: @ARGV");
151
    my $result = GetOptions (
263 dpurdie 152
                "help|h:+"      => \$opt_help,
153
                "man:3"         => \$opt_help,
261 dpurdie 154
                "debug:+"       => \$::ScmDebug,
155
                "verbose:+"     => \$::ScmVerbose,
156
                "expert:1"      => \$Expert,
157
                "all"           => \$All,
158
                "nolog"         => \$Nolog,
159
                "cache+"        => \$Cache,
160
                "project"       => \$FullJats,
161
                "package"       => \$NoPackageError,
162
                "forcebuildpkg" => \$ForceBuildPkg,
163
                );
164
    Usage() if ( $opt_help || !$result );
227 dpurdie 165
 
261 dpurdie 166
    Debug( "Debug:          $::ScmDebug" );
167
    Debug( "Verbose:        $::ScmVerbose" );
168
    Debug( "Expert:        $Expert" );
169
    Debug( "All:           $All" );
170
    Debug( "Nolog:         $Nolog" );
171
    Debug( "Cache:         $Cache" );
172
    Debug( "project:       $FullJats" );
173
    Debug( "package:       $NoPackageError" );
174
    Debug( "Force  :       $ForceBuildPkg" );
227 dpurdie 175
 
176
#.. Command
177
#
261 dpurdie 178
    my $argc = 2;
227 dpurdie 179
    $CmdSwitch = $ARGV[ $argc++ ] if ($argc <= $#ARGV);
180
    $CmdParm = $ARGV[ $argc++ ] if ($argc <= $#ARGV);
181
 
182
    Debug( "CmdSwitch: $CmdSwitch" );
183
    Debug( "CmdParm:   $CmdParm" );
184
 
185
    if ( $argc <= $#ARGV && $ARGV[ $argc ] ne "" ) {
186
        Usage( "(E) unexpected argument \"$ARGV[ $argc ]\"" );
187
    }
188
 
189
    if ( $CmdSwitch eq "interface" ) {
190
        $Interface      = 1;
191
 
192
    } elsif ( $CmdSwitch eq "rootonly" ) {
193
        $RootOnly       = 1;
194
 
195
    } elsif ( $CmdSwitch eq "clobber" ) {
196
        $Clobber        = 1;
197
 
198
    } elsif ( $CmdSwitch eq "help" || $CmdSwitch eq "usage" ) {
199
        $opt_help = 1;
200
        Usage();
201
 
202
    } elsif ( $CmdSwitch eq "changelog" ) {
203
        if ( -d "CVS" )                         # CVS support subdir
204
        {
205
            System( "$::GBE_PERL $::GBE_TOOLS/cvs2cl.pl --tags --branches --revisions --day-of-week" )
206
        }
207
        exit(1);
208
 
209
    } elsif ( $CmdSwitch ne "" ) {
210
        Usage( "(E) unknown switch \"$CmdSwitch\"" );
211
    }
212
 
213
    #
214
    #   Must inform makelib that its running under buildlib
215
    #
216
    $ScmBuildlib = 1;
217
 
218
    #
219
    #   In clobber mode System commands will not force termination
220
    #   otherwise, within build.pl, a failed system command will die.
221
    #
222
    SystemConfig ('UseShell' => 1,
223
                  'ExitOnError' => ($Clobber eq 0) );
224
}
225
 
226
 
227
#-------------------------------------------------------------------------------
228
# Function        : Log
229
#
230
# Description     : Internal function to generate a log file of the build process
231
#                   The function will print its argumenst tot he screen and a log file
232
#
233
# Inputs          : Arguments will be printed
234
#
235
# Returns         : Nothing
236
#
237
sub Log
238
{
239
    if ( ! $Clobber )
240
    {
261 dpurdie 241
        print "@_\n";
242
        FileAppend ('build.log', \@_ );
227 dpurdie 243
    }
244
}
245
 
246
#-------------------------------------------------------------------------------
247
# Function        : BuildSubDir
248
#
249
# Description     : Specify one or more directories in which makefile.pl's can be
250
#                   found to be processed.
251
#
252
#                   This function will flag the build 'src' dir.
253
#                   This will be the first directory specified UNLESS there
254
#                   is a 'src' directory in the list
255
#
256
#                   The function may be called multiple times.
257
#
258
# Inputs          : NewDirs             - An array of directories
259
#
260
# Returns         : Nothing
261
#
262
 
263
sub BuildSubDir
264
{
265
    my( @NewDirs );
266
 
267
    @NewDirs = map { split /\s+/ } @_;
268
    @NewDirs = grep { defined $_ } @NewDirs;
269
 
270
    Debug( "BuildSubDir(@NewDirs)" );
271
 
272
    foreach my $ThisDir ( @NewDirs )
273
    {
274
        unless ( $Clobber )
275
        {
276
            if ( $ThisDir eq "." )
277
            {
278
                Error( "BuildSubDir() cannot specify the current directory (.)",
279
                       "The makefile.pl in the root directory is included in all makefile.pl's" );
280
            }
281
 
282
            if ( $ThisDir =~ m~\\~)
283
            {
284
                Warning ("BuildSubDir contains a '\\' character: $ThisDir" );
285
            }
286
            if ( grep /^$ThisDir$/, @BUILDSUBDIRS )
287
            {
288
                Warning( "BuildSubDir() duplicate subdirectory ignored '$ThisDir'." );
289
                next;
290
            }
291
            if ( ! ( -e $ThisDir and -d $ThisDir ) )
292
            {
293
                Error( "BuildSubDir() non-existent subdirectory: '$ThisDir'." );
294
            }
295
            if ( ! -f $ThisDir . '/makefile.pl' )
296
            {
297
                Error( "BuildSubDir() makefile.pl not found in subdirectory: '$ThisDir'." );
298
            }
299
 
300
            push( @BUILDSUBDIRS, $ThisDir );
301
        }
302
 
303
        #
304
        #   Capture the first source directory mentioned
305
        #   This will be used as the root of the build
306
        #
307
        #   If there is a Src directory then use this
308
        #
309
        $Srcdir = $ThisDir
310
            if ( $ThisDir =~ m/^src$/i );
311
        $Srcdir = $ThisDir
312
            unless ( $Srcdir );
313
    }
314
}
315
 
316
#-------------------------------------------------------------------------------
317
# Function        : BuildAlias
318
#
319
# Description     : Create an alias for multiple targets
320
#                   The default operations will:
321
#                       Add the alias as a default platform (* in the makefile.pl)
322
#                       Perform an implicit BuildPlatform for the alias targets
323
#
324
#                   In hindsight this was not good. Options modify the behaviour
325
#                   Options:
326
#                       --NotDefault    The alias will not be a part of the default
327
#                                       platform for the makefile.pls
328
#                       --Define        Simply define text substitution
329
#                                       Do not implicitly create platforms
330
#                       --Target        Accumulate platforms with specified targets
331
#                                       Complete alias determination is delayed
332
#                                       The named targets are specified as an alias
333
#                                       until the calculation is done
334
#
335
# Inputs          : alias[,--options]   comma seperated options
336
#                   arguments           alias arguments; platforms or targets
337
#
338
# Returns         : Nothing
339
#
340
sub BuildAlias
341
{
342
    my( $alias, @arguments ) = @_;
343
    my $notdefault;
344
    my $define;
345
    my $target_mode;
346
 
347
    Debug( "BuildAlias($alias, @arguments)" );
348
    Error ("BuildAlias: No platforms specified") unless ( @arguments );
349
    Error( "BuildAlias() must appear before BuildName()..." ) if ( $BUILDNAME );
350
 
351
    #   Parse attributes
352
    #
353
    my ( @attrs ) = split( ',', $alias );
354
 
355
    $alias = "";
356
    foreach ( @attrs ) {
357
        if ( /^--/ ) {
358
            if ( /^--NotDefault$/ ) {
359
                $notdefault = 1;
360
 
361
            } elsif ( /^--Define$/ ) {
362
                $define = 1;
363
 
364
            } elsif ( /^--Target$/ ) {
365
                $target_mode = 1;
366
 
367
            } else {
368
                Warning( "BuildAlias() unknown attribute: $_ -- ignored" );
369
            }
370
 
371
        } else {
372
            Error( "BuildAlias() multiple alias specifications -- ignored" )
373
                if ( $alias ne "" );
374
            $alias = $_;
375
        }
376
    }
377
    Error( "BuildAlias() missing alias specifications" )
378
        if ( $alias eq "" );
379
 
380
 
381
    #
382
    #   If we need to recalculate the alias based on targets, then tag the alias
383
    #   to be processed
384
    #
385
    $BUILDALIAS_TARGETS{ $alias } = ''
386
        if ( $target_mode );
387
 
388
    #   Define alias
389
    #
390
    if ( $alias eq "GENERIC" )
391
    {
392
        Error( "BuildAlias() cannot create a alias named GENERIC" );
393
    }
394
    elsif ( $alias ne quotemeta( $alias ) )
395
    {
396
        Warning( "BuildAlias() alias '$alias' contains invalid characters -- ignored" );
397
    }
398
    elsif ( $BUILDALIAS{ $alias } )
399
    {
400
        Warning( "BuildAlias() duplicate alias '$alias' -- alias ignored" );
401
    }
402
    else
403
    {
404
        #
405
        #   Expand alias UNLESS using --Target.
406
        #   The --Target is a real target and not a subject to alias expansion
407
        #   This solves order dependancy problems.
408
        #
409
        @arguments = ExpandPlatforms( @arguments )
410
            unless $target_mode;
411
 
412
        my $platform = "";                   # current platform
413
        my @pargs = ();                      # current args
414
 
415
        #
416
        #   Process the expanded arguments
417
        #   Collect arguments and process when a new platform is discovered
418
        #
419
        foreach my $arg ( @arguments, '++' )
420
        {
421
            if ( $arg =~ /^--/ )
422
            {
423
                push @pargs, $arg;
424
                next;
425
            }
426
            else
427
            {
428
                #
429
                #   Start of a platform
430
                #   Process previous data, once a platform has been seen
431
                #
432
                if ( $platform )
433
                {
434
                    #   Add arguments to BUILDALIAS as we see them
435
                    #
436
                    HashJoin( \%BUILDALIAS, ' ', $alias, $platform );
437
                    HashJoin( \%BUILDALIAS, ' ', $alias, grep(!/^--Uses=/, @pargs) );
438
 
439
                    #
440
                    #   The BuildAlias can also define a platform.
441
                    #   (Sounded like a good idea at the time!)
442
                    #
443
                    unless ( $define || $target_mode )
444
                    {
445
                        push @pargs, '--NotDefault' if ( $notdefault );
446
                        push @pargs, '--FunctionName=BuildAlias';
447
                        BuildPlatforms( $platform, @pargs );
448
                    }
449
                }
450
 
451
                #
452
                #   Start collecting args for the next platform
453
                #
454
                @pargs = ();
455
                $platform = $arg;
456
            }
457
        }
458
    }
459
}
460
 
461
 
462
#-------------------------------------------------------------------------------
463
# Function        : Process_TargetAlias
464
#
465
# Description     : Post Process the --Target option for the build alias
466
#                   Filter all platforms and extract those with a matching targets
467
#
468
# Inputs          : None
469
#
470
# Returns         : Nothing
471
#
472
sub Process_TargetAlias
473
{
474
 
475
    #
476
    #   Merge any delayed aliases with the complete set of alias
477
    #   Delayed alias are not used in expansions during the processing
478
    #   of platforms and targets, but can be used to pick up
479
    #
480
    while ( my($key,$value) = each(%BUILDALIAS_DELAY) )
481
    {
482
        if ( exists($BUILDALIAS{$key}) )
483
        {
484
            Warning( "BuildAlias() duplicates internal alias '$key' -- internal alias ignored" );
485
            next;
486
        }
487
        $BUILDALIAS{$key} = $value;
488
    }
489
 
490
    foreach my $alias ( keys %BUILDALIAS_TARGETS )
491
    {
492
        Debug( "BuildTargetAlias($alias)" );
493
 
494
        #
495
        #   Replace the existing alias - it has done its JOB
496
        #
497
        my $arguments = delete $BUILDALIAS{ $alias } ;
498
 
499
        foreach my $arg ( split / /, $arguments )
500
        {
501
            if ( $arg =~ /^--/ )                # argument
502
            {
503
                #   Add arguments to BUILDALIAS as we see them
504
                #
505
                HashJoin( \%BUILDALIAS, ' ', $alias, $arg );
506
                next;
507
            }
508
 
509
            foreach my $platform ( keys %BUILDINFO )
510
            {
511
                foreach my $element ( qw (TARGET BASE ) )
512
                {
513
                    my $target = $BUILDINFO{$platform}{$element};
514
                    if ( $target && $target eq $arg )
515
                    {
516
                        HashUniqueJoin( \%BUILDALIAS, ' ', $alias, $platform );
517
                        Debug( "BuildTargetAlias: $alias, $target -> $platform" );
518
                    }
519
                }
520
            }
521
        }
522
    }
523
}
524
 
525
#-------------------------------------------------------------------------------
526
# Function        : BuildProduct
527
#
528
# Description     : Create a family of Platforms with a common product line
529
#                   ie: Create two flavors of the TP5, one based on the MOSF and
530
#                   the othe based on the MOS68 toolset.
531
#
532
# Inputs          : $product[,opts]+    The name of the product
533
#                                       This will be the base name for the family
534
#                                       Allowed options are:
535
#                                           --NotDefault    : This is not a default build platform
536
#                                           --Uses=xxx      : All use another platform
537
#
538
#                   platforms           One or more root platforms, with options
539
#                                       The platform is macro expanded.
540
#                                       Options may be a part of the platform or
541
#                                       distinct.
542
#
543
# Returns         :
544
#
545
 
546
sub BuildProduct
547
{
548
    my( $product, @arguments ) = @_;
549
    my $notdefault = 0;
550
    my @uses = ();
551
 
552
    Debug( "BuildProduct($product, @arguments)" );
553
    Error( "BuildProduct must appear before BuildName()..." )
554
        if ( $BUILDNAME ne "" );
555
 
556
    #   Parse attributes
557
    #
558
    my( @attrs ) = split( ',', $product );
559
 
560
    $product = "";
561
    foreach ( @attrs ) {
562
        if ( /^--/ ) {
563
            if ( /^--NotDefault$/ ) {
564
                $notdefault++;
565
 
566
            } elsif ( /^--Uses=(.*)/ ) {
567
                UniquePush (\@uses, $1);
568
 
569
            } else {
570
                Warning( "BuildProduct() unknown attribute: $_ -- ignored" );
571
            }
572
 
573
        } else {
574
            Error( "BuildProduct() multiple product specifications not allowed" )
575
                if ( $product ne "" );
576
            $product = $_;
577
        }
578
    }
579
 
580
    #
581
    #   Sanity test
582
    #
583
    Error( "BuildProduct() missing product specifications" )
584
        if ( $product eq "" );
585
 
586
    Error( "BuildProduct() product '$product' contains invalid characters" )
587
        if ( $product ne quotemeta( $product ) );
588
 
589
    Error( "BuildProduct() duplicate product '$product'" )
590
        if ( $BUILDPRODUCT{ $product } );
591
 
592
    Error( "BuildProduct() duplicate alias '$product'" )
593
        if ( $BUILDALIAS{ $product } );
594
 
595
    #
596
    #   Expand the user specified targets to allow the use of BuildAlias
597
    #   The (bad) side effect of this is that target options get reorganised
598
    #       PLATFORM,--Uses=ANOTHER  ==> PLATFORM --Uses=ANOTHER
599
    #
600
    #   Insert markers(++) into @aruments to mark when to process collected data
601
    #   Insert before each PLATFORM and at the end of the list
602
    #   platform specifier or the end of the list. Scan the arguments
603
    #
604
    @arguments = ExpandPlatforms( @arguments );
605
    my @new_args;
606
    foreach  ( @arguments )
607
    {
608
        push (@new_args, '++') unless ( m/^--/ );
609
        push (@new_args, $_ );
610
    }
611
    push (@new_args, '++');
612
    shift @new_args if $new_args[0] eq '++';
613
 
614
    my @targs = ();
615
    my $target;
616
    my @tuses = @uses;
617
    foreach my $arg ( @new_args )
618
    {
619
        #
620
        #   Collect per-platform arguments
621
        #
622
        if ( $arg =~ /^--Uses=(.*)/ ) {
623
            UniquePush (\@tuses, $1);
624
            next;
625
 
626
        } elsif ( $arg =~ /^--/ ) {
627
            push @targs, $arg;
628
            next;
629
        }
630
 
631
        #
632
        #   Collect target(platform) name
633
        #
634
        unless ( $arg eq '++' )
635
        {
636
            $target = $arg;
637
            Error( "BuildProduct() cannot create a product based on a GENERIC platform" )
638
                if ( $target eq "GENERIC" );
639
            next;
640
        }
641
 
642
        #
643
        #   Infer a BuildPlatform
644
        #   Do not provide a platform name. This will be created later when the
645
        #   full name is known - or can be calculated.
646
        #
647
        CreateBuildPlatformEntry('BuildProduct', $notdefault, $product, $target, \@tuses, \@targs );
648
 
649
        @targs = ();
650
        @tuses = @uses;
651
        $target = undef;
652
    }
653
}
654
 
655
#-------------------------------------------------------------------------------
656
# Function        : CreateBuildPlatformEntry
657
#
658
# Description     : Internal routine to create the Build Entry
659
#                   Single point to create a platform, whatever one of those is
660
#
661
# Inputs          : $fname                  - Name of invoking directive
662
#                   $notdefault             - True if the platform is not to be added to the
663
#                                             list of default platforms
664
#                   $product                - Optional product name
665
#                   $target                 - Target platform name
666
#                   $pUses                  - Ref to an array of 'Uses'
667
#                   $pArgs                  - Ref to an array of platform arguments
668
#
669
# Returns         :
670
#
671
 
672
my $have_generic;
673
my $have_no_generic;
674
sub CreateBuildPlatformEntry
675
{
676
    my ($fname, $notdefault, $product, $target, $pUses, $pArgs ) = @_;
677
    my %buildentry;
678
    my $platform;
679
 
680
    #
681
    #   Detect GENERIC platform
682
    #       Generic platforms force a build for all
683
    #       Don't mix generic with others
684
    #
685
    if ( $target eq "GENERIC" )
686
    {
687
        $All = 1;
688
        $have_generic = 1;
689
    }
690
    else
691
    {
692
        $have_no_generic = 1;
693
    }
694
    Error("Cannot use a 'GENERIC' platform with any other platform names")
695
        if ( $have_generic && $have_no_generic );
696
 
697
 
698
    #
699
    #   Create a basic BUILDINFO entry
700
    #
701
    $buildentry{FNAME} = $fname;
702
    $buildentry{NOT_DEFAULT} = $notdefault;
703
    $buildentry{PRODUCT} = $product;
704
    $buildentry{TARGET} = $target;
705
    $buildentry{BASE} = $target;
706
    $buildentry{USES} = [ @$pUses ] if $pUses;
707
    $buildentry{ARGS} = [ @$pArgs ] if $pArgs;
708
 
709
    #
710
    #   Allow per-platform processing to be alter the basic information
711
    #   Special processing may be perform to extend the information
712
    #   Allows special processing to be enabled on a per-target basis
713
    #
714
    #   There are three forms of processing that have been allowed for:
715
    #       1) None:        There is not platform specific extension
716
    #       2) Basic:       The extension will add or extend build information
717
    #       3) Advanced:    The extension will generate additional build information
718
    #                       structures.
719
    #
720
 
721
    #
722
    #   Locate the optional PLATFORM configuration file
723
    #   If it does exist then it can alter build-time information
724
    #
725
    if ( my $build_cfg = Require( "$::GBE_CONFIG/PLATFORM", "$target.cfg"  ) )
726
    {
727
        Verbose ("Processing(new) Platform Configuration file: $build_cfg");
728
        my $package_name = "${target}_Build";
729
 
730
        if ( $package_name->can('new_platform') )
731
        {
732
            Verbose ("Processing(new) Platform Configuration: $package_name");
733
            $package_name->new_platform( \%buildentry );
734
        }
735
        else
736
        {
737
            Debug ("Processing(new) Platform Configuration: $package_name. 'new_platform' function not found");
738
        }
739
    }
740
 
741
    #
742
    #   Add the basic entry into the build system, unless its been
743
    #   flagged as a TEMPLATE
744
    #
745
    AddBuildPlatformEntry (\%buildentry )
746
        unless ( $buildentry{TEMPLATE} );
747
}
748
 
749
 
750
#-------------------------------------------------------------------------------
751
# Function        : AddBuildPlatformEntry
752
#
753
# Description     : Internal routine to add a Build Entry into the build system
754
#                   This function MAY be called from the build extensions
755
#
756
#                   NOTES:
757
#                   No processing of the info structure is performed. This MUST
758
#                   have been done before now.
759
#
760
#                   Additional information may be added to the structure.
761
#
762
#
763
# Inputs          : $pInfo              - Reference to a BuildInfo structure
764
#
765
# Returns         : Nothing
766
#
767
sub AddBuildPlatformEntry
768
{
769
    my ($pInfo) = @_;
770
    my $fname = $pInfo->{FNAME};
771
 
772
    #
773
    #   Locate the optional PLATFORM configuration file
774
    #   If it does exist then it can extend build-time information
775
    #
776
    my $target = $pInfo->{TARGET};
241 dpurdie 777
 
243 dpurdie 778
################################################################################
779
#
780
#   Temp remove: 08-Apr-08
781
#   Does not play well with LMOS stuff, as LMOS platforms are defined within
782
#   the LMOS package. This is uggly, but its what we have.
783
#
784
#   Solutions:
785
#       1) Move LMOS magic out of the LMOS package
786
#       2) Have a config file of known targets
787
#          This will limit the auto-expandability of LMOS
788
#       3) Process later
789
#          Change the way the build.pl parser works to do two phases
790
#           a) Collect information from directives
791
#           b) Process the information
792
#          This will solve a number of problems, not only here but elsewhere.
793
#          It will:
794
#               Simplify the handling of clobber
795
#               Remove the need to order the directives
796
#               Simplify processing as all the information
797
#               will be present when the
798
#
799
#    #
800
#    #   Ensure target is known to JATS
801
#    #   Remove unknown targets from the build. Create a list of unknown
802
#    #   targets and report them later.
803
#    #
804
#    unless ( Exists( "$::GBE_CONFIG/PLATFORM", $target  ) )
805
#    {
806
#        $pInfo->{NOT_AVAILABLE} = 1;
807
#        UniquePush (\@BUILD_BADNAME, $target );
808
#    }
809
################################################################################
241 dpurdie 810
 
227 dpurdie 811
    unless ($pInfo->{NOT_AVAILABLE} )
812
    {
813
        if ( my $build_cfg = Require( "$::GBE_CONFIG/PLATFORM", "${target}.cfg"  ) )
814
        {
815
            Verbose ("Processing(add) Platform Configuration file: $build_cfg");
816
            my $package_name = "${target}_Build";
817
 
818
            if ( $package_name->can('add_platform') )
819
            {
820
                Verbose ("Processing(add) Platform Configuration: $package_name");
821
                $package_name->add_platform( $pInfo );
822
            }
823
            else
824
            {
825
                Debug ("Processing(add) Platform Configuration: $package_name. 'add_platform' function not found");
826
            }
827
        }
828
    }
829
 
830
    #
831
    #   If a product name has been provided then the platform is a product
832
    #   and will need additional processing
833
    #
834
    if ( $pInfo->{PRODUCT} )
835
    {
836
        #
837
        #   Create the platform name. Derived from the product and the target
838
        #
839
        $pInfo->{PLATFORM} = $pInfo->{PRODUCT} . '_' . $pInfo->{TARGET};
840
 
841
        #
842
        #   Remember the product name
843
        #
844
        $BUILDPRODUCT{ $pInfo->{PRODUCT} } = 1;
845
 
846
        #
847
        #   Add platform name to the alias explansion being created
848
        #   Allows the user to reference the entire FAMILY of platforms
849
        #
850
        HashJoin( \%BUILDALIAS, ' ', $pInfo->{PRODUCT}, $pInfo->{PLATFORM} );
851
 
852
        #
853
        #   Add arguments to the 'alias' based on the product
854
        #   Ensure they don't make it any further
855
        #
856
        HashJoin( \%BUILDALIAS, ' ', $pInfo->{PRODUCT}, @{$pInfo->{ARGS}} ) if ( $pInfo->{ARGS}  );
857
        $pInfo->{ARGS} = undef;
858
 
859
        #
860
        #   Create an element to assist in creating %ScmBuildProducts
861
        #
862
        $pInfo->{ISPRODUCT} = 1;
863
        $BUILDPRODUCT_PARTS{$pInfo->{PLATFORM}} = "$pInfo->{PRODUCT},$pInfo->{TARGET}";
864
    }
865
    else
866
    {
867
        $pInfo->{PRODUCT} = $pInfo->{TARGET};
868
        $pInfo->{PLATFORM} = $pInfo->{TARGET};
869
    }
870
 
871
    #---------------------------------------------------------------------------
872
    #   All the hard work has been done
873
    #   We now know the platforms full name
874
    #
875
    #   Ensure that the target platform has not been been specified
876
    #   Perhaps this should be an error
877
    #
878
    my $platform = $pInfo->{PLATFORM};
879
 
880
    if ( defined ( $BUILDINFO{$platform}) )
881
    {
882
        Warning( "$fname() duplicate platform '$platform' -- ignored" )
883
            unless $Clobber;
884
        return;
885
    }
886
 
887
    #
888
    #   Add platform (tag) to various lists
889
    #
890
    UniquePush( \@BUILDPLATFORMS, $platform );
891
    UniquePush( \@DEFBUILDPLATFORMS, $platform ) unless ( $pInfo->{NOT_DEFAULT} );
892
 
893
    #
894
    #   Create a simple alias if requested
895
    #   Used if a platform creates multiple entires
896
    #
897
    if ( $pInfo->{ALIAS} )
898
    {
899
        HashJoin( \%BUILDALIAS_DELAY, ' ', $pInfo->{ALIAS}, $platform );
900
    }
901
 
902
    #
903
    #   Create a HARDWARE type alias if requested
904
    #   ie: SOLARIS_SPARC or SOLARIS_X86
905
    #
906
    if ( $pInfo->{HARDWARE} )
907
    {
908
        HashJoin( \%BUILDALIAS_DELAY, ' ',  $pInfo->{BASE} . '_' . $pInfo->{HARDWARE}, $platform );
909
    }
910
 
911
    #
912
    #   Create the 'parts' of the platform. This is a list of unique
913
    #   bits to search. It will consist of:
914
    #       [0]     - platform
915
    #       [1]     - product
916
    #       ...     - Uses bits ...
917
    #       [last]  - target
918
    #
919
    my @parts;
920
    push @parts,    $platform;
921
 
922
    #
923
    #   Include all the product extensions
924
    #
925
    if ( $pInfo->{ISPRODUCT}  )
926
    {
927
        UniquePush (\@parts, map {+ "$pInfo->{PRODUCT}_${_}" } @{$pInfo->{USES}});
928
        UniquePush (\@parts, map {+ "$pInfo->{PRODUCT}_${_}" } @{$pInfo->{ALSO_USES}});
929
        UniquePush (\@parts, $pInfo->{PRODUCT} );
930
    }
931
 
932
    #
933
    #   Add in non-product expanded parts
934
    #
935
    UniquePush (\@parts, @{$pInfo->{EXTRA_USES}});
936
 
937
    #
938
    #   Create a structure to assist in search path resolution
939
    #   The order is important. It sets the include search order for include
940
    #   files and libraries
941
    #   If A uses B then search in A_B, A, B
942
    #       ie: GAK uses MOS68K Search stuff in GAK_MOS68K, GAK, MOS68K
943
    #
944
    #       Usage:  OBFTP uses TP5 on MOSCF(target)       (BuildProduct)
945
    #       Expansion: OBFTP, TP5_MOSCF, TP5
946
    #
947
    #       Usage: VS2003(target) also uses WIN32(uses)     (BuildPlatform)
948
    #       Expansion: VS2003, VS2003_WIN32, WIN32
949
    #
950
    if ( $pInfo->{ISPRODUCT}  )
951
    {
952
        UniquePush (\@parts, map {+ "${_}_$pInfo->{TARGET}", $_, $pInfo->{TARGET}} @{$pInfo->{USES}});
953
        UniquePush (\@parts, map {+ "${_}_$pInfo->{TARGET}", $_, $pInfo->{TARGET}} @{$pInfo->{ALSO_USES}});
954
    }
955
    else
956
    {
957
        UniquePush (\@parts, map {+ "$pInfo->{TARGET}_${_}", $pInfo->{TARGET}, $_} @{$pInfo->{USES}});
958
        UniquePush (\@parts, map {+ "$pInfo->{TARGET}_${_}", $pInfo->{TARGET}, $_} @{$pInfo->{ALSO_USES}});
959
    }
960
 
961
    #
962
    #   Finally - the target
963
    #
964
    UniquePush (\@parts, $pInfo->{TARGET} );
965
 
966
    #
967
    #   Save the PARTS
968
    #   Also saved as BUILDPLATFORM_PARTS for interface with older versions
969
    #   of the deployments scripts.
970
    #
971
    $pInfo->{PARTS} = \@parts;
972
 
973
    #
974
    #   Add any arguments to the platforms argument list
975
    #
976
    PlatformArgument( $platform, @{$pInfo->{ARGS}} ) if ( $pInfo->{ARGS} );
977
 
978
    #
979
    #   Clean up and save
980
    #
981
    delete $pInfo->{TEMPLATE};
982
    delete $pInfo->{FNAME};
983
    $BUILDINFO{$platform} = $pInfo;
984
#    DebugDumpData("BUILDINFO", \%BUILDINFO );
985
}
986
 
987
 
988
sub BuildArgument
989
{
990
    my( $platform, @arguments ) = @_;
991
    my( @platforms );
992
 
993
    Debug( "BuildArgument($platform, @arguments)" );
994
 
995
    Error( "BuildArgument must appear before BuildName()..." )
996
        if ( $BUILDNAME ne "" );
997
 
998
    #
999
    #   Allow a wildcard to apply a single argument to all platforms
1000
    #   Should only be used AFTER all the platforms have been specified
1001
    #
1002
    if ( $platform eq '*' )
1003
    {
1004
        @platforms = @BUILDPLATFORMS;          # Simple Wildcard
1005
    }
1006
    else
1007
    {
1008
        @platforms = ExpandPlatforms( $platform );  # aliasing
1009
    }
1010
 
1011
    foreach $platform ( @platforms )
1012
    {
1013
        next if ( $platform =~ /^--/ );         # argument, ignore
1014
 
1015
        PlatformArgument( $platform, @arguments );
1016
    }
1017
}
1018
 
1019
 
1020
sub BuildPlatforms
1021
{
1022
    my( @arguments ) = @_;
1023
    my $fname = "BuildPlatforms";
1024
 
1025
    Debug( "BuildPlatforms(@arguments)" );
1026
 
1027
    Error( "BuildPlatforms must appear before BuildName()..." )
1028
        if ( $BUILDNAME ne "" );
1029
 
1030
    #
1031
    #   Expand the user specified platforms to allow the use of BuildAlias
1032
    #   The (bad) side effect of this is that platform options get reorganised
1033
    #       PLATFORM,--Uses=ANOTHER  ==> PLATFORM --Uses=ANOTHER
1034
    #
1035
    #   Insert markers(++) into @aruments to mark when to process collected data
1036
    #   Insert before each PLATFORM and at the end of the list
1037
    #   platform specifier or the end of the list. Scan the arguments
1038
    #
1039
    @arguments = ExpandPlatforms( @arguments );
1040
    my @new_args;
1041
    foreach  ( @arguments )
1042
    {
1043
        push (@new_args, '++') unless ( m/^--/ );
1044
        push (@new_args, $_ );
1045
    }
1046
    push (@new_args, '++');
1047
    shift @new_args if $new_args[0] eq '++';
1048
 
1049
 
1050
    my $platform  = "";                         # current platform
1051
    my $notdefault  = 0;
1052
    my @uses = ();
1053
    my @pargs = ();
1054
 
1055
    foreach my $arg ( @new_args )
1056
    {
1057
        #
1058
        #   Extract known options
1059
        #   Unknown options bind to the current platform
1060
        #
1061
        if ( $arg =~ /^--/ ) {
1062
            if ( $arg =~ /^--NotDefault$/ ) {
1063
                $notdefault = 1;
1064
 
1065
            } elsif ( $arg =~/^--Uses=(.*)/ ) {
1066
                UniquePush (\@uses, $1);
1067
 
1068
            } elsif ( $arg =~/^--FunctionName=(.*)/ ) {
1069
                $fname = $1;
1070
 
1071
            } else {
1072
                push @pargs, $arg;
1073
            }
1074
            next;
1075
        }
1076
 
1077
        #
1078
        #   New platform. Save name for later. Collect arguments first
1079
        #
1080
        unless ( $arg eq '++' )
1081
        {
1082
            $platform = $arg;
1083
 
1084
            Error( "$fname() missing platform specification" )
1085
                unless ( $platform );
1086
 
1087
            Error( "$fname() product '$platform' contains invalid characters" )
1088
                unless ( $platform eq quotemeta( $platform ) );
1089
 
1090
            next;
1091
        }
1092
 
1093
        #
1094
        #   Create new platform
1095
        #   Have collected name and arguments
1096
        #
1097
        CreateBuildPlatformEntry($fname, $notdefault, undef, $platform, \@uses, \@pargs  );
1098
 
1099
        #
1100
        #   Reset collection variables for next platform
1101
        #
1102
        $platform = "";
1103
        $notdefault  = 0;
1104
        @uses = ();
1105
        @pargs = ();
1106
    }
1107
}
1108
 
1109
 
1110
#   PlatformArgument ---
1111
#       Append an argument list to the specified platform argument list.
1112
#       Internal use only
1113
#..
1114
 
1115
sub PlatformArgument
1116
{
1117
    my( $platform, @arguments ) = @_;
1118
 
1119
    Debug( "  PlatformArguments($platform, @arguments)" );
1120
 
1121
    HashJoin( \%BUILDPLATFORMARGS, $;, $platform, @arguments )
1122
        if ( $platform );
1123
}
1124
 
1125
 
1126
sub BuildName
1127
{
1128
    my( @arguments ) = @_;
1129
    my $relaxed_version_name = 0;
1130
    my @args;
1131
 
1132
    Debug( "BuildName(@arguments)" );
1133
 
1134
    Error( "Platform(s) not defined...\n" .
1135
            "BuildAlias, BuildProduct and BuildPlatform directives must be defined prior to BuildName()." )
1136
        unless( scalar @BUILDPLATFORMS );
1137
 
1138
#.. Parse arguments
1139
#.
1140
    my $build_info = parseBuildName( @arguments );
1141
 
1142
    $BUILDNAME_PACKAGE = $build_info->{BUILDNAME_PACKAGE};
1143
    $BUILDNAME_VERSION = $build_info->{BUILDNAME_VERSION};
1144
    $BUILDNAME_PROJECT = $build_info->{BUILDNAME_PROJECT};
1145
 
1146
    $BUILDNAME         = $build_info->{BUILDNAME};
1147
    $BUILDVERSION      = $build_info->{BUILDVERSION};
1148
 
1149
    $DEPLOY_PATCH      = $build_info->{DEPLOY_PATCH} || 0;
1150
 
1151
    #
1152
    #   Clobber processing done after values have been accumulated
1153
    #   as they may be used later
1154
    #
1155
    push @CLOBBERFILES, 'build.log';
1156
    push @CLOBBERFILES, 'ChangeLog', 'ChangeLog.bak' if ( $ScmHost eq "Unix" );
1157
    return if ( $Clobber );
1158
 
1159
#.. Create the ChangeLog
1160
#
1161
    if ( -d "CVS" )                             # CVS support subdir
1162
    {
1163
        System( "$::GBE_PERL $::GBE_TOOLS/cvs2cl.pl --tags --branches --revisions --day-of-week" )
1164
            if ( $Nolog == 0 && $ScmHost eq "Unix" );
1165
    }
1166
 
1167
 
1168
#.. Create build.log summary information
1169
#
261 dpurdie 1170
    my ($sep) = "\n".(" " x 11) . ". ";
227 dpurdie 1171
 
261 dpurdie 1172
    Log( "\nBuild configuration (version $::GBE_VERSION)" );
1173
    Log( "Name ....... $BUILDNAME ($ScmHost)" );
1174
    Log( "Version .... $BUILDNAME_VERSION" );
1175
    Log( "DeployPatch. $DEPLOY_PATCH" ) if ($DEPLOY_PATCH);
1176
    Log( "Project .... $BUILDNAME_PROJECT" )if ($BUILDNAME_PROJECT);
1177
    Log( "Project .... ****** Specifically supressed ******" )unless ($BUILDNAME_PROJECT);
1178
    Log( "DateTime ... $::CurrentTime" );
1179
    Log( "AutoBuild... Enabled:$::GBE_ABT" ) if defined($::GBE_ABT) ;
1180
    Log( "Build dir... $Cwd" ) if defined($::GBE_ABT) ;
227 dpurdie 1181
 
261 dpurdie 1182
    Log( "BIN  ....... $::GBE_BIN" );
1183
    Log( "PERL ....... $::GBE_PERL" );
1184
    Log( "TOOLS ...... $::GBE_TOOLS" );
1185
    Log( "CONFIG ..... $::GBE_CONFIG" );
1186
    Log( "MACHTYPE ... $::GBE_MACHTYPE" );
227 dpurdie 1187
 
261 dpurdie 1188
    Log( "PLATFORM ... " . PrintList([split(' ', $::GBE_PLATFORM)], $sep) )    if defined ($::GBE_PLATFORM);
1189
    Log( "BUILDFILTER. " . PrintList([split(' ', $::GBE_BUILDFILTER)], $sep) ) if defined ($::GBE_BUILDFILTER);
227 dpurdie 1190
 
261 dpurdie 1191
    Log( "DPKG_STORE.. $::GBE_DPKG_STORE" );
1192
    Log( "DPKG ....... $::GBE_DPKG" );
1193
    Log( "DPKG_CACHE . $::GBE_DPKG_CACHE" );
1194
    Log( "DPKG_LOCAL . $::GBE_DPKG_LOCAL" );
1195
    Log( "DPKG_SBOX .. $::GBE_DPKG_SBOX" );
227 dpurdie 1196
 
261 dpurdie 1197
    Log( "Platforms .. " . PrintPlatforms(\@BUILDPLATFORMS, $sep) );
227 dpurdie 1198
 
1199
    #
241 dpurdie 1200
    #   Generate a list of platforms that are completely unknown to JATS
1201
    #   May be the result of a user type or a guess
1202
    #
1203
    if ( @BUILD_BADNAME )
1204
    {
261 dpurdie 1205
        Log( "Unknown Pla . " . PrintPlatforms(\@BUILD_BADNAME, $sep) );
241 dpurdie 1206
         Warning ("The following platform names are not known to JATS", "@BUILD_BADNAME");
1207
    }
1208
 
1209
    #
227 dpurdie 1210
    #   Generate a list of active platforms
1211
    #   Ensure that there are some active platforms
1212
    #
1213
    GeneratePlatformList();
1214
    Error( "GBE_BUILDFILTER prevents any targets being built" )
1215
        unless( @BUILD_ACTIVEPLATFORMS );
261 dpurdie 1216
    Log( "Build for .. ". PrintPlatforms(\@BUILD_ACTIVEPLATFORMS, $sep));
227 dpurdie 1217
 
1218
    #
1219
    #   Generate an error if nothing can be done because the GBE_PLATFORM
1220
    #   masks any useful operation.
1221
    #
1222
    if ( $::GBE_PLATFORM )
1223
    {
1224
        my @MAKE_PLATFORMS;
1225
        my %active_platforms;
1226
 
239 dpurdie 1227
        #
1228
        #   Create a hash of active platforms based on the array of
1229
        #   active platforms to simplify testing
1230
        #
1231
        $active_platforms{$_} = 1 foreach ( @BUILD_ACTIVEPLATFORMS  );
227 dpurdie 1232
 
239 dpurdie 1233
        unless ( defined($active_platforms{GENERIC}) )
227 dpurdie 1234
        {
239 dpurdie 1235
            foreach  ( split( ' ', $::GBE_PLATFORM) )
1236
            {
1237
                push @MAKE_PLATFORMS, $_
1238
                    if ( $active_platforms{$_} );
1239
            }
227 dpurdie 1240
 
239 dpurdie 1241
            Error ("The GBE_PLATFORM filter prevents any targets being made",
1242
                   "GBE_PLATFORM: $::GBE_PLATFORM" ) unless ( @MAKE_PLATFORMS );
227 dpurdie 1243
 
261 dpurdie 1244
            Log( "Make for ... ". PrintPlatforms(\@MAKE_PLATFORMS, $sep));
239 dpurdie 1245
        }
227 dpurdie 1246
 
1247
    }
1248
 
1249
    return 1;
1250
}
1251
 
1252
 
1253
sub BuildPreviousVersion
1254
{
1255
    my( $version ) = shift;
1256
 
1257
    $BUILDPREVIOUSVERSION = $version;
261 dpurdie 1258
    Log( "Previous Version ... $BUILDPREVIOUSVERSION" );
227 dpurdie 1259
 
1260
    return 1;
1261
}
1262
 
1263
 
1264
sub BuildInterface
1265
{
1266
    my( $ifdirname ) = @_;
1267
 
1268
 
1269
    #
1270
    #   Clobber the directory - at the end.
1271
    #
1272
    if ( $Clobber )
1273
    {
1274
        #
1275
        #   If this Interface directory contains the Dpackage.cfg file
1276
        #   then JATS has created DPACKAGE and it needs to be clobbered
1277
        #   Flag that it needs to be done later - when we know where it is
1278
        #
1279
        $DeleteDPACKAGE = 1 if ( -f "$ifdirname/Dpackage.cfg" );
1280
 
1281
        push @CLOBBERDIRS, $ifdirname;
1282
        return;
1283
    }
1284
 
1285
    #
1286
    #   In AutoBuildTool mode the entire interface directory
1287
    #   will be deleted. This allows the build to be retried
1288
    #
1289
    if (  defined($::GBE_ABT) )   # clobber mode ?
1290
    {
1291
        if ( -d "$ifdirname" )
1292
        {
1293
            System( "$::GBE_BIN/chmod -fR +w $ifdirname" );
1294
            System( "$::GBE_BIN/rm -rf $ifdirname" );
1295
        }
1296
    }
1297
 
1298
    if ( $ifdirname eq "local" ) {
1299
        System( "$::GBE_BIN/mkdir -p $ifdirname/inc" );
1300
        $BUILDLOCAL = "local";
1301
 
1302
    } else {
1303
        System( "$::GBE_BIN/mkdir -p $ifdirname/include" );
1304
        $BUILDINTERFACE = $ifdirname;
1305
        $::ScmInterface = $ifdirname;
1306
    }
1307
    System( "$::GBE_BIN/mkdir -p $ifdirname/bin" );
1308
    System( "$::GBE_BIN/mkdir -p $ifdirname/lib" );
1309
 
261 dpurdie 1310
    Log( "Interface .. $ifdirname" );
227 dpurdie 1311
    return 1;
1312
}
1313
 
1314
 
1315
sub BuildDirTree
1316
{
1317
    my( $dirfile, $dirhead ) = @_;
1318
    my( $dirname, $c );
1319
 
1320
    $dirhead = '.'
1321
        unless defined( $dirhead );
1322
 
1323
    if ( $Clobber )                             # clobber mode ?
1324
    {
1325
        push @CLOBBERDIRS, $dirhead unless $dirhead eq '.';
1326
        return;
1327
    }
1328
 
1329
    #
1330
    #   Allow for an empty "dirfile". This will allow a directory to be created
1331
    #   without the overhead of the file
1332
    #
1333
    if ( ! $dirfile )
1334
    {
261 dpurdie 1335
        Log( "DirTree .... $dirhead" );
227 dpurdie 1336
        System( "$::GBE_BIN/mkdir -p $dirhead" );
1337
    }
1338
    else
1339
    {
261 dpurdie 1340
        Log( "DirTree .... $dirfile within $dirhead" );
227 dpurdie 1341
        System( "$::GBE_BIN/mkdir -p $dirhead" );
1342
 
1343
        open( DIRFILE, $dirfile ) ||
1344
            Error( "cannot open '$dirfile'" );
1345
 
1346
        while( $dirname = <DIRFILE> )
1347
        {
1348
            chop $dirname;
1349
            $dirname =~ s/#.*//;
1350
            $c = $dirname =~ s/\s*(\S+).*/$1/g;
1351
 
1352
            next unless ( $c == 1 );
1353
 
1354
            if ( ! -d "$dirhead/$dirname" )
1355
            {
261 dpurdie 1356
                Log( "Dir ........ $dirhead/$dirname" );
227 dpurdie 1357
                System( "$::GBE_BIN/mkdir -p $dirhead/$dirname" );
1358
            }
1359
        }
1360
 
1361
        close( DIRFILE );
1362
    }
1363
    $BUILDDIRTREE = $dirhead;
1364
}
1365
 
1366
#-------------------------------------------------------------------------------
1367
# Function        : IncludePkg
1368
#
1369
# Description     : Examine a fully specified package directory for a file
1370
#                   that will specify packages to be included. This allows
1371
#                   a package to be simply a package of other packages
1372
#
1373
#                   Internal function. Not to be used by users
1374
#
1375
# Inputs          : Name of the package
1376
#                   Full directory path of the package to examine
1377
#
1378
# Returns         : Nothing
1379
#
1380
sub IncludePkg
1381
{
1382
    my ($name, $pkg) = @_;
1383
    my $file = "$pkg/incpkg";
1384
 
1385
    Debug ("IncludePkg: $pkg" );
1386
 
1387
    #
1388
    #   Using a require will ensure that the package is only processed once
1389
    #   even though the function user may be called multiple times.
1390
    #   Also prevents recursion within included packages.
1391
    #
1392
    if ( -f $file  )
1393
    {
261 dpurdie 1394
        Log( "PackageIncludes. $name" ) unless ( $INC{$file} );
227 dpurdie 1395
        require $file;
1396
    }
1397
}
1398
 
1399
 
1400
sub LinkSandbox
1401
{
1402
    my( $name, $path, $platform ) = @_;
1403
 
1404
    LinkClean();                                # clean previous images
1405
 
1406
    return if ( $Clobber );                     # clobber mode ?
1407
 
1408
    Error ("LinkSandbox() expects three arguments:  @_")
1409
        unless ( $#_ == 2 );
1410
 
1411
    Debug( "LinkSandbox:" );
1412
    Debug( "Package:   $name" );
1413
    Debug( "Version:   $path" );
1414
 
1415
    DataDirective("LinkSandbox");               # This directive allowed here
1416
 
1417
#
1418
#   If GBE_BUILDFILTER exists, Import 'user' platform
1419
#   specification and filter against the BUILD_ACTIVEPLATFORMS.
1420
#
261 dpurdie 1421
    Log( "LinkSandbox. $name ($path)" );
227 dpurdie 1422
 
1423
    if ( ! -d $path )                           # sandbox exists ?
1424
    {
261 dpurdie 1425
        Log( "WARNING .... Sandbox $path not available" );
227 dpurdie 1426
    }
1427
    else
1428
    {
1429
        $path = Realpath( $path );
1430
 
1431
        if ( !defined($platform) || $platform eq "*" ) 
1432
        {
1433
            foreach my $platform ( @BUILD_ACTIVEPLATFORMS )
1434
            {
1435
                LinkEntry( $platform, $path, $name, "!sandbox", 1 );
1436
            }
1437
        }
1438
        else
1439
        {
1440
            my(@platforms) = split( ',', $platform );
1441
            @platforms = ExpandPlatforms( @platforms );
1442
 
1443
            foreach my $platform ( @platforms )
1444
            {
1445
                LinkEntry( $platform, $path, $name, "!sandbox", 1 );
1446
            }
1447
        }
1448
    }
1449
}
1450
 
1451
 
1452
#-------------------------------------------------------------------------------
1453
# Function        : LinkPkgArchive
1454
#
1455
# Description     : Include an external package into the build sandbox
1456
#                   by extending the compiler and linker search paths to
1457
#                   include suitable directories found in the package
1458
#
1459
# Inputs          : package name
1460
#                   package version
1461
#
1462
sub LinkPkgArchive
1463
{
1464
    my( $name, $version ) = @_;
1465
 
1466
    return BuildPkgArchive( @_ )
1467
        if ( $ForceBuildPkg );                  # Forcing interface directory
1468
 
1469
    LinkClean();                                # clean previous images
1470
 
1471
    return if ( $Clobber );                     # clobber mode ?
1472
 
1473
    Debug( "LinkPkgArchive:" );
1474
    Debug( "Name:      $name" );
1475
    Debug( "Version:   $version" );
1476
 
1477
    DataDirective("LinkPkgArchive");            # This directive allowed here
1478
 
1479
    #
1480
    #   Ensure that we have do not have multiple definitions
1481
    #
1482
    if ( PackageEntry::Exists( $name, $version ) )
1483
    {
261 dpurdie 1484
        Log( "Duplicate Package: $name, $version. Duplicate entry ignored" );
227 dpurdie 1485
        return;
1486
    }
1487
 
1488
    if ( $Cache && $::GBE_DPKG_CACHE )
1489
    {
1490
        my $mode = ($Cache > 1) ? "-refresh" : "";
261 dpurdie 1491
        Log( "LinkPkgArchive . $name ($version) Update Cache" );
227 dpurdie 1492
        System('--NoExit', "$::GBE_PERL $::GBE_TOOLS/cache_dpkg.pl $mode -quiet $name/$version" );
1493
    }
1494
 
1495
    #
1496
    #   Locate the package ONCE
1497
    #
261 dpurdie 1498
    Log( "LinkPkgArchive . $name ($version)" );
227 dpurdie 1499
    my ($pkg, $local ) = PackageLocate( $name, $version );
1500
    if ( $pkg )
1501
    {
1502
        #
1503
        #   Generate package rules for each active platform
1504
        #
1505
        foreach my $platform ( @BUILD_ACTIVEPLATFORMS )
1506
        {
1507
            LinkEntry( $platform, $pkg, $name, $version, 0 );
1508
        }
1509
    }
1510
}
1511
 
1512
sub LinkClean
1513
{
1514
    if ( $BUILDINTERFACE && ! $BUILDLPA_CLEAN_DONE )
1515
    {                                           # only once
1516
        Debug( "LinkClean" );
1517
 
1518
        foreach my $platform ( @BUILDPLATFORMS )
1519
        {                                       # remove generated images
1520
            System( "$::GBE_BIN/rm -rf $BUILDINTERFACE/$platform.rul" );
1521
        }
1522
 
1523
        $BUILDLPA_CLEAN_DONE = 1;
1524
    }
1525
}
1526
 
1527
 
1528
#-------------------------------------------------------------------------------
1529
# Function        : PackageLocate
1530
#
1531
# Description     : Locate a package
1532
#                   Once located a package will be processed for each
1533
#                   platform, but it need only be located ONCE
1534
#
1535
# Inputs          : package name
1536
#                   package version
1537
#
1538
# Returns         : path to the package
1539
#                   local       1 - From local package repository
1540
#
1541
sub PackageLocate
1542
{
1543
    my ($name, $uversion ) = @_;
1544
    my( @dpkgs, $pdir, $pkg );
1545
    my $local = 1;
1546
    my $sandbox = 1;
1547
    my $isa_cache = 0;
1548
    my $version;
1549
    my ($pn, $pv, $ps ) = SplitPackage ($name, $uversion );
1550
 
1551
    Debug( "PackageLocate: ($name/$uversion)" );
1552
 
1553
    #
1554
    #   Look in each package archive directory
1555
    #
1556
    foreach my $dpkg ( split( $::ScmPathSep, $::GBE_DPKG_SBOX),
1557
                       '--NotSandbox',
1558
                       split( $::ScmPathSep, $::GBE_DPKG_LOCAL),
1559
                       '--NotLocal',
1560
                       split( $::ScmPathSep, $::GBE_DPKG_CACHE),
1561
                       '--NotCache',
1562
                       split( $::ScmPathSep, $::GBE_DPKG),
1563
                       split( $::ScmPathSep, $::GBE_DPKG_STORE) )
1564
    {
1565
 
1566
        #
1567
        #   Detect various tags that have been placed in the search list
1568
        #   to flag the end of the sandbox search and the end of the local
1569
        #   archive search
1570
        #
1571
        if ( $dpkg eq '--NotSandbox' )
1572
        {
1573
            $sandbox = 0;
1574
            next;
1575
        }
1576
        if ( $dpkg eq '--NotLocal' )
1577
        {
1578
            $local = 0;
1579
            $isa_cache = 1;
1580
            next;
1581
        }
1582
        if ( $dpkg eq '--NotCache' )
1583
        {
1584
            $isa_cache = 0;
1585
            next;
1586
        }
1587
 
1588
 
1589
        #
1590
        #   If we are playing in a sandbox, then the version number is
1591
        #   not used. The Package suffix is still used so that we can
1592
        #   differentiate sysbasetypes.xxxxx.mas and sysbasetypes.xxxxx.syd
1593
        #
1594
        if ( $sandbox )
1595
        {
1596
            $version = 'sandbox';
1597
            $version .= '.' . $ps if ( $ps );
1598
        }
1599
        else
1600
        {
1601
            $version = $uversion;
1602
        }
1603
 
1604
        #
1605
        #   Alias support
1606
        #   If the 'version' is '!current' then use a version of:
1607
        #       current
1608
        #       current_<USER_NAME>
1609
        #   This is an old mechanism whose use should not be encouraged
1610
        #
1611
        #..
1612
        if ( $version eq "!current" )
1613
        {                                       # 'current' user
1614
            EnvImport( "USER" );
1615
 
1616
            $pkg = "$dpkg/$name/current";       # default
1617
 
1618
            $pkg = "$dpkg/$name/current.lnk"
1619
                if ( -e "$dpkg/$name/current.lnk" );
1620
 
1621
                                                # USER specific
1622
            $pkg = "$dpkg/$name/current_$::USER"
1623
                if ( -e "$dpkg/$name/current_$::USER" );
1624
 
1625
            $pkg = "$dpkg/$name/current_$::USER.lnk"
1626
                if ( -e "$dpkg/$name/current_$::USER.lnk" );
1627
        }
1628
        else
1629
        {                                       # standard
1630
            $pkg = "$dpkg/$name/$version";
1631
 
1632
            $pkg = "$dpkg/$name/$version.lnk"
1633
                if ( -e "$dpkg/$name/$version.lnk" );
1634
        }
1635
 
1636
        #
1637
        #   Using a soft link
1638
        #   Emulate a link in software. The link file contains one line
1639
        #   which is the real pathname of the package
1640
        #
1641
        if ( $pkg =~ m~(.*)\.lnk$~  )
1642
        {
1643
            #
1644
            #   Warn the user if both a link and a real directory
1645
            #   are both present - the link may well be incorrect
1646
            #
1647
            my $non_link = $1;
1648
            Warning ("Suspect package link: $pkg",
1649
                     "Both a link and a package where found - using the link" )
1650
                                                            if ( -d $non_link );
1651
 
1652
            Debug( "           link found -> $pkg" );
1653
            my $link_src = $pkg;
1654
            open( LNKFILE, "$pkg" ) || Error( "cannot open '$pkg'" );
1655
            $pkg = <LNKFILE>;                   # real path
1656
            close( LNKFILE );
1657
            $pkg = '' unless ( $pkg );
1658
            chomp $pkg;
1659
 
1660
            Error ("Broken link: $pkg",
1661
                   "Source link: $link_src",
1662
                   "Try deleting the .lnk file" ) unless ( -d $pkg );
1663
        }
1664
 
1665
        Debug( "           searching $pkg" );
1666
 
1667
        #   Does the package directory exist?
1668
        #   Terminate the directory name with a "/" to detect hidden spaces
1669
        #..
1670
        $pkg =~ s~//~/~g;
1671
        next unless ( -d "$pkg/" );             # exists ?
1672
 
1673
        #
1674
        #   If the package exists within the dpkg_archive cache then mark the
1675
        #   version as having been used. Used by cache cleanup algorithms
1676
        #
1677
        if ( $isa_cache  )
1678
        {
1679
            TouchFile ( "$pkg/used.cache", "Marks the cache copy as being used");
1680
        }
1681
 
1682
        #
1683
        #   Use the first suitable package found
1684
        #..
1685
 
1686
        Debug( "           importing $pkg" );
1687
        return $pkg, $local;
1688
    }
1689
 
1690
    #
1691
    #   Package not found
1692
    #   This is an error, although it can be bypassed
1693
    #
261 dpurdie 1694
    Error ("Required package not found: '$name/$version'" ) unless ( $NoPackageError );
227 dpurdie 1695
 
261 dpurdie 1696
    Log( "WARNING .... Package not available: '$name/$version'" );
227 dpurdie 1697
    return undef;
1698
}
1699
 
1700
 
1701
#-------------------------------------------------------------------------------
1702
# Function        : LinkEntry
1703
#
1704
# Description     : Scan a package an locate platform specific directories
1705
#                   Create data structures to capture the information
1706
#                   This function is used by LinkPkgArchive and LinkSandbox
1707
#                   to perfom the bulk of package inclusion work.
1708
#
1709
# Inputs          : platform being processed
1710
#                   path to the package
1711
#                   name of the package
1712
#                   version of the package
1713
#                   sandbox support (non-zero)
1714
#
1715
sub LinkEntry
1716
{
1717
    my( $platform, $pkg, $name, $version, $sandbox ) = @_;
1718
    my( $entry );
1719
 
1720
    #   Create entry record
1721
    #
1722
    #..
1723
    $entry = PackageEntry::New( $pkg, $name, $version, $sandbox, 'link' );
1724
 
1725
    #   Populate includes:
1726
    #
1727
    #   - include/$platform                 (eg include/solaris)
1728
    #   - inc/$platform                     (eg inc/solaris)
1729
    #   - include.$platform                 (eg include.solaris)
1730
    #   - inc.$platform                     (eg inc.solaris)
1731
    #   - include                           (eg include)
1732
    #   - inc                               (eg inc)
1733
    #
1734
    #   plus, product specialisation directores
1735
    #
1736
    #   eg. BuildProduct( 'IDFC', 'WIN32' );
1737
    #
1738
    #   - inc/IDFC_WIN32                    <- derived platform
1739
    #   - inc/IDFC                          <- product
1740
    #   - inc/WIN32                         <- target
1741
    #..
1742
    my $parts = $BUILDINFO{$platform}{PARTS};
1743
 
1744
    foreach my $part ( @$parts )
1745
    {
1746
        $entry->RuleInc( "/include." . $part ) if ( !$sandbox );
1747
        $entry->RuleInc( "/inc." . $part )     if ( !$sandbox );
1748
        $entry->RuleInc( "/include/" . $part ) if ( !$sandbox );
1749
        $entry->RuleInc( "/inc/" . $part );
1750
    }
1751
 
1752
    #
1753
    #   Also search the root include directory - last
1754
    #
1755
    $entry->RuleInc( "/include" )               if ( !$sandbox );
1756
    $entry->RuleInc( "/inc" );
1757
 
1758
    #   Populate libraries:
1759
    #
1760
    #   - lib/lib.$platform[D|P]            (eg lib/lib.sparcD)
1761
    #   - lib/$platform[D|P]                (eg lib/lib.sparc)
1762
    #   - lib.$platform[D|P]                (eg lib.sparcD)
1763
    #
1764
    #   plus, product specialisation directores
1765
    #
1766
    #   eg. BuildProduct( 'IDFC', 'WIN32' );
1767
    #
1768
    #   - lib/IDFC_WIN32                    <- derived platform
1769
    #   - lib/IDFC                          <- product
1770
    #   - lib/WIN32                         <- target
1771
    #..
1772
    $parts = $BUILDINFO{$platform}{PARTS};
1773
 
1774
    foreach my $part ( @$parts )
1775
    {
1776
        $entry->RuleLib("/lib" . ".$part" )     if ( !$sandbox );
1777
        $entry->RuleLib("/lib" . "/lib.$part" ) if ( !$sandbox );
1778
        $entry->RuleLib("/lib" . "/$part" );
1779
    }
1780
 
1781
    #
1782
    #   Some extra places to search
1783
    #   None. This is good as it indicates that all locations are described in PARTS
1784
    #
1785
    #   Do NOT search in /lib. There are no libraries that work on all platforms
1786
    #   Libraries are binaries!
1787
    #
1788
    #    $entry->RuleLib( "/lib" );
1789
 
1790
    #   Tools:
1791
    #
1792
    #   Tools provide an extensible search path for tools and
1793
    #   utilities used to build programs. These are tools that
1794
    #   are executable on the current host machine and are
1795
    #   independent of the toolset.
1796
    #
1797
    #..
1798
    $entry->ExamineToolPath();
1799
    $entry->ExamineThxPath($platform);
1800
    IncludePkg ( $name, $pkg );
1801
    $entry->Cleanup();                          # cleanup tables
1802
 
1803
    #
1804
    #   Add the package entry to the array of such entries for
1805
    #   the current platform. Maintain the discovery order
1806
    #
1807
    #..
1808
    push ( @{$PKGRULES{$platform}}, $entry );
1809
}
1810
 
1811
 
1812
#-------------------------------------------------------------------------------
1813
# Function        : BuildPkgArchive
1814
#
1815
# Description     : Include an external package into the build sandbox
1816
#                   by copying the packages files into the interface directory
1817
#
1818
# Inputs          : package name
1819
#                   package version
1820
#
1821
sub BuildPkgArchive
1822
{
1823
    my( $name, $version ) = @_;
1824
 
1825
    return if ( $Clobber );                     # clobber mode ?
1826
 
1827
    Debug( "BuildPkgArchive:" );
1828
    Debug( "Name:      $name" );
1829
    Debug( "Version:   $version" );
1830
 
1831
    DataDirective("BuildPkgArchive");           # This directive allowed here
1832
 
1833
    #
1834
    #   Ensure that we have do not have multiple definitions
1835
    #
1836
    if ( PackageEntry::Exists( $name, $version ) )
1837
    {
261 dpurdie 1838
        Log( "Duplicate Package: $name, $version. Duplicate entry ignored" );
227 dpurdie 1839
        return;
1840
    }
1841
 
1842
    if ( $Cache && $::GBE_DPKG_CACHE )
1843
    {
1844
        my $mode = ($Cache > 1) ? "-refresh" : "";
261 dpurdie 1845
        Log( "BuildPkgArchive . $name ($version) Update Cache" );
227 dpurdie 1846
        System('--NoExit', "$::GBE_PERL $::GBE_TOOLS/cache_dpkg.pl $mode -quiet $name/$version" );
1847
    }
1848
 
1849
    #
1850
    #   Locate the package
1851
    #   Use the first instance of the package that it found
1852
    #
261 dpurdie 1853
    Log( "BuildPkgArchive . $name ($version)" );
227 dpurdie 1854
    my ( $pkg, $local ) = PackageLocate( $name, $version );
1855
    if ( $pkg )
1856
    {
1857
        #
1858
        #   Create a Package Entry
1859
        #
1860
        my $entry = PackageEntry::New( $pkg, $name, $version, 0, 'build' );
1861
 
1862
        #
1863
        #   Determine if the package needs to be installed:
1864
        #       If the package is a 'local' package then force transfer
1865
        #       If the user has specified --cache then force transfer
1866
        #       If package is newer that copy, then force transfer
1867
        #       If copy does not exist, then force a transfer
1868
        #
1869
        my $tag_dir = "$Cwd/$BUILDINTERFACE/BuildTags";
1870
        my $tag_file = "$tag_dir/${name}_${version}.tag";
1871
 
1872
        my $package_installed;
1873
        $package_installed = 1
1874
            if ( !$local &&
1875
                 !$Cache &&
1876
                 !FileIsNewer( $entry->GetBaseDir('descpkg'), $tag_file ) );
1877
 
1878
        #
1879
        #   Determine the package format and use the appropriate installer
1880
        #   Supported formats
1881
        #       1) Package has a descpkg file (new style)
1882
        #       2) Package has a InstallPkg.sh file (old style)
1883
        #       3) Package has a Install.sh file (old style is it used ??)
1884
        #
1885
        if ( $package_installed ) {
1886
            Verbose ("Package already installed: $name, $version");
1887
 
1888
        } else {
261 dpurdie 1889
            Log( "                . installing '$pkg'" );
1890
            Log( "                . -> " . readlink($pkg) ) if ( -l $pkg );
227 dpurdie 1891
 
1892
            if ( -e "$pkg/descpkg" )
1893
            {
1894
 
1895
                #
1896
                #   If forcing a BuildPkg, then don't use symlinks
1897
                #   to files in dpkg_archive
1898
                #
1899
                my $opts = "";
1900
                $opts = "--NoSymlinks" if ( $ForceBuildPkg );
1901
 
1902
                #
1903
                #   Determine all the Platforms, Products and Targets
1904
                #   that need to be installed
1905
                #
1906
                my $arglist = GenerateInstallArgumentList();
1907
                System( "cd $pkg; $::GBE_PERL $::GBE_TOOLS/installpkg.pl $Cwd/$BUILDINTERFACE $Cwd $opts $arglist");
1908
                Error( "Package installation error" ) if ( $? != 0 );
1909
            }
1910
            elsif ( -e "$pkg/InstallPkg.sh" )
1911
            {
1912
                System( "(cd $pkg; ./InstallPkg.sh $Cwd/$BUILDINTERFACE $Cwd)" );
1913
            }
1914
            elsif ( -e "$pkg/Install.sh" )
1915
            {
1916
                System( "(cd $pkg; ./Install.sh $Cwd/$BUILDINTERFACE $Cwd)" );
1917
            }
1918
            else
1919
            {
1920
                Error ("Unknown package format for package $name/$version found in $pkg");
1921
            }
1922
 
1923
            #
1924
            #   Tag the package as installed - after it has been transferred
1925
            #
1926
            mkdir ( $tag_dir );
1927
            TouchFile( $tag_file );
1928
        }
1929
 
1930
        #
1931
        #   Process package
1932
        #
1933
        IncludePkg ( $name, $pkg );
1934
 
1935
        #
1936
        #   Complete the creation of the package entry
1937
        #   Add the information for all platforms
1938
        #
1939
        $entry->Cleanup();
1940
        for my $platform (@BUILD_ACTIVEPLATFORMS)
1941
        {
1942
            $entry->ExamineToolPath();
1943
            $entry->ExamineThxPath($platform);
1944
            push ( @{$PKGRULES{$platform}}, $entry );
1945
        }
1946
    }
1947
}
1948
 
1949
#-------------------------------------------------------------------------------
1950
# Function        : GenerateInstallArgumentList
1951
#
1952
# Description     : Generate an argument list for the installpkg.pl script
1953
#                   The argument list is of the form
1954
#                       --Platform:xx[:xx[:xx]] --Platform:yy[:yy[:yy]] ...
1955
#                   Where xx is:
1956
#                       * a 'part' of the target platform
1957
#                         Order is: platform, product, ...  target( in that order )
1958
#                       * --Option[=yyy]
1959
#                        An option to be passed to the script. These are bound only
1960
#                        to the enclosed platform.
1961
# Inputs          :
1962
#
1963
# Returns         : See above
1964
#
1965
sub GenerateInstallArgumentList
1966
{
1967
    my @arglist;
1968
 
1969
    #
1970
    #   Generate the argument list as an array
1971
    #
1972
    for (@BUILD_ACTIVEPLATFORMS)
1973
    {
1974
        my @args = '--Platform';
1975
        push @args, @{$BUILDINFO{$_}{PARTS}};
1976
        push @arglist, join (":" , @args );
1977
    }
1978
 
1979
    return "@arglist";
1980
}
1981
 
1982
#-------------------------------------------------------------------------------
1983
# Function        : GeneratePlatformList
1984
#
1985
# Description     : Return a list of platforms that should particiate in this
1986
#                   build. This is a function of
1987
#                       1) Platforms defined in the build.pl file
1988
#                       2) User filter defined in GBE_BUILDFILTER
1989
#
1990
#                   The primary use of this function is to limit the creation
1991
#                   of makefiles to those that have supported compilers on
1992
#                   the underlying machine.
1993
#
1994
#                   GBE_BUILDFILTER is a space seperated string of words
1995
#                   Each word may be one of
1996
#                       OPTION=TAG or OPTION=!TAG
1997
#                       TAG or !TAG. This is the same as --TARGET=TAG
1998
#
1999
#                   Bare tags are taken to be TARGETS.
2000
#
2001
#                   Where OPTION may be one of
2002
#                       --PLATFORM
2003
#                       --PRODUCT
2004
#                       --TARGET
2005
#
2006
#                   Special cases
2007
#                   1) If GBE_BUILDFILTER is empty, then all available platforms are used
2008
#                      The global $All is set, then all available platforms are used
2009
#                   2) If the first word of GBE_BUILDFILTER is a negative filter,
2010
#                      ie is used the !xxxx or yyy=!xxxx construct, then it is assumed
2011
#                      that the filter will start with all available platforms
2012
#                   3) The special word --ALL forces selection of ALL platforms
2013
#                      and may reset any existing scanning
2014
#                   4) GBE_BUILDFILTER is parsed left to right. It is possible to add and
2015
#                      subtract items from the list.
2016
#                   5) OPTIONS are case insensitive
2017
#                      TAGS are case sensitive
2018
#
2019
#
2020
# Inputs          : GBE_BUILDFILTER from the environment
2021
#
2022
# Returns         : An array of platforms to include in the build
2023
#                   Maintains @BUILD_ACTIVEPLATFORMS  - the last calculated result
2024
#                   Ensures that @DEFBUILDPLATFORMS is a subset of @BUILD_ACTIVEPLATFORMS
2025
#
2026
sub GeneratePlatformList
2027
{
2028
    #
2029
    #   Return the cached result for speed
2030
    #   The value need only be calculated once
2031
    #
2032
    unless ( defined @BUILD_ACTIVEPLATFORMS )
2033
    {
2034
        my ($platform_filter);
2035
        my %result;
2036
        my %part_to_platform;
2037
 
2038
        #
2039
        #   Create a data structure to assist in the production of the platform list
2040
        #   The structure will be a hash of hashes of arrays
2041
        #
2042
        #   The first level hash will be keyed by the word TARGET, PRODUCT or PLATFORM
2043
        #   The second level of the hash will keyed by available targets, products or platforms
2044
        #   The value of the field will be an array of platforms that match the keyword
2045
        #
2046
        for my $platform (keys (%::BUILDINFO))
2047
        {
2048
            my $pParts = $::BUILDINFO{$platform};
2049
 
2050
            #
2051
            #   Skip platforms that are known to be unavailable on this build
2052
            #   machine. Self configure
2053
            #
2054
            next if ( $pParts->{NOT_AVAILABLE} );
2055
 
2056
            my $target  = $pParts->{TARGET};
2057
            my $product = $pParts->{PRODUCT};
2058
 
2059
            push @{$part_to_platform{'PLATFORM'}{$platform}}, $platform;
2060
            push @{$part_to_platform{'TARGET'}  {$target}}  , $platform;
2061
            push @{$part_to_platform{'PRODUCT'} {$product}} , $platform;
2062
        }
2063
        #
2064
        #   Determine the source of the filter
2065
        #   If the user provides one, then use it.
2066
        #   Otherwise its taken from the environment.
2067
        #
2068
        #   Global build all platforms - Kill any user filter
2069
        #
2070
        if ( $All )
2071
        {
2072
            $platform_filter = "";
2073
        }
2074
        else
2075
        {
2076
            $platform_filter = "";
2077
            $platform_filter = $::GBE_BUILDFILTER
2078
                if ( defined($::GBE_BUILDFILTER) );
2079
        }
2080
        Debug( "GeneratePlatformList: Filter:$platform_filter" );
2081
 
2082
        #
2083
        #   Detect the special cases
2084
        #       1) No user definition - assume all platforms
2085
        #       2) First word contains a subtractive element
2086
        #
2087
        my (@filter) = split( ' ', $platform_filter );
2088
 
2089
        if ( !scalar @filter || $filter[0] =~ m/^$/ || $filter[0] =~ m/!/ )
2090
        {
2091
            %result = %{$part_to_platform{'PLATFORM'}}
2092
                if exists $part_to_platform{'PLATFORM'} ;
2093
        }
2094
#DebugDumpData( "PartToPlatform", \%part_to_platform );
2095
 
2096
        #
2097
        #   Process each element in the user filter list
2098
        #   Expand platforms into known aliases
2099
        #
2100
        for my $word (@filter)
2101
        {
2102
            my $platform;
2103
            my $hash_name;
2104
 
2105
            if ( $word =~ m/^--ALL/i )
2106
            {
2107
                %result = %{$part_to_platform{'PLATFORM'}};
2108
            }
2109
            elsif ( $word =~ m/^--(TARGET)=(!?)(.*)/i ||
2110
                    $word =~ m/^--(PRODUCT)=(!?)(.*)/i ||
2111
                    $word =~ m/^--(PLATFORM)=(!?)(.*)/i ||
2112
                    ( $word !~ m/^-/ && $word =~ m/()(!?)(.*)/ )
2113
                )
2114
            {
2115
                my $table = uc($1);
2116
                $table = "TARGET"
2117
                    unless ( $1 );
2118
 
2119
                #
2120
                #   Expand PLATFORMs into known aliases
2121
                #   Alias will expand to PLATFORMs so it won't work unless we are
2122
                #   processing PALTFORMs.
2123
                #
2124
                my @taglist = ( $table eq "PLATFORM" ) ? ExpandPlatforms($3) : $3;
2125
 
2126
                #
2127
                #   Add / Remove items from the result
2128
                #
2129
                for my $item ( @taglist )
2130
                {
2131
                    my $plist = $part_to_platform{$table}{$item};
2132
                    for ( @{$plist})
2133
                    {
2134
                        if ( $2 )
2135
                        {
2136
                            delete $result{$_};
2137
                        }
2138
                        else
2139
                        {
2140
                            $result{$_} = 1;
2141
                        }
2142
                    }
2143
                }
2144
            }
2145
            else
2146
            {
2147
                print "GBE_BUILDFILTER filter term not understood: $word\n";
2148
            }
2149
        }
2150
 
2151
        #
2152
        #   Return an array of platforms to process
2153
        #
2154
        @BUILD_ACTIVEPLATFORMS = sort keys %result;
2155
 
2156
        #
2157
        #   Ensure that DEFBUILDPLATFORMS is a subset of build active platforms
2158
        #
2159
        my @NEW_DEFBUILDPLATFORMS;
2160
        foreach ( @DEFBUILDPLATFORMS )
2161
        {
2162
            push @NEW_DEFBUILDPLATFORMS, $_
2163
                if ( exists $result{$_} );
2164
        }
2165
        @DEFBUILDPLATFORMS = @NEW_DEFBUILDPLATFORMS;
2166
    }
2167
 
2168
    Debug("GeneratePlatformList: Result:@BUILD_ACTIVEPLATFORMS");
2169
    return @BUILD_ACTIVEPLATFORMS;
2170
}
2171
 
2172
#-------------------------------------------------------------------------------
2173
# Function        : PrintPlatforms
2174
#
2175
# Description     : Petty print the specified platform list, breaking line
2176
#                   on either a primary key change or length width >78.
2177
#
2178
# Returns         : Formated string
2179
#
2180
# Example Output :
2181
#
2182
#           DDU_LMOS_WIN32 DDU_LMOS_linux_armv4 DDU_LMOS_linux_i386
2183
#           IDFC_LMOS_WIN32 IDFC_LMOS_linux_armv4 IDFC_LMOS_linux_i386
2184
#           LMOS_WCEPSPC_ARM LMOS_WCEPSPC_EMU LMOS_WIN32 LMOS_linux_armv4
2185
#           LMOS_linux_i386
2186
#..
2187
sub PrintPlatforms
2188
{
2189
    my ($platforms, $nl) = @_;
2190
    my ($string) = "";                          # result
2191
 
2192
    if ( defined(@$platforms) )
2193
    {
2194
        my ($key_run) = 0;
2195
        my ($pkey);                             # previous key
2196
 
2197
        #   Perform a simple formatting and determine if there is key 
2198
        #   change greater then 1 or whether the total length exceeds 78.
2199
        #
2200
        #   If the line exceeds 78, the printer shall then reformat 
2201
        #   breaking based on line length and possiblity keys.
2202
        #
2203
        $pkey = "";
2204
        for my $k (sort @$platforms) 
2205
        {
2206
            my ($d);                            # delimitor
2207
 
2208
            if (($d = index( $k, '_' )) != index( $pkey, '_' ) ||
2209
                    substr( $k, 0, $d ) ne substr( $pkey, 0, $d )) {
2210
                $key_run = 1
2211
                    if ($key_run <= 1);         # change, reset run if <= 1
2212
            } else {
2213
                $key_run++;                     # same primary key
2214
            }
2215
 
2216
            $string .= " " if ($pkey);
2217
            $string .= $k;
2218
            $pkey = $k;
2219
        }
2220
 
2221
        #   Reprint if required.
2222
        #
2223
        if (length($nl)+length($string) > 78)
2224
        {
2225
            my ($llen);                         # line length
2226
 
2227
            $llen = length($nl);
2228
 
2229
            $pkey = "";
2230
            $string = "";
2231
 
2232
            for my $k (sort @$platforms)
2233
            {
2234
                my ($klen, $d);                 # key length, delimitor
2235
 
2236
                $klen = length($k);
2237
                if ($pkey ne "")
2238
                {
2239
                    if ($llen + $klen > 78 ||
2240
                        ($key_run > 1 && (
2241
                            ($d = index( $k, '_' )) != index( $pkey, '_' ) ||
2242
                            substr( $k, 0, $d ) ne substr( $pkey, 0, $d ) )) )
2243
                    {                           # line >70 or key change
2244
                        $string .= $nl;
2245
                        $llen = length($nl);
2246
                    }
2247
                    else
2248
                    {
2249
                        $string .= " ";
2250
                        $llen++;
2251
                    }
2252
                }
2253
                $string .= $k;
2254
                $pkey = $k;
2255
                $llen += $klen;
2256
            }
2257
        }    
2258
    }
2259
    return $string;
2260
}
241 dpurdie 2261
#-------------------------------------------------------------------------------
2262
# Function        : PrintList
2263
#
2264
# Description     : Pretty format an array to fit within 80 char line
2265
#                   Perform wrapping as required
2266
#
2267
# Inputs          : $list           - Reference to an array
2268
#                   $nl             - New line stuff.
2269
#                                     Use to prefix new lines
2270
#
2271
# Returns         : string
2272
#
2273
sub PrintList
2274
{
2275
    my ($list, $nl) = @_;
2276
    my ($string) = '';                          # result
2277
    my $sep;
227 dpurdie 2278
 
241 dpurdie 2279
    if ( @$list )
2280
    {
2281
        my ($llen) = length($nl);
227 dpurdie 2282
 
241 dpurdie 2283
        for my $k (@$list)
2284
        {
2285
            my $klen = length($k);
2286
            if ($llen + $klen > 78 )
2287
            {
2288
                $string .= $nl;
2289
                $llen = length($nl);
2290
            }
2291
            else
2292
            {
2293
                if ( $sep )
2294
                {
2295
                    $string .= $sep;
2296
                    $llen++;
2297
                }
2298
                else
2299
                {
2300
                    $sep = ' ';
2301
                }
2302
            }
2303
            $string .= $k;
2304
            $llen += $klen;
2305
        }
2306
    }
2307
    return $string;
2308
}
2309
 
2310
 
227 dpurdie 2311
sub BuildReleaseFile
2312
{
2313
    my ( $BuildFilename, $BuildDir ) = @_;
2314
    my ( $SnapDir );
2315
 
2316
    # Check if archive requested...
2317
    #
2318
    return unless ( $CmdSwitch eq "archive" );
2319
 
2320
    # Build the release archive file...
2321
    #
2322
    $SnapDir = "$ENV{ \"GBE_SNAPSHOT_DIR\" }/";
2323
    $SnapDir = "" unless ($SnapDir ne "/");
2324
 
261 dpurdie 2325
    Log( "Creating release archive: $SnapDir$BuildFilename.tgz of $Cwd/$BuildDir/" );
227 dpurdie 2326
 
2327
    # GNU tar and zip the build directory NOT following links...
2328
    #
2329
    System( "$::GBE_BIN/tar czf $SnapDir$BuildFilename.tgz $BuildDir" );
2330
 
2331
    Error( "To extract use: $::GBE_BIN/tar xvzf $BuildFilename.tgz" );
2332
}
2333
 
2334
 
2335
sub BuildSnapshot
2336
{
2337
}
2338
 
2339
 
2340
#.. Check if access/permissions setting requested...
2341
#
2342
sub BuildAccessPerms
2343
{
2344
    my( $PermsFilename );
2345
 
2346
    return unless ( $CmdSwitch eq "perms" );
2347
 
2348
    # Set the build access permissions from the shell script...
2349
    $PermsFilename = $CmdParm;
2350
    if ( -e $PermsFilename )
2351
    {
261 dpurdie 2352
        Log( "Setting build access permissions from $PermsFilename..." );
227 dpurdie 2353
        System( "su root -c \"sh $PermsFilename\"" );
2354
    }
2355
    else
2356
    {
261 dpurdie 2357
        Log( "ERROR: Could not find file to set the access permissions: $PermsFilename" );
227 dpurdie 2358
    }
2359
    die "\n";
2360
}
2361
 
2362
 
2363
sub BuildSetenv
2364
{
2365
    push( @BUILDSETENV, @_ );
2366
}
2367
 
2368
#-------------------------------------------------------------------------------
2369
# Function        : DataDirective
2370
#
2371
# Description     : Called by data collection directives to ensure that we are
2372
#                   still collecting data and that we have collected other data
2373
#
2374
# Inputs          : $dname              - Directive Name
2375
#
2376
# Returns         : Will error if we are not
2377
#
2378
sub DataDirective
2379
{
2380
    my ($dname) = @_;
2381
 
2382
    Error( "$dname() must appear after BuildName()...")
2383
        if ( $BUILDNAME eq "" );
2384
 
2385
    Error( "$dname() must appear after BuildInterface()...")
2386
        unless( $BUILDINTERFACE );
2387
 
2388
    Error( "$dname() not allowed after BuildDescpkg, BuildIncpkg, BuildVersion or BuildMake")
2389
        if( $BUILDPHASE);
2390
}
2391
 
2392
#-------------------------------------------------------------------------------
2393
# Function        : StartBuildPhase
2394
#
2395
# Description     : Called by directives that deal with the building phases
2396
#                   to perform common initialisation and to ensure that
2397
#                   directives that collect data are no longer called
2398
#
2399
# Inputs          : None
2400
#
2401
# Returns         : May generate an error
2402
#
2403
sub StartBuildPhase
2404
{
2405
    #
2406
    #   Only do it once
2407
    #
2408
    return if ( $BUILDPHASE++  );
2409
 
2410
    #
2411
    #   Calcuate the aliases that are being extracted from targets
2412
    #
2413
    Process_TargetAlias();
2414
 
2415
    #
2416
    #   Sanity test the users packages
2417
    #
2418
    PackageEntry::SanityTest() unless $Clobber;
2419
 
2420
    #
2421
    #   Validate the $Srcdir before its first real use
2422
    #   This is calculated from the user directives
2423
    #
2424
 
2425
    #.. Determine default "source" root
2426
    #
2427
    if ( $Srcdir eq "" )
2428
    {
2429
        Warning( "Both the directories 'src' and 'SRC' exist ....." )
2430
            if ( $ScmHost eq "Unix" && -e "src" && -e "SRC" );
2431
 
2432
        if ( -e "src" ) {
2433
            $Srcdir = "src";
2434
        } else {
2435
            ( -e "SRC" ) ||
2436
                Error( "Neither the directory 'src' nor 'SRC' exist ....." );
2437
            $Srcdir = "SRC";
2438
        }
2439
    }
2440
 
2441
    #
2442
    #   Must have a valid Srcdir
2443
    #
2444
    Error ("Source directory not found: $Srcdir")
2445
        unless ( $Srcdir && -d $Srcdir );
2446
 
2447
    return $Srcdir;
2448
}
2449
 
2450
#-------------------------------------------------------------------------------
2451
# Function        : BuildPackageLink
2452
#
2453
# Description     : Create a soft link from sandbox_dpkg_archive to the package
2454
#                   being created by this build
2455
#
2456
#                   For backward compatability.
2457
#                   If GBE_DPKG_SBOX is not defined, then use GBE_DPKG_LOCAL
2458
#
2459
#                   This will allow multiple components to work together
2460
#
2461
#                   Note: When called in Clobber-mode the link will be deleted
2462
#
2463
# Inputs          : $BUILDNAME              - The package name
2464
#                   $BUILDNAME_PROJECT      - Project extension
2465
#                   $::GBE_DPKG_SBOX        - Path of sandbox_dpkg_archive
2466
#                   $::GBE_DPKG_LOCAL       - Path of local_dpkg_archive
2467
#                   $::GBE_DPKG             - Main repository
2468
#
2469
# Returns         : Nothing
2470
#
2471
sub BuildPackageLink
2472
{
2473
    my $target_archive;
2474
    my $target_archive_name;
2475
    my $link_file;
2476
    my $tag;
2477
 
2478
    #
2479
    #   Determine the path (and name) of the target archive
2480
    #   Use sandbox_dpkg_archive if it exists
2481
    #   Use local_dpkg_acrhive for backward compatability (should be removed after JATS 2.64.2+)
2482
    #
2483
    if ( $target_archive = $::GBE_DPKG_SBOX )
2484
    {
2485
        $target_archive_name = "sandbox_dpkg_archive";
2486
        $tag = "Sandbox";
2487
 
2488
        $link_file  = 'sandbox';
2489
        $link_file .= '.' . $BUILDNAME_PROJECT if ( $BUILDNAME_PROJECT );
2490
        $link_file .= '.lnk';
2491
    }
2492
    elsif ( $target_archive = $::GBE_DPKG_LOCAL )
2493
    {
2494
        $target_archive_name = "local_dpkg_archive";
2495
        $link_file = "$BUILDVERSION.lnk";
2496
        $tag = "Local";
2497
    }
2498
    else
2499
    {
2500
        Verbose("Cannot locate local or sandbox archive")
2501
            unless $Clobber;
2502
        return;
2503
    }
2504
 
2505
    #
2506
    #   Santity test
2507
    #   Target must be a directory
2508
    #
2509
    unless ( -d $target_archive )
2510
    {
241 dpurdie 2511
        Warning("$target_archive_name is not a directory: $target_archive")
227 dpurdie 2512
            unless $Clobber;
2513
        return;
2514
    }
2515
 
2516
    my $link_dir = "$target_archive/$BUILDNAME_PACKAGE";
2517
    my $link_path = "$link_dir/$link_file";
2518
 
2519
    if ( $Clobber )
2520
    {
2521
        unlink $link_path;          # Delete the link
2522
        rmdir $link_dir;            # Delete only if empty
2523
    }
2524
    else
2525
    {
261 dpurdie 2526
        Log( "Local Link . $BUILDNAME_PACKAGE/$link_file ($tag)");
2527
        mkdir $link_dir unless -d $link_dir;
2528
        FileCreate ( $link_path, "$Cwd/pkg/$BUILDNAME_PACKAGE");
227 dpurdie 2529
    }
2530
}
2531
 
2532
#-------------------------------------------------------------------------------
2533
# Function        : BuildSandboxData
2534
#
2535
# Description     : Create data structures to allow this package to be built
2536
#                   within a multi-package sandbox.
2537
#
2538
#                   This will allow multiple components to work together
2539
#
2540
#                   Note: When called in Clobber-mode the link will be deleted
2541
#
2542
# Inputs          : $BUILDNAME              - The package name
2543
#                   $BUILDNAME_PROJECT      - Project extension
2544
#                   $::GBE_DPKG_SBOX        - Path of sandbox_dpkg_archive
2545
#                   $::GBE_DPKG             - Main repository
2546
#
2547
# Returns         : Nothing
2548
#
2549
sub BuildSandboxData
2550
{
2551
    my $sandbox_dpkg_archive = $::GBE_DPKG_SBOX;
2552
    return unless ( $sandbox_dpkg_archive );
2553
 
2554
    unless ( -d $sandbox_dpkg_archive )
2555
    {
241 dpurdie 2556
        Error("sandbox_dpkg_archive is not a directory: $sandbox_dpkg_archive")
227 dpurdie 2557
            unless $Clobber;
2558
        return;
2559
    }
2560
 
2561
    #
2562
    #   Create a name for this package in the sandbox
2563
    #   Must use the package name and extension. Don't use the version
2564
    #   information as this will not be correct
2565
    #
2566
    #   PACKAGE/sandbox.PRJ.cfg
2567
    #
2568
    my $link_dir = "$sandbox_dpkg_archive/$BUILDNAME_PACKAGE";
2569
    my $link_file = 'sandbox';
2570
       $link_file .= '.' . $BUILDNAME_PROJECT if ( $BUILDNAME_PROJECT );
2571
       $link_file .= '.cfg';
2572
    my $link_path = "$link_dir/$link_file";
2573
 
2574
    if ( $Clobber )
2575
    {
2576
        unlink $link_path;          # Delete the link
2577
        rmdir $link_dir;            # Delete only if empty
2578
    }
2579
    else
2580
    {
261 dpurdie 2581
        Log( "Sandbox cfg. $link_file");
227 dpurdie 2582
        unlink $link_path;
2583
        mkdir $link_dir;
2584
 
2585
        #
2586
        #   Create the sandbox config data structure
2587
        #
2588
        my %sandbox_info = (
2589
            BUILDDIR     => $Cwd,
2590
            INTERFACEDIR => $BUILDINTERFACE,
2591
            );
2592
 
2593
        #
2594
        #   Write out the Parsed Config File with new information
2595
        #
2596
        my $fh = ConfigurationFile::New( $link_path );
2597
        $fh->Header( "buildlib (version $::BuildVersion)",
2598
                                  "Sandbox configuration" );
2599
 
2600
        #
2601
        #   Dump out the configuration information
2602
        #
2603
        $fh->Dump( [\%sandbox_info], [qw(*sandbox_info)] );
2604
        $fh->Close();
2605
    }
2606
}
2607
 
2608
 
2609
#-------------------------------------------------------------------------------
2610
# Function        : BuildMake
2611
#
2612
# Description     : Generate the makefiles
2613
#                   This directive MUST be the last directive in the build.pl
2614
#                   file. The directive triggers the processing of all the
2615
#                   information that has been collected
2616
#
2617
#
2618
# Inputs          : None
2619
#
2620
# Returns         : Nothing
2621
#
2622
 
2623
sub BuildMake
2624
{
2625
    my( $argc, $platform );
2626
 
2627
    #
2628
    #   Must have a valid $BUILDINTERFACE
2629
    #   Normally this is held in the interface directory, but this is not
2630
    #   always created. If there is no $BUILDINTERFACE, then use the
2631
    #   build directory
2632
    #
2633
    $BUILDINTERFACE = "." unless ( $BUILDINTERFACE );
2634
 
2635
    #.. Starting the build phase. No more data collection
2636
    #
2637
        StartBuildPhase();
2638
 
2639
    sub DeleteCfg
2640
    {
2641
        #
2642
        #   Delete files that will be re-created
2643
        #   Some of these files are read and written.
2644
        #   Errors in the files are solved by deleting the files now.
2645
        #
2646
        unlink "$BUILDINTERFACE/build.cfg";
2647
        unlink "$BUILDINTERFACE/Makefile.cfg";
2648
        unlink glob ("$BUILDINTERFACE/Makefile*.cfg");
2649
        unlink "$BUILDINTERFACE/Buildfile.cfg";
2650
        unlink "$BUILDINTERFACE/Dpackage.cfg";
2651
    }
2652
 
2653
    if ( $Clobber )                             # clobber mode ?
2654
    {
2655
        if ( -e "Makefile.gbe" )
2656
        {
263 dpurdie 2657
            JatsTool ( 'jmake.pl', 'unmakefiles');
227 dpurdie 2658
            unlink "Makefile.gbe";
2659
        }
2660
 
2661
        DeleteCfg();
2662
 
2663
        #
2664
        #   JATS creates a 'pkg' directory for the target package
2665
        #
2666
        push @CLOBBERDIRS, "pkg";
2667
 
2668
        #
2669
        #   Deployment creates a 'build/deploy' directory
2670
        #
2671
        push @CLOBBERDIRS, "build/deploy";
2672
 
2673
        #
2674
        #   Delete interface directories and other directories that have been
2675
        #   marked to be clobberd
2676
        #
2677
        foreach my $dir ( @CLOBBERDIRS )
2678
        {
2679
            next if ( $dir eq '.' );
2680
            next if ( $dir eq '..' );
2681
            if ( -d $dir )
2682
            {
2683
                System( "$::GBE_BIN/chmod -fR +w $dir" );
2684
                System( "$::GBE_BIN/rm -rf $dir" );
2685
            }
2686
        }
2687
 
2688
        foreach my $file ( @CLOBBERFILES )
2689
        {
2690
            if ( -f $file )
2691
            {
2692
                System( "$::GBE_BIN/chmod -fR +w $file" );
2693
                System( "$::GBE_BIN/rm -f $file" );
2694
            }
2695
        }
2696
 
2697
        #
2698
        #   DPACKAGE may be a user file, Only delete it if we created it
2699
        #
2700
        unlink "$Srcdir/DPACKAGE" if $DeleteDPACKAGE;
2701
 
2702
        BuildPackageLink();
2703
        BuildSandboxData();
2704
        return;
2705
    }
2706
 
2707
    #.. Build support files
2708
    #
2709
    DeleteCfg();
2710
    BuildConfig();
2711
    BuildRuleFiles();
2712
    BuildSharedLibFiles();
2713
    LinkClean();                                # clean previous images
2714
    WriteParsedBuildConfig();
2715
    BuildPackageLink();
2716
    BuildSandboxData();
2717
 
2718
    #
2719
    #  ONLY (re)building interface dir
2720
    #
2721
    return
2722
        if ( $Interface );
2723
 
2724
    #---------------------------------------------------------------------------
2725
    #
2726
    #.. Make bootstrap "makefile",
2727
    #   Simulate a top level makefile
2728
    #       Pass argumenst to makelib
2729
    #       Sumulate SubDir() operations
2730
    #       Sumulate a Platform(*);
2731
    #
2732
    #       Due to the normal way that makelib.pl is executed,
2733
    #       the following substitutions are done.
2734
    #
2735
    @ARGV = ();
2736
    $0 = "makefile.pl ";
2737
    push @ARGV, "$Cwd";                         # current working directory
2738
    push @ARGV, "$::MAKELIB_PL";                # makelib.pl image
2739
    push @ARGV, "--interface=$BUILDINTERFACE"
261 dpurdie 2740
        if ($BUILDINTERFACE);
227 dpurdie 2741
 
2742
    Debug( "ARGV:      @ARGV" );
2743
 
2744
    #.. (re)Build root makefile
2745
    #
2746
    $ScmBuildlib = 0;                           # clear Buildlib flag for 'makelib.pl'
2747
    RootMakefile();                             # inform 'makelib.pl'
2748
    MakeLibInit();                              # run initialisation
2749
 
2750
 
2751
    #.. Register subdir(s)
2752
    #
2753
    UniquePush (\@BUILDSUBDIRS, $Srcdir );
2754
    SubDir( @BUILDSUBDIRS );
2755
    Platform( @BUILD_ACTIVEPLATFORMS );
2756
 
2757
    #.. (re)build src makefiles and associated information
2758
    #
263 dpurdie 2759
    my @cmds = ('jmake.pl', 'rebuild');
227 dpurdie 2760
    push @cmds, 'NORECURSE=1' if ( $RootOnly );
2761
 
263 dpurdie 2762
    JatsTool ( @cmds);
227 dpurdie 2763
}
2764
 
2765
 
2766
#-------------------------------------------------------------------------------
2767
# Function        : BuildVersion
2768
#
2769
# Description     : Generate version.c and version.h files
2770
#
2771
# Inputs          : Options
2772
#                       --Prefix=prefix         Text prepended to variables created
2773
#                                               as a part of the "C" versions
2774
#                       --Type=type             Type of "C" style data
2775
#                                               Allowed types are: array
2776
#                       --Defs=name             Generate a "C" definitions file.
2777
#                                               This file simply contains definitions
2778
#                       --Defs                  Same as --Defs=defs
2779
#                       --Style=style           Output file style
2780
#                                               Supported styles:
2781
#                                                   "C" - Default
2782
#                                                   "CSharp"
2783
#                                                   "WinRC"
2784
#                       --File=name             Specifies the output file name
2785
#                                               Default is determined by the style
2786
#
2787
#                   Also allows for an 'old' style format in which
2788
#                   the first three arguments are prefix,type and defs
2789
# Returns         :
2790
#
2791
 
2792
sub BuildVersion
2793
{
2794
    my ( $Prefix, $Type, $Mode ) = @_;
2795
    my $ModePrefix;
2796
    my $Style = "C";
2797
    my $FileName;
2798
    my $VersionFiles;
235 dpurdie 2799
    my $IconName;
263 dpurdie 2800
    my $DefinitionsOnly;
267 dpurdie 2801
    my @opts;
2802
    my $supports_opts;
227 dpurdie 2803
 
2804
    StartBuildPhase();                          # Starting the build phase. No more data collection
2805
 
2806
    if ( defined($Prefix) && $Prefix =~ /^--/ )
2807
    {
2808
        $Prefix = undef;
2809
        $Type = undef;
2810
        $Mode = undef;
2811
        foreach  ( @_ )
2812
        {
2813
            if (      /^--Prefix=(.*)/ ) {
2814
                $Prefix = $1;
2815
                $VersionFiles = 1;
2816
 
2817
            } elsif ( /^--Type=(.*)/ ) {
2818
                $Type = $1;
2819
                $VersionFiles = 1;
2820
 
2821
            } elsif ( /^--Defs=(.*)/ ) {
2822
                $Mode = $1;
2823
                $ModePrefix = "_$1";
2824
 
2825
            } elsif ( /^--Defs$/ ) {
2826
                $Mode = 'defs';
2827
                $ModePrefix = "";
2828
 
2829
            } elsif ( /^--Style=(.*)/ ) {
2830
                $Style = $1;
267 dpurdie 2831
                $supports_opts = 1 if ( $Style =~ /^WinRC/i );
227 dpurdie 2832
 
2833
            } elsif ( /^--File=(.*)/ ) {
2834
                $FileName = $1;
2835
 
267 dpurdie 2836
            } elsif ($supports_opts ) {
2837
                push @opts, $_;
235 dpurdie 2838
 
227 dpurdie 2839
            } else {
2840
                Error ("BuildVersion: Unknown option: $_");
2841
 
2842
            }
2843
        }
2844
    }
2845
    else
2846
    {
2847
        #
2848
        #   Old style positional arguments.
2849
        #
2850
        $VersionFiles = 1;
2851
        if ( defined( $Mode ) )
2852
        {
2853
            if ( $Mode =~ m/^defs(=(.*))?$/i )
2854
            {
2855
                $Mode       = $2 ? $2    : 'defs';
2856
                $ModePrefix = $2 ? "_$2" : "";
2857
            }
2858
            else
2859
            {
2860
                Error ("BuildVersion: Bad Mode argument. Need 'defs' or 'defs=name'");
2861
            }
2862
        }
2863
    }
2864
 
2865
    #
2866
    #   Determine the style of version file to create
2867
    #
2868
    if ( $Style =~ /^CSharp/i ) {
2869
        BuildVersionCSharp( $FileName );
2870
 
229 dpurdie 2871
    } elsif ( $Style =~ /^Properties/i ) {
2872
        BuildVersionProperties( $FileName, $Prefix );
2873
 
227 dpurdie 2874
    } elsif ( $Style =~ /^WinRC/i ) {
267 dpurdie 2875
        BuildVersionWinRC( $FileName, @opts );
227 dpurdie 2876
 
2877
    } elsif ( $Style eq "C" ) {
2878
        BuildVersionC    ( $Prefix, $Type )     if ( $VersionFiles );
2879
        BuildVersionCdefs( $Mode, $ModePrefix ) if ( $Mode );
2880
 
2881
    } else {
2882
        Error("BuildVersion: Unknown style: $Style");
2883
    }
2884
}
2885
 
2886
#-------------------------------------------------------------------------------
2887
# Function        : BuildDescpkg
2888
#
2889
# Description     : Create a package description file
2890
#                   The format of this file matches that generated by JANTS
2891
#                   Take care when extending the format
2892
#
2893
#                   NOTE: It turns out that JANTS is not a standard and the
2894
#                         implementors (of JANTS) kept on changing it.
2895
#
2896
# Inputs          :
2897
#
2898
# Returns         :
2899
#
2900
sub BuildDescpkg
2901
{
2902
    StartBuildPhase();                          # Starting the build phase. No more data collection
2903
 
247 dpurdie 2904
    #
2905
    #   Store the files location for use at runtime
2906
    #   It will be a file that is 'known' to JATS
2907
    #
2908
    my $pkgfile = BuildAddKnownFile ( $Srcdir, 'descpkg' );
2909
    return if ( $Clobber );                 # clobber mode ?
227 dpurdie 2910
 
261 dpurdie 2911
    my @desc;
2912
    push @desc, "Package Name: $BUILDNAME_PACKAGE";
2913
    push @desc, "Version:      $BUILDVERSION";
2914
    push @desc, "Released By:  $::USER";
2915
    push @desc, "Released On:  $::CurrentTime";
2916
    push @desc, "Path:         $Cwd";
2917
    push @desc, "Jats Version: $::GBE_VERSION";
2918
    push @desc, "Jats Path:    $::GBE_CORE";
2919
    push @desc, "";
2920
    push @desc, "Build Dependencies:";
2921
    push @desc, "";
227 dpurdie 2922
 
2923
    foreach my $tag ( PackageEntry::GetPackageList )
2924
    {
2925
        my ($name, $version, $type) = PackageEntry::GetPackageData($tag);
2926
 
2927
        my @attributes;
2928
 
2929
        push @attributes, "name=\"$name\"";
2930
        push @attributes, "version=\"$version\"";
2931
        push @attributes, "build=\"true\"" if $type =~ /Build/i;
2932
 
261 dpurdie 2933
        push @desc, "<sandbox @attributes/>";
227 dpurdie 2934
    }
247 dpurdie 2935
 
261 dpurdie 2936
    FileCreate ($pkgfile, \@desc );
227 dpurdie 2937
}
2938
 
2939
#-------------------------------------------------------------------------------
2940
# Function        : BuildIncpkg
2941
#
2942
# Description     : Create a package inclusion file
2943
#
2944
# Inputs          :
2945
#
2946
# Returns         :
2947
#
2948
sub BuildIncpkg
2949
{
2950
    StartBuildPhase();                          # Starting the build phase. No more data collection
2951
    if ( $Clobber )                             # clobber mode ?
2952
    {
2953
        System( "$::GBE_BIN/rm -f $Srcdir/incpkg" );
2954
        return;
2955
    }
2956
 
2957
    my $fh = ConfigurationFile::New( "$Srcdir/incpkg" );
2958
    $fh->Header( "buildlib (Version $BuildVersion)",
2959
                              "Package inclusion list" );
2960
 
2961
    foreach my $tag ( PackageEntry::GetPackageList )
2962
    {
2963
        my ($name, $version, $type) = PackageEntry::GetPackageData($tag);
2964
        $type = ($type =~ /build/i) ? "Build" : "Link";
2965
 
2966
        $fh->Write( "${type}PkgArchive( '$name', '$version' );\n" );
2967
    }
2968
 
2969
    $fh->Close();
2970
}
2971
 
2972
#-------------------------------------------------------------------------------
2973
# Function        : BuildConfig
2974
#
2975
# Description     : Create the file interface/build.cfg
2976
#                   This file contains information gathered by the build process
2977
#                   that is to be used when makefiles are created and re-created
2978
#
2979
# Inputs          : None
2980
#
2981
# Returns         : Nothing
2982
#
2983
sub BuildConfig()
2984
{
2985
    Error( "No BuildInterface directive encountered\n" )
2986
        unless ($BUILDINTERFACE);
2987
 
2988
    my $fh = ConfigurationFile::New( "$BUILDINTERFACE/build.cfg");
2989
    $fh->Header( "buildlib (Version $BuildVersion)",
2990
                              "Makelib configuration file", "
2991
\$ScmBuildMachType              = \"$::GBE_MACHTYPE\";
2992
\$ScmInterfaceVersion           = \"$::InterfaceVersion\";
2993
\$ScmBuildName                  = \"$BUILDNAME\";
2994
\$ScmBuildPackage               = \"$BUILDNAME_PACKAGE\";
2995
\$ScmBuildVersion               = \"$BUILDNAME_VERSION\";
2996
\$ScmBuildProject               = \"$BUILDNAME_PROJECT\";
2997
\$ScmBuildVersionFull           = \"$BUILDVERSION\";
2998
\$ScmBuildPreviousVersion       = \"$BUILDPREVIOUSVERSION\";
2999
\$ScmLocal                      = \"$BUILDLOCAL\";
3000
\$ScmDeploymentPatch            = \"$DEPLOY_PATCH\";
3001
\$ScmSrcDir                     = \"$Srcdir\";
3002
\$ScmBuildSrc                   = \"$ScmBuildSrc\";
3003
\$ScmExpert                     = \"$Expert\";
261 dpurdie 3004
\$ScmAll                        = \"$All\";
227 dpurdie 3005
");
3006
 
3007
#.. Alias
3008
#
3009
    $fh->DumpData(
3010
        "\n# Aliases.\n#\n",
3011
        "ScmBuildAliases", \%BUILDALIAS );
3012
 
3013
#.. Products
3014
#
3015
    $fh->DumpData(
3016
        "# Product mapping.\n#\n",
3017
        "ScmBuildProducts", \%BUILDPRODUCT_PARTS );
3018
 
3019
#.. Create ScmBuildPlatforms
3020
#
3021
    my( @platforms_merged, %platform_args ) = ();
3022
 
3023
    UniquePush ( \@platforms_merged, @BUILDPLATFORMS );
3024
 
3025
    foreach my $key ( keys %BUILDPRODUCT ) {
3026
        my( @list ) = split( ' ', $BUILDALIAS{ $key } || '' );
3027
        my( $platform );
3028
 
3029
        foreach my $elem ( @list ) {
3030
            if ( $elem =~ /^--/ ) {             # argument
3031
                HashJoin( \%platform_args, $;, $platform, $elem )
3032
                    if ( defined($platform) );
3033
                next;
3034
            }
3035
            $platform = $elem;                  # platform
3036
            UniquePush( \@platforms_merged, $elem );
3037
        }
3038
    }
3039
 
3040
#.. Create ScmBuildPlatforms
3041
#   Contains per platform options extracted from alias and platform args
3042
#
3043
    my %ScmBuildPlatforms;
3044
    foreach my $key ( @platforms_merged ) {
3045
 
3046
        my( @arguments ) = ();
3047
        UniquePush( \@arguments, split( /$;/, $BUILDPLATFORMARGS{ $key } ))
3048
            if ( exists $BUILDPLATFORMARGS{ $key } );
3049
 
3050
        UniquePush( \@arguments, split( /$;/, $platform_args{ $key } ))
3051
            if ( exists $platform_args{ $key } );
3052
 
3053
        $ScmBuildPlatforms{$key} = join "$;", @arguments;
3054
    }
3055
 
3056
    $fh->DumpData(
3057
        "# Platform and global argument list.\n#\n",
3058
        "ScmBuildPlatforms", \%ScmBuildPlatforms );
3059
 
3060
 
3061
# .. Create BuildPkgRules
3062
#
3063
#    This most of the information contained within %PKGRULES, which
3064
#    requires additional processing within makelib.
3065
#
3066
    my %ScmBuildPkgRules;
3067
    foreach my $platform ( keys %PKGRULES )
3068
    {
3069
        foreach my $package ( @{$PKGRULES{$platform}} )
3070
        {
3071
            my %entry;
3072
 
3073
            $entry{ROOT}     = $package->{'base'};
3074
            $entry{NAME}     = $package->{'name'};
3075
            $entry{VERSION}  = $package->{'version'};
3076
            $entry{DNAME}    = $package->{'dname'};
3077
            $entry{DVERSION} = $package->{'dversion'};
3078
            $entry{DPROJ}    = $package->{'dproj'};
3079
            $entry{TYPE}     = $package->{'type'};
3080
            $entry{CFGDIR}   = $package->{'cfgdir'} if ( defined( $package->{'cfgdir'} ) );
3081
 
3082
 
3083
            foreach my $dir (qw (PINCDIRS PLIBDIRS TOOLDIRS THXDIRS) )
3084
            {
3085
                $entry{$dir} = $package->{$dir} ;
3086
            }
3087
 
3088
            push @{$ScmBuildPkgRules{$platform}}, \%entry;
3089
        }
3090
    }
3091
 
3092
    $fh->DumpData(
3093
        "# Imported packages.\n#\n",
3094
        "ScmBuildPkgRules", \%ScmBuildPkgRules );
3095
 
3096
#
3097
#   BUILDPLATFORMS,
3098
#       The value that is saved only contains the active platforms
3099
#
3100
#   DEFBUILDPLATFORMS,
3101
#       The value that is matchs the wildcard specification for Platform 
3102
#       directives.
3103
#
3104
    $fh->DumpData(
3105
        "# A list of platforms active within the view.\n#\n",
3106
        "BUILDPLATFORMS", \@BUILD_ACTIVEPLATFORMS );
3107
 
3108
    $fh->DumpData(
3109
        "# A list of default platforms within the view.\n#\n",
3110
        "DEFBUILDPLATFORMS", \@DEFBUILDPLATFORMS );
3111
 
3112
#
3113
#   BUILDTOOLS
3114
#       A list of toolset extension paths
3115
#
3116
    $fh->DumpData(
3117
        "# A list of paths with toolset extension programs.\n#\n",
3118
        "BUILDTOOLSPATH", \@BUILDTOOLS );
3119
 
3120
#
3121
#   BUILDPLATFORM_PARTS
3122
#       A subset of BUILDINFO exported as BUILDPLATFORM_PARTS
3123
#       This exists only for backward compatability with existing code
3124
#       in external packages ( deployfiles).
3125
#
3126
#   Only save those parts that are part of the current build
3127
#   This will prevent users attempting to build for platforms that have not
3128
#   been correctly constructed.
3129
#
3130
    my %active =  map { ${_} => 1 } @BUILD_ACTIVEPLATFORMS;
3131
    my %active_buildplatform_parts;
3132
    my %active_build_info;
3133
    foreach ( keys %BUILDINFO )
3134
    {
3135
        next unless ( $active{$_} );
3136
        $active_buildplatform_parts{$_} = $BUILDINFO{$_}{PARTS};
3137
        $active_build_info{$_}          = $BUILDINFO{$_};
3138
    }
3139
 
3140
    $fh->DumpData(
3141
        "# Parts of all platforms.\n#\n",
3142
        "BUILDPLATFORM_PARTS", \%active_buildplatform_parts );
3143
#
3144
#   BUILDINFO
3145
#       Complete TARGET Information
3146
#
3147
    $fh->DumpData(
3148
        "# Extended build information.\n#\n",
3149
        "BUILDINFO", \%active_build_info );
3150
 
3151
#
247 dpurdie 3152
#   BUILD_KNOWNFILES
3153
#       All paths are relative to the project root directory
3154
#       ie: The directory that conatins the build.pl file
3155
#
3156
    $fh->DumpData(
3157
        "# Generated Files that may be known when used as Src files.\n#\n",
3158
        "BUILD_KNOWNFILES", \%BUILD_KNOWNFILES );
3159
 
3160
#
227 dpurdie 3161
#   Close out the file
3162
#
3163
    $fh->Close();
3164
}
3165
 
3166
#-------------------------------------------------------------------------------
3167
# Function        : WriteParsedBuildConfig
3168
#
3169
# Description     : Write all the parsed build.pl data to a single file
3170
#                   Its all in there for use
3171
#
3172
# Inputs          : 
3173
#
3174
# Returns         : 
3175
#
3176
sub WriteParsedBuildConfig
3177
{
3178
    my $cfg_file = "$::BUILDINTERFACE/Buildfile.cfg";
3179
    my %cf_build_info = ();
3180
 
3181
    #
3182
    #   Examine the symbol table and capture most of the entries
3183
    #
3184
    foreach my $symname (keys %main::)
3185
    {
3186
        next if ( $symname =~ m/::/  );                 # No Typeglobs
3187
        next if ( $symname =~ m/^cf_build_info/  );     # Not myself
3188
        next unless ( $symname =~ m/^[A-Za-z]/  );      # No system type names
3189
        next if ( $symname =~ m/^SIG$/  );              # Useless
3190
        next if ( $symname =~ m/^ENV$/  );              # Don't keep the user ENV
3191
        next if ( $symname =~ m/^INC$/  );              # Don't keep the INC paths
3192
        next if ( $symname =~ m/^DEFINES/  );           # Don't keep
3193
        next if ( $symname =~ m/^TOOLSETRULES/  );      # Don't keep
3194
 
3195
        local *sym = $main::{$symname};
3196
 
3197
        $cf_build_info{"\$$symname"} =  $::sym if defined $::sym;
3198
        $cf_build_info{"\@$symname"} = \@::sym if defined @::sym;
3199
        $cf_build_info{"\%$symname"} = \%::sym if defined %::sym;
3200
    }
3201
 
3202
    #
3203
    #   Dump out the configuration information
3204
    #
3205
    my $fh = ConfigurationFile::New( "$cfg_file" );
3206
    $fh->Header( "buildlib (version $::BuildVersion)",
3207
                              "Buildfile configuration" );
3208
    $fh->Dump( [\%cf_build_info], [qw(*cf_build_info)] );
3209
    $fh->Close();
3210
}
3211
 
3212
 
3213
#-------------------------------------------------------------------------------
3214
# Function        : BuildRuleFiles
3215
#
3216
# Description     : Create a set of rule files in the interface directory
3217
#                   These will be included directly into makefiles to
3218
#                   extend library and header search paths to the Linked
3219
#                   archives
3220
#
3221
#                   One file is created for each platform to simplify the
3222
#                   inclusion rules
3223
#
3224
#
3225
#                   The PKGRULES data structure is of the form:
3226
#
3227
#                   A hash, by platform, of an array of package information
3228
#                   Each block of package information is a hash containing
3229
#                       'name'      -  short name of the package
3230
#                       'version'   -  short name of the package
3231
#                       'base'      - path of the package root
3232
#                       'PINCDIRS'  - Array of included directories
3233
#                       'PLIBDIRS'  - Array of library directories
3234
#
3235
#                   Arrays are used to preserve the user specified search
3236
#                   order, both of packages and directories within each
3237
#                   package
3238
#
3239
# Inputs          :
3240
#
3241
# Returns         :
3242
#
3243
sub BuildRuleFiles
3244
{
3245
    #
3246
    #   A file is generated for each platform
3247
    #   Within this lines are generated for each package
3248
    #
3249
    foreach my $platform ( keys %PKGRULES )
3250
    {
3251
        my $pPlatform = $PKGRULES{$platform};
3252
 
3253
        my $fh = ::ConfigurationFile::New( "$BUILDINTERFACE/$platform.rul", '--NoEof', '--Type=mak' );
3254
        $fh->Header( "Buildlib ($BuildVersion)","Package import specification" );
3255
 
3256
        $fh->Write ( "PINCDIRS\t=\t\t" . "# includes\n" );
3257
        $fh->Write ( "PLIBDIRS\t=\t\t" . "# libraries\n" );
3258
        $fh->Write ( "\n" );
3259
 
3260
        #
3261
        #   For each Available package accessable to this platform
3262
        #
3263
        foreach my $package ( @{$pPlatform} )
3264
        {
3265
            my $name = $package->{'name'} . '/' . $package->{'version'};
3266
            my $base = $package->{'base'};
3267
 
3268
            $fh->Write ( "##########################################################\n");
3269
            $fh->Write ( "# Source:  $name\n" );
3270
            $fh->Write ( "#\n" );
3271
 
3272
            #
3273
            #   List include and library directories
257 dpurdie 3274
            #   Need the True Path for windows.
3275
            #       Some makefile functions (wildcard) only work as expected
3276
            #       if the case of the pathname is correct. Really only a problem
3277
            #       with badly formed legecy packages where the Windows user
3278
            #       guessed at the package format.
227 dpurdie 3279
            #
257 dpurdie 3280
            #
227 dpurdie 3281
            for my $type (qw (PINCDIRS PLIBDIRS) )
3282
            {
3283
                for my $path ( @{$package->{$type}} )
3284
                {
257 dpurdie 3285
                    $fh->Write ( "$type\t+= " . TruePath($base . $path) . "\n" );
227 dpurdie 3286
                }
3287
            }
3288
            $fh->Write ( "\n" );
3289
        }
3290
        $fh->Close();
3291
    }
3292
}
3293
 
3294
#-------------------------------------------------------------------------------
3295
# Function        : BuildSharedLibFiles
3296
#
3297
# Description     : Create a file in the interface directory that will specify
3298
#                   the locations of shared libraries.
3299
#
3300
#                   Note: Always create a file as makefile targets depend on it.
3301
#
3302
#                   This is a bit ugly.
3303
#
3304
#                   There needs be an association between the build machine and
3305
#                   the target platform. Need to know if the current target is
3306
#                   native to the current build machine. If it is then we can
3307
#                   run tests on the machine and we then need to extend the
3308
#                   search path for the target.
3309
#
3310
#                   The BUILDINFO{EXT_SHARED} is used to control the creation of
3311
#                   the files by specifying the extension of the file.
3312
#
3313
# Inputs          : None
3314
#
3315
# Returns         :
3316
#
3317
sub BuildSharedLibFiles
3318
{
3319
    if ( $ScmHost eq "DOS" || $ScmHost eq "WIN" ) {
3320
        BuildSharedLibFiles_WIN(@_);
3321
 
3322
    } elsif ( $ScmHost eq "Unix" ) {
3323
        BuildSharedLibFiles_Unix(@_);
3324
 
3325
    } else {
3326
        Error("Cannot build. Unknown machine type: $ScmHost",
3327
              "Need WIN, DOS or Unix" );
3328
    }
3329
}
3330
 
3331
#-------------------------------------------------------------------------------
3332
# Function        : BuildSharedLibFiles_WIN
3333
#
3334
# Description     : Implementation of BuildSharedLibFiles for Windows
3335
#
3336
# Inputs          : None
3337
#
3338
sub BuildSharedLibFiles_WIN
3339
{
3340
 
3341
    foreach my $platform ( @BUILD_ACTIVEPLATFORMS )
3342
    {
3343
        next unless ( exists $BUILDINFO{$platform}{EXT_SHARED} );
3344
        my @dos_paths = BuildSharedLibFiles_list( $platform, $BUILDINFO{$platform}{EXT_SHARED} );
3345
 
3346
        #
3347
        #   Create a .bat file for WIN32
3348
        #   This may be consumed by user wrapper programs
3349
        #
229 dpurdie 3350
        #   Features: No Echo
3351
        #             Use of SETLOCAL to prevent pollution of environment
3352
        #
227 dpurdie 3353
        my $fh = ::ConfigurationFile::New( "$BUILDINTERFACE/set_$platform.bat", '--NoEof', '--Type=bat' );
229 dpurdie 3354
        $fh->Write ( "\@echo off\n");
227 dpurdie 3355
        $fh->Header( "Buildlib ($BuildVersion)","Shared Library Paths" );
229 dpurdie 3356
        $fh->Write ( "\nSETLOCAL\n");
227 dpurdie 3357
        foreach ( reverse @dos_paths )
3358
        {
3359
            $_ =~ s~/~\\~g;
3360
            $fh->Write ( "PATH=$_;\%PATH\%\n" );
3361
        }
3362
        $fh->Write ( "\n%*\n" );
229 dpurdie 3363
        $fh->Write ( "\nENDLOCAL\n");
231 dpurdie 3364
        $fh->Write ( "EXIT /B %ERRORLEVEL%\n");
227 dpurdie 3365
        $fh->Close();
3366
 
3367
        #
3368
        #   Create a .sh file for WIN32
3369
        #   This may be consumed by a shell - as used within JATS
3370
        #
3371
        $fh = ::ConfigurationFile::New( "$BUILDINTERFACE/set_$platform.sh", '--NoEof', '--Type=sh' );
3372
        $fh->Header( "Buildlib ($BuildVersion)","Shared Library Paths" );
3373
        foreach ( reverse @dos_paths )
3374
        {
3375
            tr~\\/~/~s;
3376
            $fh->Write ( "PATH=$_\\;\$PATH\n" );
3377
        }
3378
        $fh->Write ( "\n\$*\n" );
3379
        $fh->Close();
3380
    }
3381
}
3382
 
3383
#-------------------------------------------------------------------------------
3384
# Function        : BuildSharedLibFiles_Unix
3385
#
3386
# Description     : Implementation of BuildSharedLibFiles for Unix
3387
#                   Extend the Shared Library search path via LD_LIBRARY_PATH
3388
#
3389
# Inputs          : None
3390
#
3391
sub BuildSharedLibFiles_Unix
3392
{
3393
    foreach my $platform ( @BUILD_ACTIVEPLATFORMS )
3394
    {
3395
        next unless ( exists $BUILDINFO{$platform}{EXT_SHARED} );
3396
        my @unix_paths = BuildSharedLibFiles_list( $platform, $BUILDINFO{$platform}{EXT_SHARED} );
3397
 
3398
        #
3399
        #   Create a .sh file for Unix
3400
        #
229 dpurdie 3401
        my $file = "$BUILDINTERFACE/set_$platform.sh";
3402
        my $fh = ::ConfigurationFile::New( $file , '--NoEof', '--Type=sh' );
227 dpurdie 3403
        $fh->Header( "Buildlib ($BuildVersion)","Shared Library Paths" );
3404
        foreach ( reverse @unix_paths )
3405
        {
3406
            $fh->Write ( "export LD_LIBRARY_PATH=$_:\$LD_LIBRARY_PATH\n" );
3407
        }
275 dpurdie 3408
        $fh->Write ( "\n\"\$\@\"\n" );
227 dpurdie 3409
        $fh->Close();
229 dpurdie 3410
 
3411
        #
3412
        #   Make the file executable under unix
3413
        #
3414
        chmod 0755, $file;
227 dpurdie 3415
    }
3416
}
3417
 
3418
#-------------------------------------------------------------------------------
3419
# Function        : BuildSharedLibFiles_list
3420
#
3421
# Description     : Determine a list of Shared Library paths that can be used
3422
#                   by the current target
3423
#
3424
# Inputs          : $platform       - Current platform
3425
#                   $so             - Shared object extensions
3426
#
3427
# Returns         : List of search paths
3428
#
3429
sub BuildSharedLibFiles_list
3430
{
3431
    my ($platform, $so ) = @_;
3432
    my @paths;
3433
    my @parts = @{$BUILDINFO{$platform}{PARTS}};
3434
 
3435
    #
3436
    #   Paths from the current build
3437
    #       Local directory         - for installed components
3438
    #       Interface directory     - for BuildPkgArchives
3439
    #
3440
    if ( $BUILDLOCAL )
3441
    {
3442
        foreach ( @parts )
3443
        {
3444
            push @paths, AbsPath("$BUILDLOCAL/lib/$_");
3445
        }
3446
    }
3447
 
3448
    foreach ( @parts )
3449
    {
3450
            push @paths, AbsPath("$BUILDINTERFACE/lib/$_");
3451
    }
3452
 
3453
    #
3454
    #   For each LinkPkgArchive
3455
    #
3456
    foreach my $package ( @{$PKGRULES{$platform}} )
3457
    {
3458
        next unless ( $package->{'type'} eq 'link' );
3459
 
3460
        my $base = $package->{'base'};
3461
        for my $path ( @{$package->{'PLIBDIRS'}} )
3462
        {
3463
            my @so_libs = glob ( "$base$path/*$so");
3464
            next unless scalar @so_libs;
3465
 
3466
            push @paths, $base . $path;;
3467
        }
3468
    }
3469
 
3470
    #
3471
    #   Returns paths found
3472
    #
3473
    return @paths;
3474
}
3475
 
3476
#-------------------------------------------------------------------------------
247 dpurdie 3477
# Function        : BuildAddKnownFile
3478
#
3479
# Description     : Save the file as a file that will be known  to the JATS
3480
#                   makefiles. It will be available SRCS, but will not be a
3481
#                   part of any object list.
3482
#
3483
#                   Known Files will be deleted on clobber
3484
#
3485
# Inputs          : $path
3486
#                   $file
3487
#
3488
# Returns         : Path and filename
3489
#
3490
 
3491
sub BuildAddKnownFile
3492
{
3493
    my ($path, $file) = @_;
3494
    $path .= '/'. $file;
3495
    $BUILD_KNOWNFILES {$file} = $path;
3496
    push @CLOBBERFILES, $path;
3497
 
3498
    return $path;
3499
}
3500
 
3501
 
3502
#-------------------------------------------------------------------------------
227 dpurdie 3503
# Function        : Usage
3504
#
3505
# Description     : Display program usage information
3506
#
3507
# Inputs          : args            - Text message to display
3508
#
3509
#                   $opt_help       - Level of verbose ness
3510
#
3511
# Returns         : Does not return
3512
#                   This function will exit
3513
#
3514
sub Usage
3515
{
3516
    my( $msg ) = @_;
3517
    my %usage_args;
3518
 
3519
    #
3520
    #   Create a hash of arguments for the pod2usage function
3521
    #
3522
    $usage_args{'-input'} = __FILE__;
3523
    $usage_args{'-exitval'} = 42;
3524
    $usage_args{'-message'} = "\nbuildlib $msg\n" if $msg;
3525
    $usage_args{'-verbose'} = $opt_help < 3 ? $opt_help - 1 : 3 if ( $opt_help );
3526
 
3527
    #
3528
    #   Generate nice help
3529
    #
3530
    pod2usage(\%usage_args);
3531
}
3532
 
3533
#-------------------------------------------------------------------------------
3534
#   Documentation
3535
#
3536
 
3537
=pod
3538
 
3539
=head1 NAME
3540
 
3541
jats sandbox bootstrap
3542
 
3543
=head1 SYNOPSIS
3544
 
3545
jats build [options] [command]
3546
 
3547
     [perl buildlib.pl [options] PWD [command]]
3548
 
3549
 
3550
 Options:
3551
    --help          - Display terse usage
3552
    --help --help   - Display verbose usage
3553
    --man           - Display internal manual
261 dpurdie 3554
    --verbose[=n]   - Set level of progress verbosity
3555
    --debug[=n]     - Set the debug level
227 dpurdie 3556
    --nolog         - Do not generate/update Changelog
3557
    --cache         - Cache packages in the local dpkg_package cache
3558
    --cache --cache - Forced refresh dependent packages in the local cache
3559
    --project       - Generate support files for external tools
3560
    --package       - Ignore packages that are not available and continue
3561
    --forcebuildpkg - Treat LinkPkgArchive directives as BuildPkgArchive
3562
                      Also suppress the use of symlinks so that the phsical
3563
                      file will be copied locally.
3564
 
3565
 Sticky settings:
3566
    --all           - Build for all platforms ignoring GBE_BUILDFILTER
261 dpurdie 3567
    --expert[=n]    - Relaxing dependency checks on the user makefiles
227 dpurdie 3568
 
3569
 Commands:
3570
    changelog       - Only update ChangeLog.
3571
    interface       - Only (re)build the interface tree, including ChangeLog.
3572
    rootonly        - Only (re)build the root directory.
3573
    clobber         - Remove generated build system (eg Makefiles).
3574
 
3575
 
3576
=head1 OPTIONS
3577
 
3578
=over 8
3579
 
3580
=item B<--help>
3581
 
3582
Print a brief help message and exits.
3583
 
3584
=item B<-help -help>
3585
 
3586
Print a detailed help message with an explanation for each option.
3587
 
3588
=item B<-man>
3589
 
3590
Prints the manual page and exits.
3591
 
261 dpurdie 3592
=item B<--verbose[=n]>
227 dpurdie 3593
 
261 dpurdie 3594
Increases program output.
227 dpurdie 3595
 
261 dpurdie 3596
If an argument is provided, then it will be used to set the level, otherwise the
3597
existing level will be incremented. This option may be specified multiple times.
227 dpurdie 3598
 
261 dpurdie 3599
=item B<-debug>
3600
 
227 dpurdie 3601
Increases program output. Enable internal debugging messages to generate detailed
3602
progress information.
3603
 
261 dpurdie 3604
If an argument is provided, then it will be used to set the level, otherwise the
3605
existing level will be incremented. This option may be specified multiple times.
3606
 
227 dpurdie 3607
=item B<--nolog>
3608
 
3609
Do not generate or update the ChangeLog maintained when a CVS directory is detected
3610
in the build directory.
3611
 
3612
=item B<--cache>
3613
 
3614
This option will cause dependent packages to be cached in the local
3615
dpkg_archive cache.
3616
 
3617
If the option is used twice then the packages will be forcibly refreshed.
3618
 
3619
=item B<--project>
3620
 
3621
This option is used to indicate that the build.pl is being processed by a full
3622
JATS environment and not by any pre-existing mechanism.
3623
 
3624
This option will prevent the generation of configuration batch files that are
3625
not required by the full environment.
3626
 
3627
=item B<--package>
3628
 
3629
This option will cause the build process to ignore packages that cannot be
3630
located. The package build may fail at a later stage.
3631
 
3632
This option is used by the Auto Build Tool to handle packages that may not be
3633
needed in all builds.
3634
 
3635
=item B<--forcebuildpkg>
3636
 
3637
This option will force LinkPkgArchive directives to be treated as
3638
BuildPkgArchive directives. The result is that the 'interface' directory will be
3639
populated with the contents of all dependent packages. Moreover, on a Unix
3640
machine, the files will be copied and not referenced with a soft link.
3641
 
3642
This may be useful for:
3643
 
3644
=over 8
3645
 
3646
=item * Remote Development
3647
 
3648
=item * Collecting header files for scanning
3649
 
3650
=item * Local modification of files for test/debug/development
3651
 
3652
=back
3653
 
3654
=item B<--all>
3655
 
3656
This option will cause the build process to generate makefiles for all
3657
possible build targets ignoring the use of GBE_BUILDFILTER.
3658
 
3659
This option is sticky. Once used in a build it will be retained when makefiles
3660
are rebuilt.
3661
 
261 dpurdie 3662
=item B<--expert[=n]>
227 dpurdie 3663
 
3664
This option causes the generation of makefiles with relaxed dependancy checks.
3665
 
261 dpurdie 3666
If an argument is provided, then it will be used to set the level, otherwise a
3667
level of '1' will be set.
3668
 
227 dpurdie 3669
The makefiles will have no dependancy between the makefiles and the JATS build
3670
files or the users makefile. If the user's makefile.pl is changed then JATS
3671
will not detect the change and will not rebuild the makefiles. The user manually
3672
force the rebuild with the command 'jats rebuild'.
3673
 
3674
This option should be used with care and with full knowledge of its impact.
3675
 
3676
This option is sticky. Once used in a build it will be retained when makefiles
261 dpurdie 3677
are rebuilt. It will only be lost when the next 'jats build' is perfromed.
227 dpurdie 3678
 
261 dpurdie 3679
The effect of the option can be changed when the makefiles are processed. This
3680
option simply sets the default' mode of operation.
3681
 
227 dpurdie 3682
=item B<changelog>
3683
 
3684
This command will only update the CVS change log.
3685
 
3686
=item B<interface>
3687
 
3688
This command will only build, or rebuild, the 'interface' directory and the
3689
changelog ( if required ).
3690
 
261 dpurdie 3691
This command will not build, or rebuild, the root directory. The build
227 dpurdie 3692
process will not recurse through the subdirectories creating makefiles.
3693
 
261 dpurdie 3694
=item B<rootonly>
3695
 
3696
This command will only build, or rebuild, the 'interface' directory, the
3697
changelog (if required) and the root-level makefiles.
3698
 
3699
The build process will not recurse through the subdirectories creating
3700
makefiles. These can be made on-demand by jats if a 'make' command is issued.
3701
 
227 dpurdie 3702
=item B<clobber>
3703
 
3704
This command will remove generated build system files and directories.
3705
 
3706
=back
3707
 
3708
=head1 DESCRIPTION
3709
 
3710
The default build process will parse the user's build.pl file and create the
3711
'interface' directory before creating makefiles for each target platform.
3712
 
3713
The 'build' process simply generates the build sandbox. It does not invoke the
3714
generated makefiles. This must be done by the user in a different phase.
3715
 
3716
The 'build' process need only be invoked if the build.pl file has changed. The
3717
generated makefiles will detected changes to the makefile.pl's and cause them to
3718
be generated as required. The 'build' step sets up the sandboxes external
3719
environment.
3720
 
3721
=head1 INVOCATION
3722
 
3723
This perl library (buildlib.pl) is not designed to be invoked directly by the
3724
user. It should be invoked through a 'build.pl' file. Moreover, for historical
3725
reasons, the build.pl is not easily invoked. It is best to only invoke the
3726
'build' process via the JATS wrapper scripts : jats.bat or jats.sh.
3727
 
3728
The build.pl file must be invoked with two fixed arguments, followed by user
3729
options and subcommands
3730
 
3731
=over 8
3732
 
3733
=item   1 The current working directory
3734
 
3735
This could have been derived directly by the program, rather than having it
3736
passed in.
3737
 
3738
=item   2 The absolute path to buildlib.pl (this library)
3739
 
3740
In practice this value is not used, but is provided for historical reasons.
3741
 
3742
=item   3 Options and commands may follow the first two mandatory arguments.
3743
 
3744
=back
3745
 
3746
The build.pl file must 'require' the buildlib.pl and makelib.pl. The preferred
3747
code is:
3748
 
3749
=over 8
3750
 
3751
    build.pl: First statements
3752
    $MAKELIB_PL     = "$ENV{ GBE_TOOLS }/makelib.pl";
3753
    $BUILDLIB_PL    = "$ENV{ GBE_TOOLS }/buildlib.pl";
3754
 
3755
    require         "$BUILDLIB_PL";
3756
    require         "$MAKELIB_PL";
3757
 
3758
=back
3759
 
3760
=cut
3761
 
3762
1;