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