Subversion Repositories DevTools

Rev

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

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