Subversion Repositories DevTools

Rev

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