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