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