Subversion Repositories DevTools

Rev

Rev 7308 | Rev 7310 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
363 dpurdie 1
########################################################################
7300 dpurdie 2
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
227 dpurdie 3
#
4
# Module name   : buildlib.pl
5
# Module type   : Makefile system
363 dpurdie 6
# Compiler(s)   : Perl
7
# Environment(s): jats
227 dpurdie 8
#
363 dpurdie 9
# Description   : Process build.pl file and create the build environment
227 dpurdie 10
#
363 dpurdie 11
# Usage         : Refer to documentation at the end of the file
227 dpurdie 12
#
363 dpurdie 13
#......................................................................#
227 dpurdie 14
 
15
use strict;
16
use warnings;
17
 
363 dpurdie 18
use JatsError;
227 dpurdie 19
use BuildVersion;
20
use BuildName;
21
use PackageEntry;
22
use JatsEnv;
23
use JatsSystem;
24
use JatsVersionUtils;
25
use FileUtils;
6133 dpurdie 26
use ToolsetFiles;
227 dpurdie 27
use Pod::Usage;
261 dpurdie 28
use Getopt::Long;
305 dpurdie 29
use File::Path;
5969 dpurdie 30
use XML::Writer;
5986 dpurdie 31
use ArrayHashUtils;
7301 dpurdie 32
use File::Find;
33
use Digest::SHA qw(sha1);
34
use IPC::Open3;
227 dpurdie 35
 
36
our $BuildVersion           = "2.1.0";
37
 
38
#.. Switchs
39
#
40
our $ScmBuildlib            = 0;
41
our $ScmBuildSrc            = "";
42
 
43
our $CmdSwitch              = "";
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;
5109 dpurdie 51
our $Cache                  = $ENV{GBE_DPKG_CACHE_CTL} || 0;
261 dpurdie 52
our $NoPackageError         = 0;
227 dpurdie 53
our $ForceBuildPkg          = 0;
54
our $Srcdir                 = "";               # default source root
331 dpurdie 55
our $ForceBuild             = 1;
2078 dpurdie 56
our $IgnorePkgs             = 0;
4778 dpurdie 57
our $GenericBuild           = undef;            # Build System Generic Build Test
227 dpurdie 58
 
59
#.. Public symbols, referenced by many build.pl implementations
60
#
61
our $BUILDPREVIOUSVERSION   = "0.0.0";          # BuildPreviousVersion()
62
our @BUILDPLATFORMS         = ();               # BuildPlatforms()
63
our %BUILDINFO              = ();               # BuildInfo
64
our @DEFBUILDPLATFORMS      = ();
65
our %BUILDPLATFORMARGS      = ();
66
our @BUILD_ACTIVEPLATFORMS  = ();
67
our @BUILDSUBDIRS           = ();               # BuildSubDir()
68
our @BUILDSETENV            = ();               # BuildSetenv()
69
our $BUILDINTERFACE         = "";               # BuildInterface()
70
our $BUILDLOCAL             = "";               # BuildInterface()
71
our $BUILDDIRTREE           = "";               # BuildDirTree()
241 dpurdie 72
our @BUILD_BADNAME          = ();               # Unknown platforms
7309 dpurdie 73
our @GENERIC_TARGETS        = ();               # Generic targets - only one allowed
74
our %BUILDERINFO            = ();               # Complete build info
227 dpurdie 75
 
76
our $BUILDNAME              = "";               # BuildName()
77
our $BUILDVERSION           = "";               # BuildName()
78
our $BUILDNAME_PACKAGE;                         # Name
79
our $BUILDNAME_VERSION;                         # Version
80
our $BUILDNAME_PROJECT;                         # Project(optional)
359 dpurdie 81
our $BUILDNAME_SUFFIX;                          # Project (available)
227 dpurdie 82
our $DEPLOY_PATCH           = 0;                # Deplyment patch number
7301 dpurdie 83
our $BUILDSIGNATURE;                            # Source signature
227 dpurdie 84
 
85
our %BUILDALIAS_DELAY       = ();               # Delayed aliases
86
our %BUILDALIAS_TARGETS     = ();               # BuildAlias from --Targets
87
our %BUILDALIAS             = ();               # BuildAlias
88
our %BUILDPRODUCT           = ();               # BuildProduct
89
our %BUILDPRODUCT_PARTS     = ();               # BuildProduct parts
90
our %PKGRULES               = ();               # Package include and link rules
91
our @BUILDTOOLS             = ();               # Extended tool path
92
our $BUILDPHASE             = 0;                # In Build Phase
93
our @CLOBBERDIRS            = ();               # Directories to clobber
375 dpurdie 94
our @REMOVEDIRS             = ();               # Directories to remove - if empty
247 dpurdie 95
our %BUILD_KNOWNFILES       = ();               # Files that will be known
5679 dpurdie 96
our @BUILDEXCLUDE           = ();               # Platforms to be excluded
227 dpurdie 97
 
333 dpurdie 98
our $Makelib                = "";
263 dpurdie 99
our $GBE_CORE;                                  # Root of JATS
100
our $InterfaceVersion;                          # Interface directory format version
3967 dpurdie 101
our $ScmRoot;                                   # Package Root
263 dpurdie 102
our $ScmInterface;                              # Interface directory
363 dpurdie 103
our $ScmBuildFilter;                            # Build Filter when build was created
4003 dpurdie 104
our $NoBuild                = 0;                # Dummy Build under ABT only
7300 dpurdie 105
our $BUILD_UUID             = time() . substr(rand(),2); # Build Unique Identifier
227 dpurdie 106
 
107
my  $DeleteDPACKAGE         = 0;                # Must clobber DPACKAGE
305 dpurdie 108
my  $build_source_pkg       = 0;                # Flag to build source package
227 dpurdie 109
my  $opt_help               = 0;
6133 dpurdie 110
my  $pkgFromSandbox         = 0;                # Flags that we have imported a package from a sandbox
227 dpurdie 111
 
6133 dpurdie 112
my  $genToolsetPlatform     = 0;                # BuildToolset directive has been seen
113
my  $genToolsetActive       = 0;                # TOOLSET platform required:1, Error:2
114
my  $toolsetPlatform        = 'NONE';           # TOOLSET Display Value
115
my  @genToolsetArgs;                            # Args for a generated TOOLSET
116
 
227 dpurdie 117
BuildLibInit();
118
 
119
sub BuildLibInit
120
{
121
 
122
#.. Set environment
123
#
331 dpurdie 124
    EnvImport( 'GBE_VERSION' );
125
    EnvImport( 'GBE_BIN' );
126
    EnvImport( 'GBE_CORE' );
127
    EnvImport( 'GBE_PERL' );
128
    EnvImport( 'GBE_TOOLS' );
129
    EnvImport( 'GBE_CONFIG' );
130
    EnvImport( 'GBE_DPKG' );
131
    EnvImport( 'GBE_MACHTYPE' );
132
    EnvImport( 'USER' );
133
    EnvImport( 'GBE_HOSTNAME');
134
    EnvImport( 'GBE_DRV' )
135
        if ( $ScmHost ne 'Unix' );            # DOS or WIN special
227 dpurdie 136
 
4688 dpurdie 137
    EnvImportOptional ( 'GBE_DPKG_REPLICA','' );
227 dpurdie 138
    EnvImportOptional ( 'GBE_DPKG_STORE','' );
139
    EnvImportOptional ( 'GBE_DPKG_CACHE','' );
140
    EnvImportOptional ( 'GBE_DPKG_LOCAL','' );
141
    EnvImportOptional ( 'GBE_DPKG_SBOX' ,'' );
313 dpurdie 142
    EnvImportOptional ( 'GBE_DPLY'      ,'' );
341 dpurdie 143
    EnvImportOptional ( 'GBE_SANDBOX'   ,'' );
227 dpurdie 144
 
145
    EnvImportOptional ( 'GBE_PLATFORM' );           # optional PLATFORM filter
146
    EnvImportOptional ( 'GBE_BUILDFILTER' );        # optional BUILD filter       
147
    EnvImportOptional ( 'GBE_ABT' );                # optional ABT flags          
148
 
149
#.. Common stuff
150
#
151
    require "$::GBE_TOOLS/common.pl";
331 dpurdie 152
    CommonInit( 'buildlib' );
227 dpurdie 153
    Debug( "Version:   $BuildVersion" );
279 dpurdie 154
    Require( "$::GBE_CONFIG/PLATFORM", "PLATFORM_CFG.PM"  );
227 dpurdie 155
 
156
#.. Parse command line
157
#
158
    $ScmBuildSrc = $0;                          # Name of the build file
331 dpurdie 159
    $Cwd = shift @ARGV;
227 dpurdie 160
    $Cwd =~ tr~\\/~/~s;;                        # Need / in path, Remove doubles
3967 dpurdie 161
    $::ScmRoot = StripDrive($Cwd);
333 dpurdie 162
    $Makelib = shift @ARGV;                     # Only for legacy build.pl files
227 dpurdie 163
 
261 dpurdie 164
    Verbose ("Command Line: @ARGV");
313 dpurdie 165
    my $result = GetOptions( "help|h:+"      => \$opt_help,
166
                             "man:3"         => \$opt_help,
167
                             "debug:+"       => \$::ScmDebug,
168
                             "verbose:+"     => \$::ScmVerbose,
169
                             "expert:1"      => \$Expert,
170
                             "all"           => \$All,
331 dpurdie 171
                             "cache:+"       => \$Cache,
313 dpurdie 172
                             "package"       => \$NoPackageError,
2078 dpurdie 173
                             "nopackages"    => \$IgnorePkgs,
313 dpurdie 174
                             "forcebuildpkg" => \$ForceBuildPkg,
331 dpurdie 175
                             "force!"        => \$ForceBuild,
4778 dpurdie 176
                             "generic!"      => \$GenericBuild,
313 dpurdie 177
                             );
261 dpurdie 178
    Usage() if ( $opt_help || !$result );
227 dpurdie 179
 
331 dpurdie 180
    Debug( "Host:          ", $ScmHost );
181
    Debug( "Cwd:           ", $Cwd );
333 dpurdie 182
    Debug( "Makelib:       ", $Makelib );
331 dpurdie 183
    Debug( "BuildFile:     ", $ScmBuildSrc );
184
    Debug( "Debug:         ", $::ScmDebug );
185
    Debug( "Verbose:       ", $::ScmVerbose );
186
    Debug( "Expert:        ", $Expert );
187
    Debug( "All:           ", $All );
188
    Debug( "Cache:         ", $Cache );
189
    Debug( "package:       ", $NoPackageError );
190
    Debug( "ForcePkg  :    ", $ForceBuildPkg );
191
    Debug( "ForceBuild :   ", $ForceBuild );
4778 dpurdie 192
    Debug( "IgnorePkgs :   ", $IgnorePkgs );
193
    Debug( "GenericTest :  ", $GenericBuild );
227 dpurdie 194
 
195
#.. Command
196
#
3967 dpurdie 197
 
198
    $CmdSwitch = (lc shift @ARGV) if @ARGV;
331 dpurdie 199
    Debug( "CmdSwitch:     ", $CmdSwitch );
227 dpurdie 200
 
331 dpurdie 201
    if ( $CmdSwitch )
202
    {
203
        if ( $CmdSwitch eq "interface" ) {
204
            $Interface      = 1;
227 dpurdie 205
 
331 dpurdie 206
        } elsif ( $CmdSwitch eq "rootonly" ) {
207
            $RootOnly       = 1;
227 dpurdie 208
 
331 dpurdie 209
        } elsif ( $CmdSwitch eq "clobber" ) {
210
            $Clobber        = 1;
227 dpurdie 211
 
331 dpurdie 212
        } elsif ( $CmdSwitch eq "help" || $CmdSwitch eq "usage" ) {
213
            $opt_help = 1;
214
            Usage();
227 dpurdie 215
 
331 dpurdie 216
        } else {
217
            Usage( "(E) build. Unknown command \"$CmdSwitch\"" );
218
        }
219
    }
227 dpurdie 220
 
331 dpurdie 221
    #
341 dpurdie 222
    #   If we are not performing a ForceBuild, then we don't need to continue
223
    #   We have updated the interface directory with BuildPkgArchive
224
    #   information.
331 dpurdie 225
    #
341 dpurdie 226
    unless ( $::GBE_SANDBOX )
331 dpurdie 227
    {
341 dpurdie 228
        TestForForcedBuild();
227 dpurdie 229
    }
230
 
231
    #
232
    #   Must inform makelib that its running under buildlib
233
    #
234
    $ScmBuildlib = 1;
235
 
236
    #
237
    #   In clobber mode System commands will not force termination
238
    #   otherwise, within build.pl, a failed system command will die.
239
    #
240
    SystemConfig ('UseShell' => 1,
283 dpurdie 241
                  'ExitOnError' => ($Clobber == 0) );
5109 dpurdie 242
 
243
    #
244
    #   Capture messages while processing directives
245
    # 
246
    StartCapture(1) 
247
        unless ($Clobber);
227 dpurdie 248
}
249
 
250
 
251
#-------------------------------------------------------------------------------
252
# Function        : Log
253
#
254
# Description     : Internal function to generate a log file of the build process
341 dpurdie 255
#                   The function will print its arguments to the screen and a log file
227 dpurdie 256
#
257
# Inputs          : Arguments will be printed
258
#
259
# Returns         : Nothing
260
#
261
sub Log
262
{
263
    if ( ! $Clobber )
264
    {
261 dpurdie 265
        print "@_\n";
266
        FileAppend ('build.log', \@_ );
227 dpurdie 267
    }
268
}
269
 
270
#-------------------------------------------------------------------------------
271
# Function        : BuildSubDir
272
#
273
# Description     : Specify one or more directories in which makefile.pl's can be
274
#                   found to be processed.
275
#
276
#                   This function will flag the build 'src' dir.
277
#                   This will be the first directory specified UNLESS there
278
#                   is a 'src' directory in the list
279
#
280
#                   The function may be called multiple times.
281
#
282
# Inputs          : NewDirs             - An array of directories
283
#
284
# Returns         : Nothing
285
#
286
 
287
sub BuildSubDir
288
{
289
    my( @NewDirs );
290
 
291
    @NewDirs = map { split /\s+/ } @_;
292
    @NewDirs = grep { defined $_ } @NewDirs;
293
 
294
    Debug( "BuildSubDir(@NewDirs)" );
295
 
296
    foreach my $ThisDir ( @NewDirs )
297
    {
298
        unless ( $Clobber )
299
        {
2450 dpurdie 300
            $ThisDir =~ s~/+$~~;
227 dpurdie 301
            if ( $ThisDir eq "." )
302
            {
303
                Error( "BuildSubDir() cannot specify the current directory (.)",
304
                       "The makefile.pl in the root directory is included in all makefile.pl's" );
305
            }
306
 
307
            if ( $ThisDir =~ m~\\~)
308
            {
309
                Warning ("BuildSubDir contains a '\\' character: $ThisDir" );
310
            }
311
            if ( grep /^$ThisDir$/, @BUILDSUBDIRS )
312
            {
313
                Warning( "BuildSubDir() duplicate subdirectory ignored '$ThisDir'." );
314
                next;
315
            }
316
            if ( ! ( -e $ThisDir and -d $ThisDir ) )
317
            {
318
                Error( "BuildSubDir() non-existent subdirectory: '$ThisDir'." );
319
            }
320
            if ( ! -f $ThisDir . '/makefile.pl' )
321
            {
322
                Error( "BuildSubDir() makefile.pl not found in subdirectory: '$ThisDir'." );
323
            }
324
 
325
            push( @BUILDSUBDIRS, $ThisDir );
326
        }
327
 
328
        #
329
        #   Capture the first source directory mentioned
330
        #   This will be used as the root of the build
331
        #
332
        #   If there is a Src directory then use this
333
        #
334
        $Srcdir = $ThisDir
335
            if ( $ThisDir =~ m/^src$/i );
336
        $Srcdir = $ThisDir
337
            unless ( $Srcdir );
338
    }
339
}
340
 
341
#-------------------------------------------------------------------------------
6133 dpurdie 342
# Function        : isKeyword 
343
#
344
# Description     : Test for an attempt to use reserved platform name 
345
#
346
# Inputs          : $test   - Name to test
347
#
348
# Returns         : Reserved word or none
349
#
350
sub isKeyword
351
{
352
    my ($test) = @_;
7307 dpurdie 353
    foreach my $keyword ( @PlatformConfig::BuildKeywords )
6133 dpurdie 354
    {
355
        return $keyword if (uc($test) eq $keyword);
356
    }
357
 
358
    return undef;
359
}
360
 
361
 
362
#-------------------------------------------------------------------------------
227 dpurdie 363
# Function        : BuildAlias
364
#
365
# Description     : Create an alias for multiple targets
366
#                   The default operations will:
367
#                       Add the alias as a default platform (* in the makefile.pl)
368
#                       Perform an implicit BuildPlatform for the alias targets
369
#
370
#                   In hindsight this was not good. Options modify the behaviour
371
#                   Options:
372
#                       --NotDefault    The alias will not be a part of the default
373
#                                       platform for the makefile.pls
374
#                       --Define        Simply define text substitution
375
#                                       Do not implicitly create platforms
376
#                       --Target        Accumulate platforms with specified targets
377
#                                       Complete alias determination is delayed
378
#                                       The named targets are specified as an alias
379
#                                       until the calculation is done
380
#
381
# Inputs          : alias[,--options]   comma seperated options
382
#                   arguments           alias arguments; platforms or targets
383
#
384
# Returns         : Nothing
385
#
386
sub BuildAlias
387
{
388
    my( $alias, @arguments ) = @_;
389
    my $notdefault;
390
    my $define;
391
    my $target_mode;
392
 
393
    Debug( "BuildAlias($alias, @arguments)" );
394
    Error ("BuildAlias: No platforms specified") unless ( @arguments );
395
    Error( "BuildAlias() must appear before BuildName()..." ) if ( $BUILDNAME );
396
 
397
    #   Parse attributes
398
    #
399
    my ( @attrs ) = split( ',', $alias );
400
 
401
    $alias = "";
402
    foreach ( @attrs ) {
403
        if ( /^--/ ) {
404
            if ( /^--NotDefault$/ ) {
405
                $notdefault = 1;
406
 
407
            } elsif ( /^--Define$/ ) {
408
                $define = 1;
409
 
410
            } elsif ( /^--Target$/ ) {
411
                $target_mode = 1;
412
 
413
            } else {
414
                Warning( "BuildAlias() unknown attribute: $_ -- ignored" );
415
            }
416
 
417
        } else {
5262 dpurdie 418
            Error( "BuildAlias() multiple alias specifications", "First: $alias and now $_" )
227 dpurdie 419
                if ( $alias ne "" );
420
            $alias = $_;
421
        }
422
    }
423
    Error( "BuildAlias() missing alias specifications" )
424
        if ( $alias eq "" );
425
 
7307 dpurdie 426
    if ( isKeyword($alias) ) {
427
        Error   ("BuildAlias() attempt to alias a keyword: $alias") unless defined($::GBE_ABT);
428
        Warning ("BuildAlias() attempt to alias a keyword: $alias -- builtin ignored");
429
    }
227 dpurdie 430
 
431
    #
432
    #   If we need to recalculate the alias based on targets, then tag the alias
433
    #   to be processed
434
    #
435
    $BUILDALIAS_TARGETS{ $alias } = ''
436
        if ( $target_mode );
437
 
438
    #   Define alias
439
    #
6133 dpurdie 440
    if ( PlatformConfig::targetHasTag($alias, 'GENERIC') )
227 dpurdie 441
    {
4551 dpurdie 442
        Error( "BuildAlias() cannot create an alias named $alias", "That name is reserved for generic targets" );
227 dpurdie 443
    }
444
    elsif ( $alias ne quotemeta( $alias ) )
445
    {
6133 dpurdie 446
        Error   ("BuildAlias() alias '$alias' contains invalid characters") unless defined($::GBE_ABT);
227 dpurdie 447
        Warning( "BuildAlias() alias '$alias' contains invalid characters -- ignored" );
448
    }
449
    elsif ( $BUILDALIAS{ $alias } )
450
    {
6133 dpurdie 451
        Error   ("BuildAlias() duplicate alias '$alias'") unless defined($::GBE_ABT);
227 dpurdie 452
        Warning( "BuildAlias() duplicate alias '$alias' -- alias ignored" );
453
    }
454
    else
455
    {
456
        #
457
        #   Expand alias UNLESS using --Target.
458
        #   The --Target is a real target and not a subject to alias expansion
459
        #   This solves order dependancy problems.
460
        #
461
        @arguments = ExpandPlatforms( @arguments )
462
            unless $target_mode;
463
 
6133 dpurdie 464
        my $platform = '';                   # current platform
227 dpurdie 465
        my @pargs = ();                      # current args
466
 
467
        #
468
        #   Process the expanded arguments
469
        #   Collect arguments and process when a new platform is discovered
470
        #
471
        foreach my $arg ( @arguments, '++' )
472
        {
473
            if ( $arg =~ /^--/ )
474
            {
475
                push @pargs, $arg;
476
                next;
477
            }
478
            else
479
            {
480
                #
481
                #   Start of a platform
482
                #   Process previous data, once a platform has been seen
483
                #
484
                if ( $platform )
485
                {
486
                    #   Add arguments to BUILDALIAS as we see them
487
                    #
488
                    HashJoin( \%BUILDALIAS, ' ', $alias, $platform );
489
                    HashJoin( \%BUILDALIAS, ' ', $alias, grep(!/^--Uses=/, @pargs) );
490
 
491
                    #
492
                    #   The BuildAlias can also define a platform.
493
                    #   (Sounded like a good idea at the time!)
494
                    #
495
                    unless ( $define || $target_mode )
496
                    {
497
                        push @pargs, '--NotDefault' if ( $notdefault );
498
                        push @pargs, '--FunctionName=BuildAlias';
499
                        BuildPlatforms( $platform, @pargs );
500
                    }
501
                }
502
 
503
                #
504
                #   Start collecting args for the next platform
505
                #
506
                @pargs = ();
507
                $platform = $arg;
508
            }
509
        }
510
    }
511
}
512
 
6133 dpurdie 513
#-------------------------------------------------------------------------------
514
# Function        : BuildAliasDef  
515
#
516
# Description     : Shorthand for BuildAlias (xxx,-Define, ... )
517
#                   The way is should have been done  :(
518
#
519
# Inputs          : $alias          Name of alias to define
520
#                   arguments       Alias arguments; platforms or targets
521
#
522
sub BuildAliasDef()
523
{
524
    my( $alias, @arguments ) = @_;
525
    BuildAlias($alias . ',--Define', @arguments);
526
}
227 dpurdie 527
 
528
#-------------------------------------------------------------------------------
529
# Function        : Process_TargetAlias
530
#
531
# Description     : Post Process the --Target option for the build alias
532
#                   Filter all platforms and extract those with a matching targets
533
#
534
# Inputs          : None
535
#
536
# Returns         : Nothing
537
#
538
sub Process_TargetAlias
539
{
540
 
541
    #
542
    #   Merge any delayed aliases with the complete set of alias
543
    #   Delayed alias are not used in expansions during the processing
5410 dpurdie 544
    #   of platforms and targets, but can be used to pick up errors
227 dpurdie 545
    #
546
    while ( my($key,$value) = each(%BUILDALIAS_DELAY) )
547
    {
548
        if ( exists($BUILDALIAS{$key}) )
549
        {
5867 dpurdie 550
            abtWarning(0,"BuildAlias() duplicates internal alias '$key'");
227 dpurdie 551
            next;
552
        }
553
        $BUILDALIAS{$key} = $value;
554
    }
5410 dpurdie 555
    ErrorDoExit();
227 dpurdie 556
 
557
    foreach my $alias ( keys %BUILDALIAS_TARGETS )
558
    {
559
        Debug( "BuildTargetAlias($alias)" );
560
 
561
        #
562
        #   Replace the existing alias - it has done its JOB
563
        #
564
        my $arguments = delete $BUILDALIAS{ $alias } ;
565
 
566
        foreach my $arg ( split / /, $arguments )
567
        {
568
            if ( $arg =~ /^--/ )                # argument
569
            {
570
                #   Add arguments to BUILDALIAS as we see them
571
                #
572
                HashJoin( \%BUILDALIAS, ' ', $alias, $arg );
573
                next;
574
            }
575
 
576
            foreach my $platform ( keys %BUILDINFO )
577
            {
578
                foreach my $element ( qw (TARGET BASE ) )
579
                {
580
                    my $target = $BUILDINFO{$platform}{$element};
581
                    if ( $target && $target eq $arg )
582
                    {
583
                        HashUniqueJoin( \%BUILDALIAS, ' ', $alias, $platform );
584
                        Debug( "BuildTargetAlias: $alias, $target -> $platform" );
585
                    }
586
                }
587
            }
588
        }
589
    }
590
}
591
 
592
#-------------------------------------------------------------------------------
6133 dpurdie 593
# Function        : CleanUp_Aliases 
594
#
595
# Description     : Will fully expand aliases to simplify display and processing 
596
#                       Remove arguments that  start with a '-'
597
#                       Remove bits that start with a !
598
#
599
# Inputs          : 
600
#
601
# Returns         : 
602
#
603
sub CleanUp_Aliases
604
{
605
    #
606
    #   Clean up Aliases
607
    #
608
#DebugDumpData("BEFORE CleanUp_Aliases", \%BUILDALIAS);
609
    foreach my $alias ( keys %BUILDALIAS )
610
    {
611
        my @aliasList = split(/ /, $BUILDALIAS{$alias});
612
        my @expanded =  ExpandPlatforms(@aliasList);
613
 
614
        my %add;
615
        my %remove;
616
 
617
        foreach ( @expanded)
618
        {
619
            if (m/^-/) {
620
            } elsif (m/^!(.*)/) {
621
                $remove{$1} = 1;
622
            } else {
623
                $add{$_} = 1;
624
            }
625
        }
626
 
627
        #
628
        #   If there are NO additive expressions in the alias, then
629
        #   assume all the active targets
630
        #
631
        unless (keys %add) {
632
            foreach  ( @BUILD_ACTIVEPLATFORMS)
633
            {
634
                 $add{$_} = 1;
635
            }
636
        }
637
 
638
 
639
        foreach ( keys %remove) {
640
            delete $add { $_};
641
        }
642
 
643
        $BUILDALIAS{$alias} = join(' ',keys %add);
644
    }
645
#DebugDumpData("AFTER CleanUp_Aliases", \%BUILDALIAS);
646
}
647
 
648
 
649
#-------------------------------------------------------------------------------
227 dpurdie 650
# Function        : BuildProduct
651
#
652
# Description     : Create a family of Platforms with a common product line
653
#                   ie: Create two flavors of the TP5, one based on the MOSF and
654
#                   the othe based on the MOS68 toolset.
655
#
656
# Inputs          : $product[,opts]+    The name of the product
657
#                                       This will be the base name for the family
658
#                                       Allowed options are:
7304 dpurdie 659
#                                           --NotDefault       : This is not a default build platform
660
#                                           --Uses=x1,x2:x3    : All use another platform
661
#                                           --Alias=y1,y2:x3   : All alias to this name
227 dpurdie 662
#
663
#                   platforms           One or more root platforms, with options
664
#                                       The platform is macro expanded.
665
#                                       Options may be a part of the platform or
666
#                                       distinct.
667
#
668
# Returns         :
669
#
670
 
671
sub BuildProduct
672
{
673
    my( $product, @arguments ) = @_;
674
    my $notdefault = 0;
7304 dpurdie 675
    my @commonArgs = ();
227 dpurdie 676
 
677
    Debug( "BuildProduct($product, @arguments)" );
678
    Error( "BuildProduct must appear before BuildName()..." )
679
        if ( $BUILDNAME ne "" );
680
 
681
    #   Parse attributes
682
    #
683
    my( @attrs ) = split( ',', $product );
684
 
685
    $product = "";
686
    foreach ( @attrs ) {
687
        if ( /^--/ ) {
688
            if ( /^--NotDefault$/ ) {
689
                $notdefault++;
690
 
7304 dpurdie 691
            } elsif ( /^(--Uses=.*)/ ) {
692
                UniquePush (\@commonArgs, $1 );
227 dpurdie 693
 
5115 dpurdie 694
            } elsif ( /^(--Alias=.*)/ ) {
7304 dpurdie 695
                UniquePush (\@commonArgs, $1 );
5115 dpurdie 696
 
227 dpurdie 697
            } else {
698
                Warning( "BuildProduct() unknown attribute: $_ -- ignored" );
699
            }
700
 
701
        } else {
702
            Error( "BuildProduct() multiple product specifications not allowed" )
703
                if ( $product ne "" );
704
            $product = $_;
705
        }
706
    }
707
 
708
    #
709
    #   Sanity test
710
    #
711
    Error( "BuildProduct() missing product specifications" )
712
        if ( $product eq "" );
713
 
714
    Error( "BuildProduct() product '$product' contains invalid characters" )
715
        if ( $product ne quotemeta( $product ) );
716
 
717
    Error( "BuildProduct() duplicate product '$product'" )
718
        if ( $BUILDPRODUCT{ $product } );
719
 
720
    Error( "BuildProduct() duplicate alias '$product'" )
721
        if ( $BUILDALIAS{ $product } );
722
 
723
    #
724
    #   Expand the user specified targets to allow the use of BuildAlias
725
    #   The (bad) side effect of this is that target options get reorganised
726
    #       PLATFORM,--Uses=ANOTHER  ==> PLATFORM --Uses=ANOTHER
727
    #
7304 dpurdie 728
    #   Insert markers(++) into @arguments to mark when to process collected data
227 dpurdie 729
    #   Insert before each PLATFORM and at the end of the list
730
    #   platform specifier or the end of the list. Scan the arguments
731
    #
732
    @arguments = ExpandPlatforms( @arguments );
733
    my @new_args;
734
    foreach  ( @arguments )
735
    {
736
        push (@new_args, '++') unless ( m/^--/ );
737
        push (@new_args, $_ );
738
    }
739
    push (@new_args, '++');
740
    shift @new_args if $new_args[0] eq '++';
741
 
7304 dpurdie 742
    my @targs = @commonArgs;
227 dpurdie 743
    my $target;
744
    foreach my $arg ( @new_args )
745
    {
746
        #
747
        #   Collect per-platform arguments
748
        #
7304 dpurdie 749
        if ( $arg =~ /^--/ ) {
227 dpurdie 750
            push @targs, $arg;
751
            next;
752
        }
753
 
754
        #
755
        #   Collect target(platform) name
756
        #
757
        unless ( $arg eq '++' )
758
        {
759
            $target = $arg;
760
            Error( "BuildProduct() cannot create a product based on a GENERIC platform" )
6133 dpurdie 761
                if ( PlatformConfig::targetHasTag($target,'GENERIC') );
227 dpurdie 762
            next;
763
        }
764
 
765
        #
766
        #   Infer a BuildPlatform
767
        #   Do not provide a platform name. This will be created later when the
768
        #   full name is known - or can be calculated.
769
        #
7304 dpurdie 770
        CreateBuildPlatformEntry('BuildProduct', $notdefault, $product, $target, \@targs );
227 dpurdie 771
 
7304 dpurdie 772
        @targs = @commonArgs;
227 dpurdie 773
        $target = undef;
774
    }
775
}
776
 
777
#-------------------------------------------------------------------------------
778
# Function        : CreateBuildPlatformEntry
779
#
780
# Description     : Internal routine to create the Build Entry
781
#                   Single point to create a platform, whatever one of those is
782
#
783
# Inputs          : $fname                  - Name of invoking directive
784
#                   $notdefault             - True if the platform is not to be added to the
785
#                                             list of default platforms
786
#                   $product                - Optional product name
787
#                   $target                 - Target platform name
788
#                   $pArgs                  - Ref to an array of platform arguments
7304 dpurdie 789
#                                             Known: --Uses=aaa,bbb and --Alias=xxx,yyy
227 dpurdie 790
#
791
# Returns         :
792
#
793
 
794
sub CreateBuildPlatformEntry
795
{
7304 dpurdie 796
    my ($fname, $notdefault, $product, $target, $pArgs ) = @_;
227 dpurdie 797
    my %buildentry;
798
    my $platform;
799
 
800
    #
801
    #   Create a basic BUILDINFO entry
802
    #
803
    $buildentry{FNAME} = $fname;
804
    $buildentry{NOT_DEFAULT} = $notdefault;
805
    $buildentry{PRODUCT} = $product;
806
    $buildentry{TARGET} = $target;
807
    $buildentry{BASE} = $target;
363 dpurdie 808
    foreach ( @$pArgs )
809
    {
810
        if ( m~^--Alias=(.+)~ ) {
7304 dpurdie 811
            foreach my $alias (split('[:,]',$1))
6133 dpurdie 812
            {
813
                Error ("$fname() attempt to alias a keyword: $alias")
814
                    if ( isKeyword($alias) );
815
                push @{$buildentry{USERALIAS}},$alias;
816
            }
7304 dpurdie 817
        } elsif ( m~^--Uses=(.+)~ ) {
818
            push @{$buildentry{USES}},split('[:,]',$1);
819
 
6133 dpurdie 820
        } else {
363 dpurdie 821
            push @{$buildentry{ARGS}}, $_;
822
        }
823
    }
227 dpurdie 824
 
4728 dpurdie 825
    #   Detect reserved words being misused as a platform name
6133 dpurdie 826
    #   At the moment, the value of NATIVE and TOOLSET are calculate towards the end of the
827
    #   build process so that it can be limited to platforms that are present.
828
    foreach my $reserved ( qw (NATIVE TOOLSET INSTRUMENT))
829
    {
830
        Error("Invalid use of the platform alias $reserved","The $reserved alias cannot be used to define build platforms")
831
            if (uc($target) eq uc($reserved));
832
    }
4728 dpurdie 833
 
227 dpurdie 834
    #
7308 dpurdie 835
    #   Allow per-platform processing to alter the basic information
227 dpurdie 836
    #   Special processing may be perform to extend the information
837
    #   Allows special processing to be enabled on a per-target basis
838
    #
839
    #   There are three forms of processing that have been allowed for:
840
    #       1) None:        There is not platform specific extension
841
    #       2) Basic:       The extension will add or extend build information
842
    #       3) Advanced:    The extension will generate additional build information
843
    #                       structures.
844
    #
845
 
846
    #
847
    #   Locate the optional PLATFORM configuration file
848
    #   If it does exist then it can alter build-time information
849
    #
850
    if ( my $build_cfg = Require( "$::GBE_CONFIG/PLATFORM", "$target.cfg"  ) )
851
    {
852
        Verbose ("Processing(new) Platform Configuration file: $build_cfg");
853
 
297 dpurdie 854
        #
303 dpurdie 855
        #   Create package name with an uppercase target
856
        #   Target should be UC, but under windows its not detected
857
        #   at this time
858
        #
859
        my $package_name = uc($target) . '_Build';
860
 
861
        #
4551 dpurdie 862
        #   Ensure that the CFG is correctly formed
297 dpurdie 863
        #       Perhaps the package that it implements was misnamed
864
        #
303 dpurdie 865
        Error ("INTERNAL: $target.cfg does not satisfy API " )
297 dpurdie 866
            unless ( $package_name->can('new_platform') || $package_name->can('add_platform') );
867
 
227 dpurdie 868
        if ( $package_name->can('new_platform') )
869
        {
870
            Verbose ("Processing(new) Platform Configuration: $package_name");
871
            $package_name->new_platform( \%buildentry );
872
        }
873
        else
874
        {
875
            Debug ("Processing(new) Platform Configuration: $package_name. 'new_platform' function not found");
876
        }
877
    }
878
 
879
    #
880
    #   Add the basic entry into the build system, unless its been
881
    #   flagged as a TEMPLATE
882
    #
883
    AddBuildPlatformEntry (\%buildentry )
884
        unless ( $buildentry{TEMPLATE} );
885
}
886
 
7309 dpurdie 887
END {
888
    DebugDumpData("BUILDERINFO", \%BUILDERINFO);
889
    }
227 dpurdie 890
 
891
#-------------------------------------------------------------------------------
892
# Function        : AddBuildPlatformEntry
893
#
894
# Description     : Internal routine to add a Build Entry into the build system
895
#                   This function MAY be called from the build extensions
896
#
897
#                   NOTES:
898
#                   No processing of the info structure is performed. This MUST
899
#                   have been done before now.
900
#
901
#                   Additional information may be added to the structure.
902
#
903
#
904
# Inputs          : $pInfo              - Reference to a BuildInfo structure
905
#
906
# Returns         : Nothing
907
#
908
sub AddBuildPlatformEntry
909
{
910
    my ($pInfo) = @_;
911
    my $fname = $pInfo->{FNAME};
912
 
913
    #
914
    #   Locate the optional PLATFORM configuration file
915
    #   If it does exist then it can extend build-time information
916
    #
917
    my $target = $pInfo->{TARGET};
241 dpurdie 918
 
279 dpurdie 919
    #
4551 dpurdie 920
    #   Detect GENERIC targets
921
    #       The Build file is only allowed to have one that can be built on any one machine
922
    #
7309 dpurdie 923
    my $buildAvailability = PlatformConfig::targetHasTag( $target, 'MACHTYPE' );
924
    if (PlatformConfig::targetHasTag( $target, 'GENERIC' ) )
4551 dpurdie 925
    {
926
        UniquePush (\@GENERIC_TARGETS, $target );
6133 dpurdie 927
    }
928
 
929
    #
930
    #   Detect GENERIC_<machType> targets
931
    #
7309 dpurdie 932
    if (PlatformConfig::targetHasTag( $target, 'GENERIC_MACHTYPE' ) )
6133 dpurdie 933
    {
4551 dpurdie 934
        $pInfo->{IS_GENERIC} = 1;
6133 dpurdie 935
        $pInfo->{ALIAS} = 'GENERIC';
936
        $pInfo->{NOT_AVAILABLE} = 1 unless needToolset();
937
        $All = 1;
4551 dpurdie 938
    }
939
 
940
    #
279 dpurdie 941
    #   Ensure target is known to JATS
942
    #   Remove unknown targets from the build. Create a list of unknown
943
    #   targets and report them later.
944
    #
7309 dpurdie 945
    unless ( $pInfo->{NOT_AVAILABLE} || exists $BUILDINFO{$target} || $pInfo->{IS_GENERIC} || ($target =~ m~^GENERIC_~) )
227 dpurdie 946
    {
7309 dpurdie 947
        my $base_target = PlatformConfig::targetHasTag( $target, 'BASE_TARGET' ) || $target;
279 dpurdie 948
        unless ( Exists( "$::GBE_CONFIG/PLATFORM", $base_target  ) )
949
        {
6133 dpurdie 950
            UniquePush (\@BUILD_BADNAME, $target ); 
279 dpurdie 951
            $pInfo->{NOT_AVAILABLE} = 1;
952
        }
953
    }
954
 
7309 dpurdie 955
    if ($buildAvailability)
956
    {
957
        $BUILDERINFO{$target}{$buildAvailability} = 1;
958
         $pInfo->{NOT_AVAILABLE} = 1 unless ($buildAvailability eq $::GBE_MACHTYPE)
959
    }
960
 
279 dpurdie 961
    #
4551 dpurdie 962
    #   Mark as NOT_AVAILABLE platforms that are not available on this machine
279 dpurdie 963
    #
964
    unless ($pInfo->{NOT_AVAILABLE} )
965
    {
966
        $pInfo->{NOT_AVAILABLE} = 1
7309 dpurdie 967
            unless ($buildAvailability);
279 dpurdie 968
    }
969
 
970
    unless ($pInfo->{NOT_AVAILABLE} )
971
    {
4551 dpurdie 972
        my $target_cfg = $pInfo->{TARGET_CFG} || $target;
317 dpurdie 973
        if ( my $build_cfg = Require( "$::GBE_CONFIG/PLATFORM", "${target_cfg}.cfg"  ) )
227 dpurdie 974
        {
975
            Verbose ("Processing(add) Platform Configuration file: $build_cfg");
317 dpurdie 976
            my $package_name = "${target_cfg}_Build";
227 dpurdie 977
 
978
            if ( $package_name->can('add_platform') )
979
            {
980
                Verbose ("Processing(add) Platform Configuration: $package_name");
981
                $package_name->add_platform( $pInfo );
982
            }
983
            else
984
            {
985
                Debug ("Processing(add) Platform Configuration: $package_name. 'add_platform' function not found");
986
            }
987
        }
988
    }
989
 
990
    #
991
    #   If a product name has been provided then the platform is a product
992
    #   and will need additional processing
993
    #
994
    if ( $pInfo->{PRODUCT} )
995
    {
996
        #
997
        #   Create the platform name. Derived from the product and the target
998
        #
999
        $pInfo->{PLATFORM} = $pInfo->{PRODUCT} . '_' . $pInfo->{TARGET};
1000
 
1001
        #
1002
        #   Remember the product name
1003
        #
1004
        $BUILDPRODUCT{ $pInfo->{PRODUCT} } = 1;
1005
 
1006
        #
1007
        #   Add platform name to the alias explansion being created
1008
        #   Allows the user to reference the entire FAMILY of platforms
1009
        #
1010
        HashJoin( \%BUILDALIAS, ' ', $pInfo->{PRODUCT}, $pInfo->{PLATFORM} );
1011
 
1012
        #
1013
        #   Create an element to assist in creating %ScmBuildProducts
1014
        #
1015
        $pInfo->{ISPRODUCT} = 1;
1016
        $BUILDPRODUCT_PARTS{$pInfo->{PLATFORM}} = "$pInfo->{PRODUCT},$pInfo->{TARGET}";
1017
    }
1018
    else
1019
    {
1020
        $pInfo->{PRODUCT} = $pInfo->{TARGET};
1021
        $pInfo->{PLATFORM} = $pInfo->{TARGET};
1022
    }
1023
 
1024
    #---------------------------------------------------------------------------
1025
    #   All the hard work has been done
1026
    #   We now know the platforms full name
1027
    #
1028
    #   Ensure that the target platform has not been been specified
1029
    #   Perhaps this should be an error
1030
    #
1031
    my $platform = $pInfo->{PLATFORM};
1032
 
5109 dpurdie 1033
    if ( defined ( $BUILDINFO{$platform}) && ! $Clobber)
227 dpurdie 1034
    {
5867 dpurdie 1035
        abtWarning(1,"$fname() duplicate platform '$platform'");
5429 dpurdie 1036
        return;
227 dpurdie 1037
    }
1038
 
1039
    #
1040
    #   Add platform (tag) to various lists
1041
    #
1042
    UniquePush( \@BUILDPLATFORMS, $platform );
1043
    UniquePush( \@DEFBUILDPLATFORMS, $platform ) unless ( $pInfo->{NOT_DEFAULT} );
1044
 
1045
    #
1046
    #   Create a simple alias if requested
1047
    #   Used if a platform creates multiple entires
1048
    #
1049
    if ( $pInfo->{ALIAS} )
1050
    {
317 dpurdie 1051
        HashJoin( \%BUILDALIAS_DELAY, ' ', $_, $platform )
1052
            foreach ( ArrayList($pInfo->{ALIAS}) );
227 dpurdie 1053
    }
1054
 
363 dpurdie 1055
    if ( $pInfo->{USERALIAS} )
1056
    {
1057
        HashJoin( \%BUILDALIAS_DELAY, ' ', $_, $platform )
1058
            foreach ( ArrayList($pInfo->{USERALIAS}) );
1059
    }
1060
 
227 dpurdie 1061
    #
1062
    #   Create a HARDWARE type alias if requested
1063
    #   ie: SOLARIS_SPARC or SOLARIS_X86
1064
    #
1065
    if ( $pInfo->{HARDWARE} )
1066
    {
1067
        HashJoin( \%BUILDALIAS_DELAY, ' ',  $pInfo->{BASE} . '_' . $pInfo->{HARDWARE}, $platform );
1068
    }
1069
 
1070
    #
1071
    #   Create the 'parts' of the platform. This is a list of unique
1072
    #   bits to search. It will consist of:
1073
    #       [0]     - platform
1074
    #       [1]     - product
1075
    #       ...     - Uses bits ...
1076
    #       [last]  - target
1077
    #
1078
    my @parts;
1079
 
379 dpurdie 1080
    if ( $pInfo->{USES_FIRST} )
1081
    {
1082
        UniquePush (\@parts, @{$pInfo->{USES_FIRST}} );
1083
    }
1084
 
1085
    UniquePush (\@parts, $platform);
1086
 
227 dpurdie 1087
    #
1088
    #   Include all the product extensions
1089
    #
1090
    if ( $pInfo->{ISPRODUCT}  )
1091
    {
1092
        UniquePush (\@parts, map {+ "$pInfo->{PRODUCT}_${_}" } @{$pInfo->{USES}});
1093
        UniquePush (\@parts, map {+ "$pInfo->{PRODUCT}_${_}" } @{$pInfo->{ALSO_USES}});
1094
        UniquePush (\@parts, $pInfo->{PRODUCT} );
1095
    }
1096
 
1097
    #
1098
    #   Add in non-product expanded parts
1099
    #
1100
    UniquePush (\@parts, @{$pInfo->{EXTRA_USES}});
1101
 
1102
    #
1103
    #   Create a structure to assist in search path resolution
1104
    #   The order is important. It sets the include search order for include
1105
    #   files and libraries
1106
    #   If A uses B then search in A_B, A, B
1107
    #       ie: GAK uses MOS68K Search stuff in GAK_MOS68K, GAK, MOS68K
1108
    #
1109
    #       Usage:  OBFTP uses TP5 on MOSCF(target)       (BuildProduct)
1110
    #       Expansion: OBFTP, TP5_MOSCF, TP5
1111
    #
1112
    #       Usage: VS2003(target) also uses WIN32(uses)     (BuildPlatform)
1113
    #       Expansion: VS2003, VS2003_WIN32, WIN32
1114
    #
1115
    if ( $pInfo->{ISPRODUCT}  )
1116
    {
1117
        UniquePush (\@parts, map {+ "${_}_$pInfo->{TARGET}", $_, $pInfo->{TARGET}} @{$pInfo->{USES}});
1118
        UniquePush (\@parts, map {+ "${_}_$pInfo->{TARGET}", $_, $pInfo->{TARGET}} @{$pInfo->{ALSO_USES}});
1119
    }
1120
    else
1121
    {
1122
        UniquePush (\@parts, map {+ "$pInfo->{TARGET}_${_}", $pInfo->{TARGET}, $_} @{$pInfo->{USES}});
1123
        UniquePush (\@parts, map {+ "$pInfo->{TARGET}_${_}", $pInfo->{TARGET}, $_} @{$pInfo->{ALSO_USES}});
1124
    }
1125
 
1126
    #
1127
    #   Finally - the target
1128
    #
1129
    UniquePush (\@parts, $pInfo->{TARGET} );
1130
 
1131
    #
1132
    #   Save the PARTS
1133
    #   Also saved as BUILDPLATFORM_PARTS for interface with older versions
1134
    #   of the deployments scripts.
1135
    #
1136
    $pInfo->{PARTS} = \@parts;
1137
 
1138
    #
1139
    #   Add any arguments to the platforms argument list
1140
    #
1141
    PlatformArgument( $platform, @{$pInfo->{ARGS}} ) if ( $pInfo->{ARGS} );
1142
 
1143
    #
1144
    #   Clean up and save
1145
    #
1146
    delete $pInfo->{TEMPLATE};
1147
    delete $pInfo->{FNAME};
1148
    $BUILDINFO{$platform} = $pInfo;
1149
#    DebugDumpData("BUILDINFO", \%BUILDINFO );
1150
}
1151
 
1152
 
1153
sub BuildArgument
1154
{
1155
    my( $platform, @arguments ) = @_;
1156
    my( @platforms );
1157
 
1158
    Debug( "BuildArgument($platform, @arguments)" );
1159
 
1160
    Error( "BuildArgument must appear before BuildName()..." )
1161
        if ( $BUILDNAME ne "" );
1162
 
1163
    #
1164
    #   Allow a wildcard to apply a single argument to all platforms
1165
    #   Should only be used AFTER all the platforms have been specified
1166
    #
1167
    if ( $platform eq '*' )
1168
    {
1169
        @platforms = @BUILDPLATFORMS;          # Simple Wildcard
1170
    }
1171
    else
1172
    {
1173
        @platforms = ExpandPlatforms( $platform );  # aliasing
1174
    }
1175
 
283 dpurdie 1176
    foreach my $platform ( @platforms )
227 dpurdie 1177
    {
1178
        next if ( $platform =~ /^--/ );         # argument, ignore
1179
 
1180
        PlatformArgument( $platform, @arguments );
1181
    }
1182
}
1183
 
1184
 
1185
sub BuildPlatforms
1186
{
1187
    my( @arguments ) = @_;
1188
    my $fname = "BuildPlatforms";
1189
 
1190
    Debug( "BuildPlatforms(@arguments)" );
1191
 
1192
    Error( "BuildPlatforms must appear before BuildName()..." )
1193
        if ( $BUILDNAME ne "" );
1194
 
1195
    #
1196
    #   Expand the user specified platforms to allow the use of BuildAlias
1197
    #   The (bad) side effect of this is that platform options get reorganised
1198
    #       PLATFORM,--Uses=ANOTHER  ==> PLATFORM --Uses=ANOTHER
1199
    #
1200
    #   Insert markers(++) into @aruments to mark when to process collected data
1201
    #   Insert before each PLATFORM and at the end of the list
1202
    #   platform specifier or the end of the list. Scan the arguments
1203
    #
1204
    @arguments = ExpandPlatforms( @arguments );
1205
    my @new_args;
1206
    foreach  ( @arguments )
1207
    {
1208
        push (@new_args, '++') unless ( m/^--/ );
1209
        push (@new_args, $_ );
1210
    }
1211
    push (@new_args, '++');
1212
    shift @new_args if $new_args[0] eq '++';
1213
 
1214
 
1215
    my $platform  = "";                         # current platform
1216
    my $notdefault  = 0;
1217
    my @pargs = ();
1218
 
1219
    foreach my $arg ( @new_args )
1220
    {
1221
        #
1222
        #   Extract known options
1223
        #   Unknown options bind to the current platform
1224
        #
1225
        if ( $arg =~ /^--/ ) {
1226
            if ( $arg =~ /^--NotDefault$/ ) {
1227
                $notdefault = 1;
1228
 
1229
            } elsif ( $arg =~/^--FunctionName=(.*)/ ) {
1230
                $fname = $1;
1231
 
1232
            } else {
1233
                push @pargs, $arg;
1234
            }
1235
            next;
1236
        }
1237
 
1238
        #
1239
        #   New platform. Save name for later. Collect arguments first
1240
        #
1241
        unless ( $arg eq '++' )
1242
        {
1243
            $platform = $arg;
1244
 
1245
            Error( "$fname() missing platform specification" )
1246
                unless ( $platform );
1247
 
1248
            Error( "$fname() product '$platform' contains invalid characters" )
1249
                unless ( $platform eq quotemeta( $platform ) );
1250
 
1251
            next;
1252
        }
1253
 
1254
        #
1255
        #   Create new platform
1256
        #   Have collected name and arguments
1257
        #
7304 dpurdie 1258
        CreateBuildPlatformEntry($fname, $notdefault, undef, $platform, \@pargs  );
227 dpurdie 1259
 
1260
        #
1261
        #   Reset collection variables for next platform
1262
        #
1263
        $platform = "";
1264
        $notdefault  = 0;
1265
        @pargs = ();
1266
    }
1267
}
1268
 
1269
 
1270
#   PlatformArgument ---
1271
#       Append an argument list to the specified platform argument list.
1272
#       Internal use only
1273
#..
1274
 
1275
sub PlatformArgument
1276
{
1277
    my( $platform, @arguments ) = @_;
1278
 
1279
    Debug( "  PlatformArguments($platform, @arguments)" );
1280
 
1281
    HashJoin( \%BUILDPLATFORMARGS, $;, $platform, @arguments )
1282
        if ( $platform );
1283
}
1284
 
279 dpurdie 1285
#-------------------------------------------------------------------------------
5679 dpurdie 1286
# Function        : BuildExclude 
1287
#
1288
# Description     : Allow specific platforms to be excluded from the Build
1289
#                   Intended use:
1290
#                       Allow the use if a platform alias, but not all elements of it
1291
#                       ie: Use DEVLINUX, but not ARM9TDMI as we no longer support it 
1292
#                           in this version.
1293
#                   Multiple BuildExclude directives are allowed
1294
#                   Order or location is not important        
1295
#
1296
# Inputs          : Platforms names and options
1297
#                   Format:
1298
#                       --PLATFORM=xxxxx    (Marginal use)
1299
#                       --PRODUCT=yyyy      (Not very useful)
1300
#                       --TARGET=zzzz       (Default)
1301
#                       zzzz                (Same as --TARGET=ZZZZ)
1302
#                       
1303
#
1304
# Returns         : Nothing 
1305
#
1306
sub BuildExclude
1307
{
1308
    my( @arguments ) = @_;
1309
    Debug( "BuildExclude(@arguments)" );
1310
 
1311
    Error( "BuildExclude must appear before BuildName()..." )
1312
        if ( $BUILDNAME ne "" );
1313
 
1314
    #
1315
    #   Simply save the arguments for later
1316
    #   Allow multiple specs in the one definition
1317
    #
1318
    foreach ( @arguments)
1319
    {
5680 dpurdie 1320
        Error ("Invalid format: $_") if m/[,\s]/;
5679 dpurdie 1321
        UniquePush (\@BUILDEXCLUDE, split(/\s*,\s*/,$_));
1322
    }
1323
}
1324
 
1325
#-------------------------------------------------------------------------------
6133 dpurdie 1326
# Function        : BuildToolset 
1327
#
1328
# Description     : Indicate that this package will build binary parts of a JATS
1329
#                   toolset.
1330
#                   
1331
#                   Should be used to indicate that it building non-binary parts
1332
#                   too.
1333
#                   
1334
#                   Used as a sanity test.
1335
#
1336
# Inputs          : Options to limit the Machine Types affected 
1337
#
1338
# Returns         : 
1339
#
1340
sub BuildToolset
1341
{
1342
    my( @arguments ) = @_;
1343
    my ($exclude, $include, $including);
1344
 
1345
    $genToolsetPlatform = 1;
1346
    Debug( "BuildToolset(@arguments)" );
1347
    Error( "BuildToolset must appear before BuildName()..." )
1348
        if ( $BUILDNAME ne "" );
1349
 
1350
    #
1351
    #   Process TOOLSET specific options
1352
    #       --ExcludeMachType=xxxx,yyy
1353
    #       --MachType=xxxx,yyy
1354
    #
1355
    foreach ( @arguments )
1356
    {
1357
        if ( m~^--ExcludeMachType=(.+)~i ) {
1358
            foreach my $arch (split(',',$1))
1359
            {
1360
                if (uc($arch) eq uc($::GBE_MACHTYPE))
1361
                {
1362
                    Verbose("Exclude TOOLSET on this machine");
1363
                    $exclude = 1;
1364
                    last;
1365
                }
1366
            }
1367
        } elsif ( m~^--MachType=(.+)~i ) {
1368
            $including = 1;
1369
            foreach my $arch (split(',',$1))
1370
            {
1371
                if (uc($arch) eq uc($::GBE_MACHTYPE))
1372
                {
1373
                    Verbose("Include TOOLSET on this machine");
1374
                    $include = 1;
1375
                    last;
1376
                }
1377
            }
1378
 
1379
        } else {
1380
            Error ("BuildToolset: Unknown option: $_");
1381
        }
1382
    }
1383
 
1384
    #
1385
    #   Show we build for this architecture
1386
    #
1387
    $genToolsetActive = 0;
1388
    if ($exclude) {
1389
        $toolsetPlatform = 'Excluded';
1390
        return;
1391
    }
1392
 
1393
    if ($including) {
1394
        if ($include) {
1395
            $genToolsetActive = 1;
1396
        } else {
1397
            $toolsetPlatform = 'Not included';
1398
        }
1399
        return;
1400
    }
1401
 
1402
    $genToolsetActive = 1;
1403
    return;
1404
}
1405
 
1406
 
1407
#-------------------------------------------------------------------------------
279 dpurdie 1408
# Function        : BuildName
1409
#
1410
# Description     : Defines the package name and version
1411
#
1412
# Inputs          : build arguments
1413
#                   Various formats are allowed for backward compatability
1414
#                   Must support a number of different formats
1415
#                       "name nn.nn.nn prj"
1416
#                       "name nn.nn.nn.prj"
1417
#
1418
#                       "name nn.nn.nn prj", "nn.nn.nn"
1419
#                       "name nn.nn.nn.prj", "nn.nn.nn"
1420
#
1421
#                       "name", "nn.nn.nn.prj"
1422
#
1423
#                       "name", "nn.nn.nn", "prj", --RelaxedVersion
1424
#
1425
# Returns         : Nothing
1426
#
227 dpurdie 1427
sub BuildName
1428
{
1429
    my( @arguments ) = @_;
1430
    my $relaxed_version_name = 0;
1431
    my @args;
1432
 
1433
    Debug( "BuildName(@arguments)" );
315 dpurdie 1434
    Error( "Platform(s) not defined.",
227 dpurdie 1435
            "BuildAlias, BuildProduct and BuildPlatform directives must be defined prior to BuildName()." )
1436
        unless( scalar @BUILDPLATFORMS );
1437
 
1438
#.. Parse arguments
1439
#.
1440
    my $build_info = parseBuildName( @arguments );
1441
 
1442
    $BUILDNAME_PACKAGE = $build_info->{BUILDNAME_PACKAGE};
1443
    $BUILDNAME_VERSION = $build_info->{BUILDNAME_VERSION};
1444
    $BUILDNAME_PROJECT = $build_info->{BUILDNAME_PROJECT};
359 dpurdie 1445
    $BUILDNAME_SUFFIX  = $BUILDNAME_PROJECT ? '.' . $BUILDNAME_PROJECT : '';
227 dpurdie 1446
 
1447
    $BUILDNAME         = $build_info->{BUILDNAME};
1448
    $BUILDVERSION      = $build_info->{BUILDVERSION};
1449
 
1450
    $DEPLOY_PATCH      = $build_info->{DEPLOY_PATCH} || 0;
1451
 
1452
    #
1453
    #   Clobber processing done after values have been accumulated
1454
    #   as they may be used later
1455
    #
1456
    return if ( $Clobber );
6133 dpurdie 1457
    ToolsetFiles::AddFile('build.log');
4003 dpurdie 1458
 
227 dpurdie 1459
#.. Create build.log summary information
1460
#
261 dpurdie 1461
    my ($sep) = "\n".(" " x 11) . ". ";
227 dpurdie 1462
 
261 dpurdie 1463
    Log( "\nBuild configuration (version $::GBE_VERSION)" );
1464
    Log( "Name ....... $BUILDNAME ($ScmHost)" );
1465
    Log( "Version .... $BUILDNAME_VERSION" );
1466
    Log( "DeployPatch. $DEPLOY_PATCH" ) if ($DEPLOY_PATCH);
1467
    Log( "Project .... $BUILDNAME_PROJECT" )if ($BUILDNAME_PROJECT);
1468
    Log( "Project .... ****** Specifically supressed ******" )unless ($BUILDNAME_PROJECT);
1469
    Log( "DateTime ... $::CurrentTime" );
1470
    Log( "AutoBuild... Enabled:$::GBE_ABT" ) if defined($::GBE_ABT) ;
359 dpurdie 1471
    Log( "Build dir... $Cwd" ) if defined($::GBE_ABT) || $::GBE_DPKG_SBOX;
4161 dpurdie 1472
    Log( "Build Mach.. $::GBE_HOSTNAME" ) if defined($::GBE_ABT);
227 dpurdie 1473
 
359 dpurdie 1474
    Log( "PERL ....... $::GBE_PERL" );
261 dpurdie 1475
    Log( "BIN  ....... $::GBE_BIN" );
1476
    Log( "TOOLS ...... $::GBE_TOOLS" );
1477
    Log( "CONFIG ..... $::GBE_CONFIG" );
1478
    Log( "MACHTYPE ... $::GBE_MACHTYPE" );
227 dpurdie 1479
 
261 dpurdie 1480
    Log( "PLATFORM ... " . PrintList([split(' ', $::GBE_PLATFORM)], $sep) )    if defined ($::GBE_PLATFORM);
5708 dpurdie 1481
    Log( "EXCLUDE .... " . PrintList([@BUILDEXCLUDE], $sep) )    if (@BUILDEXCLUDE);
261 dpurdie 1482
    Log( "BUILDFILTER. " . PrintList([split(' ', $::GBE_BUILDFILTER)], $sep) ) if defined ($::GBE_BUILDFILTER);
227 dpurdie 1483
 
261 dpurdie 1484
    Log( "DPKG_STORE.. $::GBE_DPKG_STORE" );
1485
    Log( "DPKG ....... $::GBE_DPKG" );
4688 dpurdie 1486
    Log( "DPKG_REPLI . $::GBE_DPKG_REPLICA" );
261 dpurdie 1487
    Log( "DPKG_CACHE . $::GBE_DPKG_CACHE" );
1488
    Log( "DPKG_LOCAL . $::GBE_DPKG_LOCAL" );
1489
    Log( "DPKG_SBOX .. $::GBE_DPKG_SBOX" );
7301 dpurdie 1490
    Log( "Sandbox .... Development" );
7307 dpurdie 1491
    Log( "LocalFilter. $::GBE_DPKG_SBOX/buildfilter") if ( $::GBE_DPKG_SBOX && -f $::GBE_DPKG_SBOX . '/buildfilter' );
227 dpurdie 1492
 
1493
    #
241 dpurdie 1494
    #   Generate a list of platforms that are completely unknown to JATS
4003 dpurdie 1495
    #   May be the result of a user typo or a guess
241 dpurdie 1496
    #
1497
    if ( @BUILD_BADNAME )
1498
    {
281 dpurdie 1499
        Log( "Unknown Pl . " . PrintPlatforms(\@BUILD_BADNAME, $sep) );
4551 dpurdie 1500
        Warning ("The following platform names are not known to JATS", "@BUILD_BADNAME");
241 dpurdie 1501
    }
4551 dpurdie 1502
 
241 dpurdie 1503
    #
4551 dpurdie 1504
    #   Detect multiple GENERIC targets
1505
    #       Only one such target can be processed on any one machine
1506
    #
1507
    if ($#GENERIC_TARGETS > 0)
1508
    {
1509
        Error ("Multiple GENERIC targets detected", PrintPlatforms(\@GENERIC_TARGETS, $sep));
1510
    }
1511
    if ($#GENERIC_TARGETS >= 0 )
1512
    {
1513
        $All = 1;
1514
    }
1515
 
1516
    #
227 dpurdie 1517
    #   Generate a list of active platforms
1518
    #   Ensure that there are some active platforms
1519
    #
1520
    GeneratePlatformList();
6133 dpurdie 1521
    Log( "Platforms .. " . PrintPlatforms(\@BUILDPLATFORMS, $sep) );
4551 dpurdie 1522
 
1523
    #
1524
    #   Detect a mix of Generic and non Generic targets
1525
    #       Cannot mix generic and non-generic targets
1526
    #
1527
    if ($#GENERIC_TARGETS >= 0 && $#BUILD_ACTIVEPLATFORMS >= 0)
1528
    {
1529
        if ($#BUILD_ACTIVEPLATFORMS != $#GENERIC_TARGETS )
1530
        {
1531
            Verbose("Active:", @BUILD_ACTIVEPLATFORMS);
1532
            Verbose("Generic:", @GENERIC_TARGETS);
1533
            Error("Cannot mix GENERIC and non-GENERIC targets in the one build");
1534
        }
1535
    }
1536
 
4778 dpurdie 1537
    #
6133 dpurdie 1538
    #   Build System Generic Sanity Test
4778 dpurdie 1539
    #       If Generic   then MUST be a GENERIC build
1540
    #       If NoGeneric then MUST not be a GENERIC build
1541
    #
1542
    if (defined $GenericBuild)
1543
    {
1544
        if ( scalar(@GENERIC_TARGETS) ne $GenericBuild)
1545
        {
1546
            Error("Generic build inconsistency",
1547
                  "Release Manager entry indicates: $GenericBuild",
1548
                  "Build File indicates: " . scalar(@GENERIC_TARGETS)
1549
                  );
1550
        }
1551
    }
1552
 
4003 dpurdie 1553
    unless( @BUILD_ACTIVEPLATFORMS )
1554
    {
5109 dpurdie 1555
        my $msg = 'GBE_BUILDFILTER prevents any targets being built';
7301 dpurdie 1556
        if (defined($::GBE_ABT) || 1) {
227 dpurdie 1557
 
4003 dpurdie 1558
            # Build filter on this machine prevents the package building
1559
            # On a Build System this is not an error
1560
            #   Create a dummy platform called NOBUILD
1561
            #   Do not populate the interface directory with package data
1562
            #   Flag for jmake to do very little
1563
            #
1564
            CreateBuildPlatformEntry('Internal', 0, undef, 'NOBUILD');
1565
            $IgnorePkgs = 1;
1566
            $NoBuild = 1;
5109 dpurdie 1567
            Log( "Build for .. ". PrintPlatforms(['NOBUILD - ' . $msg], $sep));
4003 dpurdie 1568
 
1569
        } else {
5109 dpurdie 1570
            Error( $msg );
4003 dpurdie 1571
        }
1572
    }
1573
    else
1574
    {
1575
        Log( "Build for .. ". PrintPlatforms(\@BUILD_ACTIVEPLATFORMS, $sep));
1576
    }
1577
 
6133 dpurdie 1578
    ProcessToolSetPlatform() if $genToolsetActive;
1579
    Log( "Toolset .... " . $toolsetPlatform ) if $genToolsetPlatform;
1580
    Error ("No suitable TOOLSET platform found") if (($genToolsetActive > 1) && $::GBE_ABT);
1581
 
227 dpurdie 1582
    #
1583
    #   Generate an error if nothing can be done because the GBE_PLATFORM
1584
    #   masks any useful operation.
1585
    #
1586
    if ( $::GBE_PLATFORM )
1587
    {
1588
        my @MAKE_PLATFORMS;
1589
        my %active_platforms;
1590
 
239 dpurdie 1591
        #
1592
        #   Create a hash of active platforms based on the array of
1593
        #   active platforms to simplify testing
1594
        #
1595
        $active_platforms{$_} = 1 foreach ( @BUILD_ACTIVEPLATFORMS  );
227 dpurdie 1596
 
4551 dpurdie 1597
        unless ( $#GENERIC_TARGETS >= 0 )
227 dpurdie 1598
        {
239 dpurdie 1599
            foreach  ( split( ' ', $::GBE_PLATFORM) )
1600
            {
1601
                push @MAKE_PLATFORMS, $_
1602
                    if ( $active_platforms{$_} );
1603
            }
227 dpurdie 1604
 
239 dpurdie 1605
            Error ("The GBE_PLATFORM filter prevents any targets being made",
1606
                   "GBE_PLATFORM: $::GBE_PLATFORM" ) unless ( @MAKE_PLATFORMS );
227 dpurdie 1607
 
261 dpurdie 1608
            Log( "Make for ... ". PrintPlatforms(\@MAKE_PLATFORMS, $sep));
239 dpurdie 1609
        }
227 dpurdie 1610
 
1611
    }
1612
 
1613
    return 1;
1614
}
1615
 
6133 dpurdie 1616
#-------------------------------------------------------------------------------
1617
# Function        : needToolset 
1618
#
1619
# Description     : Internal. Determine if this machine needs to build for
1620
#                   a TOOLSET or a GENERIC_<MachType>
1621
#                   
1622
#                   In Build System
1623
#                       BUILDFILTER must identify the machine performing TOOLSET builds
1624
#                       
1625
#                       The build filter MUST contain the psuedo platform TOOLSET in order for 
1626
#                       the alias to be created. This requires that the build daemons be configured to 
1627
#                       specify a TOOLSET. 
1628
#                       
1629
#                       Care MUST be taken to not configure multiple TOOLSET candiates 
1630
#                       on similar machine types.
1631
#                       
1632
#                   Non Build Sytem (User Development)
1633
#                       True    
1634
#
1635
# Inputs          : 
1636
#
1637
# Returns         : 
1638
#
1639
sub needToolset
1640
{
1641
    my $toolsetNeeded;
227 dpurdie 1642
 
6133 dpurdie 1643
    $toolsetNeeded = 1 if (!defined($::GBE_ABT));
1644
    if (!$toolsetNeeded && defined($::GBE_BUILDFILTER) ) {
1645
        $toolsetNeeded = grep( /^TOOLSET$/, split( ' ', $::GBE_BUILDFILTER ) );
1646
    }
1647
 
1648
    return $toolsetNeeded;
1649
}
1650
 
1651
#-------------------------------------------------------------------------------
1652
# Function        : ProcessToolSetPlatform 
1653
#
1654
# Description     : Locate the TOOLSET platform if required
1655
#                   In Build System
1656
#                       BUILDFILTER must identify the machine performing TOOLSET builds
1657
#                       The first suitable target will be chosen
1658
#                       
1659
#                       The build filter MUST contain the psuedo platform TOOLSET in order for 
1660
#                       the alias to be created. This requires that the build daemons be configured to 
1661
#                       specify a TOOLSET. 
1662
#                       
1663
#                       Care MUST be taken to not configure multiple TOOLSET candiates 
1664
#                       on similar machine types.
1665
#                       
1666
#                   Non Build Sytem (User Development)
1667
#                       The first suitable target will be chosen    
1668
#
1669
# Inputs          : 
1670
#
1671
# Returns         : 
1672
#
1673
sub ProcessToolSetPlatform
1674
{
1675
    my $toolsetNeeded;
1676
    my $toolset;
1677
 
1678
    #
1679
    #   User is not allowed to create a TOOLSET alias
1680
    #       This should be captured before here, but ...
1681
    #
1682
    if (exists $BUILDALIAS{TOOLSET})
1683
    {
1684
        Error('Internal: User has manually specified a TOOLSET alias' );
1685
    }
1686
 
1687
    #
1688
    #   Determine if we need to do any work
1689
    #
1690
    return unless needToolset();
1691
 
1692
    #
1693
    #   Need to ensure that we have a TOOLSET platform in the build set
1694
    #
1695
    my %activePlatformMap = map {$_ => 1} @BUILD_ACTIVEPLATFORMS;
1696
    my @toolsetTargets = PlatformConfig::getTargetsByTag('TOOLSET'); 
1697
    foreach my $item (@toolsetTargets)
1698
    {
1699
        if (exists($activePlatformMap{$item}))
1700
        {
1701
            #
1702
            #   Add TOOLSET arguments into the existing target
1703
            #   Really only expecting --OnlyProd
1704
            #
1705
            if ( @genToolsetArgs) {
1706
                PlatformArgument($item, @genToolsetArgs);
1707
            }
1708
 
1709
            # Update the displayed Toolset platform
1710
            $toolset = $item;
1711
            $toolsetPlatform = $toolset;
1712
            last;
1713
        }
1714
    }
1715
 
1716
    #
1717
    #   No toolset platform found in the current build set
1718
    #   
1719
    unless ($toolset) {
1720
        $toolsetPlatform = "None found in current build set"; 
1721
        $genToolsetActive = 2;
1722
        return;
1723
    }
1724
 
1725
    #
1726
    #   Insert alias information
1727
    #
1728
    $BUILDALIAS{TOOLSET} = $toolset;
1729
    push @{$BUILDINFO{$toolset}{USERALIAS}}, 'TOOLSET';
1730
}
1731
 
1732
#-------------------------------------------------------------------------------
1733
# Function        : BuildPreviousVersion 
1734
#
1735
# Description     : Deprecated. Do not use 
1736
#
1737
# Inputs          : 
1738
#
1739
# Returns         : 
1740
#
227 dpurdie 1741
sub BuildPreviousVersion
1742
{
1743
    my( $version ) = shift;
1744
 
1745
    $BUILDPREVIOUSVERSION = $version;
261 dpurdie 1746
    Log( "Previous Version ... $BUILDPREVIOUSVERSION" );
227 dpurdie 1747
 
1748
    return 1;
1749
}
1750
 
1751
 
1752
sub BuildInterface
1753
{
1754
    my( $ifdirname ) = @_;
1755
 
1756
    #
1757
    #   Clobber the directory - at the end.
1758
    #
1759
    if ( $Clobber )
1760
    {
1761
        #
1762
        #   If this Interface directory contains the Dpackage.cfg file
1763
        #   then JATS has created DPACKAGE and it needs to be clobbered
1764
        #   Flag that it needs to be done later - when we know where it is
1765
        #
1766
        $DeleteDPACKAGE = 1 if ( -f "$ifdirname/Dpackage.cfg" );
1767
    }
1768
 
1769
    #
6133 dpurdie 1770
    #   Generate the required directory
227 dpurdie 1771
    #
6133 dpurdie 1772
    BuildInterfaceInternal($ifdirname);
1773
    Log( "Interface .. $ifdirname" );
1774
    return 1;
1775
}
227 dpurdie 1776
 
6133 dpurdie 1777
#-------------------------------------------------------------------------------
1778
# Function        : BuildInterfaceInternal  
1779
#
1780
# Description     : Internal Use Only
1781
#                   Guts of the BuildInterface processing 
1782
#
1783
# Inputs          : $ifdirname  - Name of an interface directory
1784
#
1785
# Returns         : 
1786
#
1787
 
1788
sub BuildInterfaceInternal
1789
{
1790
    my( $ifdirname ) = @_;
1791
    my @createDirs;
1792
 
1793
    push @CLOBBERDIRS, $ifdirname;
1794
 
227 dpurdie 1795
    if ( $ifdirname eq "local" ) {
6133 dpurdie 1796
        push @createDirs, "$ifdirname/inc";
227 dpurdie 1797
        $BUILDLOCAL = "local";
1798
 
1799
    } else {
6133 dpurdie 1800
        push @createDirs, "$ifdirname/include";
227 dpurdie 1801
        $BUILDINTERFACE = $ifdirname;
1802
        $::ScmInterface = $ifdirname;
1803
    }
1804
 
6133 dpurdie 1805
    unless ($Clobber) {
1806
        push @createDirs, "$ifdirname/bin";
1807
        push @createDirs, "$ifdirname/lib";
1808
 
1809
        foreach my $dir ( @createDirs)
1810
        {
1811
            mkpath($dir);
1812
        }
1813
        ToolsetFiles::AddDir($ifdirname, 'Internal');
1814
    }
227 dpurdie 1815
}
1816
 
1817
 
6133 dpurdie 1818
 
227 dpurdie 1819
sub BuildDirTree
1820
{
1821
    my( $dirfile, $dirhead ) = @_;
1822
    my( $dirname, $c );
1823
 
1824
    $dirhead = '.'
1825
        unless defined( $dirhead );
1826
 
1827
    if ( $Clobber )                             # clobber mode ?
1828
    {
1829
        push @CLOBBERDIRS, $dirhead unless $dirhead eq '.';
1830
        return;
1831
    }
1832
 
1833
    #
1834
    #   Allow for an empty "dirfile". This will allow a directory to be created
1835
    #   without the overhead of the file
1836
    #
1837
    if ( ! $dirfile )
1838
    {
261 dpurdie 1839
        Log( "DirTree .... $dirhead" );
341 dpurdie 1840
        mkpath ( $dirhead );
227 dpurdie 1841
    }
1842
    else
1843
    {
261 dpurdie 1844
        Log( "DirTree .... $dirfile within $dirhead" );
341 dpurdie 1845
        mkpath ( $dirhead );
1846
 
283 dpurdie 1847
        open( DIRFILE, '<' ,$dirfile ) ||
227 dpurdie 1848
            Error( "cannot open '$dirfile'" );
1849
 
1850
        while( $dirname = <DIRFILE> )
1851
        {
1852
            chop $dirname;
1853
            $dirname =~ s/#.*//;
1854
            $c = $dirname =~ s/\s*(\S+).*/$1/g;
1855
 
1856
            next unless ( $c == 1 );
1857
 
1858
            if ( ! -d "$dirhead/$dirname" )
1859
            {
261 dpurdie 1860
                Log( "Dir ........ $dirhead/$dirname" );
341 dpurdie 1861
                mkpath ( "$dirhead/$dirname" );
227 dpurdie 1862
            }
1863
        }
1864
 
1865
        close( DIRFILE );
1866
    }
1867
    $BUILDDIRTREE = $dirhead;
1868
}
1869
 
1870
#-------------------------------------------------------------------------------
1871
# Function        : IncludePkg
1872
#
1873
# Description     : Examine a fully specified package directory for a file
1874
#                   that will specify packages to be included. This allows
1875
#                   a package to be simply a package of other packages
1876
#
1877
#                   Internal function. Not to be used by users
1878
#
1879
# Inputs          : Name of the package
1880
#                   Full directory path of the package to examine
1881
#
1882
# Returns         : Nothing
1883
#
1884
sub IncludePkg
1885
{
1886
    my ($name, $pkg) = @_;
1887
    my $file = "$pkg/incpkg";
1888
 
363 dpurdie 1889
    Debug ("IncludePkg: $name, $pkg" );
227 dpurdie 1890
 
1891
    #
1892
    #   Using a require will ensure that the package is only processed once
1893
    #   even though the function user may be called multiple times.
1894
    #   Also prevents recursion within included packages.
1895
    #
1896
    if ( -f $file  )
1897
    {
261 dpurdie 1898
        Log( "PackageIncludes. $name" ) unless ( $INC{$file} );
227 dpurdie 1899
        require $file;
1900
    }
1901
}
1902
 
1903
#-------------------------------------------------------------------------------
1904
# Function        : LinkPkgArchive
1905
#
1906
# Description     : Include an external package into the build sandbox
1907
#                   by extending the compiler and linker search paths to
1908
#                   include suitable directories found in the package
1909
#
1910
# Inputs          : package name
1911
#                   package version
1912
#
1913
sub LinkPkgArchive
1914
{
1915
    my( $name, $version ) = @_;
1916
 
1917
    return BuildPkgArchive( @_ )
1918
        if ( $ForceBuildPkg );                  # Forcing interface directory
1919
    return if ( $Clobber );                     # clobber mode ?
1920
 
1921
    Debug( "LinkPkgArchive:" );
1922
    Debug( "Name:      $name" );
1923
    Debug( "Version:   $version" );
1924
 
1925
    DataDirective("LinkPkgArchive");            # This directive allowed here
1926
 
7301 dpurdie 1927
#   if ( $IgnorePkgs )
1928
#   {
1929
#       Log( "LinkPkgArchive .. $name ($version) - Ignored" );
1930
#       return;
1931
#   }
2078 dpurdie 1932
 
227 dpurdie 1933
    #
1934
    #   Ensure that we have do not have multiple definitions
1935
    #
1936
    if ( PackageEntry::Exists( $name, $version ) )
1937
    {
261 dpurdie 1938
        Log( "Duplicate Package: $name, $version. Duplicate entry ignored" );
227 dpurdie 1939
        return;
1940
    }
1941
 
1942
    if ( $Cache && $::GBE_DPKG_CACHE )
1943
    {
1944
        my $mode = ($Cache > 1) ? "-refresh" : "";
331 dpurdie 1945
        Log( "LinkPkgArchive .. $name ($version) Update Cache" );
5744 dpurdie 1946
        System('--NoExit', "$::GBE_PERL $::GBE_TOOLS/cache_dpkg.pl $mode -wait -quiet $name/$version" );
227 dpurdie 1947
    }
1948
 
1949
    #
1950
    #   Locate the package ONCE
1951
    #
331 dpurdie 1952
    Log( "LinkPkgArchive .. $name ($version)" );
7301 dpurdie 1953
    my ($pkg, $local, $pkgSig ) = PackageLocate( $name, $version );
227 dpurdie 1954
    if ( $pkg )
1955
    {
1956
        #
1957
        #   Generate package rules for each active platform
1958
        #
363 dpurdie 1959
        IncludePkg ( $name, $pkg );
1960
        foreach my $platform ( @BUILD_ACTIVEPLATFORMS, '--' )
227 dpurdie 1961
        {
7301 dpurdie 1962
            LinkEntry( $platform, $pkg, $name, $version, 0, $local, $pkgSig );
227 dpurdie 1963
        }
1964
    }
1965
}
1966
 
1967
#-------------------------------------------------------------------------------
1968
# Function        : PackageLocate
1969
#
1970
# Description     : Locate a package
1971
#                   Once located a package will be processed for each
1972
#                   platform, but it need only be located ONCE
1973
#
1974
# Inputs          : package name
1975
#                   package version
1976
#
1977
# Returns         : path to the package
1978
#                   local       1 - From local package repository
7301 dpurdie 1979
#                   Package Signature
227 dpurdie 1980
#
1981
sub PackageLocate
1982
{
1983
    my ($name, $uversion ) = @_;
283 dpurdie 1984
    my $pkg;
227 dpurdie 1985
    my $local = 1;
7301 dpurdie 1986
    my $sandbox = 1;
227 dpurdie 1987
    my $isa_cache = 0;
1988
    my $version;
7302 dpurdie 1989
    my $pkgSig = 'Unknown';
227 dpurdie 1990
 
1991
    Debug( "PackageLocate: ($name/$uversion)" );
1992
 
1993
    #
7301 dpurdie 1994
    #   If we are in a SandBox, then we use package signatures to locate pre-built
1995
    #   packages.
1996
    #
1997
    if ($::GBE_SANDBOX)
1998
    {
1999
        my @ret = PackageLocateBySignature(@_);
2000
        if ($ret[0])
2001
        {
2002
            return @ret;
2003
        }
7303 dpurdie 2004
        Log ("                  Not found by signature - revert to package version");
7301 dpurdie 2005
    }
2006
 
2007
    #
227 dpurdie 2008
    #   Look in each package archive directory
2009
    #
2010
    foreach my $dpkg ( split( $::ScmPathSep, $::GBE_DPKG_SBOX),
2011
                       '--NotSandbox',
2012
                       split( $::ScmPathSep, $::GBE_DPKG_LOCAL),
2013
                       '--NotLocal',
2014
                       split( $::ScmPathSep, $::GBE_DPKG_CACHE),
2015
                       '--NotCache',
4688 dpurdie 2016
                       split( $::ScmPathSep, $::GBE_DPKG_REPLICA),
227 dpurdie 2017
                       split( $::ScmPathSep, $::GBE_DPKG),
313 dpurdie 2018
                       split( $::ScmPathSep, $::GBE_DPLY),
227 dpurdie 2019
                       split( $::ScmPathSep, $::GBE_DPKG_STORE) )
2020
    {
2021
 
2022
        #
2023
        #   Detect various tags that have been placed in the search list
2024
        #   to flag the end of the sandbox search and the end of the local
2025
        #   archive search
2026
        #
2027
        if ( $dpkg eq '--NotSandbox' )
2028
        {
2029
            $sandbox = 0;
2030
            next;
2031
        }
2032
        if ( $dpkg eq '--NotLocal' )
2033
        {
2034
            $local = 0;
2035
            $isa_cache = 1;
2036
            next;
2037
        }
2038
        if ( $dpkg eq '--NotCache' )
2039
        {
2040
            $isa_cache = 0;
2041
            next;
2042
        }
2043
 
2044
        #
2045
        #   If we are playing in a sandbox, then the version number is
2046
        #   not used. The Package suffix is still used so that we can
2047
        #   differentiate sysbasetypes.xxxxx.mas and sysbasetypes.xxxxx.syd
2048
        #
2049
        if ( $sandbox )
2050
        {
359 dpurdie 2051
            my ($pn, $pv, $ps ) = SplitPackage ($name, $uversion );
227 dpurdie 2052
            $version = 'sandbox';
2053
            $version .= '.' . $ps if ( $ps );
2054
        }
2055
        else
2056
        {
2057
            $version = $uversion;
2058
        }
2059
 
6133 dpurdie 2060
        $pkg = "$dpkg/$name/$version";
2061
        $pkg = "$dpkg/$name/$version.lnk"
2062
            if ( -e "$dpkg/$name/$version.lnk" );
2063
 
227 dpurdie 2064
        #
2065
        #   Using a soft link
2066
        #   Emulate a link in software. The link file contains one line
2067
        #   which is the real pathname of the package
2068
        #
2069
        if ( $pkg =~ m~(.*)\.lnk$~  )
2070
        {
2071
            #
2072
            #   Warn the user if both a link and a real directory
2073
            #   are both present - the link may well be incorrect
2074
            #
2075
            my $non_link = $1;
2076
            Warning ("Suspect package link: $pkg",
2077
                     "Both a link and a package where found - using the link" )
2078
                                                            if ( -d $non_link );
2079
 
2080
            Debug( "           link found -> $pkg" );
2081
            my $link_src = $pkg;
6133 dpurdie 2082
            $pkg = TagFileRead($pkg);
2083
            $pkg =~ s~\\~/~g;
5819 dpurdie 2084
            if ($pkg =~ s~^GBE_SANDBOX/~$::GBE_SANDBOX/~)
2085
            {
7307 dpurdie 2086
                    $pkgFromSandbox++;
2087
 
5819 dpurdie 2088
                    # If the target sandbox is in the 'deploymode' then the package
2089
                    # will not be in the expected location. It will be in a 'build/deploy'
2090
                    # subdir. Remove the pkg/name dir to get to the root of the package
2091
                    my @dirs = File::Spec->splitdir( $pkg );
2092
                    splice(@dirs, -2);
2093
                    my $deployBox = catdir(@dirs, 'build', 'deploy');
2094
                    $pkg = $deployBox if ( -d $deployBox);
2095
            }
227 dpurdie 2096
 
2078 dpurdie 2097
            unless ( -d $pkg )
2098
            {
2099
                Error ("Broken link: $pkg",
2100
                       "Source link: $link_src",
2101
                       "Try deleting the .lnk file" ) unless ( $NoPackageError );
2102
 
2103
                Warning ("Package not available. Broken link: $pkg");
2104
            }
227 dpurdie 2105
        }
2106
 
2107
        Debug( "           searching $pkg" );
2108
 
2109
        #   Does the package directory exist?
2110
        #   Terminate the directory name with a "/" to detect hidden spaces
2111
        #..
2112
        $pkg =~ s~//~/~g;
2113
        next unless ( -d "$pkg/" );             # exists ?
2114
 
2115
        #
2116
        #   If the package exists within the dpkg_archive cache then mark the
2117
        #   version as having been used. Used by cache cleanup algorithms
2118
        #
2119
        if ( $isa_cache  )
2120
        {
2121
            TouchFile ( "$pkg/used.cache", "Marks the cache copy as being used");
2122
        }
2123
 
2124
        #
2125
        #   Use the first suitable package found
2126
        #..
2127
 
2128
        Debug( "           importing $pkg" );
7301 dpurdie 2129
        return $pkg, $local, $pkgSig;
227 dpurdie 2130
    }
2131
 
2132
    #
2133
    #   Package not found
2134
    #   This is an error, although it can be bypassed
2135
    #
261 dpurdie 2136
    Error ("Required package not found: '$name/$version'" ) unless ( $NoPackageError );
227 dpurdie 2137
 
261 dpurdie 2138
    Log( "WARNING .... Package not available: '$name/$version'" );
283 dpurdie 2139
    return;
227 dpurdie 2140
}
2141
 
7301 dpurdie 2142
#-------------------------------------------------------------------------------
2143
# Function        : PackageLocateBySignature
2144
#
2145
# Description     : Locate a package via its signature
2146
#                   In a monoRepo sandbox pre-build package artifacts are located
2147
#                   via the signature of the source package. This must be generated
2148
#                   before it can be used.
2149
#                   
2150
#                   At the moment we simply generate an error if the signature cannot be
2151
#                   found. We could be clever and invoke jats to generate the required 
2152
#                   signature.
2153
#                   
2154
#
2155
# Inputs          : package name
2156
#                   package version
2157
#
2158
# Returns         : path to the package
2159
#                   local       1 - From local package repository
2160
#                   Package Signature
2161
#
2162
sub PackageLocateBySignature
2163
{
2164
    my ($name, $uversion ) = @_;
2165
    my $prj = '';
2166
    my $pkg;
2167
    my $local = 1;
2168
    my $in_sandbox = 1;
2169
    my $isa_cache = 0;
2170
    my $version;
7302 dpurdie 2171
    my $pkgSig = 'Unknown';
227 dpurdie 2172
 
7301 dpurdie 2173
    Debug( "PackageLocateBySignature: ($name/$uversion)" );
2174
 
2175
    # 
2176
    #   We are in a sandbox and expect to find a interface/Package.sig file
2177
    #   This will allow us to locate the package in the package store
2178
    #   
2179
    #   If there is no interface/Package.sig, then the user must build (not make)
2180
    #   the package in the sandbox.
2181
    #   
2182
    #   ie: the interface/Package.sig file allows us to use the package from package cache
2183
    #       or indicates that the user has not yet built the package
2184
    #       
2185
    #
2186
    #   First locate the packages interface directory
2187
    #   We have a nice link from the sandbox to assist in this
2188
    #
2189
    my ($pn, $pv, $ps ) = SplitPackage ($name, $uversion );
2190
    $version = 'sandbox';
2191
    $prj = '.' . $ps if ( $ps ); 
2192
    $version .= $prj;
2193
 
2194
    my $ifaceDir = catdir($::GBE_SANDBOX, 'sandbox_dpkg_archive', $name, $version . '.int');
2195
    $ifaceDir = TagFileRead($ifaceDir);
2196
    $ifaceDir =~ s~\\~/~g;
2197
    $ifaceDir =~ s~GBE_SANDBOX/~$::GBE_SANDBOX/~;
2198
    my $pkgSigFile = catfile( $ifaceDir, 'Package.sig');
2199
 
2200
    return unless -f $pkgSigFile; 
2201
 
2202
    Error("Package signature not found for $name/$version", "You must 'build' the package before using it")
2203
        unless ( -f $pkgSigFile);
2204
    $pkgSig = TagFileRead($pkgSigFile);
2205
    Error("Package signature invalid for $name/$version", "Signature: $pkgSig") 
7302 dpurdie 2206
        if((length($pkgSig) != 40) && $pkgSig !~ m~^MSG:~) ;
7301 dpurdie 2207
 
2208
    #
2209
    #   Look in each package archive directory
2210
    #
2211
    foreach my $dpkg ( split( $::ScmPathSep, $::GBE_DPKG_SBOX),
2212
                       '--NotSandbox',
2213
                       split( $::ScmPathSep, $::GBE_DPKG_LOCAL),
2214
                       '--NotLocal',
2215
                       split( $::ScmPathSep, $::GBE_DPKG_CACHE),
2216
                       '--NotCache',
2217
                       split( $::ScmPathSep, $::GBE_DPKG_REPLICA),
2218
                       split( $::ScmPathSep, $::GBE_DPKG),
2219
                       split( $::ScmPathSep, $::GBE_DPLY),
2220
                       split( $::ScmPathSep, $::GBE_DPKG_STORE) )
2221
    {
2222
 
2223
        #
2224
        #   Detect various tags that have been placed in the search list
2225
        #   to flag the end of the sandbox search and the end of the local
2226
        #   archive search
2227
        #
2228
        if ( $dpkg eq '--NotSandbox' )
2229
        {
2230
            $in_sandbox = 0;
2231
            next;
2232
        }
2233
        if ( $dpkg eq '--NotLocal' )
2234
        {
2235
            $local = 0;
2236
            $isa_cache = 1;
2237
            next;
2238
        }
2239
        if ( $dpkg eq '--NotCache' )
2240
        {
2241
            $isa_cache = 0;
2242
            next;
2243
        }
2244
 
2245
        $pkg = "$dpkg/$name$prj/$pkgSig";
2246
        $pkg = "$dpkg/$name/$version.lnk"
2247
            if ( -e "$dpkg/$name/$version.lnk" );
2248
 
2249
        #
2250
        #   If we are scanning the sandbox archive itself, then we can will override the signature
2251
        #   if the package has been built within the sandbox. This is indicated by the presence of a
2252
        #   valid .lnk file.
2253
        #   
2254
        #       Note: The .lnk file may be present, but it won't point to anything valid until
2255
        #             the package has been built.
2256
        #
2257
        if ($in_sandbox)
2258
        {
2259
            my $pkgLinkFile = $pkg;
2260
            $pkgLinkFile =~ s~pkgsig$~lnk~;
2261
 
2262
            if ( -f $pkgLinkFile )
2263
            {
2264
                Debug( "           link found -> $pkg" );
2265
                my $pkgLink = TagFileRead($pkgLinkFile);
2266
                $pkgLink =~ s~\\~/~g;
2267
                if ($pkgLink =~ s~^GBE_SANDBOX/~$::GBE_SANDBOX/~)
2268
                {
2269
                        # If the target sandbox is in the 'deploymode' then the package
2270
                        # will not be in the expected location. It will be in a 'build/deploy'
2271
                        # subdir. Remove the pkg/name dir to get to the root of the package
2272
                        my @dirs = File::Spec->splitdir( $pkgLink );
2273
                        splice(@dirs, -2);
2274
                        my $deployBox = catdir(@dirs, 'build', 'deploy');
2275
                        $pkgLink = $deployBox if ( -d $deployBox);
2276
                }
2277
 
2278
                # 
2279
                #   Handle badly formed packages - test for descpkg file
2280
                #   Or those have the body of the code in the pkg directory
2281
                #   
2282
                my $pkgDescpkg = catfile( $pkgLink, 'descpkg');
2283
                if (-d $pkgLink && -f $pkgDescpkg)
2284
                {
2285
                    $pkg = $pkgLink;
2286
Debug0("============== From Sandbox: $pkgSig");
2287
#                    $pkgFromSandbox++;
2288
                }
2289
            }
2290
        }
2291
 
2292
        Debug( "           searching $pkg" );
2293
 
2294
        #   Does the package directory exist?
2295
        #   Terminate the directory name with a "/" to detect hidden spaces
2296
        #..
2297
        $pkg =~ s~//~/~g;
2298
        next unless ( -d "$pkg/" );             # exists ?
2299
 
2300
        #
2301
        #   If the package exists within the dpkg_archive cache then mark the
2302
        #   version as having been used. Used by cache cleanup algorithms
2303
        #
2304
        if ( $isa_cache  )
2305
        {
2306
            TouchFile ( "$pkg/used.cache", "Marks the cache copy as being used");
2307
        }
2308
 
2309
        #
2310
        #   Use the first suitable package found
2311
        #..
2312
 
2313
        Debug( "           importing $pkg" );
2314
        return $pkg, $local, $pkgSig;
2315
    }
2316
 
2317
    #
2318
    #   Package not found
2319
    #   This is an error, although it can be bypassed
2320
    #
2321
    Error ("Required package not found: '$name/$version'" ) unless ( $NoPackageError );
2322
 
2323
    Log( "WARNING .... Package not available: '$name/$version'" );
2324
    return;
2325
}
2326
 
227 dpurdie 2327
#-------------------------------------------------------------------------------
2328
# Function        : LinkEntry
2329
#
2330
# Description     : Scan a package an locate platform specific directories
2331
#                   Create data structures to capture the information
2332
#                   This function is used by LinkPkgArchive and LinkSandbox
2333
#                   to perfom the bulk of package inclusion work.
2334
#
2335
# Inputs          : platform being processed
2336
#                   path to the package
2337
#                   name of the package
2338
#                   version of the package
2339
#                   sandbox support (non-zero)
331 dpurdie 2340
#                   local package
7301 dpurdie 2341
#                   package Signature
227 dpurdie 2342
#
2343
sub LinkEntry
2344
{
7301 dpurdie 2345
    my( $platform, $pkg, $name, $version, $sandbox, $local, $pkgSig ) = @_;
227 dpurdie 2346
    my( $entry );
2347
 
2348
    #   Create entry record
2349
    #
2350
    #..
7301 dpurdie 2351
    $entry = PackageEntry::New( $pkg, $name, $version, $sandbox, 'link', $local, $pkgSig );
227 dpurdie 2352
 
2353
    #   Populate includes:
2354
    #
2355
    #   - include/$platform                 (eg include/solaris)
2356
    #   - inc/$platform                     (eg inc/solaris)
2357
    #   - include.$platform                 (eg include.solaris)
2358
    #   - inc.$platform                     (eg inc.solaris)
2359
    #   - include                           (eg include)
2360
    #   - inc                               (eg inc)
2361
    #
2362
    #   plus, product specialisation directores
2363
    #
2364
    #   eg. BuildProduct( 'IDFC', 'WIN32' );
2365
    #
2366
    #   - inc/IDFC_WIN32                    <- derived platform
2367
    #   - inc/IDFC                          <- product
2368
    #   - inc/WIN32                         <- target
2369
    #..
2370
    my $parts = $BUILDINFO{$platform}{PARTS};
2371
 
2372
    foreach my $part ( @$parts )
2373
    {
2374
        $entry->RuleInc( "/include." . $part ) if ( !$sandbox );
2375
        $entry->RuleInc( "/inc." . $part )     if ( !$sandbox );
2376
        $entry->RuleInc( "/include/" . $part ) if ( !$sandbox );
2377
        $entry->RuleInc( "/inc/" . $part );
2378
    }
2379
 
2380
    #
2381
    #   Also search the root include directory - last
2382
    #
2383
    $entry->RuleInc( "/include" )               if ( !$sandbox );
2384
    $entry->RuleInc( "/inc" );
2385
 
2386
    #   Populate libraries:
2387
    #
2388
    #   - lib/lib.$platform[D|P]            (eg lib/lib.sparcD)
2389
    #   - lib/$platform[D|P]                (eg lib/lib.sparc)
2390
    #   - lib.$platform[D|P]                (eg lib.sparcD)
2391
    #
2392
    #   plus, product specialisation directores
2393
    #
2394
    #   eg. BuildProduct( 'IDFC', 'WIN32' );
2395
    #
2396
    #   - lib/IDFC_WIN32                    <- derived platform
2397
    #   - lib/IDFC                          <- product
2398
    #   - lib/WIN32                         <- target
2399
    #..
2400
    $parts = $BUILDINFO{$platform}{PARTS};
2401
 
2402
    foreach my $part ( @$parts )
2403
    {
2404
        $entry->RuleLib("/lib" . ".$part" )     if ( !$sandbox );
2405
        $entry->RuleLib("/lib" . "/lib.$part" ) if ( !$sandbox );
2406
        $entry->RuleLib("/lib" . "/$part" );
2407
    }
2408
 
2409
    #
2410
    #   Some extra places to search
2411
    #   None. This is good as it indicates that all locations are described in PARTS
2412
    #
2413
    #   Do NOT search in /lib. There are no libraries that work on all platforms
2414
    #   Libraries are binaries!
2415
    #
2416
    #    $entry->RuleLib( "/lib" );
2417
 
2418
    #   Tools:
2419
    #
2420
    #   Tools provide an extensible search path for tools and
2421
    #   utilities used to build programs. These are tools that
2422
    #   are executable on the current host machine and are
2423
    #   independent of the toolset.
2424
    #
2425
    #..
2426
    $entry->ExamineToolPath();
2427
    $entry->ExamineThxPath($platform);
2428
    $entry->Cleanup();                          # cleanup tables
2429
 
2430
    #
2431
    #   Add the package entry to the array of such entries for
2432
    #   the current platform. Maintain the discovery order
2433
    #
2434
    #..
2435
    push ( @{$PKGRULES{$platform}}, $entry );
2436
}
2437
 
2438
 
2439
#-------------------------------------------------------------------------------
2440
# Function        : BuildPkgArchive
2441
#
2442
# Description     : Include an external package into the build sandbox
2443
#                   by copying the packages files into the interface directory
2444
#
2445
# Inputs          : package name
2446
#                   package version
2447
#
2448
sub BuildPkgArchive
2449
{
2450
    my( $name, $version ) = @_;
2451
 
2452
    return if ( $Clobber );                     # clobber mode ?
2453
 
2454
    Debug( "BuildPkgArchive:" );
2455
    Debug( "Name:      $name" );
2456
    Debug( "Version:   $version" );
2457
 
2458
    DataDirective("BuildPkgArchive");           # This directive allowed here
2459
 
7301 dpurdie 2460
#   if ( $IgnorePkgs )
2461
#   {
2462
#       Log( "BuildPkgArchive . $name ($version) - Ignored" );
2463
#       return;
2464
#   }
2078 dpurdie 2465
 
227 dpurdie 2466
    #
2467
    #   Ensure that we have do not have multiple definitions
2468
    #
2469
    if ( PackageEntry::Exists( $name, $version ) )
2470
    {
261 dpurdie 2471
        Log( "Duplicate Package: $name, $version. Duplicate entry ignored" );
227 dpurdie 2472
        return;
2473
    }
2474
 
2475
    if ( $Cache && $::GBE_DPKG_CACHE )
2476
    {
2477
        my $mode = ($Cache > 1) ? "-refresh" : "";
261 dpurdie 2478
        Log( "BuildPkgArchive . $name ($version) Update Cache" );
5744 dpurdie 2479
        System('--NoExit', "$::GBE_PERL $::GBE_TOOLS/cache_dpkg.pl $mode -wait -quiet $name/$version" );
227 dpurdie 2480
    }
2481
 
2482
    #
2483
    #   Locate the package
6133 dpurdie 2484
    #   Use the first instance of the package that is found
227 dpurdie 2485
    #
261 dpurdie 2486
    Log( "BuildPkgArchive . $name ($version)" );
7301 dpurdie 2487
    my ( $pkg, $local, $pkgSig ) = PackageLocate( $name, $version );
227 dpurdie 2488
    if ( $pkg )
2489
    {
2490
        #
2491
        #   Create a Package Entry
2492
        #
7301 dpurdie 2493
        my $entry = PackageEntry::New( $pkg, $name, $version, 0, 'build', $local, $pkgSig );
227 dpurdie 2494
 
2495
        #
2496
        #   Determine if the package needs to be installed:
2497
        #       If the package is a 'local' package then force transfer
2498
        #       If the user has specified --cache then force transfer
2499
        #       If package is newer that copy, then force transfer
2500
        #       If copy does not exist, then force a transfer
2501
        #
2502
        my $tag_dir = "$Cwd/$BUILDINTERFACE/BuildTags";
2503
        my $tag_file = "$tag_dir/${name}_${version}.tag";
6073 dpurdie 2504
        my $arglist = GenerateInstallArgumentList();
227 dpurdie 2505
 
2506
        my $package_installed;
2507
        $package_installed = 1
2508
            if ( !$local &&
2509
                 !$Cache &&
6073 dpurdie 2510
                 !FileIsNewer( $entry->GetBaseDir('descpkg'), $tag_file ) &&
2511
                 TagFileMatch( $tag_file, $arglist)
2512
                  );
227 dpurdie 2513
 
2514
        #
2515
        #   Determine the package format and use the appropriate installer
2516
        #   Supported formats
6133 dpurdie 2517
        #       1) Package has a descpkg file (only style currently supported)
227 dpurdie 2518
        #
2519
        if ( $package_installed ) {
2520
            Verbose ("Package already installed: $name, $version");
2521
 
2522
        } else {
261 dpurdie 2523
            Log( "                . installing '$pkg'" );
2524
            Log( "                . -> " . readlink($pkg) ) if ( -l $pkg );
227 dpurdie 2525
 
2526
            if ( -e "$pkg/descpkg" )
2527
            {
2528
 
2529
                #
2530
                #   If forcing a BuildPkg, then don't use symlinks
2531
                #   to files in dpkg_archive
2532
                #
331 dpurdie 2533
                my @opts;
2534
                push @opts, "--NoSymlinks" if ( $ForceBuildPkg );
2535
                push @opts, "--AllowOverWrite" if ( $local );
227 dpurdie 2536
 
2537
                #
2538
                #   Determine all the Platforms, Products and Targets
2539
                #   that need to be installed
2540
                #
6073 dpurdie 2541
 
331 dpurdie 2542
                System( "cd $pkg; $::GBE_PERL $::GBE_TOOLS/installpkg.pl $Cwd/$BUILDINTERFACE $Cwd @opts $arglist");
227 dpurdie 2543
                Error( "Package installation error" ) if ( $? != 0 );
2544
            }
2545
            else
2546
            {
2547
                Error ("Unknown package format for package $name/$version found in $pkg");
2548
            }
2549
 
2550
            #
2551
            #   Tag the package as installed - after it has been transferred
2552
            #
2553
            mkdir ( $tag_dir );
6073 dpurdie 2554
            FileCreate( $tag_file, $arglist );
227 dpurdie 2555
        }
2556
 
2557
        #
2558
        #   Process package
2559
        #
2560
        IncludePkg ( $name, $pkg );
2561
 
2562
        #
2563
        #   Complete the creation of the package entry
2564
        #   Add the information for all platforms
2565
        #
2566
        $entry->Cleanup();
2567
        for my $platform (@BUILD_ACTIVEPLATFORMS)
2568
        {
2569
            $entry->ExamineToolPath();
2570
            $entry->ExamineThxPath($platform);
2571
            push ( @{$PKGRULES{$platform}}, $entry );
2572
        }
2573
    }
2574
}
2575
 
2576
#-------------------------------------------------------------------------------
311 dpurdie 2577
# Function        : CreateInterfacePackage
2578
#
2579
# Description     : Create a dummy package entry to describe the Interface
2580
#                   This is done AFTER all the BuildPkgArchive directives have
2581
#                   been processed so that the interface directory is fully
2582
#                   processed
2583
#
2584
# Inputs          : None
2585
#
2586
# Returns         : 
2587
#
2588
sub CreateInterfacePackage
2589
{
2590
    foreach my $platform ( @BUILD_ACTIVEPLATFORMS )
2591
    {
2592
        my $entry = PackageEntry::Interface( "$::Cwd/$BUILDINTERFACE" );
2593
 
2594
        #
2595
        #   Locate include and lib bits within the interface
2596
        #   This is much simpler than for a LinkPkgArchive as the form
2597
        #   has been sanitized
2598
        #
2599
        my $parts = $BUILDINFO{$platform}{PARTS};
2600
 
2601
        foreach my $part ( @$parts )
2602
        {
2603
            $entry->RuleInc( "/include/" . $part );
2604
        }
2605
        $entry->RuleInc( "/include" );
2606
 
2607
        foreach my $part ( @$parts )
2608
        {
2609
            $entry->RuleLib("/lib/" . $part );
2610
        }
2611
 
2612
        $entry->ExamineToolPath();
2613
        $entry->ExamineThxPath($platform);
2614
        $entry->Cleanup();
2615
 
2616
        #
2617
        #   Add the package entry to the array of such entries for
2618
        #   the current platform. Force it to be the first one as
2619
        #   the interface directory will be scanned first
2620
        #
2621
        unshift ( @{$PKGRULES{$platform}}, $entry );
2622
    }
2623
}
2624
 
2625
#-------------------------------------------------------------------------------
227 dpurdie 2626
# Function        : GenerateInstallArgumentList
2627
#
2628
# Description     : Generate an argument list for the installpkg.pl script
2629
#                   The argument list is of the form
2630
#                       --Platform:xx[:xx[:xx]] --Platform:yy[:yy[:yy]] ...
2631
#                   Where xx is:
2632
#                       * a 'part' of the target platform
2633
#                         Order is: platform, product, ...  target( in that order )
2634
#                       * --Option[=yyy]
2635
#                        An option to be passed to the script. These are bound only
2636
#                        to the enclosed platform.
2637
# Inputs          :
2638
#
2639
# Returns         : See above
2640
#
2641
sub GenerateInstallArgumentList
2642
{
2643
    my @arglist;
2644
 
2645
    #
2646
    #   Generate the argument list as an array
2647
    #
2648
    for (@BUILD_ACTIVEPLATFORMS)
2649
    {
2650
        my @args = '--Platform';
2651
        push @args, @{$BUILDINFO{$_}{PARTS}};
2652
        push @arglist, join (":" , @args );
2653
    }
2654
 
2655
    return "@arglist";
2656
}
2657
 
2658
#-------------------------------------------------------------------------------
2659
# Function        : GeneratePlatformList
2660
#
2661
# Description     : Return a list of platforms that should particiate in this
2662
#                   build. This is a function of
2663
#                       1) Platforms defined in the build.pl file
5679 dpurdie 2664
#                       2) Platforms excluded in the build.pl file
2665
#                       3) User filter defined in GBE_BUILDFILTER
227 dpurdie 2666
#
2667
#                   The primary use of this function is to limit the creation
2668
#                   of makefiles to those that have supported compilers on
2669
#                   the underlying machine.
2670
#
2671
#                   GBE_BUILDFILTER is a space seperated string of words
2672
#                   Each word may be one of
2673
#                       OPTION=TAG or OPTION=!TAG
2674
#                       TAG or !TAG. This is the same as --TARGET=TAG
2675
#
2676
#                   Bare tags are taken to be TARGETS.
2677
#
2678
#                   Where OPTION may be one of
2679
#                       --PLATFORM
2680
#                       --PRODUCT
2681
#                       --TARGET
5679 dpurdie 2682
#                   For a BuildProduct( AA,BB,CC)
2683
#                       Product     - AA
2684
#                       Targets     - BB, CC
2685
#                       Platforms   - AA_BB, AA_CC
227 dpurdie 2686
#
2687
#                   Special cases
2688
#                   1) If GBE_BUILDFILTER is empty, then all available platforms are used
2689
#                      The global $All is set, then all available platforms are used
2690
#                   2) If the first word of GBE_BUILDFILTER is a negative filter,
2691
#                      ie is used the !xxxx or yyy=!xxxx construct, then it is assumed
2692
#                      that the filter will start with all available platforms
2693
#                   3) The special word --ALL forces selection of ALL platforms
2694
#                      and may reset any existing scanning
2695
#                   4) GBE_BUILDFILTER is parsed left to right. It is possible to add and
2696
#                      subtract items from the list.
2697
#                   5) OPTIONS are case insensitive
2698
#                      TAGS are case sensitive
2699
#
2700
#
2701
# Inputs          : GBE_BUILDFILTER from the environment
2702
#
2703
# Returns         : An array of platforms to include in the build
2704
#                   Maintains @BUILD_ACTIVEPLATFORMS  - the last calculated result
2705
#                   Ensures that @DEFBUILDPLATFORMS is a subset of @BUILD_ACTIVEPLATFORMS
2706
#
2707
sub GeneratePlatformList
2708
{
2709
    #
2710
    #   Return the cached result for speed
2711
    #   The value need only be calculated once
2712
    #
2931 dpurdie 2713
    unless ( @BUILD_ACTIVEPLATFORMS )
227 dpurdie 2714
    {
2715
        my ($platform_filter);
2716
        my %result;
2717
        my %part_to_platform;
2718
 
2719
        #
2720
        #   Create a data structure to assist in the production of the platform list
2721
        #   The structure will be a hash of hashes of arrays
2722
        #
2723
        #   The first level hash will be keyed by the word TARGET, PRODUCT or PLATFORM
2724
        #   The second level of the hash will keyed by available targets, products or platforms
2725
        #   The value of the field will be an array of platforms that match the keyword
2726
        #
2727
        for my $platform (keys (%::BUILDINFO))
2728
        {
2729
            my $pParts = $::BUILDINFO{$platform};
2730
 
2731
            #
2732
            #   Skip platforms that are known to be unavailable on this build
2733
            #   machine. Self configure
2734
            #
2735
            next if ( $pParts->{NOT_AVAILABLE} );
2736
 
2737
            my $target  = $pParts->{TARGET};
2738
            my $product = $pParts->{PRODUCT};
2739
 
2740
            push @{$part_to_platform{'PLATFORM'}{$platform}}, $platform;
2741
            push @{$part_to_platform{'TARGET'}  {$target}}  , $platform;
2742
            push @{$part_to_platform{'PRODUCT'} {$product}} , $platform;
2743
        }
2744
        #
2745
        #   Determine the source of the filter
2746
        #   If the user provides one, then use it.
2747
        #   Otherwise its taken from the environment.
2748
        #
2749
        #   Global build all platforms - Kill any user filter
2750
        #
2751
        if ( $All )
2752
        {
2753
            $platform_filter = "";
2754
        }
2755
        else
2756
        {
2757
            $platform_filter = "";
2758
            $platform_filter = $::GBE_BUILDFILTER
2759
                if ( defined($::GBE_BUILDFILTER) );
2760
        }
2761
        Debug( "GeneratePlatformList: Filter:$platform_filter" );
2762
 
2763
        #
2764
        #   Detect the special cases
5679 dpurdie 2765
        #       1) No user definition
227 dpurdie 2766
        #       2) First word contains a subtractive element
5679 dpurdie 2767
        #   And assume all platforms    
227 dpurdie 2768
        #
2769
        my (@filter) = split( ' ', $platform_filter );
2770
 
2771
        if ( !scalar @filter || $filter[0] =~ m/^$/ || $filter[0] =~ m/!/ )
2772
        {
2773
            %result = %{$part_to_platform{'PLATFORM'}}
2774
                if exists $part_to_platform{'PLATFORM'} ;
2775
        }
5679 dpurdie 2776
 
227 dpurdie 2777
#DebugDumpData( "PartToPlatform", \%part_to_platform );
2778
 
2779
        #
2780
        #   Process each element in the user filter list
2781
        #   Expand platforms into known aliases
2782
        #
2783
        for my $word (@filter)
2784
        {
2785
            my $platform;
2786
 
2787
            if ( $word =~ m/^--ALL/i )
2788
            {
2789
                %result = %{$part_to_platform{'PLATFORM'}};
2790
            }
2791
            elsif ( $word =~ m/^--(TARGET)=(!?)(.*)/i ||
2792
                    $word =~ m/^--(PRODUCT)=(!?)(.*)/i ||
2793
                    $word =~ m/^--(PLATFORM)=(!?)(.*)/i ||
2794
                    ( $word !~ m/^-/ && $word =~ m/()(!?)(.*)/ )
2795
                )
2796
            {
2797
                my $table = uc($1);
2798
                $table = "TARGET"
2799
                    unless ( $1 );
2800
 
2801
                #
2802
                #   Expand PLATFORMs into known aliases
2803
                #   Alias will expand to PLATFORMs so it won't work unless we are
6133 dpurdie 2804
                #   processing PLATFORMs.
227 dpurdie 2805
                #
2806
                my @taglist = ( $table eq "PLATFORM" ) ? ExpandPlatforms($3) : $3;
2807
 
2808
                #
2809
                #   Add / Remove items from the result
2810
                #
2811
                for my $item ( @taglist )
2812
                {
2813
                    my $plist = $part_to_platform{$table}{$item};
2814
                    for ( @{$plist})
2815
                    {
6133 dpurdie 2816
                        if ( $2 ) {
227 dpurdie 2817
                            delete $result{$_};
6133 dpurdie 2818
                        } else {
227 dpurdie 2819
                            $result{$_} = 1;
2820
                        }
2821
                    }
2822
                }
2823
            }
2824
            else
2825
            {
2826
                print "GBE_BUILDFILTER filter term not understood: $word\n";
2827
            }
2828
        }
2829
 
2830
        #
5679 dpurdie 2831
        #   Process BuildExclude
6133 dpurdie 2832
        #   A list of targets to be excluded
2833
        #       INSTRUMENT is a key word
5679 dpurdie 2834
        #
2835
        for my $word (@BUILDEXCLUDE)
2836
        {
2837
            my $platform;
2838
 
2839
            Error('BuildExclude: Unknown option: ' . $word) if ($word =~ m~^-~);
2840
            Error('BuildExclude: Invalid format: ' . $word) if ($word =~ m~^!~);
2841
 
2842
            #
6133 dpurdie 2843
            #   INSTRUMENT is a key word
2844
            #       Remove all instrumented builds
5679 dpurdie 2845
            #
6133 dpurdie 2846
            if ($word eq 'INSTRUMENT')
5679 dpurdie 2847
            {
6133 dpurdie 2848
                for ( keys %result) {
2849
                    if ( PlatformConfig::targetHasTag( $_, 'INSTRUMENT') ) {
2850
                        delete $result{$_} ;
2851
                    }
2852
                }
5679 dpurdie 2853
            }
6133 dpurdie 2854
            else
2855
            {
2856
                #
2857
                #   Remove items from the result
2858
                #
2859
                my $table = "PLATFORM";
2860
                my $plist = $part_to_platform{$table}{$word};
2861
                if ($plist) {
2862
                    for ( @{$plist}) {
2863
                        delete $result{$_};
2864
                    }
2865
                }
2866
                else  {
2867
                    Warning('BuildExclude: Unknown target:' . $word ) 
2868
                        unless exists $::BUILDINFO{$word};
2869
                }
2870
            }
5679 dpurdie 2871
        }
2872
 
2873
        #
227 dpurdie 2874
        #   Return an array of platforms to process
2875
        #
2876
        @BUILD_ACTIVEPLATFORMS = sort keys %result;
2877
 
2878
        #
2879
        #   Ensure that DEFBUILDPLATFORMS is a subset of build active platforms
2880
        #
2881
        my @NEW_DEFBUILDPLATFORMS;
2882
        foreach ( @DEFBUILDPLATFORMS )
2883
        {
2884
            push @NEW_DEFBUILDPLATFORMS, $_
2885
                if ( exists $result{$_} );
2886
        }
2887
        @DEFBUILDPLATFORMS = @NEW_DEFBUILDPLATFORMS;
2888
    }
2889
 
2890
    Debug("GeneratePlatformList: Result:@BUILD_ACTIVEPLATFORMS");
2891
    return @BUILD_ACTIVEPLATFORMS;
2892
}
2893
 
2894
#-------------------------------------------------------------------------------
2895
# Function        : PrintPlatforms
2896
#
2897
# Description     : Petty print the specified platform list, breaking line
2898
#                   on either a primary key change or length width >78.
2899
#
2900
# Returns         : Formated string
2901
#
2902
# Example Output :
2903
#
2904
#           DDU_LMOS_WIN32 DDU_LMOS_linux_armv4 DDU_LMOS_linux_i386
2905
#           IDFC_LMOS_WIN32 IDFC_LMOS_linux_armv4 IDFC_LMOS_linux_i386
2906
#           LMOS_WCEPSPC_ARM LMOS_WCEPSPC_EMU LMOS_WIN32 LMOS_linux_armv4
2907
#           LMOS_linux_i386
2908
#..
2909
sub PrintPlatforms
2910
{
2911
    my ($platforms, $nl) = @_;
2912
    my ($string) = "";                          # result
2913
 
2931 dpurdie 2914
    if ( @$platforms )
227 dpurdie 2915
    {
2916
        my ($key_run) = 0;
2917
        my ($pkey);                             # previous key
2918
 
2919
        #   Perform a simple formatting and determine if there is key 
2920
        #   change greater then 1 or whether the total length exceeds 78.
2921
        #
2922
        #   If the line exceeds 78, the printer shall then reformat 
2923
        #   breaking based on line length and possiblity keys.
2924
        #
2925
        $pkey = "";
2926
        for my $k (sort @$platforms) 
2927
        {
2928
            my ($d);                            # delimitor
2929
 
2930
            if (($d = index( $k, '_' )) != index( $pkey, '_' ) ||
2931
                    substr( $k, 0, $d ) ne substr( $pkey, 0, $d )) {
2932
                $key_run = 1
2933
                    if ($key_run <= 1);         # change, reset run if <= 1
2934
            } else {
2935
                $key_run++;                     # same primary key
2936
            }
2937
 
2938
            $string .= " " if ($pkey);
2939
            $string .= $k;
2940
            $pkey = $k;
2941
        }
2942
 
2943
        #   Reprint if required.
2944
        #
2945
        if (length($nl)+length($string) > 78)
2946
        {
2947
            my ($llen);                         # line length
2948
 
2949
            $llen = length($nl);
2950
 
2951
            $pkey = "";
2952
            $string = "";
2953
 
2954
            for my $k (sort @$platforms)
2955
            {
2956
                my ($klen, $d);                 # key length, delimitor
2957
 
2958
                $klen = length($k);
2959
                if ($pkey ne "")
2960
                {
2961
                    if ($llen + $klen > 78 ||
2962
                        ($key_run > 1 && (
2963
                            ($d = index( $k, '_' )) != index( $pkey, '_' ) ||
2964
                            substr( $k, 0, $d ) ne substr( $pkey, 0, $d ) )) )
2965
                    {                           # line >70 or key change
2966
                        $string .= $nl;
2967
                        $llen = length($nl);
2968
                    }
2969
                    else
2970
                    {
2971
                        $string .= " ";
2972
                        $llen++;
2973
                    }
2974
                }
2975
                $string .= $k;
2976
                $pkey = $k;
2977
                $llen += $klen;
2978
            }
2979
        }    
2980
    }
2981
    return $string;
2982
}
241 dpurdie 2983
#-------------------------------------------------------------------------------
2984
# Function        : PrintList
2985
#
2986
# Description     : Pretty format an array to fit within 80 char line
2987
#                   Perform wrapping as required
2988
#
2989
# Inputs          : $list           - Reference to an array
2990
#                   $nl             - New line stuff.
2991
#                                     Use to prefix new lines
2992
#
2993
# Returns         : string
2994
#
2995
sub PrintList
2996
{
2997
    my ($list, $nl) = @_;
2998
    my ($string) = '';                          # result
2999
    my $sep;
227 dpurdie 3000
 
241 dpurdie 3001
    if ( @$list )
3002
    {
3003
        my ($llen) = length($nl);
227 dpurdie 3004
 
241 dpurdie 3005
        for my $k (@$list)
3006
        {
3007
            my $klen = length($k);
3008
            if ($llen + $klen > 78 )
3009
            {
3010
                $string .= $nl;
3011
                $llen = length($nl);
3012
            }
3013
            else
3014
            {
3015
                if ( $sep )
3016
                {
3017
                    $string .= $sep;
3018
                    $llen++;
3019
                }
3020
                else
3021
                {
3022
                    $sep = ' ';
3023
                }
3024
            }
3025
            $string .= $k;
3026
            $llen += $klen;
3027
        }
3028
    }
3029
    return $string;
3030
}
3031
 
305 dpurdie 3032
#-------------------------------------------------------------------------------
3033
# Function        : BuildReleaseFile
3034
#
3035
# Description     : Legacy function
3036
#                   Don't know what it was meant to do
3037
#                   Unfortunately it is present in a lot of build.pl files
3038
#
3039
#                   Not well supported on all machine types
3040
#
331 dpurdie 3041
# Inputs          : None that are used
305 dpurdie 3042
#
331 dpurdie 3043
# Returns         : Undefined
305 dpurdie 3044
#
227 dpurdie 3045
sub BuildReleaseFile
3046
{
3047
}
3048
 
305 dpurdie 3049
#-------------------------------------------------------------------------------
3050
# Function        : BuildSnapshot
3051
#
3052
# Description     : Legacy function
3053
#                   Don't know what it was meant to do
3054
#                   Unfortunately it is present in a lot of build.pl files
3055
#
3056
# Inputs          : None that are used
3057
#
3058
# Returns         : Undefined
3059
#
227 dpurdie 3060
sub BuildSnapshot
3061
{
3062
}
3063
 
305 dpurdie 3064
#-------------------------------------------------------------------------------
3065
# Function        : BuildSrcArchive
3066
#
3067
# Description     : Create a source snapshot of the build source
3068
#                   Designed to provide a source image for packaging
3069
#                   examples
3070
#
3071
#                   Should be platform independent
3072
#
3073
#                   Creates an archive file and places it into the
3074
#                   interface directory. The archive will be packaged
3075
#                   automatically by the build process
3076
#
3077
#                   Use the 'pax' utility
3078
#                       1) Can massage the file path such that the stored
3079
#                          directory image contains the package name and version
3080
#
3081
#                   Directive can be used at any time before the BuildMake
3082
#
3083
#                   Will handle the existence of an auto.pl file by inserting
3084
#                   it as build.pl.
3085
#
6133 dpurdie 3086
# Inputs          : $platform   - In ABT mode. Process under this platform name
305 dpurdie 3087
#
3088
#
3089
# Returns         : 
3090
#
3091
sub BuildSrcArchive
3092
{
6133 dpurdie 3093
    my ($platform) = @_;
3094
    Error ("BuildSrcArchive requires one platform specifier") unless (defined $platform);
3095
 
3096
 
305 dpurdie 3097
    #
3098
    #   If we are clobbering, then there is nothing to do
3099
    #   The generated file is placed within the interface
3100
    #   directory and that directory will be deleted during the clobber
3101
    #
3102
    return if ( $Clobber );
3103
    DataDirective("BuildSrcArchive");
227 dpurdie 3104
 
305 dpurdie 3105
    #
6133 dpurdie 3106
    #   If not in ABT mode, then build archive on developers machine
3107
    #   In ABT mode only build the archive on a machine whose platform name is in the build filter
3108
    #
3109
    my $doBuild;
3110
    if (defined($::GBE_ABT))
3111
    {
3112
        if (defined ($::GBE_BUILDFILTER))
3113
        {
3114
            $doBuild  = grep( /^$platform/, split( ' ', $::GBE_BUILDFILTER ) );
3115
        }
3116
        unless ( $doBuild )
3117
        {
3118
            Log( "SrcPackage . Not on this machine" );
3119
            return; 
3120
        }
3121
    }
3122
 
3123
 
3124
    #
305 dpurdie 3125
    #   Currently this operation is only supported of some platforms
3126
    #   Only supported on Unix platforms
3127
    #   Uses the 'pax' utility
3128
    #
3129
    unless ( LocateProgInPath ( 'pax', '--All' ) && ( $ScmHost eq "Unix" ) )
3130
    {
3131
        Log( "SrcPackage . Not supported" );
3132
        return;
3133
    }
3134
 
3135
    #
3136
    #   Only allow one instance of the directive
3137
    #
3138
    Error ("Multiple BuildSrcArchive directives not supported")
3139
        if ( $build_source_pkg );
3140
 
3141
    #
3142
    #   Create the name of the archive
3143
    #       Based on the package name and version
3144
    #       Has no spaces
3145
    #
3146
    my $build_name = $BUILDNAME;
3147
    $build_name =~ s~\s+~_~g;
3148
 
3149
    #
3150
    #   Create the archive in the interface directory
3151
    #   Don't need to clobber it as the entire interface directory
3152
    #   will be clobbered
3153
    #
3154
    $build_source_pkg = $build_name;
3155
}
3156
 
3157
#-------------------------------------------------------------------------------
3158
# Function        : BuildSrcArchiveBody
227 dpurdie 3159
#
305 dpurdie 3160
# Description     : Function to implement the body of the BuildSrcArchive
3161
#                   operation. Will be invoked during BuildMake
3162
#
3163
# Inputs          : None
3164
#
3165
# Returns         : 
3166
#
3167
sub BuildSrcArchiveBody
3168
{
3169
    return unless ( $build_source_pkg );
3170
 
3171
    my $archive_dir = "pkg/$BUILDNAME_PACKAGE/src";
3172
    my $archive_file = "$build_source_pkg" . '.tar';
3173
 
3174
    Log( "SrcPackage . $archive_file.gz" );
3175
    unlink "$archive_dir/$archive_file";
3176
    unlink "$archive_dir/$archive_file.gz";
3177
    mkpath($archive_dir, 0, 0775);
3178
 
3179
    #
3180
    #   Create a list of files and top-level dirs to add to source archive
3181
    #   Many files are ignored
3182
    #   Should only be executed on the first 'build' thus many internal
3183
    #   directories will not be present
3184
    #
3185
    my @flist;
3186
    my $auto_pl;
3187
    opendir (my $tp, '.' ) or Error ("Cannot read current directory");
3188
    while ( $_ = readdir($tp) )
3189
    {
3190
        next if ( m/^\.$/ );
3191
        next if ( m'^\.\.$' );
3192
        next if ( m'^build\.log$' );
3193
        next if ( m'\.gbe$' );
6133 dpurdie 3194
        next if ( m'\.svn$' );
3195
        next if ( m'\.git$' );
3196
        next if ( m'\.cvs$' );
3197
        next if ( m'local_dpkg_archive$' );
3198
        next if ( m'\.jats.packageroot$' );
305 dpurdie 3199
        next if ( m'^local$' );
3200
        next if ( m'^pkg$' );
3201
        next if ( m/^$BUILDINTERFACE$/ );
3202
        $auto_pl = 1, next  if ( m'^auto\.pl$' );
3203
        next if (  m'^build\.pl$' );
3204
        next if ( m/^$build_source_pkg$/ );
3205
        push @flist, $_;
3206
    }
3207
    closedir $tp;
3208
 
3209
    #
3210
    #   If we don't have an auto.pl, then we add the build.pl file
3211
    #   If we do have a auto.pl - it gets tricky. Its don't after the
3212
    #   initial pax command
3213
    #
3214
    unless ( $auto_pl )
3215
    {
3216
        push @flist, 'build.pl';
3217
    }
3218
 
3219
    #
3220
    #   Create the command to be executed
3221
    #   Prefix archive paths with build_name
3222
    #
3223
    my @command = ( 'pax', '-w', '-f', "$archive_dir/$archive_file" );
3224
    System( '--NoShell' , @command, '-s', "~^~$build_source_pkg/~", @flist );
3225
 
3226
    #
3227
    #   If we have an auto.pl file, then we need to add it to the archive
3228
    #   but it needs to be called build.pl
3229
    #
3230
    if ( $auto_pl )
3231
    {
3232
        System( '--NoShell' , @command, '-a', '-s', "~^auto.pl~$build_source_pkg/build.pl~" , 'auto.pl' );
3233
    }
3234
 
3235
    #
3236
    #   Must now zip the file
3237
    #   Can't zip and append at the same time
3238
    #
3239
    System( '--NoShell' , 'gzip', "$archive_dir/$archive_file" );
3240
 
3241
    #
3242
    #   Display the results
3243
    #
3244
    System ('--NoShell', 'pax', '-z', "-f$archive_dir/$archive_file.gz")
3245
        if (IsVerbose (1));
3246
}
3247
 
3248
#-------------------------------------------------------------------------------
3249
# Function        : BuildAccessPerms
3250
#
3251
# Description     : Check if access/permissions setting requested...
3252
#                   Legacy
3253
#
331 dpurdie 3254
#                   Don't know what it was meant to do
3255
#                   Unfortunately it is present in a lot of build.pl files
305 dpurdie 3256
#
331 dpurdie 3257
# Inputs          : None that are used
305 dpurdie 3258
#
331 dpurdie 3259
# Returns         : Undefined
3260
#
227 dpurdie 3261
sub BuildAccessPerms
3262
{
3263
}
3264
 
3265
 
3266
sub BuildSetenv
3267
{
3268
    push( @BUILDSETENV, @_ );
3269
}
3270
 
3271
#-------------------------------------------------------------------------------
3272
# Function        : DataDirective
3273
#
3274
# Description     : Called by data collection directives to ensure that we are
3275
#                   still collecting data and that we have collected other data
3276
#
3277
# Inputs          : $dname              - Directive Name
3278
#
3279
# Returns         : Will error if we are not
3280
#
3281
sub DataDirective
3282
{
3283
    my ($dname) = @_;
3284
 
3285
    Error( "$dname() must appear after BuildName()...")
3286
        if ( $BUILDNAME eq "" );
3287
 
3288
    Error( "$dname() must appear after BuildInterface()...")
3289
        unless( $BUILDINTERFACE );
3290
 
3291
    Error( "$dname() not allowed after BuildDescpkg, BuildIncpkg, BuildVersion or BuildMake")
3292
        if( $BUILDPHASE);
3293
}
3294
 
3295
#-------------------------------------------------------------------------------
3296
# Function        : StartBuildPhase
3297
#
3298
# Description     : Called by directives that deal with the building phases
3299
#                   to perform common initialisation and to ensure that
3300
#                   directives that collect data are no longer called
3301
#
305 dpurdie 3302
# Inputs          : last                - True: Last directive expected
227 dpurdie 3303
#
3304
# Returns         : May generate an error
3305
#
3306
sub StartBuildPhase
3307
{
305 dpurdie 3308
    my ($last) = @_;
3309
 
227 dpurdie 3310
    #
305 dpurdie 3311
    #   Ensure directive is allowed
3312
    #       $BUILDPHASE >  1     - No more directives allowed
3313
    #       $BUILDPHASE == 1     - Allowed directive
3314
    #
3315
    if ( $BUILDPHASE > 1 )
3316
    {
3317
        my $function = (caller(1))[3];
3318
        $function =~ s~.*::~~;
3319
        Error ("Directive not allowed: $function","'BuildMake' must be the last directive in the build file");
3320
    }
3321
 
3322
    #
227 dpurdie 3323
    #   Only do it once
3324
    #
305 dpurdie 3325
    return if ( $BUILDPHASE  );
3326
    $BUILDPHASE = 1;
227 dpurdie 3327
 
3328
    #
341 dpurdie 3329
    #   If we are not performing a ForceBuild, then we don't need to continue
3330
    #   We have updated the interface directory with BuildPkgArchive
3331
    #   information.
3332
    #
3333
    TestForForcedBuild();
3334
 
3335
    #
6133 dpurdie 3336
    #   Calculate the aliases that are being extracted from targets
227 dpurdie 3337
    #
3338
    Process_TargetAlias();
3339
 
3340
    #
7307 dpurdie 3341
    #   Calculate defined aliases
6133 dpurdie 3342
    #       Limit the Aliases to active platforms
7307 dpurdie 3343
    #       ie: NATIVE INSTRUMENT PKG_WIN PKG_RPM PKG_DEB SK
4728 dpurdie 3344
    #
7307 dpurdie 3345
    foreach my $alias ( @PlatformConfig::BuildAliases )
4728 dpurdie 3346
    {
7307 dpurdie 3347
        if (exists $BUILDALIAS{$alias}) 
4728 dpurdie 3348
        {
7307 dpurdie 3349
            # Will occur if GBE_ABT has been set, for backward compatibility
6133 dpurdie 3350
            Warning("User has manually specified a $alias alias",'Default alias will not be set.');
4728 dpurdie 3351
        }
6133 dpurdie 3352
        else
3353
        {
7300 dpurdie 3354
            my %activePlatformMap;
3355
            foreach my $item (@BUILD_ACTIVEPLATFORMS) {
3356
                    $activePlatformMap{$item} = $item;
3357
            }
3358
 
6133 dpurdie 3359
            my @activeAliases;
7309 dpurdie 3360
            foreach my $item (PlatformConfig::getTargetsByTag($alias)) {
7300 dpurdie 3361
                push (@activeAliases, $activePlatformMap{$item}) if exists($activePlatformMap{$item});
6133 dpurdie 3362
            }
3363
            $BUILDALIAS{$alias} = join(' ', @activeAliases) if (@activeAliases);
3364
 
3365
            #
3366
            #   Add to the build entry too
3367
            #
3368
            foreach my $aliasTarget (@activeAliases)
3369
            {
3370
                push @{$BUILDINFO{$aliasTarget}{USERALIAS}}, $alias;
3371
            }
3372
        }
4728 dpurdie 3373
    }
6133 dpurdie 3374
    CleanUp_Aliases();
4728 dpurdie 3375
 
3376
    #
311 dpurdie 3377
    #   Create dummy package to describe the Interface directory
3378
    #
3379
    CreateInterfacePackage();
3380
 
3381
    #
227 dpurdie 3382
    #   Sanity test the users packages
6133 dpurdie 3383
    #       In a sandbox all bet are off
227 dpurdie 3384
    #
6133 dpurdie 3385
    PackageEntry::SanityTest() unless ($Clobber || $::GBE_SANDBOX);
227 dpurdie 3386
 
3387
    #
3388
    #   Validate the $Srcdir before its first real use
3389
    #   This is calculated from the user directives
3390
    #
3391
 
3392
    #.. Determine default "source" root
3393
    #
3394
    if ( $Srcdir eq "" )
3395
    {
3396
        Warning( "Both the directories 'src' and 'SRC' exist ....." )
3397
            if ( $ScmHost eq "Unix" && -e "src" && -e "SRC" );
3398
 
3399
        if ( -e "src" ) {
3400
            $Srcdir = "src";
3401
        } else {
3402
            ( -e "SRC" ) ||
3403
                Error( "Neither the directory 'src' nor 'SRC' exist ....." );
3404
            $Srcdir = "SRC";
3405
        }
3406
    }
3407
 
3408
    #
3409
    #   Must have a valid Srcdir
3410
    #
3411
    Error ("Source directory not found: $Srcdir")
3412
        unless ( $Srcdir && -d $Srcdir );
3413
 
305 dpurdie 3414
    #
3415
    #   Create source package
3416
    #
3417
    BuildSrcArchiveBody();
3418
 
227 dpurdie 3419
    return $Srcdir;
3420
}
3421
 
3422
#-------------------------------------------------------------------------------
341 dpurdie 3423
# Function        : TestForForcedBuild
3424
#
3425
# Description     : If a non-forced build has been requested, then see
3426
#                   if a build is required ( ie: build.pl modified )
6133 dpurdie 3427
#                   
3428
#                   Check:
3429
#                       Time stamp of build.pl
3430
#                       Time stamp of Makefile.gbe
3431
#                       BuildFilter has not changed
3432
#                       Signature of dependencies has not changed
3433
#                       No packages consumed from within the sandbox
341 dpurdie 3434
#
3435
# Inputs          : None
3436
#
3437
# Returns         : May not return
6133 dpurdie 3438
#                   Will return if we need to perform a build
341 dpurdie 3439
#
3440
sub TestForForcedBuild
3441
{
3442
    #
3443
    #   Always return if in clobber mode
3444
    #
3445
    return if ( $Clobber );
3446
 
3447
    if ( ! $ForceBuild  )
3448
    {
3449
        my @build_warn;
3450
        my $bstamp = -M "$Cwd/$ScmBuildSrc";
3451
        my $tstamp = -M "$Cwd/Makefile.gbe";
3452
 
3453
        push @build_warn, "Missing: Makefile.gbe" unless ( defined $tstamp );
3454
        push @build_warn, "Modified build file ($ScmBuildSrc)" if ( $tstamp && $bstamp < $tstamp );
3455
 
363 dpurdie 3456
        #
3457
        #   Ensure that the build filter has not changed
3458
        #   If the user has changed the buildfilter, then we need to
3459
        #   force a build.
3460
        #
6133 dpurdie 3461
        #   The root Makefile.gbe will have a $ScmBuildFilter entry
363 dpurdie 3462
        #
3463
        unless ( @build_warn )
3464
        {
3465
            use JatsMakeInfo;
3466
            ReadMakeInfo();
5726 dpurdie 3467
            my $line = $::ScmBuildFilter || '';
3468
            $line =~ s~\s+~ ~g;
363 dpurdie 3469
 
5726 dpurdie 3470
            my $filter = $::GBE_BUILDFILTER || '';
3471
            $filter =~ s~\s+~ ~g;
3472
            if ( $line ne $filter )
3473
            {
3474
                push @build_warn, "Build filter has changed";
3475
                Verbose2 ("Buildfilter Test: Was:$line, Is:$::GBE_BUILDFILTER");
3476
            }
363 dpurdie 3477
        }
3478
 
6133 dpurdie 3479
        #
7301 dpurdie 3480
        #   See if the dependencies have changed
3481
        #   
3482
        my $BuildpkgSig = Digest::SHA->new;
3483
        $BuildpkgSig->add("PKGNAME: $BUILDNAME_PACKAGE $BUILDNAME_VERSION $BUILDNAME_SUFFIX");
3484
 
3485
        #
3486
        #   Include the signature of ALL dependent packages
3487
        #   Ie: The build fingerprint is a function of the source and its dependents
3488
        #
3489
        my $depTagFile = catfile($ScmInterface, 'build.bfp');
3490
        unless (-f $depTagFile) {
3491
            push @build_warn, "Missing: $depTagFile";
3492
        }
3493
        else
3494
        {
3495
            foreach my $tag ( PackageEntry::GetPackageList() )
3496
            {
3497
                my $pkgSig = PackageEntry::GetPackageSignature($tag);
3498
                $BuildpkgSig->add("PKGSIGNATURE: $pkgSig");
3499
            }
3500
            my $depSha1 =  $BuildpkgSig->hexdigest;
3501
            Debug2("DepSha1: $depSha1");
3502
            unless (TagFileMatch ($depTagFile, $depSha1))
3503
            {
3504
                push @build_warn, "Dependency signatures have changed";
3505
            }
3506
        }
3507
 
3508
        #
6133 dpurdie 3509
        #   If any of the imported packages are from a sandbox, then we must force a build
3510
        #   and a make.
3511
        #
3512
        if ($pkgFromSandbox)
3513
        {
3514
            push @build_warn, "Consuming packages from within the sandbox";
3515
        }
3516
 
341 dpurdie 3517
        if ( @build_warn )
3518
        {
363 dpurdie 3519
            Verbose ("Forcing Build.", @build_warn );
341 dpurdie 3520
        }
3521
        else
3522
        {
3523
            Verbose ("No build performed. Build files up to date");
3524
            Log ("Build files up to date") if $::GBE_SANDBOX;
3525
            exit 0;
3526
        }
3527
    }
3528
}
3529
 
3530
#-------------------------------------------------------------------------------
305 dpurdie 3531
# Function        : LastBuildDirective
3532
#
3533
# Description     : No more build directives allowed
3534
#
3535
# Inputs          : 
3536
#
3537
# Returns         : 
3538
#
3539
sub LastBuildDirective
3540
{
3541
    $BUILDPHASE = 2;
3542
}
3543
 
3544
#-------------------------------------------------------------------------------
227 dpurdie 3545
# Function        : BuildPackageLink
3546
#
3547
# Description     : Create a soft link from sandbox_dpkg_archive to the package
3548
#                   being created by this build
3549
#
3550
#                   For backward compatability.
3551
#                   If GBE_DPKG_SBOX is not defined, then use GBE_DPKG_LOCAL
3552
#
3553
#                   This will allow multiple components to work together
3554
#
3555
#                   Note: When called in Clobber-mode the link will be deleted
3556
#
3557
# Inputs          : $BUILDNAME              - The package name
3558
#                   $BUILDNAME_PROJECT      - Project extension
3559
#                   $::GBE_DPKG_SBOX        - Path of sandbox_dpkg_archive
3560
#                   $::GBE_DPKG_LOCAL       - Path of local_dpkg_archive
3561
#                   $::GBE_DPKG             - Main repository
3562
#
3563
# Returns         : Nothing
3564
#
3565
sub BuildPackageLink
3566
{
3567
    my $target_archive;
3568
    my $target_archive_name;
3569
    my $link_file;
3570
    my $tag;
371 dpurdie 3571
    my $root_path;
227 dpurdie 3572
 
3573
    #
3574
    #   Determine the path (and name) of the target archive
3575
    #   Use sandbox_dpkg_archive if it exists
3576
    #   Use local_dpkg_acrhive for backward compatability (should be removed after JATS 2.64.2+)
3577
    #
3578
    if ( $target_archive = $::GBE_DPKG_SBOX )
3579
    {
3580
        $target_archive_name = "sandbox_dpkg_archive";
3581
        $tag = "Sandbox";
7301 dpurdie 3582
        $link_file  = 'sandbox' . ${BUILDNAME_SUFFIX} . '.lnk';
371 dpurdie 3583
        $root_path = 'GBE_SANDBOX' . substr($Cwd, length($::GBE_SANDBOX));
3584
        Verbose2("Root Path: $::GBE_SANDBOX, $root_path");
227 dpurdie 3585
    }
3586
    elsif ( $target_archive = $::GBE_DPKG_LOCAL )
3587
    {
3588
        $target_archive_name = "local_dpkg_archive";
3589
        $link_file = "$BUILDVERSION.lnk";
3590
        $tag = "Local";
371 dpurdie 3591
        $root_path = $Cwd;
227 dpurdie 3592
    }
3593
    else
3594
    {
3595
        Verbose("Cannot locate local or sandbox archive")
3596
            unless $Clobber;
3597
        return;
3598
    }
3599
 
3600
    #
3601
    #   Santity test
3602
    #   Target must be a directory
3603
    #
3604
    unless ( -d $target_archive )
3605
    {
241 dpurdie 3606
        Warning("$target_archive_name is not a directory: $target_archive")
227 dpurdie 3607
            unless $Clobber;
3608
        return;
3609
    }
3610
 
3611
    my $link_dir = "$target_archive/$BUILDNAME_PACKAGE";
3612
    my $link_path = "$link_dir/$link_file";
3613
 
6133 dpurdie 3614
    if ( $Clobber || $NoBuild )
227 dpurdie 3615
    {
3616
        unlink $link_path;          # Delete the link
3617
        rmdir $link_dir;            # Delete only if empty
3618
    }
3619
    else
3620
    {
261 dpurdie 3621
        Log( "Local Link . $BUILDNAME_PACKAGE/$link_file ($tag)");
3622
        mkdir $link_dir unless -d $link_dir;
371 dpurdie 3623
        FileCreate ( $link_path, "$root_path/pkg/$BUILDNAME_PACKAGE");
227 dpurdie 3624
    }
3625
}
3626
 
3627
#-------------------------------------------------------------------------------
3628
# Function        : BuildSandboxData
3629
#
3630
# Description     : Create data structures to allow this package to be built
3631
#                   within a multi-package sandbox.
3632
#
3633
#                   This will allow multiple components to work together
6133 dpurdie 3634
#                   Creates:
3635
#                       sandbox.int     - Rel path to the packages interface
3636
#                       sandbox.ffp     - Fast FingerPrint over the package body
3637
#                       sandbox.nob     - No Build marker
227 dpurdie 3638
#
3639
#                   Note: When called in Clobber-mode the link will be deleted
3640
#
3641
# Inputs          : $BUILDNAME              - The package name
3642
#                   $BUILDNAME_PROJECT      - Project extension
3643
#                   $::GBE_DPKG_SBOX        - Path of sandbox_dpkg_archive
3644
#                   $::GBE_DPKG             - Main repository
3645
#
3646
# Returns         : Nothing
3647
#
3648
sub BuildSandboxData
3649
{
3650
    my $sandbox_dpkg_archive = $::GBE_DPKG_SBOX;
3651
    return unless ( $sandbox_dpkg_archive );
3652
 
3653
    unless ( -d $sandbox_dpkg_archive )
3654
    {
241 dpurdie 3655
        Error("sandbox_dpkg_archive is not a directory: $sandbox_dpkg_archive")
227 dpurdie 3656
            unless $Clobber;
3657
        return;
3658
    }
3659
 
3660
    #
3661
    #   Create a name for this package in the sandbox
3662
    #   Must use the package name and extension. Don't use the version
3663
    #   information as this will not be correct
3664
    #
3665
    #   PACKAGE/sandbox.PRJ.cfg
3666
    #
3667
    my $link_dir = "$sandbox_dpkg_archive/$BUILDNAME_PACKAGE";
6133 dpurdie 3668
    my $base = 'sandbox' . ${BUILDNAME_SUFFIX}; 
359 dpurdie 3669
 
6133 dpurdie 3670
    my $nob_path  = $base . ".nob";
3671
    my $ffp_path  = $base . ".ffp";
3672
    my $int_path  = $base . ".int";
227 dpurdie 3673
 
6133 dpurdie 3674
    $nob_path = "$link_dir/$nob_path";
3675
    $ffp_path = "$link_dir/$ffp_path";
3676
    $int_path = "$link_dir/$int_path";
3677
 
227 dpurdie 3678
    if ( $Clobber )
3679
    {
3680
        rmdir $link_dir;            # Delete only if empty
3681
    }
3682
    else
3683
    {
6133 dpurdie 3684
        ToolsetFiles::AddFile($nob_path);
3685
        ToolsetFiles::AddFile($ffp_path);
3686
        ToolsetFiles::AddFile($int_path);
3687
 
3688
        #Log( "Sandbox Data. $base");
3689
        unlink $int_path;
227 dpurdie 3690
        mkdir $link_dir;
3691
 
3692
        #
6133 dpurdie 3693
        #   File with path to the interface directory
3694
        #   Relative to the base of the sandbox
227 dpurdie 3695
        #
6133 dpurdie 3696
        FileCreate($int_path, catdir('GBE_SANDBOX',RelPath($Cwd,$::GBE_SANDBOX),$BUILDINTERFACE ));
227 dpurdie 3697
 
3698
        #
6133 dpurdie 3699
        #   Indicate packages not build on this machine
227 dpurdie 3700
        #
6133 dpurdie 3701
        unlink $nob_path;           # Delete the NoBuild marker
3702
        if ($NoBuild) {
3703
            TouchFile($nob_path);
3704
        }
227 dpurdie 3705
    }
3706
}
3707
 
3708
 
3709
#-------------------------------------------------------------------------------
3710
# Function        : BuildMake
3711
#
3712
# Description     : Generate the makefiles
3713
#                   This directive MUST be the last directive in the build.pl
3714
#                   file. The directive triggers the processing of all the
3715
#                   information that has been collected
3716
#
3717
#
3718
# Inputs          : None
3719
#
3720
# Returns         : Nothing
3721
#
3722
 
3723
sub BuildMake
3724
{
3725
    my( $argc, $platform );
3726
 
3727
    #
3728
    #   Must have a valid $BUILDINTERFACE
3729
    #   Normally this is held in the interface directory, but this is not
3730
    #   always created. If there is no $BUILDINTERFACE, then use the
3731
    #   build directory
3732
    #
6133 dpurdie 3733
    BuildInterfaceInternal($::ScmInterface) unless ( $BUILDINTERFACE );
227 dpurdie 3734
 
6133 dpurdie 3735
 
227 dpurdie 3736
    #.. Starting the build phase. No more data collection
3737
    #
305 dpurdie 3738
    StartBuildPhase();
3739
    LastBuildDirective();
227 dpurdie 3740
 
5109 dpurdie 3741
    #
3742
    #   Now that the bulk of the information has been displayed
3743
    #   we can display captured messages. These warnings will be 
3744
    #   at the end of the log so that users can see them.
3745
    DumpCapture();
3746
 
227 dpurdie 3747
    sub DeleteCfg
3748
    {
3749
        #
3750
        #   Delete files that will be re-created
3751
        #   Some of these files are read and written.
3752
        #   Errors in the files are solved by deleting the files now.
3753
        #
3754
        unlink "$BUILDINTERFACE/build.cfg";
3755
        unlink "$BUILDINTERFACE/Makefile.cfg";
3756
        unlink glob ("$BUILDINTERFACE/Makefile*.cfg");
3757
        unlink "$BUILDINTERFACE/Buildfile.cfg";
3758
        unlink "$BUILDINTERFACE/Dpackage.cfg";
3759
    }
3760
 
3761
    if ( $Clobber )                             # clobber mode ?
3762
    {
4003 dpurdie 3763
        #
3764
        #   Unmake all the makefiles
3765
        #   No longer needed as we track the file that are created
3766
        #
3767
        #if ( -e "Makefile.gbe" )
3768
        #{
3769
        #    JatsTool ( 'jmake.pl', 'unmakefiles');
3770
        #}
3771
 
3772
        #
3773
        #   Delete my own configuration files
3774
        #
227 dpurdie 3775
        DeleteCfg();
3776
 
3777
        #
3778
        #   JATS creates a 'pkg' directory for the target package
3779
        #
3780
        push @CLOBBERDIRS, "pkg";
3781
 
3782
        #
3783
        #   Deployment creates a 'build/deploy' directory
375 dpurdie 3784
        #   The 'build' directory may contain user files - only remove if empty
227 dpurdie 3785
        #
3786
        push @CLOBBERDIRS, "build/deploy";
375 dpurdie 3787
        push @REMOVEDIRS, "build";
227 dpurdie 3788
 
3789
        #
6133 dpurdie 3790
        #   List of files maintained by the build system
3791
        #
3792
        my @toolsetFiles = ToolsetFiles::GetFiles();
3793
 
3794
        #
227 dpurdie 3795
        #   Delete interface directories and other directories that have been
375 dpurdie 3796
        #   marked to be clobbered
227 dpurdie 3797
        #
3798
        foreach my $dir ( @CLOBBERDIRS )
3799
        {
3800
            next if ( $dir eq '.' );
3801
            next if ( $dir eq '..' );
3802
            if ( -d $dir )
3803
            {
361 dpurdie 3804
                RmDirTree ( $dir );
227 dpurdie 3805
            }
3806
        }
3807
 
375 dpurdie 3808
        foreach my $dir ( @REMOVEDIRS )
3809
        {
3810
            next if ( $dir eq '.' );
3811
            next if ( $dir eq '..' );
3812
            if ( -d $dir )
3813
            {
3814
                rmdir ( $dir ); # Only if empty
3815
            }
3816
        }
3817
 
6133 dpurdie 3818
        foreach my $file (@toolsetFiles)
227 dpurdie 3819
        {
6133 dpurdie 3820
            RmDirTree ( $file ) if ( -f $file );
227 dpurdie 3821
        }
3822
 
3823
        #
3824
        #   DPACKAGE may be a user file, Only delete it if we created it
3825
        #
299 dpurdie 3826
        unlink "$Srcdir/DPACKAGE.$::GBE_MACHTYPE" if $DeleteDPACKAGE;
227 dpurdie 3827
 
3828
        BuildPackageLink();
3829
        BuildSandboxData();
3830
        return;
3831
    }
3832
 
3833
    #.. Build support files
3834
    #
3835
    DeleteCfg();
3836
    BuildConfig();
3837
    BuildSharedLibFiles();
3838
    WriteParsedBuildConfig();
3839
    BuildPackageLink();
3840
    BuildSandboxData();
4003 dpurdie 3841
    NoBuildMarker();
227 dpurdie 3842
 
3843
    #
3844
    #  ONLY (re)building interface dir
3845
    #
3846
    return
3847
        if ( $Interface );
3848
 
3849
    #---------------------------------------------------------------------------
3850
    #
3851
    #.. Make bootstrap "makefile",
3852
    #   Simulate a top level makefile
3853
    #       Pass argumenst to makelib
3854
    #       Sumulate SubDir() operations
3855
    #       Sumulate a Platform(*);
3856
    #
3857
    #       Due to the normal way that makelib.pl is executed,
3858
    #       the following substitutions are done.
3859
    #
3860
    @ARGV = ();
3861
    $0 = "makefile.pl ";
3862
    push @ARGV, "$Cwd";                         # current working directory
331 dpurdie 3863
    push @ARGV, "$::GBE_TOOLS/makelib.pl";     # makelib.pl image
227 dpurdie 3864
    push @ARGV, "--interface=$BUILDINTERFACE"
261 dpurdie 3865
        if ($BUILDINTERFACE);
227 dpurdie 3866
 
3867
    Debug( "ARGV:      @ARGV" );
3868
 
3869
    #.. (re)Build root makefile
3870
    #
3871
    $ScmBuildlib = 0;                           # clear Buildlib flag for 'makelib.pl'
3872
    RootMakefile();                             # inform 'makelib.pl'
3873
    MakeLibInit();                              # run initialisation
3874
 
3875
    #.. Register subdir(s)
3876
    #
3877
    UniquePush (\@BUILDSUBDIRS, $Srcdir );
3878
    SubDir( @BUILDSUBDIRS );
3879
    Platform( @BUILD_ACTIVEPLATFORMS );
3880
 
3881
    #.. (re)build src makefiles and associated information
367 dpurdie 3882
    #   JatsTool will not return on error
227 dpurdie 3883
    #
263 dpurdie 3884
    my @cmds = ('jmake.pl', 'rebuild');
227 dpurdie 3885
    push @cmds, 'NORECURSE=1' if ( $RootOnly );
263 dpurdie 3886
    JatsTool ( @cmds);
305 dpurdie 3887
 
3888
    #
7301 dpurdie 3889
    #   Generate package signature
3890
    #
6133 dpurdie 3891
    ErrorConfig( 'name' => 'buildlib')   ;
7301 dpurdie 3892
    BuildSignature();
3893
 
3894
    #
305 dpurdie 3895
    #   Generate some warnings that will be seen at the end of the build
3896
    #
3897
    Warning ("BuildSrcArchive Directive Present","Read JATS Manual for correct usage")
3898
        if ($build_source_pkg);
227 dpurdie 3899
}
3900
 
7301 dpurdie 3901
#-------------------------------------------------------------------------------
3902
# Function        : BuildSignature 
3903
#
3904
# Description     : Generate a package 'signature' for this package
3905
#               
3906
#                   The signature is used to bypass the entire Make processing in a sandbox
3907
#                   If we can find a matching package in the package store then we don't 
3908
#                   need to 'make' this package.
3909
#
3910
#                   There are two scenarios:
3911
#                       In a GIT enabled sandbox
3912
#                       Without GIT
3913
#                       
3914
#                   In a GIT enabled sandbox the signature allows the use of a pre-built 
3915
#                   package - even if the package has been built on a different branch.
3916
#                   
3917
#                       The signature includes:
3918
#                           The name of this package
3919
#                           The GIT sha1 of the directory trees that contain this package
3920
#                           The package signatures of all dependent packages
3921
#                           
3922
#                   In a Non-GIT enabled sandbox the package signature will be set such that
3923
#                   the package will never be found in the package store and the package MUST
3924
#                   be built within the sandbox.
3925
#                   
7302 dpurdie 3926
#                   The hard part is determing the directory trees that contains this package
7301 dpurdie 3927
#                   Ideally this is a single dir-tree, but this cannot be enforced.
3928
#                   
3929
#                   Source directories have been gathered during makefile generation
3930
#                   
3931
#                   This suits most cases, but there are a few where the user needs
3932
#                   to give JATS a hint. Use the AsdSrcDir directive to extend
3933
#                   the signature paths to directories not under the build.pl
3934
#                   or any makefile included by the build.pl
3935
#                       
3936
# Inputs          : 
3937
#
3938
# Returns         : 
3939
#
3940
sub BuildSignature
3941
{
3942
    my %sigExcludeDirs;
3943
    my %sigExcludeFiles;
3944
    my $BuildSignatureSha1;
3945
    my $signatureFile = catfile($Cwd, $BUILDINTERFACE, 'Package.sig');
3946
    my $sigDebugFile  = catfile($Cwd, $BUILDINTERFACE, 'Package.dsig');
3947
    my @sigList;
227 dpurdie 3948
 
7301 dpurdie 3949
    #
3950
    #   Only create the Signature file ONCE
3951
    #   Done on first build (after a clobber)
3952
    #
3953
#   if (-f $signatureFile)
3954
#   {
3955
#       Message("Generate Package Signature - Already generated");
3956
#       return;
3957
#   }
3958
 
3959
    Message("Generate Package Signature");
3960
 
3961
    #
3962
    #   Determine if this is a GIT enabled sandbox build
3963
    #   Need a .git directory or file in the root of the sandbox
3964
    #
3965
    my $gitEnabled;
3966
    if ($::GBE_SANDBOX && -e catfile ($::GBE_SANDBOX, '.git') )
3967
    {
3968
        $gitEnabled = 1;
3969
    }
3970
 
3971
    #
3972
    #   Start generating the signature
3973
    #       Include the package Name,Version and Project
3974
    #
3975
    $BuildSignatureSha1 = Digest::SHA->new;
3976
    $BuildSignatureSha1->add("PKGNAME: $BUILDNAME_PACKAGE $BUILDNAME_VERSION $BUILDNAME_SUFFIX");
3977
    push @sigList, "PKGNAME: $BUILDNAME_PACKAGE $BUILDNAME_VERSION $BUILDNAME_SUFFIX: " . $BuildSignatureSha1->clone->hexdigest;
3978
 
3979
    #
3980
    #   Include the signature of ALL dependent packages
3981
    #   Ie: The package signature is a function of the source and its dependents
3982
    #
3983
    foreach my $tag ( PackageEntry::GetPackageList() )
3984
    {
3985
        my $pkgSig = PackageEntry::GetPackageSignature($tag);
3986
        $BuildSignatureSha1->add("PKGSIGNATURE: $pkgSig");
7302 dpurdie 3987
        push @sigList, sprintf("PKGSIGNATURE: [%s] %s: %s", PackageEntry::GetNameVersion($tag), $pkgSig , $BuildSignatureSha1->clone->hexdigest);
7301 dpurdie 3988
    }
3989
 
3990
    #
3991
    #   Save the signature of the package header and the dependencies
3992
    #   This will be used for a simple test to see in we need to rebuild the build file 
3993
    #
3994
    my $depSha1 =  $BuildSignatureSha1->clone->hexdigest;
3995
    Debug2("DepSha1: $depSha1");
3996
    FileCreate( catfile($ScmInterface, 'build.bfp'), $depSha1 );
3997
 
3998
    if ($gitEnabled)
3999
    {
4000
        #
4001
        #   Include the sha1 of all 'git' tree items that form the complete source image
4002
        #
4003
        my @relDirList = map { my $relName = $_; $relName =~ s~^$::GBE_SANDBOX/~~; $relName  } ToolsetFiles::GetSubTrees(); 
4004
        my @cmdList = map { 'HEAD:' . $_  } @relDirList;
4005
Debug0(" GIT DIR: @relDirList" );
4006
Debug0(" GIT CMD: " . "git rev-parse @cmdList" );
4007
        my $index = 0;
4008
 
4009
        my $callback = sub {
4010
            my ($cdata, $line) = @_;
4011
            $line =~ s~\s+$~~;
4012
Debug0(" GIT OUT: " . $line  );
4013
            $BuildSignatureSha1->add($line);
4014
            push @sigList, "PKGSRC: $relDirList[$index++]: $line: " . $BuildSignatureSha1->clone->hexdigest;
4015
            return 0;
4016
        };
4017
 
4018
        GitCmd('rev-parse', @cmdList, { process => $callback } );
4019
        $BUILDSIGNATURE =  $BuildSignatureSha1->hexdigest;
4020
    }
4021
    else
4022
    {
7302 dpurdie 4023
        $BUILDSIGNATURE = 'MSG: Sandbox is not git enabled';
7301 dpurdie 4024
    }
4025
 
4026
    Message("Signature: $BUILDSIGNATURE");
4027
    push @sigList, "Signature: $BUILDSIGNATURE";
4028
    FileCreate( $signatureFile, $BUILDSIGNATURE );
4029
    FileCreate( $sigDebugFile, @sigList );
4030
Debug0("sigDebugFile: $sigDebugFile");
4031
 
4032
    #
4033
    #   Create the descpkg file - to include the signature
4034
    #
4035
    BuildDescpkg('Internal');
4036
}
4037
 
227 dpurdie 4038
#-------------------------------------------------------------------------------
7301 dpurdie 4039
# Function        : GitCmd
4040
#
4041
# Description     : Run a Git Command and capture/process the output
4042
#
4043
#                   Based on JatsSvnCore:GitCmd
4044
#
4045
# Inputs          : Command
4046
#                   Command arguments
4047
#                   Last argument may be a hash of options.
4048
#                       nosavedata  - Don't save the data
4049
#                       process     - Callback function
4050
#                       printdata   - Print data
4051
#                       error       - Error Message
4052
#                                     Used as first line of an Error call
4053
#
4054
# Returns         : non-zero on errors detected
4055
#
4056
sub GitCmd
4057
{
4058
    my $self;           # Local storage
4059
    Debug ("GitCmd");
4060
 
4061
    #
4062
    #   Locate essential tools
4063
    #
4064
    our $GBE_SVN_PATH;
4065
    EnvImportOptional('GBE_GIT_PATH', '');
4066
    Debug ("GBE_GIT_PATH", $::GBE_GIT_PATH);
4067
 
4068
    my $stdmux = LocateProgInPath ( 'stdmux');
4069
    my $git    = LocateProgInPath ( 'git', '--All', '--Path=' . $::GBE_GIT_PATH );
4070
 
4071
    #
4072
    #   Extract arguments and options
4073
    #   If last argument is a hash, then its a hash of options
4074
    #
4075
    my $opt;
4076
    $opt = pop @_
4077
        if (@_ > 0 and UNIVERSAL::isa($_[-1],'HASH'));
4078
 
4079
    $self->{PRINTDATA} = $opt->{'printdata'} if ( exists $opt->{'printdata'} );
4080
 
4081
    Verbose2 "GitCmd $git @_";
4082
 
4083
    #
4084
    # Useful debugging
4085
    #
4086
    # $self->{LAST_CMD} = [$svn, @_];
4087
 
4088
    #
4089
    #   Reset command output data
4090
    #
4091
    $self->{ERROR_LIST} = [];
4092
    $self->{RESULT_LIST} = [];
4093
#    $self->{LAST_CMD} = \@_;
4094
 
4095
    #
4096
    #   Make use of a wrapper program to mux the STDERR and STDOUT into
4097
    #   one stream (STDOUT). #   This solves a lot of problems
4098
    #
4099
    #   Do not use IO redirection of STDERR because as this will cause a
4100
    #   shell (sh or cmd.exe) to be invoked and this makes it much
4101
    #   harder to kill on all platforms.
4102
    #
4103
    #   Use open3 as it allows the arguments to be passed
4104
    #   directly without escaping and without any shell in the way
4105
    #
4106
    local (*CHLD_OUT, *CHLD_IN);
4107
    my $pid = open3( \*CHLD_IN, \*CHLD_OUT, '>&STDERR', $stdmux, $git, @_);
4108
 
4109
    #
4110
    #   Looks as though we always get a PID - even if the process dies
4111
    #   straight away or can't be found. I suspect that open3 doesn't set
4112
    #   $! anyway. I know it doesn't set $?
4113
    #
4114
    Debug ("Pid: $pid");
4115
    Error ("Can't run command: $!") unless $pid;
4116
 
4117
    #
4118
    #   Close the input handle
4119
    #   We don't have anything to send to this program
4120
    #
4121
    close(CHLD_IN);
4122
 
4123
    #
4124
    #   Monitor the output from the utility
4125
    #   Have used stdmux to multiplex stdout and stderr
4126
    #
4127
    #   Note: IO::Select doesn't work on Windows :(
4128
    #   Note: Open3 will cause blocking unless both streams are read
4129
    #         Can read both streams becsue IO::Select doesn't work
4130
    #
4131
    #   Observation:
4132
    #       svn puts errors to STDERR
4133
    #       svn puts status to STDOUT
4134
    #
4135
    while (<CHLD_OUT>)
4136
    {
4137
        s~\s+$~~;
4138
        tr~\\/~/~;
4139
 
4140
 
4141
        Verbose3 ( "GitCmd:" . $_);
4142
        m~^STD(...):(.+)~;
4143
        my $data = $1 ? $2 : $_;
4144
        next unless ( $data );
4145
 
4146
        if ( $1 && $1 eq 'ERR' )
4147
        {
4148
            #
4149
            #   Process STDERR output
4150
            #
4151
            push @{$self->{ERROR_LIST}}, $data;
4152
        }
4153
        else
4154
        {
4155
            #
4156
            #   Process STDOUT data
4157
            #
4158
            push @{$self->{RESULT_LIST}}, $data unless ($opt->{'nosavedata'});
4159
 
4160
            #
4161
            #   If the user has specified a processing function then pass each
4162
            #   line to the specified function.  A non-zero return will
4163
            #   be taken as a signal to kill the command.
4164
            #
4165
            if ( exists ($opt->{'process'}) && $opt->{'process'}($self, $data) )
4166
            {
4167
                kill 9, $pid;
4168
                sleep(1);
4169
                last;
4170
            }
4171
        }
4172
    }
4173
 
4174
    close(CHLD_OUT);
4175
 
4176
    #
4177
    #   MUST wait for the process
4178
    #   Under Windows if this is not done then we eventually fill up some
4179
    #   perl-internal structure and can't spawn anymore processes.
4180
    #
4181
    my $rv = waitpid ( $pid, 0);
4182
 
4183
    #
4184
    #   If an error condition was detected and the user has provided
4185
    #   an error message, then display the error
4186
    #
4187
    #   This simplifies the user error processing
4188
    #
4189
    if ( @{$self->{ERROR_LIST}} && $opt->{'error'}  )
4190
    {
4191
        Error ( $opt->{'error'}, @{$self->{ERROR_LIST}} );
4192
    }
4193
 
4194
    #
4195
    #   Exit status has no meaning since open3 has been used
4196
    #   This is because perl does not treat the opened process as a child
4197
    #   Not too sure it makes any difference anyway
4198
    #
4199
    #
4200
    Debug ("Useless Exit Status: $rv");
4201
    my $result = @{$self->{ERROR_LIST}} ? 1 : 0;
4202
    Verbose3 ("Exit Code: $result");
4203
 
4204
    return $result;
4205
}
4206
 
4207
 
4208
#-------------------------------------------------------------------------------
227 dpurdie 4209
# Function        : BuildVersion
4210
#
4211
# Description     : Generate version.c and version.h files
4212
#
4213
# Inputs          : Options
4214
#                       --Prefix=prefix         Text prepended to variables created
4215
#                                               as a part of the "C" versions
4216
#                       --Type=type             Type of "C" style data
4217
#                                               Allowed types are: array
4218
#                       --Defs=name             Generate a "C" definitions file.
4219
#                                               This file simply contains definitions
4220
#                       --Defs                  Same as --Defs=defs
4221
#                       --Style=style           Output file style
4222
#                                               Supported styles:
4223
#                                                   "C" - Default
4224
#                                                   "CSharp"
4225
#                                                   "WinRC"
289 dpurdie 4226
#                                                   "Delphi"
315 dpurdie 4227
#                                                   "VB"
227 dpurdie 4228
#                       --File=name             Specifies the output file name
4229
#                                               Default is determined by the style
4230
#
4231
#                   Also allows for an 'old' style format in which
4232
#                   the first three arguments are prefix,type and defs
4233
# Returns         :
4234
#
4235
 
4236
sub BuildVersion
4237
{
4238
    my ( $Prefix, $Type, $Mode ) = @_;
4239
    my $ModePrefix;
4240
    my $Style = "C";
4241
    my $FileName;
4242
    my $VersionFiles;
267 dpurdie 4243
    my @opts;
4244
    my $supports_opts;
227 dpurdie 4245
 
4246
    StartBuildPhase();                          # Starting the build phase. No more data collection
4247
 
279 dpurdie 4248
    if ( defined($Prefix) && $Prefix =~ /^-/ )
227 dpurdie 4249
    {
4250
        $Prefix = undef;
4251
        $Type = undef;
4252
        $Mode = undef;
4253
        foreach  ( @_ )
4254
        {
4255
            if (      /^--Prefix=(.*)/ ) {
4256
                $Prefix = $1;
4257
                $VersionFiles = 1;
4258
 
4259
            } elsif ( /^--Type=(.*)/ ) {
4260
                $Type = $1;
4261
                $VersionFiles = 1;
4262
 
4263
            } elsif ( /^--Defs=(.*)/ ) {
4264
                $Mode = $1;
4265
                $ModePrefix = "_$1";
4266
 
4267
            } elsif ( /^--Defs$/ ) {
4268
                $Mode = 'defs';
4269
                $ModePrefix = "";
4270
 
4271
            } elsif ( /^--Style=(.*)/ ) {
4272
                $Style = $1;
279 dpurdie 4273
                $VersionFiles = 1;
267 dpurdie 4274
                $supports_opts = 1 if ( $Style =~ /^WinRC/i );
227 dpurdie 4275
 
4276
            } elsif ( /^--File=(.*)/ ) {
4277
                $FileName = $1;
4278
 
267 dpurdie 4279
            } elsif ($supports_opts ) {
4280
                push @opts, $_;
235 dpurdie 4281
 
227 dpurdie 4282
            } else {
4283
                Error ("BuildVersion: Unknown option: $_");
4284
 
4285
            }
4286
        }
4287
    }
4288
    else
4289
    {
4290
        #
4291
        #   Old style positional arguments.
4292
        #
4293
        $VersionFiles = 1;
4294
        if ( defined( $Mode ) )
4295
        {
4296
            if ( $Mode =~ m/^defs(=(.*))?$/i )
4297
            {
4298
                $Mode       = $2 ? $2    : 'defs';
4299
                $ModePrefix = $2 ? "_$2" : "";
4300
            }
4301
            else
4302
            {
4303
                Error ("BuildVersion: Bad Mode argument. Need 'defs' or 'defs=name'");
4304
            }
4305
        }
4306
    }
4307
 
4308
    #
4309
    #   Determine the style of version file to create
4310
    #
4311
    if ( $Style =~ /^CSharp/i ) {
4312
        BuildVersionCSharp( $FileName );
4313
 
229 dpurdie 4314
    } elsif ( $Style =~ /^Properties/i ) {
4315
        BuildVersionProperties( $FileName, $Prefix );
4316
 
227 dpurdie 4317
    } elsif ( $Style =~ /^WinRC/i ) {
267 dpurdie 4318
        BuildVersionWinRC( $FileName, @opts );
227 dpurdie 4319
 
289 dpurdie 4320
    } elsif ( $Style =~ /^Delphi/i ) {
4321
        BuildVersionDelphi( $FileName, $Prefix );
315 dpurdie 4322
 
4323
    } elsif ( $Style =~ /^VB/i ) {
4324
        BuildVersionVB( $FileName, $Prefix );
289 dpurdie 4325
 
227 dpurdie 4326
    } elsif ( $Style eq "C" ) {
289 dpurdie 4327
        BuildVersionC    ( $FileName, $Prefix, $Type )     if ( $VersionFiles );
4328
        BuildVersionCdefs( $FileName, $Mode, $ModePrefix ) if ( $Mode );
227 dpurdie 4329
 
4330
    } else {
4331
        Error("BuildVersion: Unknown style: $Style");
4332
    }
4333
}
4334
 
4335
#-------------------------------------------------------------------------------
4336
# Function        : BuildDescpkg
4337
#
4338
# Description     : Create a package description file
4339
#                   The format of this file matches that generated by JANTS
4340
#                   Take care when extending the format
4341
#
4342
#                   NOTE: It turns out that JANTS is not a standard and the
4343
#                         implementors (of JANTS) kept on changing it.
4344
#
7301 dpurdie 4345
# Inputs          : $mode - 'Internal' - Skip sanity test
227 dpurdie 4346
#
4347
# Returns         :
4348
#
4349
sub BuildDescpkg
4350
{
7301 dpurdie 4351
    my ($mode) = @_;
4352
    unless ($mode && $mode eq 'Internal')
4353
    {
4354
        StartBuildPhase();                  # Starting the build phase. No more data collection
4355
    }
4003 dpurdie 4356
    return if ( $Clobber );                 # clobber mode ?
227 dpurdie 4357
 
247 dpurdie 4358
    #
4359
    #   Store the files location for use at runtime
4360
    #   It will be a file that is 'known' to JATS
4361
    #
4003 dpurdie 4362
    my $pkgfile = BuildAddKnownFile ( $NoBuild ? $Cwd : $Srcdir, 'descpkg' );
227 dpurdie 4363
 
261 dpurdie 4364
    my @desc;
279 dpurdie 4365
    push @desc, "Package Name:  $BUILDNAME_PACKAGE";
4366
    push @desc, "Version:       $BUILDVERSION";
7301 dpurdie 4367
    push @desc, "Signature:     $BUILDSIGNATURE" if defined $BUILDSIGNATURE;
279 dpurdie 4368
    push @desc, "Released By:   $::USER";
4369
    push @desc, "Released On:   $::CurrentTime";
4370
    push @desc, "Build Machine: $::GBE_HOSTNAME";
4371
    push @desc, "Path:          $Cwd";
4372
    push @desc, "Jats Version:  $::GBE_VERSION";
4373
    push @desc, "Jats Path:     $::GBE_CORE";
261 dpurdie 4374
    push @desc, "";
4375
    push @desc, "Build Dependencies:";
4376
    push @desc, "";
227 dpurdie 4377
 
4378
    foreach my $tag ( PackageEntry::GetPackageList )
4379
    {
4380
        my ($name, $version, $type) = PackageEntry::GetPackageData($tag);
4381
 
4382
        my @attributes;
4383
 
4384
        push @attributes, "name=\"$name\"";
4385
        push @attributes, "version=\"$version\"";
4386
        push @attributes, "build=\"true\"" if $type =~ /Build/i;
4387
 
261 dpurdie 4388
        push @desc, "<sandbox @attributes/>";
227 dpurdie 4389
    }
247 dpurdie 4390
 
261 dpurdie 4391
    FileCreate ($pkgfile, \@desc );
227 dpurdie 4392
}
4393
 
4394
#-------------------------------------------------------------------------------
4003 dpurdie 4395
# Function        : NoBuildMarker
4396
#
4397
# Description     : Maintain the nobuild marker
4398
#                   This is file placed in the interface directory simply
4399
#                   to indicate to the 'create_dpkg' utility that this build
4400
#                   does not do anything useful.
4401
#
6133 dpurdie 4402
#                   It will only be used on a build machine by the build daemon
4003 dpurdie 4403
#
4404
#                   Its not placed in the interface directory as it would be
4405
#                   harder for create_dpkg to find it.
4406
#
4407
# Inputs          : None
4408
# Globals         : $NoBuild, $Clobber
4409
#
4410
# Returns         : Nothing
4411
#
4412
sub NoBuildMarker
4413
{
4414
    return if ( $Clobber );
4415
 
4416
    # Always delete the file - in case we toggle build forms
4417
    #
5986 dpurdie 4418
    my $markerFile = BuildAddKnownFile( $::ScmRoot, 'noBuild.gbe');
4003 dpurdie 4419
    unlink($markerFile);
4420
 
4421
    TouchFile($markerFile)
4422
        if ($NoBuild);
4423
}
4424
 
4425
#-------------------------------------------------------------------------------
227 dpurdie 4426
# Function        : BuildIncpkg
4427
#
4428
# Description     : Create a package inclusion file
4429
#
4430
# Inputs          :
4431
#
4432
# Returns         :
4433
#
4434
sub BuildIncpkg
4435
{
4436
    StartBuildPhase();                          # Starting the build phase. No more data collection
4437
    if ( $Clobber )                             # clobber mode ?
4438
    {
361 dpurdie 4439
        RmDirTree( "$Srcdir/incpkg" );
227 dpurdie 4440
        return;
4441
    }
4442
 
4443
    my $fh = ConfigurationFile::New( "$Srcdir/incpkg" );
4444
    $fh->Header( "buildlib (Version $BuildVersion)",
4445
                              "Package inclusion list" );
4446
 
4447
    foreach my $tag ( PackageEntry::GetPackageList )
4448
    {
4449
        my ($name, $version, $type) = PackageEntry::GetPackageData($tag);
4450
        $type = ($type =~ /build/i) ? "Build" : "Link";
4451
 
4452
        $fh->Write( "${type}PkgArchive( '$name', '$version' );\n" );
4453
    }
4454
 
4455
    $fh->Close();
4456
}
4457
 
4458
#-------------------------------------------------------------------------------
4459
# Function        : BuildConfig
4460
#
4461
# Description     : Create the file interface/build.cfg
4462
#                   This file contains information gathered by the build process
4463
#                   that is to be used when makefiles are created and re-created
4464
#
4465
# Inputs          : None
4466
#
4467
# Returns         : Nothing
4468
#
283 dpurdie 4469
sub BuildConfig
227 dpurdie 4470
{
4471
    Error( "No BuildInterface directive encountered\n" )
4472
        unless ($BUILDINTERFACE);
4473
 
4474
    my $fh = ConfigurationFile::New( "$BUILDINTERFACE/build.cfg");
4475
    $fh->Header( "buildlib (Version $BuildVersion)",
4476
                              "Makelib configuration file", "
4477
\$ScmBuildMachType              = \"$::GBE_MACHTYPE\";
4478
\$ScmInterfaceVersion           = \"$::InterfaceVersion\";
4479
\$ScmBuildName                  = \"$BUILDNAME\";
4480
\$ScmBuildPackage               = \"$BUILDNAME_PACKAGE\";
4481
\$ScmBuildVersion               = \"$BUILDNAME_VERSION\";
4482
\$ScmBuildProject               = \"$BUILDNAME_PROJECT\";
4483
\$ScmBuildVersionFull           = \"$BUILDVERSION\";
4484
\$ScmBuildPreviousVersion       = \"$BUILDPREVIOUSVERSION\";
4485
\$ScmLocal                      = \"$BUILDLOCAL\";
4486
\$ScmDeploymentPatch            = \"$DEPLOY_PATCH\";
4487
\$ScmSrcDir                     = \"$Srcdir\";
4488
\$ScmBuildSrc                   = \"$ScmBuildSrc\";
4489
\$ScmExpert                     = \"$Expert\";
261 dpurdie 4490
\$ScmAll                        = \"$All\";
4003 dpurdie 4491
\$ScmNoBuild                    = \"$NoBuild\";
7300 dpurdie 4492
\$ScmBuildUuid                  = \"$BUILD_UUID\";
227 dpurdie 4493
");
4494
 
4495
#.. Alias
4496
#
4497
    $fh->DumpData(
4498
        "\n# Aliases.\n#\n",
4499
        "ScmBuildAliases", \%BUILDALIAS );
4500
 
4501
#.. Products
4502
#
4503
    $fh->DumpData(
4504
        "# Product mapping.\n#\n",
4505
        "ScmBuildProducts", \%BUILDPRODUCT_PARTS );
4506
 
4507
#.. Create ScmBuildPlatforms
4508
#
4509
    my( @platforms_merged, %platform_args ) = ();
4510
 
4511
    UniquePush ( \@platforms_merged, @BUILDPLATFORMS );
4512
 
4513
    foreach my $key ( keys %BUILDPRODUCT ) {
4514
        my( @list ) = split( ' ', $BUILDALIAS{ $key } || '' );
4515
        my( $platform );
4516
 
4517
        foreach my $elem ( @list ) {
4518
            if ( $elem =~ /^--/ ) {             # argument
4519
                HashJoin( \%platform_args, $;, $platform, $elem )
4520
                    if ( defined($platform) );
4521
                next;
4522
            }
4523
            $platform = $elem;                  # platform
4524
            UniquePush( \@platforms_merged, $elem );
4525
        }
4526
    }
4527
 
4528
#.. Create ScmBuildPlatforms
4529
#   Contains per platform options extracted from alias and platform args
4530
#
4531
    my %ScmBuildPlatforms;
4532
    foreach my $key ( @platforms_merged ) {
4533
 
4534
        my( @arguments ) = ();
4535
        UniquePush( \@arguments, split( /$;/, $BUILDPLATFORMARGS{ $key } ))
4536
            if ( exists $BUILDPLATFORMARGS{ $key } );
4537
 
4538
        UniquePush( \@arguments, split( /$;/, $platform_args{ $key } ))
4539
            if ( exists $platform_args{ $key } );
4540
 
4541
        $ScmBuildPlatforms{$key} = join "$;", @arguments;
4542
    }
4543
 
4544
    $fh->DumpData(
4545
        "# Platform and global argument list.\n#\n",
4546
        "ScmBuildPlatforms", \%ScmBuildPlatforms );
4547
 
4548
 
4549
# .. Create BuildPkgRules
4550
#
367 dpurdie 4551
#    This is most of the information contained within %PKGRULES, which
227 dpurdie 4552
#    requires additional processing within makelib.
4553
#
367 dpurdie 4554
#   Need the True Path for windows.
4555
#       Some makefile functions (wildcard) only work as expected
4556
#       if the case of the pathname is correct. Really only a problem
4557
#       with badly formed legecy packages where the Windows user
4558
#       guessed at the package format.
4559
#
227 dpurdie 4560
    my %ScmBuildPkgRules;
4561
    foreach my $platform ( keys %PKGRULES )
4562
    {
4563
        foreach my $package ( @{$PKGRULES{$platform}} )
4564
        {
4565
            my %entry;
4566
 
367 dpurdie 4567
            $entry{ROOT}     = TruePath( $package->{'base'} );
227 dpurdie 4568
            $entry{NAME}     = $package->{'name'};
4569
            $entry{VERSION}  = $package->{'version'};
4570
            $entry{DNAME}    = $package->{'dname'};
4571
            $entry{DVERSION} = $package->{'dversion'};
4572
            $entry{DPROJ}    = $package->{'dproj'};
4573
            $entry{TYPE}     = $package->{'type'};
4574
            $entry{CFGDIR}   = $package->{'cfgdir'} if ( defined( $package->{'cfgdir'} ) );
4575
 
367 dpurdie 4576
            foreach my $dir (qw (TOOLDIRS) )
227 dpurdie 4577
            {
4578
                $entry{$dir} = $package->{$dir} ;
4579
            }
4580
 
367 dpurdie 4581
            my $baselen = length($package->{'base'});
4582
            foreach my $dir (qw (PINCDIRS PLIBDIRS THXDIRS) )
4583
            {
4584
                $entry{$dir} = [];
4585
                foreach my $file ( @{$package->{$dir}} )
4586
                {
4587
                    push @{$entry{$dir}}, substr TruePath($package->{'base'} . $file ), $baselen;
4588
                }
4589
            }
4590
 
227 dpurdie 4591
            push @{$ScmBuildPkgRules{$platform}}, \%entry;
4592
        }
4593
    }
4594
 
4595
    $fh->DumpData(
4596
        "# Imported packages.\n#\n",
4597
        "ScmBuildPkgRules", \%ScmBuildPkgRules );
4598
 
4599
#
4600
#   BUILDPLATFORMS,
4601
#       The value that is saved only contains the active platforms
4602
#
4603
#   DEFBUILDPLATFORMS,
4604
#       The value that is matchs the wildcard specification for Platform 
4605
#       directives.
4606
#
4607
    $fh->DumpData(
4608
        "# A list of platforms active within the view.\n#\n",
4609
        "BUILDPLATFORMS", \@BUILD_ACTIVEPLATFORMS );
4610
 
4611
    $fh->DumpData(
4612
        "# A list of default platforms within the view.\n#\n",
4613
        "DEFBUILDPLATFORMS", \@DEFBUILDPLATFORMS );
4614
 
4615
#
4616
#   BUILDTOOLS
4617
#       A list of toolset extension paths
4618
#
4619
    $fh->DumpData(
4620
        "# A list of paths with toolset extension programs.\n#\n",
4621
        "BUILDTOOLSPATH", \@BUILDTOOLS );
4622
 
4623
#
4624
#   BUILDPLATFORM_PARTS
4625
#       A subset of BUILDINFO exported as BUILDPLATFORM_PARTS
4626
#       This exists only for backward compatability with existing code
4627
#       in external packages ( deployfiles).
4628
#
4629
#   Only save those parts that are part of the current build
4630
#   This will prevent users attempting to build for platforms that have not
4631
#   been correctly constructed.
4632
#
4633
    my %active =  map { ${_} => 1 } @BUILD_ACTIVEPLATFORMS;
4634
    my %active_buildplatform_parts;
4635
    my %active_build_info;
4636
    foreach ( keys %BUILDINFO )
4637
    {
4638
        next unless ( $active{$_} );
4639
        $active_buildplatform_parts{$_} = $BUILDINFO{$_}{PARTS};
4640
        $active_build_info{$_}          = $BUILDINFO{$_};
4641
    }
4642
 
4643
    $fh->DumpData(
4644
        "# Parts of all platforms.\n#\n",
4645
        "BUILDPLATFORM_PARTS", \%active_buildplatform_parts );
4646
#
4647
#   BUILDINFO
4648
#       Complete TARGET Information
4649
#
4650
    $fh->DumpData(
4651
        "# Extended build information.\n#\n",
4652
        "BUILDINFO", \%active_build_info );
4653
 
4654
#
247 dpurdie 4655
#   BUILD_KNOWNFILES
4656
#       All paths are relative to the project root directory
4657
#       ie: The directory that conatins the build.pl file
4658
#
4659
    $fh->DumpData(
4660
        "# Generated Files that may be known when used as Src files.\n#\n",
4661
        "BUILD_KNOWNFILES", \%BUILD_KNOWNFILES );
4662
 
4663
#
227 dpurdie 4664
#   Close out the file
4665
#
4666
    $fh->Close();
363 dpurdie 4667
 
227 dpurdie 4668
}
4669
 
4670
#-------------------------------------------------------------------------------
4671
# Function        : WriteParsedBuildConfig
4672
#
4673
# Description     : Write all the parsed build.pl data to a single file
4674
#                   Its all in there for use
4675
#
4676
# Inputs          : 
4677
#
4678
# Returns         : 
4679
#
4680
sub WriteParsedBuildConfig
4681
{
4682
    my $cfg_file = "$::BUILDINTERFACE/Buildfile.cfg";
4683
    my %cf_build_info = ();
4684
 
4685
    #
4686
    #   Examine the symbol table and capture most of the entries
4687
    #
4688
    foreach my $symname (keys %main::)
4689
    {
4690
        next if ( $symname =~ m/::/  );                 # No Typeglobs
4691
        next if ( $symname =~ m/^cf_build_info/  );     # Not myself
4692
        next unless ( $symname =~ m/^[A-Za-z]/  );      # No system type names
4693
        next if ( $symname =~ m/^SIG$/  );              # Useless
4694
        next if ( $symname =~ m/^ENV$/  );              # Don't keep the user ENV
4695
        next if ( $symname =~ m/^INC$/  );              # Don't keep the INC paths
4696
        next if ( $symname =~ m/^DEFINES/  );           # Don't keep
4697
        next if ( $symname =~ m/^TOOLSETRULES/  );      # Don't keep
4698
 
331 dpurdie 4699
        no strict 'vars';
227 dpurdie 4700
        local *sym = $main::{$symname};
4701
 
331 dpurdie 4702
        $cf_build_info{"\$$symname"} =  $sym if defined $sym;
369 dpurdie 4703
        $cf_build_info{"\@$symname"} = \@sym if @sym;
4704
        $cf_build_info{"\%$symname"} = \%sym if %sym;
331 dpurdie 4705
        use strict 'vars';
227 dpurdie 4706
    }
4707
 
4708
    #
4709
    #   Dump out the configuration information
4710
    #
4711
    my $fh = ConfigurationFile::New( "$cfg_file" );
4712
    $fh->Header( "buildlib (version $::BuildVersion)",
4713
                              "Buildfile configuration" );
4714
    $fh->Dump( [\%cf_build_info], [qw(*cf_build_info)] );
4715
    $fh->Close();
4716
}
4717
 
4718
 
4719
#-------------------------------------------------------------------------------
4720
# Function        : BuildSharedLibFiles
4721
#
4722
# Description     : Create a file in the interface directory that will specify
4723
#                   the locations of shared libraries.
4724
#
4725
#                   Note: Always create a file as makefile targets depend on it.
4726
#
4727
#                   This is a bit ugly.
4728
#
4729
#                   There needs be an association between the build machine and
4730
#                   the target platform. Need to know if the current target is
4731
#                   native to the current build machine. If it is then we can
4732
#                   run tests on the machine and we then need to extend the
4733
#                   search path for the target.
4734
#
4735
#                   The BUILDINFO{EXT_SHARED} is used to control the creation of
4736
#                   the files by specifying the extension of the file.
4737
#
4738
# Inputs          : None
4739
#
4740
# Returns         :
4741
#
4742
sub BuildSharedLibFiles
4743
{
4744
    if ( $ScmHost eq "DOS" || $ScmHost eq "WIN" ) {
4745
        BuildSharedLibFiles_WIN(@_);
4746
 
4747
    } elsif ( $ScmHost eq "Unix" ) {
4748
        BuildSharedLibFiles_Unix(@_);
4749
 
4750
    } else {
4751
        Error("Cannot build. Unknown machine type: $ScmHost",
4752
              "Need WIN, DOS or Unix" );
4753
    }
4754
}
4755
 
4756
#-------------------------------------------------------------------------------
4757
# Function        : BuildSharedLibFiles_WIN
4758
#
4759
# Description     : Implementation of BuildSharedLibFiles for Windows
4760
#
4761
# Inputs          : None
4762
#
4763
sub BuildSharedLibFiles_WIN
4764
{
4765
 
4766
    foreach my $platform ( @BUILD_ACTIVEPLATFORMS )
4767
    {
4768
        next unless ( exists $BUILDINFO{$platform}{EXT_SHARED} );
4769
        my @dos_paths = BuildSharedLibFiles_list( $platform, $BUILDINFO{$platform}{EXT_SHARED} );
4770
 
4771
        #
4772
        #   Create a .bat file for WIN32
4773
        #   This may be consumed by user wrapper programs
4774
        #
229 dpurdie 4775
        #   Features: No Echo
4776
        #             Use of SETLOCAL to prevent pollution of environment
4777
        #
227 dpurdie 4778
        my $fh = ::ConfigurationFile::New( "$BUILDINTERFACE/set_$platform.bat", '--NoEof', '--Type=bat' );
229 dpurdie 4779
        $fh->Write ( "\@echo off\n");
227 dpurdie 4780
        $fh->Header( "Buildlib ($BuildVersion)","Shared Library Paths" );
229 dpurdie 4781
        $fh->Write ( "\nSETLOCAL\n");
227 dpurdie 4782
        foreach ( reverse @dos_paths )
4783
        {
4784
            $_ =~ s~/~\\~g;
4785
            $fh->Write ( "PATH=$_;\%PATH\%\n" );
4786
        }
4787
        $fh->Write ( "\n%*\n" );
229 dpurdie 4788
        $fh->Write ( "\nENDLOCAL\n");
231 dpurdie 4789
        $fh->Write ( "EXIT /B %ERRORLEVEL%\n");
227 dpurdie 4790
        $fh->Close();
4791
 
4792
        #
4793
        #   Create a .sh file for WIN32
4794
        #   This may be consumed by a shell - as used within JATS
4795
        #
4796
        $fh = ::ConfigurationFile::New( "$BUILDINTERFACE/set_$platform.sh", '--NoEof', '--Type=sh' );
4797
        $fh->Header( "Buildlib ($BuildVersion)","Shared Library Paths" );
4798
        foreach ( reverse @dos_paths )
4799
        {
4800
            tr~\\/~/~s;
4801
            $fh->Write ( "PATH=$_\\;\$PATH\n" );
4802
        }
287 dpurdie 4803
        $fh->Write ( "\n" . '[ -n "$*" ] && "$@"'  ."\n" );
227 dpurdie 4804
        $fh->Close();
4805
    }
4806
}
4807
 
4808
#-------------------------------------------------------------------------------
4809
# Function        : BuildSharedLibFiles_Unix
4810
#
4811
# Description     : Implementation of BuildSharedLibFiles for Unix
4812
#                   Extend the Shared Library search path via LD_LIBRARY_PATH
5877 dpurdie 4813
#                   
4814
#                   Create sonames for all external shared libraries
227 dpurdie 4815
#
4816
# Inputs          : None
4817
#
4818
sub BuildSharedLibFiles_Unix
4819
{
4820
    foreach my $platform ( @BUILD_ACTIVEPLATFORMS )
4821
    {
4822
        next unless ( exists $BUILDINFO{$platform}{EXT_SHARED} );
4823
        my @unix_paths = BuildSharedLibFiles_list( $platform, $BUILDINFO{$platform}{EXT_SHARED} );
4824
 
4825
        #
5877 dpurdie 4826
        #   Create sonames for all shared libraries
4827
        #   Append to the begging of the search list - so that it will rendered last
4828
        #   
4829
        my $sodir = BuildSoNameLinks_Unix($platform, @unix_paths);
4830
        unshift( @unix_paths, $sodir ) if defined $sodir;
4831
 
4832
        #
227 dpurdie 4833
        #   Create a .sh file for Unix
4834
        #
229 dpurdie 4835
        my $file = "$BUILDINTERFACE/set_$platform.sh";
4836
        my $fh = ::ConfigurationFile::New( $file , '--NoEof', '--Type=sh' );
227 dpurdie 4837
        $fh->Header( "Buildlib ($BuildVersion)","Shared Library Paths" );
4838
        foreach ( reverse @unix_paths )
4839
        {
4840
            $fh->Write ( "export LD_LIBRARY_PATH=$_:\$LD_LIBRARY_PATH\n" );
4841
        }
275 dpurdie 4842
        $fh->Write ( "\n\"\$\@\"\n" );
227 dpurdie 4843
        $fh->Close();
229 dpurdie 4844
 
4845
        #
4846
        #   Make the file executable under unix
4847
        #
4848
        chmod 0755, $file;
227 dpurdie 4849
    }
4850
}
4851
 
4852
#-------------------------------------------------------------------------------
5877 dpurdie 4853
# Function        : BuildSoNameLinks_Unix 
4854
#
4855
# Description     : Generate soname links for all shared libraries from external
4856
#                   packages.
4857
#                   
4858
#                   There is a bit of a cheat. We don't examine the library to determine
4859
#                   the soname. We simple create all possible sonames to the library
4860
#
4861
# Inputs          : $platform       - Target platform
4862
#                   @paths          - Array of paths to scan for libraries 
4863
#
4864
# Returns         : soLinkDir       - Absolute path to the directory of gernerated
4865
#                                     symlinks
4866
#
4867
sub BuildSoNameLinks_Unix
4868
{
4869
    my ($platform, @paths) = @_;
4870
    my $soLinkDir = catdir($BUILDINTERFACE, 'soLinks', $platform );
4871
 
4872
    Verbose("Create Unix SoName links - $soLinkDir");
4873
    RmDirTree( $soLinkDir );
4874
 
4875
    #
4876
    #   Search provided library paths for shared libaries
4877
    #       These are names of the form *.so.* ie : libz.so.1.2.5
4878
    #
4879
    foreach my $path (@paths)
4880
    {
4881
        foreach my $file (glob(catdir($path, '*.so.*')))
4882
        {
4883
            #
4884
            #   Skip the debug symbol files
4885
            #
4886
            next if $file =~ m~\.debug$~;
4887
            next if $file =~ m~\.dbg$~;
4888
 
4889
            #
4890
            #   Generate all possible sonames by removing .nnnn from the 
4891
            #   end of the file name
4892
            #   
4893
            my $sofile = $file;
4894
            while ($sofile =~ m~(.*)\.\d+$~)
4895
            {
4896
                $sofile = $1;
4897
                unless (-f $sofile) {
4898
                    Verbose2("Need Soname: $sofile");
4899
 
4900
                    #
4901
                    #   Create link from soname to full name
4902
                    #   
4903
                    mkpath ( $soLinkDir ) unless -d $soLinkDir;
4904
                    my $sofilename = $sofile;
4905
                    $sofilename =~ s~.*/~~;
4906
                    $sofilename = catdir($soLinkDir, $sofilename);
4907
                    unless (-f $sofilename) {
4908
                        symlink ($file, $sofilename) || Error ("Cannot create symlink to $sofilename. $!"); 
4909
                    }
4910
                }
4911
            }
4912
        }
4913
    }
4914
 
4915
    #
4916
    #   Return the path the generated soLink dir
4917
    #
4918
    return AbsPath($soLinkDir) if (-d $soLinkDir);
4919
    return undef;
4920
}
4921
 
4922
#-------------------------------------------------------------------------------
227 dpurdie 4923
# Function        : BuildSharedLibFiles_list
4924
#
4925
# Description     : Determine a list of Shared Library paths that can be used
4926
#                   by the current target
4927
#
4928
# Inputs          : $platform       - Current platform
4929
#                   $so             - Shared object extensions
4930
#
4931
# Returns         : List of search paths
4932
#
4933
sub BuildSharedLibFiles_list
4934
{
4935
    my ($platform, $so ) = @_;
4936
    my @paths;
4937
    my @parts = @{$BUILDINFO{$platform}{PARTS}};
4938
 
4939
    #
4940
    #   Paths from the current build
4941
    #       Local directory         - for installed components
4942
    #       Interface directory     - for BuildPkgArchives
4943
    #
4944
    if ( $BUILDLOCAL )
4945
    {
5986 dpurdie 4946
        my @localParts;
4947
        UniquePush \@localParts, $BUILDINFO{$platform}{PLATFORM} , $BUILDINFO{$platform}{PRODUCT}, $BUILDINFO{$platform}{TARGET};
4948
        foreach ( @localParts )
227 dpurdie 4949
        {
4950
            push @paths, AbsPath("$BUILDLOCAL/lib/$_");
4951
        }
4952
    }
4953
 
4954
    foreach ( @parts )
4955
    {
4956
            push @paths, AbsPath("$BUILDINTERFACE/lib/$_");
4957
    }
4958
 
4959
    #
4960
    #   For each LinkPkgArchive
4961
    #
4962
    foreach my $package ( @{$PKGRULES{$platform}} )
4963
    {
4964
        next unless ( $package->{'type'} eq 'link' );
4965
 
4966
        my $base = $package->{'base'};
4967
        for my $path ( @{$package->{'PLIBDIRS'}} )
4968
        {
289 dpurdie 4969
            my @so_libs;
317 dpurdie 4970
            push @so_libs, glob ( "$base$path/*$_") foreach ( ArrayList($so) );
227 dpurdie 4971
            next unless scalar @so_libs;
4972
            push @paths, $base . $path;;
4973
        }
4974
    }
4975
 
4976
    #
4977
    #   Returns paths found
4978
    #
4979
    return @paths;
4980
}
4981
 
4982
#-------------------------------------------------------------------------------
247 dpurdie 4983
# Function        : BuildAddKnownFile
4984
#
4985
# Description     : Save the file as a file that will be known  to the JATS
4986
#                   makefiles. It will be available SRCS, but will not be a
4987
#                   part of any object list.
4988
#
4989
#                   Known Files will be deleted on clobber
4990
#
4991
# Inputs          : $path
4992
#                   $file
289 dpurdie 4993
#                   $noadd                    - Don't add to known
247 dpurdie 4994
#
4995
# Returns         : Path and filename
4996
#
4997
 
4998
sub BuildAddKnownFile
4999
{
289 dpurdie 5000
    my ($path, $file, $noadd) = @_;
247 dpurdie 5001
    $path .= '/'. $file;
2450 dpurdie 5002
    $path =~ tr~/~/~s;
289 dpurdie 5003
    $BUILD_KNOWNFILES {$file} = $path
5004
        unless ( defined($noadd) && $noadd);
4003 dpurdie 5005
 
6133 dpurdie 5006
    ToolsetFiles::AddFile( $path )
3967 dpurdie 5007
        unless ($Clobber);
5008
 
247 dpurdie 5009
    return $path;
5010
}
5011
 
5012
#-------------------------------------------------------------------------------
5969 dpurdie 5013
# Function        : WinPath 
5014
#
5015
# Description     : Covert path to a windows formatted path
5016
#
5017
# Inputs          : One path element
5018
#
5019
# Returns         : One ugly path element
5020
#
5021
 
5022
sub WinFullPath
5023
{
5024
    my ($path) = @_;
5025
    $path = FullPath($path);
5026
    $path =~ tr~\\/~\\~s;
5027
    return $path;
5028
}
5029
 
5030
#-------------------------------------------------------------------------------
5031
# Function        : BuildPropertyPages 
5032
#
5033
# Description     : Create a props file suitable for use by VS2010, VS2012 (possibly others)
5034
#                   Only supported for C/C++ projects
5035
#                   Provide info for:
5036
#                       Include Search paths
5037
#                       Library search paths
5038
#                       Nice Macros 
5039
#
5040
# Inputs          : 
5041
#
5042
# Returns         : 
5043
#
5044
sub BuildPropertyPages
5045
{
5046
    StartBuildPhase();                      # Starting the build phase. No more data collection
5986 dpurdie 5047
    return if $Clobber;
5969 dpurdie 5048
    foreach my $platform ( keys %BUILDINFO )
5049
    {
5050
        next unless $BUILDINFO{$platform}{MSBUILDPROPS};
5986 dpurdie 5051
        my $propsFile = BuildAddKnownFile ($Srcdir, 'jats_'. $BUILDINFO{$platform}{TARGET} . '.props');
5052
 
5969 dpurdie 5053
        Message("BuildPropertyPages: $propsFile");
5054
 
5055
        my %macros;
5056
        my @libpaths;
5057
        my @incpaths;
5058
        my @parts = @{$BUILDINFO{$platform}{PARTS}};
5059
 
5060
        #
5061
        #   Basic definitions
5062
        #   
5063
        $macros{'GBE_ROOT'}     = WinFullPath(".");
5064
        $macros{'GBE_PLATFORM'} = $BUILDINFO{$platform}{PLATFORM};
5065
        $macros{'GBE_PRODUCT'}  = $BUILDINFO{$platform}{PRODUCT};
5066
        $macros{'GBE_TARGET'}   = $BUILDINFO{$platform}{TARGET};
5067
        $macros{'GBE_MACHTYPE'} = $::GBE_MACHTYPE;
5068
        $macros{'GBE_PKGDIR'}   = WinFullPath('./pkg/' . $BUILDNAME_PACKAGE);
5069
        $macros{'GBE_BUILDNAME'}= $BUILDNAME_PACKAGE;
5070
 
5071
        #
5072
        #   Paths from the current build
5073
        #       Local directory         - for installed components
5074
        #       Interface directory     - for BuildPkgArchives
5075
        #
5076
        if ( $BUILDLOCAL )
5077
        {
5078
            my $macroName = 'GBE_LOCALDIR';
5079
            $macros{$macroName} = WinFullPath("$BUILDLOCAL") ;
5080
            $macroName = '$(' . $macroName . ')';
5986 dpurdie 5081
            my @localParts;
5082
            UniquePush \@localParts, $BUILDINFO{$platform}{PLATFORM} , $BUILDINFO{$platform}{PRODUCT}, $BUILDINFO{$platform}{TARGET};
5083
            foreach ( @localParts )
5969 dpurdie 5084
            {
5085
                push @libpaths, catdir($macroName, 'lib', $_);
5086
                push @incpaths, catdir($macroName ,'include' ,$_);
5087
            }
5088
            push @incpaths, catdir($macroName ,'include');
5089
        }
5090
 
5091
        my $macroName = 'GBE_INTERFACEDIR';
5092
        $macros{$macroName} = WinFullPath("$BUILDINTERFACE") ;
5093
        $macroName = '$(' . $macroName . ')';
5094
 
5095
        foreach ( @parts )
5096
        {
5097
                push @libpaths, catdir($macroName, 'lib' , $_);
5098
                push @incpaths, catdir($macroName ,'include' ,$_);
5099
        }
5100
        push @incpaths, catdir($macroName ,'include');
5101
 
5102
        #
5103
        #   For each LinkPkgArchive
5104
        #
5105
        foreach my $package ( @{$PKGRULES{$platform}} )
5106
        {
5107
            next unless ( $package->{'type'} eq 'link' );
5108
 
5109
            my $macroName = 'GBE_PACKAGE_'.$package->{'name'};
5110
            $macros{$macroName} = WinFullPath($package->{'base'}) ;
5111
            $macroName = '$(' . $macroName . ')';
5112
 
5113
            for my $path ( @{$package->{'PLIBDIRS'}} )
5114
            {
5115
                push @libpaths, catdir($macroName, $path);
5116
            }
5117
            for my $path ( @{$package->{'PINCDIRS'}} )
5118
            {
5119
                push @incpaths, catdir($macroName, $path);
5120
            }
5121
        }
5122
 
5123
        my $AdditionalIncludeDirectories = join(';', @incpaths );
5124
        my $AdditionalLibraryDirectories = join(';', @libpaths);
5125
        my $PreprocessorDefinitions = 'JATS=1';
5126
 
5127
        #
5128
        #   Create a props file formatted for VS2012
5129
        #
5130
        open (my $XML, '>', $propsFile) || Error ("Cannot create output file: $propsFile", $!);
5131
 
5132
        my $writer = XML::Writer->new(OUTPUT => $XML, UNSAFE => 0, DATA_INDENT => 4, DATA_MODE => 1);
5133
        $writer->xmlDecl("UTF-8");
5134
        $writer->comment('This file is generated by JATS build');
5135
        $writer->comment('Do not edit this file');
5136
        $writer->comment('Do not version control this file');
5137
        $writer->startTag('Project', "ToolsVersion", "4.0", "xmlns", "http://schemas.microsoft.com/developer/msbuild/2003");
5138
        $writer->emptyTag('ImportGroup', 'Label' , "PropertySheets");
5139
 
5140
        #
5141
        #   Special Macro for handling production/debug libraries
5142
        #
5143
        $writer->startTag('PropertyGroup', 'Label' , "UserMacros", 'Condition', "'\$(Configuration)' == 'Debug'");
5144
        $writer->dataElement('GBE_TYPE', 'D');
5145
        $writer->endTag('PropertyGroup');
5146
 
5147
        $writer->startTag('PropertyGroup', 'Label' , "UserMacros", 'Condition', "'\$(Configuration)' != 'Debug'");
5148
        $writer->dataElement('GBE_TYPE', 'P');
5149
        $writer->endTag('PropertyGroup');
5150
 
5151
        #
5152
        #   Define macros
5153
        #   
5154
        $writer->startTag('PropertyGroup', 'Label' , "UserMacros");
5155
        foreach my $key ( sort keys %macros)
5156
        {
5157
            $writer->dataElement($key, $macros{$key});
5158
        }
5159
        $writer->endTag('PropertyGroup');
5160
        $macros{'GBE_TYPE'}     = 1;
5161
 
5162
        #
5163
        #   Extend the search paths for includes and libaraies
5164
        #   
5165
        #$writer->emptyTag('ItemDefinitionGroup');
5166
        $writer->startTag('ItemDefinitionGroup');
5167
 
5168
        $writer->startTag('ClCompile');
5169
        $writer->dataElement('AdditionalIncludeDirectories', $AdditionalIncludeDirectories . ';%(AdditionalIncludeDirectories)');
5170
        $writer->dataElement('PreprocessorDefinitions', $PreprocessorDefinitions . ';%(PreprocessorDefinitions)');
5171
        $writer->endTag('ClCompile');
5172
 
5173
        $writer->startTag('Link');
5174
        $writer->dataElement('AdditionalLibraryDirectories', $AdditionalLibraryDirectories . ';%(AdditionalLibraryDirectories)');
5175
        $writer->endTag('Link');
5176
        $writer->endTag('ItemDefinitionGroup');
5177
 
5178
        #
5179
        #   Specify all macro names
5180
        #
5181
        $writer->startTag('ItemGroup');
5182
        foreach my $key ( sort keys %macros)
5183
        {
5184
            $writer->startTag('BuildMacro', 'Include' , $key);
5185
            $writer->dataElement('Value', '$(' . $key . ')');
5186
            $writer->endTag('BuildMacro');
5187
        }
5188
 
5189
        #
5190
        #   Close tags and write the XML file
5191
        #
5192
        $writer->endTag('ItemGroup');
5193
        $writer->endTag('Project');
5194
        $writer->end();
5195
    }
5196
}
5197
 
5198
 
5199
#-------------------------------------------------------------------------------
227 dpurdie 5200
# Function        : Usage
5201
#
5202
# Description     : Display program usage information
5203
#
5204
# Inputs          : args            - Text message to display
5205
#
5206
#                   $opt_help       - Level of verbose ness
5207
#
5208
# Returns         : Does not return
5209
#                   This function will exit
5210
#
5211
sub Usage
5212
{
5213
    my( $msg ) = @_;
5214
    my %usage_args;
5215
 
5216
    #
5217
    #   Create a hash of arguments for the pod2usage function
5218
    #
5219
    $usage_args{'-input'} = __FILE__;
5220
    $usage_args{'-exitval'} = 42;
5221
    $usage_args{'-message'} = "\nbuildlib $msg\n" if $msg;
5222
    $usage_args{'-verbose'} = $opt_help < 3 ? $opt_help - 1 : 3 if ( $opt_help );
5223
 
5224
    #
5225
    #   Generate nice help
5226
    #
5227
    pod2usage(\%usage_args);
5228
}
5229
 
5230
#-------------------------------------------------------------------------------
5231
#   Documentation
5232
#
5233
 
5234
=pod
5235
 
361 dpurdie 5236
=for htmltoc    JATS::build
5237
 
227 dpurdie 5238
=head1 NAME
5239
 
361 dpurdie 5240
build - Build Environment and Makefiles
227 dpurdie 5241
 
5242
=head1 SYNOPSIS
5243
 
5244
jats build [options] [command]
5245
 
5246
     [perl buildlib.pl [options] PWD [command]]
5247
 
5248
 Options:
331 dpurdie 5249
    -help          - Display terse usage
361 dpurdie 5250
    -help -help    - Display verbose usage
331 dpurdie 5251
    -man           - Display internal manual
5252
    -verbose[=n]   - Set level of progress verbosity
5253
    -debug[=n]     - Set the debug level
5254
    -cache         - Cache packages in the local dpkg_package cache
361 dpurdie 5255
    -cache -cache  - Forced refresh dependent packages in the local cache
331 dpurdie 5256
    -package       - Ignore packages that are not available and continue
2078 dpurdie 5257
    -nopackages    - Ignore package processing directives
331 dpurdie 5258
    -forcebuildpkg - Treat LinkPkgArchive directives as BuildPkgArchive
361 dpurdie 5259
                     Also suppress the use of symlinks so that the physical
5260
                     file will be copied locally.
331 dpurdie 5261
    -[no]force     - Force build even if build.pl is not newer
363 dpurdie 5262
                     Default: -force
4778 dpurdie 5263
    -[no]generic   - Build system sanity test
5264
                     Default: Do not test
227 dpurdie 5265
 
5266
 Sticky settings:
331 dpurdie 5267
    -all           - Build for all platforms ignoring GBE_BUILDFILTER
5268
    -expert[=n]    - Relaxing dependency checks on the user makefiles
227 dpurdie 5269
 
5270
 Commands:
2078 dpurdie 5271
    clobber        - Remove generated build system (eg Makefiles).
6133 dpurdie 5272
    interface      - Only (re)build the interface tree.
361 dpurdie 5273
    rootonly       - Only (re)build the root directory.
227 dpurdie 5274
 
5275
=head1 OPTIONS
5276
 
5277
=over 8
5278
 
331 dpurdie 5279
=item B<-help>
227 dpurdie 5280
 
5281
Print a brief help message and exits.
5282
 
5283
=item B<-help -help>
5284
 
5285
Print a detailed help message with an explanation for each option.
5286
 
5287
=item B<-man>
5288
 
5289
Prints the manual page and exits.
5290
 
331 dpurdie 5291
=item B<-verbose[=n]>
227 dpurdie 5292
 
261 dpurdie 5293
Increases program output.
227 dpurdie 5294
 
261 dpurdie 5295
If an argument is provided, then it will be used to set the level, otherwise the
5296
existing level will be incremented. This option may be specified multiple times.
227 dpurdie 5297
 
261 dpurdie 5298
=item B<-debug>
5299
 
227 dpurdie 5300
Increases program output. Enable internal debugging messages to generate detailed
5301
progress information.
5302
 
261 dpurdie 5303
If an argument is provided, then it will be used to set the level, otherwise the
5304
existing level will be incremented. This option may be specified multiple times.
5305
 
331 dpurdie 5306
=item B<-cache>
227 dpurdie 5307
 
5308
This option will cause dependent packages to be cached in the local
5309
dpkg_archive cache.
5310
 
5311
If the option is used twice then the packages will be forcibly refreshed.
5312
 
331 dpurdie 5313
=item B<-package>
227 dpurdie 5314
 
5315
This option will cause the build process to ignore packages that cannot be
5316
located. The package build may fail at a later stage.
5317
 
5318
This option is used by the Auto Build Tool to handle packages that may not be
5319
needed in all builds.
5320
 
2078 dpurdie 5321
=item B<-nopackage>
5322
 
5323
This options will cause all the directives that process external packages to be
5324
ignored.
5325
 
5326
This directive has limited use. It can be used in conjunction with the
5327
'interface' build command in order to create Version Information files in a
5328
sandbox where the required packages do not yet exist.
5329
 
331 dpurdie 5330
=item B<-forcebuildpkg>
227 dpurdie 5331
 
5332
This option will force LinkPkgArchive directives to be treated as
5333
BuildPkgArchive directives. The result is that the 'interface' directory will be
5334
populated with the contents of all dependent packages. Moreover, on a Unix
5335
machine, the files will be copied and not referenced with a soft link.
5336
 
5337
This may be useful for:
5338
 
5339
=over 8
5340
 
361 dpurdie 5341
=item *
227 dpurdie 5342
 
361 dpurdie 5343
Remote Development
227 dpurdie 5344
 
361 dpurdie 5345
=item *
227 dpurdie 5346
 
361 dpurdie 5347
Collecting header files for scanning
5348
 
5349
=item *
5350
 
5351
Local modification of files for test/debug/development
5352
 
227 dpurdie 5353
=back
5354
 
331 dpurdie 5355
=item B<-[no]force>
227 dpurdie 5356
 
331 dpurdie 5357
The '-noforce' option will only perform a build, if the build.pl file
363 dpurdie 5358
has been modified, or the buildfilter has changed, since the last build.
331 dpurdie 5359
 
363 dpurdie 5360
The default operation will always force a build.
331 dpurdie 5361
 
4778 dpurdie 5362
=item B<-[no]generic>
5363
 
5364
If used, this option will perform a sanity test on the build type. If set to 
5365
Generic then the build must be a GENERIC build. If set to noGeneric then the build
5366
must not be a GENERIC build.
5367
 
5368
The default is to not perform the test.
5369
 
5370
This option is intended to be used by the automated build system.
5371
 
331 dpurdie 5372
=item B<-all>
5373
 
227 dpurdie 5374
This option will cause the build process to generate makefiles for all
5375
possible build targets ignoring the use of GBE_BUILDFILTER.
5376
 
5377
This option is sticky. Once used in a build it will be retained when makefiles
5378
are rebuilt.
5379
 
331 dpurdie 5380
=item B<-expert[=n]>
227 dpurdie 5381
 
5382
This option causes the generation of makefiles with relaxed dependancy checks.
5383
 
261 dpurdie 5384
If an argument is provided, then it will be used to set the level, otherwise a
5385
level of '1' will be set.
5386
 
227 dpurdie 5387
The makefiles will have no dependancy between the makefiles and the JATS build
5388
files or the users makefile. If the user's makefile.pl is changed then JATS
5389
will not detect the change and will not rebuild the makefiles. The user manually
5390
force the rebuild with the command 'jats rebuild'.
5391
 
5392
This option should be used with care and with full knowledge of its impact.
5393
 
5394
This option is sticky. Once used in a build it will be retained when makefiles
363 dpurdie 5395
are rebuilt. It will only be lost when the next 'jats build' is performed.
227 dpurdie 5396
 
261 dpurdie 5397
The effect of the option can be changed when the makefiles are processed. This
5398
option simply sets the default' mode of operation.
5399
 
227 dpurdie 5400
=item B<interface>
5401
 
6133 dpurdie 5402
This command will only build, or rebuild, the 'interface' directory.
227 dpurdie 5403
 
261 dpurdie 5404
This command will not build, or rebuild, the root directory. The build
227 dpurdie 5405
process will not recurse through the subdirectories creating makefiles.
5406
 
261 dpurdie 5407
=item B<rootonly>
5408
 
6133 dpurdie 5409
This command will only build, or rebuild, the 'interface' directory and 
5410
the root-level makefiles.
261 dpurdie 5411
 
5412
The build process will not recurse through the subdirectories creating
5413
makefiles. These can be made on-demand by jats if a 'make' command is issued.
5414
 
227 dpurdie 5415
=item B<clobber>
5416
 
5417
This command will remove generated build system files and directories.
5418
 
5419
=back
5420
 
5421
=head1 DESCRIPTION
5422
 
5423
The default build process will parse the user's build.pl file and create the
5424
'interface' directory before creating makefiles for each target platform.
5425
 
5426
The 'build' process simply generates the build sandbox. It does not invoke the
5427
generated makefiles. This must be done by the user in a different phase.
5428
 
5429
The 'build' process need only be invoked if the build.pl file has changed. The
5430
generated makefiles will detected changes to the makefile.pl's and cause them to
5431
be generated as required. The 'build' step sets up the sandboxes external
5432
environment.
5433
 
5434
=head1 INVOCATION
5435
 
5436
This perl library (buildlib.pl) is not designed to be invoked directly by the
5437
user. It should be invoked through a 'build.pl' file. Moreover, for historical
5438
reasons, the build.pl is not easily invoked. It is best to only invoke the
5439
'build' process via the JATS wrapper scripts : jats.bat or jats.sh.
5440
 
331 dpurdie 5441
The build.pl file must be invoked with one fixed arguments, followed by user
227 dpurdie 5442
options and subcommands
5443
 
5444
=over 8
5445
 
361 dpurdie 5446
=item   1
227 dpurdie 5447
 
361 dpurdie 5448
The current working directory
5449
 
227 dpurdie 5450
This could have been derived directly by the program, rather than having it
5451
passed in.
5452
 
361 dpurdie 5453
=item   2
227 dpurdie 5454
 
361 dpurdie 5455
Options and commands may follow the first two mandatory arguments.
5456
 
227 dpurdie 5457
=back
5458
 
5459
The build.pl file must 'require' the buildlib.pl and makelib.pl. The preferred
5460
code is:
5461
 
5462
=over 8
5463
 
5464
    build.pl: First statements
5465
    $MAKELIB_PL     = "$ENV{ GBE_TOOLS }/makelib.pl";
5466
    $BUILDLIB_PL    = "$ENV{ GBE_TOOLS }/buildlib.pl";
5467
 
5468
    require         "$BUILDLIB_PL";
5469
    require         "$MAKELIB_PL";
5470
 
5471
=back
5472
 
5473
=cut
5474
 
5475
1;