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