Subversion Repositories DevTools

Rev

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

Rev Author Line No. Line
227 dpurdie 1
########################################################################
6177 dpurdie 2
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
227 dpurdie 3
#
4
# Module name   : jats.sh
5
# Module type   : Makefile system
6
# Compiler(s)   : n/a
7
# Environment(s): jats
8
#
9
# Description   : Top level Makefile supervisor
10
#                 The function of this program is to call the target makefiles
6133 dpurdie 11
#                 in a suitable manner.
227 dpurdie 12
#
13
# History       : Once upon a time this was done with another makefile and
6133 dpurdie 14
#                 some really ugly shell, embedded within the makefile
227 dpurdie 15
#                 This had a number of limitations, including
16
#                   - Limited to makefile command line syntax
17
#                   - Overly complex makefile
6133 dpurdie 18
#                   - Very slow execution
227 dpurdie 19
#
6133 dpurdie 20
# Usage         : See POD
227 dpurdie 21
#
22
#......................................................................#
23
 
255 dpurdie 24
require 5.006_001;
227 dpurdie 25
use strict;
26
use warnings;
27
 
28
use Pod::Usage;                             # For help support
29
use JatsError;
30
use JatsSystem;
31
use JatsEnv;
32
use JatsMakeInfo;
33
use ReadBuildConfig qw(:All);
34
use Getopt::Long;
35
use FileUtils;
36
use ArrayHashUtils;
37
use JatsDPackage;
38
 
39
my $VERSION = "1.0.0";                      # Update this
40
 
41
#
5708 dpurdie 42
#   Default values
43
#   
5746 dpurdie 44
use constant GBE_MAXMAKE_DEFAULT => '4h';
5708 dpurdie 45
#
227 dpurdie 46
#   Options
47
#
48
my $opt_debug   = $ENV{'GBE_DEBUG'};        # Allow global debug
49
my $opt_verbose = $ENV{'GBE_VERBOSE'};      # Allow global verbose
50
my $opt_help = 0;
51
my $opt_silent = 1;
52
my $opt_default;
5695 dpurdie 53
my $opt_max_make;
227 dpurdie 54
 
55
#
56
#   Global variables
57
#
58
our %cf_info;
59
our $GBE_TOOLS;                             # Base of tools
60
our $GBE_ABT;                               # Optional ABT indication
61
our $GBE_PLATFORM;                          # Optional GBE_PLATFORM
5695 dpurdie 62
our $GBE_MAXMAKE;                           # Optional GBE_MAXMAKE
227 dpurdie 63
our $ScmInterface;                          # Current interface directory
64
our $ScmRoot;                               # Build root
4003 dpurdie 65
our $ScmNoBuild;                            # Dummy Build and Make
227 dpurdie 66
 
67
my $Tags;                                   # Reference to hash of tags
68
my %defs;                                   # Make definitions
69
my @defs;                                   # Make definitions
70
my @targets;                                # Make targets
71
my $makelib;                                # Path to makelib.pl
72
my $update = 0;                             # Makefiles updated
73
my $build_error = 0;                        # Build Error encountered
74
my $tlen = 4;                               # Max length of targets
75
my %common_cmd;                             # Short circuit some commands
76
my %gbe_platform;                           # Nice form of GBE_PLATFORM
77
 
78
#
79
#   Known commands
4761 dpurdie 80
#   A hash of known commands and information about the commands
81
#       common      - Command operation modifiers
227 dpurdie 82
#                     Flags: 1 - Command not executed for debug+prod
83
#                     Flags: 2 - Command is only executed ONCE per platform
84
#       local       - The command is handled locally.
85
#       nomakecheck - Don't check for makefile being out of date
86
#       IFLAG       - iteration flag,
87
#                       0   No external dependencies.
88
#                       1   Source dependency list.
89
#                       2   Shared library dependency list.
90
#                       3   Application dependency list.
91
#   Note:   gmake attempts to build includes prior to invoking other
92
#   rules when the source is non-existent, which can/do fail as a
93
#   result of the prereq rules not being executed, the IFLAG inhabits
94
#   includes during these prereq rules.
95
#
96
my %composite_commands = (
97
    #
98
    #   Composite commands
99
    #
100
    'lint'                  => [ 'mkdepends', 'generate_debug', 'install_hdr_debug',
101
                                 'lint_lib', 'lint_shlib', 'lint_prog' ] ,
102
    'ctags'                 => [ 'mkdepends', 'generate_debug', 'ctags_debug' ] ,
103
    'test'                  => [ 'make_test' ] ,
104
    'mkdepends'             => [ 'makefiles', 'make_init'] ,
4728 dpurdie 105
    'run_tests'             => [ 'preprocess_tests', 'exec_tests', 
106
                                 'postprocess_tests', 'collate_test_results' ] ,
107
    'run_unit_tests'        => [ 'preprocess_tests', 'exec_unit_tests', 
108
                                 'postprocess_tests', 'collate_test_results' ] ,
5073 dpurdie 109
    # Convenient phases of the build
110
    'hdrs'                  => [ 'mkdepends', 'generate', 'install_hdr'],
111
    'libs'                  => [ 'hdrs', 'depend', 'make_lib', 'install_lib'],
112
    'slibs'                 => [ 'libs', 'make_install_shlib'],
113
    'progs'                 => [ 'slibs', 'make_prog', 'make_test', 'install_prog', 'install_class'],
6387 dpurdie 114
    'build'                 => [ 'progs','install_dirs'],
5073 dpurdie 115
    'install'               => [ 'build' ] ,
116
    'all'                   => [ 'install', 'package', 'deploy' ] ,
227 dpurdie 117
    );
118
 
119
my %commands = (
120
    #
121
    #   Basic commands / phases of the build process
122
    #   This should be a list of all known makefile commands
123
    #
124
    'help'                  => { 'tag' => 0, 'local' => \&DoHelp },
281 dpurdie 125
    'show'                  => { 'tag' => 0, 'local' => \&ShowMakefiles },
227 dpurdie 126
    'rebuild'               => { 'tag' => 0, 'local' => \&TestMakeFiles },
127
    'makefiles'             => { 'tag' => 0, 'local' => \&TestMakeFiles },
128
    'unmakefiles'           => { 'tag' => 0, 'local' => \&UnMakeFiles },
129
    'make_init'             => { 'tag' => 1, 'nomakecheck' => 1, 'common' => 3, },
130
    'generate'              => { 'tag' => 1 },
131
    'install_hdr'           => { 'tag' => 1 },
261 dpurdie 132
    'depend'                => { 'tag' => 1, 'unless' => ['NODEPEND','EXPERT'] },
227 dpurdie 133
    'make_lib'              => { 'tag' => 1, 'IFLAG' => 1 },
261 dpurdie 134
    'make_mlib'             => { 'tag' => 1, 'IFLAG' => 1 },
227 dpurdie 135
    'install_lib'           => { 'tag' => 1, 'IFLAG' => 1 },
136
    'make_install_shlib'    => { 'tag' => 1, 'IFLAG' => 2 },
137
    'make_prog'             => { 'tag' => 1, 'IFLAG' => 3 },
138
    'make_test'             => { 'tag' => 1, 'IFLAG' => 3 },
139
    'install_prog'          => { 'tag' => 1, 'IFLAG' => 3 },
140
    'install_class'         => { 'tag' => 1 },
6387 dpurdie 141
    'install_dirs'          => { 'tag' => 1 },
227 dpurdie 142
    'package'               => { 'tag' => 1, 'IFLAG' => 3 },
143
    'deploy'                => { 'tag' => 1, 'IFLAG' => 1 },
144
 
145
    #
261 dpurdie 146
    #   Special
147
    #   make_dir is directly invoked by jmake. It doesn't need
148
    #   to be a part of a command sequence
149
    #
150
    'make_dir'              => { 'nomakecheck' => 1, 'tag' => 1 },
151
 
152
    #
227 dpurdie 153
    #   Basic commands, that appear to be unused in composite commands
154
    #   Not too sure why
155
    #
156
    'make_script'           => { 'commands' => [], 'tag' => 1 },
157
 
158
    #
159
    #   Lint related targets
160
    #
161
    'lint_lib',             => { 'tag' => 'make_lib'            , 'IFLAG' => 1 },
162
    'lint_shlib',           => { 'tag' => 'make_install_shlib'  , 'IFLAG' => 2 },
163
    'lint_prog'             => { 'tag' => 'make_prog'           , 'IFLAG' => 3 },
164
 
165
    #
4728 dpurdie 166
    #   Unit testing related commands
167
    #
168
    'exec_tests'            => { 'nomakecheck' => 1, 'tag' => 1, 'IFLAG' => 3},
169
    'exec_unit_tests'       => { 'nomakecheck' => 1, 'tag' => 1, 'IFLAG' => 3},
170
    'preprocess_tests'      => { 'nomakecheck' => 1, 'tag' => 'process_tests'},
171
    'postprocess_tests'     => { 'nomakecheck' => 1, 'tag' => 'process_tests'},
4761 dpurdie 172
    'collate_test_results'  => { 'nomakecheck' => 1, 'tag' => 'process_tests', 'common' => 2},
4728 dpurdie 173
 
174
    #
227 dpurdie 175
    #   Following commands should NOT be a part of a composite command
176
    #
177
    'clean'                 => { 'nomakecheck' => 1},
178
    'clobber'               => { 'nomakecheck' => 1},
179
    'rmlitter'              => { 'nomakecheck' => 1},
180
    'unbuild'               => { 'nomakecheck' => 1},
261 dpurdie 181
    'undepend'              => { 'nomakecheck' => 1 , 'tag' => 'depend'},
182
    'ungenerate'            => { 'nomakecheck' => 1 , 'tag' => 'generate'},
227 dpurdie 183
    'uninstall'             => { 'nomakecheck' => 1},
6387 dpurdie 184
    'uninstall_dirs'        => { 'nomakecheck' => 1},
227 dpurdie 185
    'uninstall_class'       => { 'nomakecheck' => 1},
261 dpurdie 186
    'uninstall_hdr'         => { 'nomakecheck' => 1 , 'tag' => 'install_hdr'},
187
    'uninstall_lib'         => { 'nomakecheck' => 1 , 'tag' => 'install_lib'},
188
    'uninstall_prog'        => { 'nomakecheck' => 1 , 'tag' => 'install_prog'},
189
    'unmake_lib'            => { 'nomakecheck' => 1 , 'tag' => 'make_mlib'},
190
    'unmake_mlib'           => { 'nomakecheck' => 1 , 'tag' => 'make_mlib'},
191
    'unmake_prog'           => { 'nomakecheck' => 1 , 'tag' => 'make_prog'},
192
    'unmake_script'         => { 'nomakecheck' => 1 , 'tag' => 'make_script'},
193
    'unmake_test'           => { 'nomakecheck' => 1 , 'tag' => 'make_test'},
227 dpurdie 194
    'unobj'                 => { 'nomakecheck' => 1},
261 dpurdie 195
    'unpackage'             => { 'nomakecheck' => 1 , 'tag' => 'package'},
196
    'unmake_dir'            => { 'nomakecheck' => 1 , 'tag' => 'make_dir'},
227 dpurdie 197
 
198
    );
199
#    DebugDumpData ("Commands", \%commands);
200
 
201
#-------------------------------------------------------------------------------
202
# Function        : Mainline Entry Point
203
#
204
# Description     :
205
#
206
# Inputs          :
207
#
208
 
209
#
210
#   Parse the user options
211
#
212
my $result = GetOptions (
261 dpurdie 213
                "help:+"        => \$opt_help,              # flag, multiple use allowed
214
                "manual:3"      => \$opt_help,              # flag, multiple use allowed
215
                "verbose:+"     => \$opt_verbose,           # flag, multiple use allowed
216
                "d|debug:+"     => \$opt_debug,             # flag, multiple use allowed
227 dpurdie 217
                "default=s"     => \$opt_default,           # string
5695 dpurdie 218
                "maxTime=s"     => \$opt_max_make,          # string
227 dpurdie 219
                );
220
 
221
                #
222
                #   UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!
223
                #
224
 
225
#
226
#   Process help and manual options
227
#
228
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
261 dpurdie 229
pod2usage(-verbose => 1)  if ( $opt_help == 2 );
230
pod2usage(-verbose => 2)  if ( $opt_help > 2 );
227 dpurdie 231
 
232
#
233
#   Configure the error reporting process now that we have the user options
234
#
235
ErrorConfig( 'name'    => 'Make',
236
             'verbose' => $opt_verbose,
237
             'debug'   => $opt_debug );
238
 
5695 dpurdie 239
# Global information
227 dpurdie 240
#
5695 dpurdie 241
EnvImportOptional ( 'GBE_ABT' );
242
EnvImportOptional ( 'GBE_PLATFORM' );
5708 dpurdie 243
EnvImportOptional ( 'GBE_MAXMAKE', GBE_MAXMAKE_DEFAULT );
5695 dpurdie 244
 
245
#
246
#   Sanity check arguments
247
#
248
$opt_max_make = $GBE_MAXMAKE unless defined $opt_max_make;
249
Error ("Invalid maxTime: $opt_max_make") 
250
    unless ($opt_max_make =~ m~^[0-9]*\.?[0-9]+[smhd]?$~);
251
Warning("Time limit is disabled ") unless $opt_max_make;
5708 dpurdie 252
Verbose("Time limit: $opt_max_make");
5695 dpurdie 253
 
254
#
227 dpurdie 255
#   Configure the 'System' process so that it will terminate on any error
256
#   and not report the complete command line
257
#
258
SystemConfig ( 'ExitOnError' => 2);
259
 
260
#
261
#   Extract non-option commands
262
#   Much of this is for backward compatability
263
#   Support the following arguments
264
#       XXXXX=yyyy      Makefile Definition
265
#       -XXXX           Flags passed to make
266
#       XXXX            Raw target name
267
#
268
foreach my $arg ( @ARGV )
269
{
270
    Verbose2 ("Arg: $arg");
271
    if ( $arg =~ m~(\w+)=(.+)~ ) {
272
        $defs{uc($1)} = $2;
273
 
274
    } elsif ( $arg =~ m/^-/ ) {
275
        push @defs, $arg;
276
 
277
    } else {
278
        push @targets, $arg;
279
 
280
    }
281
}
282
 
283
#
284
#   Misc. Initialisation
285
#
286
InitFileUtils();
287
 
288
EnvImport( 'GBE_TOOLS' );
289
$makelib = "$GBE_TOOLS/makelib.pl";
290
Error ("Cannot locate JATS file: $makelib") unless ( -f $makelib );
291
 
292
#
293
#   Validate user options
294
#
295
@targets = ($opt_default)
296
    if ( $opt_default && ! @targets);
297
Error ("No make targets specified" ) unless ( @targets );
298
 
299
#
300
#   Build the @defs array
301
#   This is a set of definitions passed to the makefiles
302
#   It is created on the fly to allow command line options to modify the definitions
303
#
304
foreach  ( sort keys %defs )
305
{
306
    next if ( m~^DEBUG$~i );                    # Naughty user
307
    push @defs, "$_=$defs{$_}";                 # Makefile defs are XXXX=aaaa
308
}
309
 
310
#
311
#   Look for OPTIONS=*args* and disable the silent make operation
312
#   This will allow the make to output messages
313
#
314
if (( exists $defs{OPTIONS} && $defs{OPTIONS} =~ m/args/ ) || $opt_verbose || $opt_debug )
315
{
316
    $opt_silent = 0;
317
}
318
 
319
#
320
#   Read in the local Makefile.gbe file
321
#   This will provide a path to the interface directory
322
#
323
ReadMakeInfo();
324
 
325
#
326
#   Read in the global build variables
327
#
328
ReadBuildConfig( "$::ScmRoot/$::ScmInterface" );
329
 
330
#
4551 dpurdie 331
#   Process GBE_PLATFORM and create a usable hash
332
#
333
if ( $GBE_PLATFORM )
334
{
335
    Verbose2 ("GBE_PLATFORM: $GBE_PLATFORM");
336
    $gbe_platform{$_} = 1 foreach ( split( / /, $GBE_PLATFORM ) );
337
 
338
    # Insert targets that are GENERIC, there should only be one
339
    foreach my $target (keys %BUILDINFO) {
340
        if ($BUILDINFO{$target}{IS_GENERIC})
341
        {
342
            $gbe_platform{$target} = 1;
343
        }
344
    }
345
}
346
 
347
#
4003 dpurdie 348
#   Process the user specified targets
227 dpurdie 349
#
4003 dpurdie 350
ProcessTargets();
227 dpurdie 351
 
4003 dpurdie 352
#
353
#   All done
354
#
355
exit (0);
356
 
227 dpurdie 357
#-------------------------------------------------------------------------------
4003 dpurdie 358
# Function        : ProcessTargets
227 dpurdie 359
#
4003 dpurdie 360
# Description     : Process the user specified targets
227 dpurdie 361
#
4003 dpurdie 362
# Inputs          :
363
#
364
# Returns         : 
365
#
366
sub ProcessTargets
227 dpurdie 367
{
4003 dpurdie 368
    if($ScmNoBuild)
369
    {
370
            Verbose2 ("Processing Skipped in noBuild");
371
            return;
372
    }
227 dpurdie 373
 
374
    #
4003 dpurdie 375
    #   Determine the max size of the target name
376
    #   Makes a nice display
227 dpurdie 377
    #
4003 dpurdie 378
    foreach ( @BUILDPLATFORMS )
379
    {
380
        my $len = length ($_);
381
        $tlen = $len if ( $len > $tlen );
227 dpurdie 382
    }
383
 
4003 dpurdie 384
    #-------------------------------------------------------------------------------
385
    #   Scan the list of targets and perform 'alias' expansion
386
    #   targets are of the form
387
    #       platform_command_type
388
    #       Where:
389
    #           type        may be _prod or _debug or not present
390
    #           command     may be either a composite command or a simple command
391
    #           platform    may be a platform or an alias
227 dpurdie 392
    #
393
    #
4003 dpurdie 394
    foreach my $arg ( @targets )
227 dpurdie 395
    {
4003 dpurdie 396
        my $suffix = '';
397
        my @commands;
398
        my @platforms;
399
 
400
        #
401
        #   Remove the only available suffix ( _debug | _prod )
402
        #   Also detect commnads of debug or prod
403
        #
404
        if ( $arg =~ m~(.+)_(debug)$~ ) {
405
            $suffix = $2;
406
            $arg = $1;
407
        } elsif ( $arg =~ m~(.+)_(prod)$~ ) {
408
            $suffix = $2;
409
            $arg = $1;
410
        } elsif ( $arg eq 'debug' ) {
411
            $suffix = $arg;
227 dpurdie 412
            $arg = '';
4003 dpurdie 413
        } elsif ( $arg eq 'prod' ) {
414
            $suffix = $arg;
415
            $arg = '';
227 dpurdie 416
        }
4003 dpurdie 417
 
418
        #
419
        #   Remove valid make commands from the remaining argument
420
        #   Have a hash of all known makefile commands
421
        #
422
        foreach my $cmd ( keys %composite_commands, keys %commands )
227 dpurdie 423
        {
4003 dpurdie 424
            if ( $arg eq $cmd )
425
            {
426
                @commands = ExpandComposite($cmd);
427
                $arg = '';
428
            }
429
            elsif ( $arg =~ m~(.+)_($cmd)$~ )
430
            {
431
                $arg = $1;
432
                @commands = ExpandComposite($2);
433
                last;
434
            }
227 dpurdie 435
        }
436
 
4003 dpurdie 437
        #
438
        #   See of we can extract an platform alias from the command
439
        #   Rip into target + command
440
        #
441
        if ( $arg )
227 dpurdie 442
        {
4003 dpurdie 443
            if ( exists $ScmBuildAliases{$arg}  )
227 dpurdie 444
            {
4003 dpurdie 445
                @platforms =  split (/ /, $ScmBuildAliases{$arg} );
227 dpurdie 446
            }
4003 dpurdie 447
            elsif ( exists $ScmBuildPlatforms{$arg} )
448
            {
449
                @platforms = ($arg);
450
            }
227 dpurdie 451
            else
452
            {
4003 dpurdie 453
                if ( @commands )
454
                {
455
                    Error ("Unknown target: $arg");
456
                }
457
                else
458
                {
459
                    Message ("Unknown command. Passed to make: $arg");
460
                    @commands = $arg;
461
                }
227 dpurdie 462
            }
463
        }
464
 
4003 dpurdie 465
        #
466
        #   Insert defaults
467
        #
468
        @platforms = @DEFBUILDPLATFORMS
469
            unless ( @platforms );
470
        @commands = ExpandComposite('all')
471
            unless ( @commands);
227 dpurdie 472
 
4003 dpurdie 473
        #
474
        #   Perform GBE_PLATFORM filtering
475
        #
476
        @platforms = grep ( exists $gbe_platform{$_} , @platforms )
477
            if ( %gbe_platform );
227 dpurdie 478
 
4003 dpurdie 479
        Error ("No platforms to be processed. Check GBE_PLATFORM")
480
            unless ( @platforms );
227 dpurdie 481
 
4003 dpurdie 482
        #
483
        #   Iterate commands over platforms
484
        #
485
        foreach my $cmd ( @commands )
486
        {
487
            PerformCommand (\@platforms, $cmd, $suffix );
488
        }
227 dpurdie 489
    }
490
}
491
 
492
#-------------------------------------------------------------------------------
493
# Function        : PerformCommand
494
#
495
# Description     : Perform the make on a platform command
496
#
497
# Inputs          : $platform_ref   - platforms to process
498
#                   $cmd            - simple make command
499
#                   $suffix         - debug,prod,none
500
#
501
# Returns         : 
502
#
503
sub PerformCommand
504
{
505
    my ($platform_ref, $cmd, $suffix) = @_;
506
    my $do_prod = 1;
507
    my $do_debug = 1;
508
 
509
    #
510
    #   Clean up some ugly commands from lint and ctags
511
    #
512
    if ( $cmd =~ m~(.+)_(debug)$~ )
513
    {
514
        $cmd = $1;
515
        $suffix = $2;
516
    }
517
    Verbose2 ("Processing Target: $cmd, $suffix");
518
 
519
    #
520
    #   Limit command to production or debug
521
    #
522
    if ( $suffix eq 'debug' ) {
523
        $do_prod  = 0;
524
    } elsif ( $suffix eq 'prod' ) {
525
        $do_debug  = 0;
526
    }
527
 
528
    #
529
    #   Some commands can be suppressed by options
261 dpurdie 530
    #   These are an array of options
227 dpurdie 531
    #
532
    if ( exists $commands{$cmd}{'unless'}  )
533
    {
261 dpurdie 534
        foreach my $check ( @{$commands{$cmd}{'unless'}} )
227 dpurdie 535
        {
261 dpurdie 536
            if ( exists $defs{$check} && $defs{$check} )
537
            {
538
                Verbose2 ("Skipping: $cmd because $check");
539
                return;
540
            }
227 dpurdie 541
        }
542
    }
543
 
544
    #
545
    #   Interecpt commands that are handled locally
546
    #
547
    if ( exists $commands{$cmd}{'local'} )
548
    {
549
        $commands{$cmd}{'local'}( $cmd, $platform_ref );
550
        return;
551
    }
552
 
553
    #
554
    #   Process and recurse directory tree
555
    #
556
    Verbose ("Processing: $cmd, @{$platform_ref}");
557
 
558
    #
559
    #   Determine the local tag name and state
560
    #   The tag is used to short circuit makefile commands in recursive makes
561
    #   It greatly reduces the work required
562
    #
563
    #   Many commands have a tag that is the same as the command, but a few don't
564
    #
565
    my $tag = 0;
566
    if ( exists $commands{$cmd}{tag}  )
567
    {
568
        $tag = $commands{$cmd}{tag};
569
        $tag = $cmd if ( $tag eq '1' );
570
    }
571
 
4761 dpurdie 572
    #   Ensure this element is defined
573
    #       Simplifies testing in the remainder of the code
574
    $commands{$cmd}{'common'} = 0 
575
        unless exists($commands{$cmd}{'common'});
576
 
577
    if ( $commands{$cmd}{'common'} & 1 )
227 dpurdie 578
    {
4761 dpurdie 579
        InvokeSubMake( $::Cwd, $platform_ref ,$cmd, $tag, 1, 'C' );
227 dpurdie 580
    }
581
    else
582
    {
4761 dpurdie 583
        InvokeSubMake( $::Cwd, $platform_ref ,$cmd, $tag, 1, 'D' ) if $do_debug;
584
        InvokeSubMake( $::Cwd, $platform_ref ,$cmd, $tag, 0, 'P' ) if $do_prod;
227 dpurdie 585
    }
586
}
587
 
588
#-------------------------------------------------------------------------------
589
# Function        : InvokeSubMake
590
#
591
# Description     : Build recursion
592
#                   Determine if there is anything to be done for the current
593
#                   target within a specified directory
594
#
595
# Inputs          : $dir
596
#                   $pref                   - Ref to an array of platforms
597
#                   $cmd
598
#                   $tag
4761 dpurdie 599
#                   $do_debug               - 0:Production, 1:Debug
600
#                   $text                   - Single Char display text (C, P or D)
227 dpurdie 601
#
602
# Returns         : 
603
#
604
sub InvokeSubMake
605
{
4761 dpurdie 606
    my ( $dir, $pref, $cmd, $tag, $do_debug, $text) = @_;
227 dpurdie 607
 
608
    #
609
    #   Ensure the current directory is known to the Tags database
610
    #
611
    $Tags = ReadMaketags( $dir );
612
    Error ("Directory not in tag database", $dir ) unless ( $Tags );
613
 
614
    #
615
    #   Process commands in the current directory
616
    #   If the command is tagged, then we may be able to skip it
617
    #   Otherwise we need to do it
618
    #
4761 dpurdie 619
    InvokeMake( $dir, $pref, $cmd, $tag, $do_debug, $text );
227 dpurdie 620
 
621
    #
622
    #   Recurse into any subdirectories that may be a part of the build
623
    #
624
    unless ( exists $defs{NORECURSE} && $defs{NORECURSE}  )
625
    {
626
        #
627
        #   Process subdirectories for the current command
628
        #   If the command is tagged, then we may be able to skip it
629
        #   Otherwise we need to do it
630
        #
631
        foreach my $subdir (@{$Tags->{$dir}{subdirs}} )
632
        {
633
 
4761 dpurdie 634
            InvokeSubMake( CleanDirName( "$dir/$subdir"), $pref, $cmd, $tag, $do_debug, $text );
227 dpurdie 635
        }
636
    }
637
}
638
 
639
#-------------------------------------------------------------------------------
640
# Function        : InvokeMake
641
#
642
# Description     : Actually invoke the make for debug and production as required
643
#
644
# Inputs          : $dir
645
#                   $pref
646
#                   $cmd
647
#                   $tag
4761 dpurdie 648
#                   $do_debug               - 0:Production, 1:Debug
649
#                   $text                   - Single Char display text (C, P or D)
227 dpurdie 650
#
651
#
652
# Returns         : 
653
#
654
sub InvokeMake
655
{
4761 dpurdie 656
    my ( $dir, $pref, $cmd, $tag, $do_debug, $text ) = @_;
227 dpurdie 657
 
279 dpurdie 658
    Verbose2 ("InvokeMake: $dir");
227 dpurdie 659
    #
660
    #   Ensure that the current directory actually has makefile targets
661
    #   Not all makefile.pl create .mk files
662
    #       1) Top-level makefile.pl
663
    #       2) Makefiles that use --NoPlatformBuilds
664
    #
665
    if ( $Tags->{$dir}{root} )
666
    {
667
        Verbose2 "Root directory has no makefiles: $dir";
668
        return;
669
    }
670
 
671
    if ( $Tags->{$dir}{noplatforms} )
672
    {
673
        Verbose2 "No make targets in $dir";
674
        return;
675
    }
676
 
677
    #
678
    #   Process each platform
679
    #
680
    foreach my $target ( @{$pref} )
681
    {
682
        unless ( exists $Tags->{$dir}{platforms}{$target} )
683
        {
684
            Verbose2 "No make targets in $dir, for $target";
685
            next;
686
        }
687
 
688
        #
689
        #   Do we need to do any thing for this target / tag
690
        #
691
        if ( $tag )
692
        {
693
            unless ( exists $Tags->{$dir}{full}{$target}{'%MakeTags'}{$tag} )
694
            {
261 dpurdie 695
                Verbose2 ("Skipping $cmd in $dir for $tag");
227 dpurdie 696
                next;
697
            }
698
        }
699
 
700
        #
4761 dpurdie 701
        #   common modifier mask=2, (Bit-1)
702
        #       Only process target ONCE for each platform
703
        #       Don't care when its used
227 dpurdie 704
        #
4761 dpurdie 705
        if ( $commands{$cmd}{'common'} & 2 )
227 dpurdie 706
        {
4761 dpurdie 707
            if ( $common_cmd{$cmd}{$text}{$target} )
227 dpurdie 708
            {
4761 dpurdie 709
                Verbose2 "Already performed $cmd for $target in mode $text";
227 dpurdie 710
                next;
711
            }
4761 dpurdie 712
            $common_cmd{$cmd}{$text}{$target} = 1;
227 dpurdie 713
        }
714
 
715
        #
716
        #   Is the build limited to only debug or production
717
        #
4761 dpurdie 718
        unless ( $commands{$cmd}{'common'} & 1 )
227 dpurdie 719
        {
720
            if ( $do_debug == 0 ) {
5619 dpurdie 721
                unless ( $Tags->{$dir}{platforms}{$target}{prod} )
722
                {
723
                    Verbose("Skip debug build in Production Only build");
724
                    next;
725
                }
227 dpurdie 726
 
727
            } elsif  ( $do_debug == 1 ) {
5619 dpurdie 728
                unless ( $Tags->{$dir}{platforms}{$target}{debug} )
729
                {
730
                    Verbose("Skip prod build in Debug Only build");
731
                    next;
732
                }
227 dpurdie 733
            }
734
        }
735
 
736
        #
737
        #   Final sanity test
738
        #   Must have the makefile. We should have detected this error before now
739
        #
740
        Error ("Makefile not found - $target") unless ( -f "$dir/$target.mk" );
741
 
742
        #
275 dpurdie 743
        #   Export data into the user environment
744
        #   Allows underlying tools to locate data files with little effort
745
        #
746
        $ENV{'GBE_MAKE_TYPE'} = $text;                  # P or D or C
747
        $ENV{'GBE_MAKE_TARGET'} = $target;              # Target platform
748
        $ENV{'GBE_MAKE_CFG'} = $Tags->{$dir}{config};   # Ref to config data
749
        $ENV{'GBE_MAKE_CMD'} = $cmd;                    # Make phase
750
 
751
        #
227 dpurdie 752
        #   Build up the make command line
753
        #   Examine command specfic flags
754
        #
755
        my @args = @defs;
756
        push @args, "IFLAG=$commands{$cmd}{IFLAG}" if ( exists $commands{$cmd}{IFLAG} );
757
 
758
        my $cdir = CleanDirName ($dir);
759
        my @make_command;
5695 dpurdie 760
        push @make_command, "timeout", "-Time:$opt_max_make" if ($opt_max_make); 
227 dpurdie 761
        push @make_command, "$ENV{GBE_BIN}/xmake";
762
        push @make_command, "-s" if $opt_silent;
763
        push @make_command, "--no-print-directory";
764
        push @make_command, "-C", $cdir unless ( $cdir eq $::Cwd );
765
        push @make_command, "-f", "$target.mk";
766
        push @make_command, @args;
767
        push @make_command, 'make_dir' unless exists $commands{$cmd}{nomakecheck} ;
768
        push @make_command, $cmd;
769
 
770
        Message ( sprintf ("[$text] %-${tlen}s, $cmd, $cdir", $target ));
771
        System (@make_command, "DEBUG=$do_debug" );
772
    }
773
}
774
 
775
#-------------------------------------------------------------------------------
776
# Function        : TestMakeFiles
777
#
778
# Description     : Test all the makefile dependent files to see if any of the
779
#                   makefiles need to be rebuilt.
780
#
781
#                   Walk the directory tree looking for makefiles to be
782
#                   rebuilt.
783
#
784
# Inputs          : $cmd            - Current command
785
#                   $pref           - Ref to an array of platforms
786
#
787
# Returns         : 
788
#
789
sub TestMakeFiles
790
{
791
    my ( $cmd, $pref ) = @_;
792
    Verbose ("Test makefile dependencies");
793
 
794
    #
795
    #   Read in the Tag file for the current directory
796
    #   This will provide the current list of subdirectories
797
    #
798
    #   Process Test the current makefiles, then test any subdirs
799
    #
800
    TestSubMake( $cmd, $Cwd, $pref );
801
 
802
    #
803
    #   Report build errors
804
    #   Done after all makefiles have been processed
805
    #
806
    if ( $build_error )
807
    {
808
        Error ("Error creating makefiles. Errors previously reported");
809
    }
810
 
811
    #
812
    #   Post makefile build processing
813
    #   Only required if a files have been re-built
814
    #
815
    if ( $update )
816
    {
817
        #
818
        #   Sanity test the makefile structure
819
        #   Ensure that makefiles have only one parent.
820
        #
821
        TestParents();
822
 
823
        #
824
        #   Sanity test the installed and packaged files
825
        #   Generate warnings and errors if a file if packaged from two
826
        #   locations
827
        #
828
        TestPackages();
829
 
830
        #
831
        #   Generate DPACKAGE file if required
832
        #
833
        JatsDPackage::DPackageGenerate( $::ScmRoot, $::ScmInterface  );
834
    }
835
 
836
    #
837
    #
838
    #   Check that the build.pl file is not newer that the tags file
839
    #   This will not be an error, but it will be a nagging warning
840
    #
841
    my @build_warn;
842
    my $bstamp = -M "$::ScmRoot/$ScmBuildSrc";
843
    my $tstamp = -M "$::ScmRoot/Makefile.gbe";
844
 
845
    push @build_warn, "Missing: Makefile.gbe" unless ( defined $tstamp );
846
    push @build_warn, "Modified build file ($ScmBuildSrc)" if ( $tstamp && $bstamp < $tstamp );
847
    if ( @build_warn )
848
    {
849
        Warning ("The build file is newer than the generated files",
850
                 "The project needs to be built for these changes to be included",
851
                 @build_warn );
852
    }
853
}
854
 
855
#-------------------------------------------------------------------------------
856
# Function        : TestSubMake
857
#
858
# Description     : Test the makefiles in the current directory
859
#                   Recurse into subdirectories
860
#
861
# Inputs          : $cmd            - Current command
862
#                   $dir            - Directory to test
863
#                   $pref           - Ref to an array of platforms
864
#
865
# Returns         : 
866
#
867
sub TestSubMake
868
{
869
    my ($cmd, $dir, $pref ) = @_;
870
 
871
    $Tags = ReadMaketags( $dir, 1 );
872
    unless ( $Tags )
873
    {
874
        Verbose2 ("TestSubMake :Directory not in tag database", $dir );
875
        MakeBuild( $dir);
876
    }
877
    else
878
    {
879
        TestMake( $cmd, $dir, $pref );
880
    }
881
 
882
    #
883
    #   Recurse into any subdirectories that may be a part of the build
884
    #
885
    unless ( exists $defs{NORECURSE} && $defs{NORECURSE}  )
886
    {
887
        foreach my $subdir (@{$Tags->{$dir}{subdirs}} )
888
        {
889
            TestSubMake( $cmd, CleanDirName( "$dir/$subdir"), $pref );
890
        }
891
    }
892
}
893
 
894
#-------------------------------------------------------------------------------
281 dpurdie 895
# Function        : ShowMakefiles
896
#
897
# Description     : Show the makefiles used in the build
898
#
899
# Inputs          : $cmd            - Current command
900
#                   $pref           - Ref to an array of platforms
901
#
902
# Returns         : 
903
#
904
sub ShowMakefiles
905
{
906
    my ( $cmd, $pref ) = @_;
907
    Verbose ("Show makefiles");
363 dpurdie 908
    ShowTargetsAlaises();
281 dpurdie 909
 
910
    #
911
    #   Read in the Tag file for the current directory
912
    #   This will provide the current list of subdirectories
913
    #
914
    #   Process Test the current makefiles, then any subdirs
915
    #
916
    ShowSubMake( $cmd, $Cwd, $pref, 0 );
917
}
918
 
919
#-------------------------------------------------------------------------------
920
# Function        : ShowSubMake
921
#
922
# Description     : Test the makefiles in the current directory
923
#                   Recurse into subdirectories
924
#
925
# Inputs          : $cmd            - Current command
926
#                   $dir            - Directory to test
927
#                   $pref           - Ref to an array of platforms
928
#                   $level          - Recursion depth
929
#
930
# Returns         : 
931
#
932
sub ShowSubMake
933
{
934
    my ($cmd, $dir, $pref, $level ) = @_;
935
 
936
    $Tags = ReadMaketags( $dir, 1 );
937
    unless ( $Tags )
938
    {
939
        Verbose2 ("ShowSubMake :Directory not in tag database", $dir );
940
        MakeBuild( $dir);
941
    }
942
    elsif ( $level )
943
    {
944
        print ("Makefile : " . ' ' x (4 * ($level - 1) ) . DisplayPath(RelPath($dir)) ,"\n");
945
    } else {
946
        print ("\nBuildfile: ", DisplayPath($dir), "\n" );
947
    }
948
 
949
    #
950
    #   Recurse into any subdirectories that may be a part of the build
951
    #
952
    foreach my $subdir (@{$Tags->{$dir}{subdirs}} )
953
    {
954
        ShowSubMake( $cmd, CleanDirName( "$dir/$subdir"), $pref, $level + 1 );
955
    }
956
}
957
 
958
#-------------------------------------------------------------------------------
227 dpurdie 959
# Function        : TestMake
960
#
961
# Description     : Test the makefiles component files
962
#                   and determine if the makefile(s) need to be rebuilt
963
#
964
# Inputs          : $cmd            - Current command
965
#                   $dir            - Directory to test
966
#                   $pref           - Ref to an array of platforms
967
#
968
# Returns         : 
969
#
970
sub TestMake
971
{
972
    my ( $cmd, $dir, $pref ) = @_;
973
    my @must_rebuild;
974
 
975
    if ( $cmd eq 'rebuild' )
976
    {
977
        MakeBuild( $dir);
978
        return;
979
    }
980
 
981
    #
982
    #   Check that the local makefile.pl is not newer than
983
    #   the Tags file. Not all makefile.pl's create .mk files
984
    #
985
    my $mstamp = -M "$dir/makefile.pl";
986
    my $tstamp = -M "$dir/Makefile.gbe";
987
 
988
    unless ( defined $tstamp )
989
    {
990
        UniquePush (\@must_rebuild, "Missing: $dir/Makefile.gbe");
991
    }
992
 
993
    if ( $mstamp && $mstamp < $tstamp  )
994
    {
995
        UniquePush (\@must_rebuild, "Updated: $dir/makefile.pl");
996
    }
997
    else
998
    {
999
        if ( $Tags->{$dir}{root} )
1000
        {
1001
            Verbose2 "TestMake: Root directory has no makefiles: $dir";
1002
            return;
1003
        }
1004
 
1005
        if ( $Tags->{$dir}{noplatforms} )
1006
        {
1007
            Verbose2 "TestMake: No make targets in $dir";
1008
            return;
1009
        }
1010
 
1011
        #
1012
        #   Process only the required build targets
1013
        #
1014
        foreach my $tgt ( keys %{$Tags->{$dir}{platforms}}   )
1015
        {
285 dpurdie 1016
            next if ( %gbe_platform && ! exists $gbe_platform{$tgt} );
227 dpurdie 1017
            #
1018
            #   Locate all the makefile dependent files
1019
            #
1020
            my $data = $Tags->{$dir}{full}{$tgt}{'@ScmDepends'};
1021
            if ( $data )
1022
            {
1023
                Verbose2 ("Processing: $dir : $tgt");
1024
                my $base_stamp = -M "$dir/$tgt.mk";
1025
                unless ( defined $base_stamp )
1026
                {
1027
                    UniquePush (\@must_rebuild, "Missing: $dir/$tgt.mk");
1028
                }
1029
                else
1030
                {
1031
                    foreach my $file ( "$dir/makefile.pl" ,@$data )
1032
                    {
325 dpurdie 1033
                        $file = FullPath ( $file, $dir );
227 dpurdie 1034
                        my $stamp = -M $file;
1035
                        if ( defined $stamp )
1036
                        {
1037
                            Verbose3 ("Timestamp: $stamp, $file");
1038
                            if ( $stamp < $base_stamp  )
1039
                            {
1040
                                UniquePush (\@must_rebuild, $file);
1041
                            }
1042
                        }
1043
                        else
1044
                        {
1045
                            UniquePush (\@must_rebuild, "Missing: $file");
1046
                        }
1047
                    }
1048
                }
1049
            }
1050
            else
1051
            {
1052
                Warning ("No dependency information for: $tgt in $dir");
1053
            }
1054
        }
1055
    }
1056
 
1057
    if ( @must_rebuild )
1058
    {
1059
        my @display;
1060
        push (@display, CleanDirName($_) ) foreach ( @must_rebuild );
1061
        Message ("One or more JATS source or internal files have changed, Makefiles will be rebuilt",
1062
                  "Target is: $dir",
1063
                  @display );
1064
        MakeBuild ($dir);
1065
    }
1066
    return;
1067
}
1068
 
1069
#-------------------------------------------------------------------------------
1070
# Function        : MakeBuild
1071
#
1072
# Description     : Rebuild the makefiles in the specified directory
1073
#                   This does not involve recursion - thats already been
1074
#                   done.
1075
#
1076
#                   Once the makefiles have been re-built the tags database
1077
#                   must be read in again as it may have changed.
1078
#
1079
# Inputs          : 
1080
#
1081
# Returns         : 
1082
#
1083
sub MakeBuild
1084
{
1085
    my ($dir) = @_;
1086
 
1087
    #
1088
    #   No makefiles to build in the root directory
1089
    #   Can't rebuild the top-level Makefile.gbe file
1090
    #
1091
    return if ( $Tags->{$dir}{root} );
1092
 
1093
    #
1094
    #   Try to rebuild the makefile
1095
    #
1096
    chdir $dir || Error ("Cannot change directory to $dir");
261 dpurdie 1097
    my $result = System ('--NoExit', $ENV{GBE_PERL}, 'makefile.pl',
1098
                            $::ScmRoot, $makelib, "--interface=$::ScmInterface" );
227 dpurdie 1099
    chdir $::Cwd || Error ("Cannot change directory to $::Cwd");
1100
 
1101
    #
1102
    #   Re-read the tags database
1103
    #
1104
    $Tags = ReadMaketags( $dir, 2 );
1105
 
1106
    #
1107
    #   Flag that makefiles have been modified
1108
    #
1109
    $update = 1;
261 dpurdie 1110
    $build_error = 1 if ( $result );
227 dpurdie 1111
}
1112
 
1113
#-------------------------------------------------------------------------------
1114
# Function        : UnMakeFiles
1115
#
1116
# Description     : Delete generated makefiles and control files
1117
#
1118
# Inputs          : $cmd            - Current command
1119
#                   $pref           - Ref to an array of platforms
1120
#
1121
# Returns         : 
1122
#
1123
sub UnMakeFiles
1124
{
1125
    #
1126
    #   Recurse down the tree
1127
    #   Recurse, then performs operations in the current directory
1128
    #
1129
    sub UnSubMakeFiles
1130
    {
1131
        my ($dir) = @_;
1132
        $Tags = ReadMaketags( $dir, 1 );
1133
        foreach my $subdir (@{$Tags->{$dir}{subdirs}} )
1134
        {
1135
            UnSubMakeFiles( CleanDirName( "$dir/$subdir") );
1136
        }
1137
        UnMake( $dir );
1138
    }
1139
 
1140
    #
1141
    #   Delete makefiles in the current directory
1142
    #
1143
    sub UnMake
1144
    {
1145
        my ($dir) = @_;
1146
        Verbose("Unmake in $dir");
1147
        foreach my $tgt ( keys %{$Tags->{$dir}{platforms}}   )
1148
        {
1149
            Verbose2("Unmake. Delete ${tgt}.mk");
1150
            unlink ("$dir/${tgt}.mk");
1151
        }
1152
        unlink ("$dir/Makefile.gbe");
1153
        Verbose2("Unmake. Delete Makefile.gbe");
1154
    }
1155
 
1156
    #
1157
    #   Depth first recursion through the tree
1158
    #
1159
    UnSubMakeFiles ( $Cwd );
1160
}
1161
 
1162
#-------------------------------------------------------------------------------
1163
# Function        : TestParents
1164
#
1165
# Description     : Ensure that each makefile node has exactly one parent
1166
#                   Prevent the user from creating recursive loops
1167
#
1168
# Inputs          : 
1169
#
1170
# Returns         : 
1171
#
1172
my %parents;
1173
sub TestParents
1174
{
1175
    Verbose ("Test makefile parents");
1176
    #
1177
    #   Init the hash. Command may be invoked multiple times
1178
    #
1179
    %parents = ();
1180
 
1181
    #
1182
    #   Recurse down the tree
1183
    #   Recurse, then performs operations in the current directory
1184
    #
1185
    sub RecurseDown
1186
    {
1187
        my ($dir) = @_;
1188
        $Tags = ReadMaketags( $dir, 1 );
1189
        Verbose2("TestParents in $dir");
1190
        foreach my $subdir (@{$Tags->{$dir}{subdirs}} )
1191
        {
1192
            my $subdir = CleanDirName( "$dir/$subdir");
1193
            push @{$parents{$subdir}}, $dir;
1194
            RecurseDown( $subdir );
1195
        }
1196
    }
1197
 
1198
    #
1199
    #   Depth first recursion through the tree
1200
    #
1201
    RecurseDown ( $Cwd );
1202
 
1203
    #
1204
    #   Test for only one parent
1205
    #   The root makefile won't have any
1206
    #
1207
    foreach my $dir ( sort keys %{$Tags} )
1208
    {
1209
        my $count = $#{$parents{$dir}};
1210
        if ( $count > 0 )
1211
        {
1212
            if ( defined($GBE_ABT) )
1213
            {
1214
                Warning ("Error supressed by ABT");
1215
                Warning ("makefile.pl with multiple parents",
1216
                         "makefile.pl in: $dir",
1217
                         "Parented by:", @{$parents{$dir}} );
1218
            }
1219
            else
1220
            {
1221
                unlink $Tags->{$dir}{config};
1222
                Error ("makefile.pl with multiple parents",
1223
                       "makefile.pl in: $dir",
1224
                       "Parented by:", @{$parents{$dir}} );
1225
            }
1226
        }
1227
    }
1228
}
1229
 
1230
#-------------------------------------------------------------------------------
1231
# Function        : TestPackages
1232
#
1233
# Description     : Ensure that files that are packaged and installed are
1234
#                   only done from one makefile. Warn if the same file
1235
#                   is being packaged from multiple makefiles.
1236
#
1237
# Inputs          : 
1238
#
1239
# Returns         : 
1240
#
1241
my %test_packages;
1242
sub TestPackages
1243
{
1244
    Verbose ("Test packaged files");
1245
    #
1246
    #   Init the hash. Command may be invoked multiple times
1247
    #
1248
    %test_packages = ();
1249
 
1250
    #
1251
    #   Recurse down the tree
1252
    #   Recurse, then performs operations in the current directory
1253
    #
1254
    sub TRecurseDown
1255
    {
1256
        my ($dir) = @_;
1257
        Verbose2("TestPackages in $dir");
1258
        $Tags = ReadMaketags( $dir, 1 );
1259
        #
1260
        #   Process makefile
1261
        #   Examine all the %PACKAGE_xxx and %INSTALL_xxx fields thare listed
1262
        #   in the @PACKAGE_VARS and @INSTALL_VARS array
1263
        #
1264
        foreach my $target ( keys %{$Tags->{$dir}{platforms}}   )
1265
        {
285 dpurdie 1266
            next if ( %gbe_platform && ! exists $gbe_platform{$target} );
227 dpurdie 1267
            foreach my $field ( @{$Tags->{$dir}{full}{$target}{'@PACKAGE_VARS'}},
1268
                                @{$Tags->{$dir}{full}{$target}{'@INSTALL_VARS'}} )
1269
            {
1270
                foreach my $entry ( keys %{$Tags->{$dir}{full}{$target}{$field}} )
1271
                {
1272
                    Verbose3("TestPackages: $target, File: $entry");
1273
                    push @{$test_packages{$target}{$entry}}, $dir;
1274
                }
1275
            }
1276
        }
1277
 
1278
        #
1279
        #   Process subdirectories too
1280
        #
1281
        foreach my $subdir (@{$Tags->{$dir}{subdirs}} )
1282
        {
1283
            TRecurseDown( CleanDirName( "$dir/$subdir") );
1284
        }
1285
    }
1286
 
1287
 
1288
 
1289
    #
1290
    #   Depth first recursion through the tree
1291
    #
1292
    TRecurseDown ( $Cwd );
1293
 
1294
    #
1295
    #   Test and report files that are packaged in different makefiles
1296
    #   There are two issues:
1297
    #       1) Not good practice
1298
    #       2) May be different files
1299
    #   The warning message is a bit ugly - but it shouldn't pop up often.
1300
    #
1301
#    DebugDumpData ("test_packages", \%test_packages);
1302
 
1303
    foreach my $target ( sort keys %test_packages )
1304
    {
1305
        foreach my $file ( sort keys %{$test_packages{$target}} )
1306
        {
1307
            #
1308
            #   The descpkg file is known to be packaged from multiple dirs
1309
            #
1310
            next if ( $file =~ m~/descpkg~ );
1311
            if ( $#{$test_packages{$target}{$file}} > 0 )
1312
            {
1313
                Warning ("File is packaged or installed from multiple makefiles",
1314
                         "Target: $target, Packaged file: $file",
1315
                         "Packaged from the following directories:", @{$test_packages{$target}{$file}} );
1316
            }
1317
        }
1318
    }
1319
}
1320
 
1321
 
1322
#-------------------------------------------------------------------------------
1323
# Function        : DoHelp
1324
#
1325
# Description     : Display basic help information
1326
#
1327
# Inputs          : None
1328
#
1329
# Returns         :
1330
#
1331
sub DoHelp
1332
{
1333
 
1334
#
1335
#   Display basic usage information
1336
#
1337
    pod2usage(-verbose => 0,
1338
              -message => "Version: $VERSION",
1339
              -exitval => 'NOEXIT');
1340
 
363 dpurdie 1341
    ShowTargetsAlaises();
1342
}
1343
 
1344
#-------------------------------------------------------------------------------
1345
# Function        : ShowTargetsAlaises
1346
#
1347
# Description     : Display make targets and aliases
1348
#                   Used by 'show' and 'help'
1349
#
1350
# Inputs          : None
1351
#
1352
# Returns         : Nothing
1353
#                   Output via 'print'
1354
#
1355
sub ShowTargetsAlaises
1356
{
1357
    my @targets = sort keys %BUILDINFO;
1358
    my @alias = sort keys %ScmBuildAliases;
1359
 
1360
    #
1361
    #   Determine the max length of target or alias
1362
    #   Used to make pretty display
1363
    #
1364
    my $flen = 6;
1365
    foreach ( @alias, @targets )
227 dpurdie 1366
    {
363 dpurdie 1367
        my $len = length $_;
1368
        $flen = $len if ( $len > $flen );
1369
    }
1370
 
1371
    print "\nActive Platform targets\n";
1372
    foreach (@targets)
1373
    {
227 dpurdie 1374
        print "    $_\n";
1375
    }
1376
 
1377
    if ( $#alias >=0 )
1378
    {
363 dpurdie 1379
        print "\nAlias targets\n";
1380
 
1381
        #   Display aliases
1382
        #   Indent list by 4 spaces
1383
        #
227 dpurdie 1384
        foreach ( @alias )
1385
        {
363 dpurdie 1386
            print PrintList("    $_",4+$flen, split(' ', $ScmBuildAliases{$_}));
227 dpurdie 1387
        }
1388
    }
1389
}
1390
 
1391
#-------------------------------------------------------------------------------
363 dpurdie 1392
# Function        : PrintList
1393
#
6276 dpurdie 1394
# Description     : Pretty format an array to fit within 100 char line
363 dpurdie 1395
#                   Perform wrapping as required
1396
#
1397
# Inputs          : $title          - Title string
1398
#                   $len            - Desired length of title area
1399
#                   @list           - An array of items to print
1400
#
1401
# Returns         : string
1402
#
1403
sub PrintList
1404
{
1405
    my ($title, $llen, @list) = @_;
1406
    my $string = sprintf ("%-${llen}s :", $title);
1407
 
1408
    my $nlen = length($string);
1409
    my $nl = "\n" . (' ' x  $nlen );
1410
    $llen = $nlen;
1411
 
1412
    for my $k (sort @list)
1413
    {
1414
        my $klen = length($k);
6276 dpurdie 1415
        if ($llen + $klen >= 100 )
363 dpurdie 1416
        {
1417
            $string .= $nl;
1418
            $llen = $nlen;
1419
        }
1420
        $string .= ' ' .  $k;
1421
        $llen += $klen + 1;
1422
    }
1423
    return $string . "\n";
1424
}
1425
 
1426
#-------------------------------------------------------------------------------
227 dpurdie 1427
# Function        : ReadMaketags
1428
#
1429
# Description     : Read in the global make tags data base
1430
#                   This contains information on all the components within
1431
#                   the build. The tags allow recursive makes to be pruned.
1432
#
1433
#                   The file may change while the build is running
1434
#                   It can be read multiple times
1435
#
1436
# Inputs          : $dir            - Directory entry to read
321 dpurdie 1437
#                   $test           - 0: Read. Error if not available (default)
1438
#                                     1: Read if available
227 dpurdie 1439
#                                     2: Force read
1440
#
1441
# Returns         : Reference to the tag data for the requested directory
1442
#                   Will error if no available
1443
#
1444
our %cf_minfo;
1445
our %cf_minfo2;
1446
my %tag_data;
1447
sub ReadMaketags
1448
{
1449
    my ($dir, $test) = @_;
321 dpurdie 1450
    $test ||= 0;
227 dpurdie 1451
 
1452
    #
1453
    #   Force data re-aquisition
1454
    #
1455
    delete $tag_data{$dir}
321 dpurdie 1456
        if ( $test == 2 );
227 dpurdie 1457
 
1458
    #
1459
    #   Do we already have the entry
1460
    #
1461
    return \%tag_data
1462
        if ( exists ($tag_data{$dir} ));
1463
 
1464
    #
1465
    #   If the entry is not known, then re-read the index file
1466
    #
321 dpurdie 1467
#DebugDumpData ("ReadMaketags", \%::cf_filelist);
227 dpurdie 1468
    unless ( $::cf_filelist{$dir} )
1469
    {
1470
        my $index_file = "$::ScmRoot/$::ScmInterface/Makefile.cfg";
1471
        Error ("Makefile index missing. Rebuild required") unless ( -f $index_file );
1472
 
1473
        #
1474
        #   Kill the entry in %INC to force the file to be read in
1475
        #
1476
        $::cf_filelist = ();
1477
        delete $INC{ $index_file };
1478
        require $index_file;
1479
    }
1480
 
1481
    my $cfg_filen = $::cf_filelist{$dir};
1482
    unless ( $cfg_filen )
1483
    {
285 dpurdie 1484
        return if ( $test );
227 dpurdie 1485
        Error ("Makefile index entry missing: $dir. Rebuild required");
1486
    }
1487
 
1488
 
1489
    #
1490
    #   Read in all the Makefile_x.cfg files
1491
    #
1492
    %cf_minfo = ();
1493
    %cf_minfo2 = ();
1494
    my $cfg_file = "$::ScmRoot/$::ScmInterface/$cfg_filen";
1495
 
1496
    unless ( -f $cfg_file )
1497
    {
285 dpurdie 1498
        return if ( $test );
227 dpurdie 1499
        Error ("Make data file missing: $cfg_file. Rebuild required");
1500
    }
1501
 
1502
    delete $INC{ $cfg_file };
1503
    require $cfg_file;
1504
 
1505
    Error ("Makefile info2 not present")
1506
        unless ( keys %::cf_info2 );
1507
 
1508
    Error ("Makefile info2 incorrect version. Rebuild required")
285 dpurdie 1509
        unless ( exists $::cf_info2{version} && $::cf_info2{version} == 1 );
227 dpurdie 1510
 
1511
    %{$tag_data{$dir}} = %::cf_info2;
1512
    $tag_data{$dir}{config} = $cfg_file;
1513
    %{$tag_data{$dir}{full}} = %::cf_info;
1514
 
1515
#DebugDumpData ("ReadMaketags", $tag_data{$dir});
1516
    return \%tag_data;
1517
 
1518
}
1519
 
1520
#-------------------------------------------------------------------------------
1521
# Function        : ExpandComposite
1522
#
1523
# Description     : Expand a command via composite command expansion
1524
#                   A composite command may contain other composite commands
261 dpurdie 1525
#                   Detect, as an error, recursive expansions
227 dpurdie 1526
#
1527
# Inputs          : $cmd    - command to expand
1528
#
1529
# Returns         : An array of commands
1530
#
1531
sub ExpandComposite
1532
{
285 dpurdie 1533
    my @scmds = $_[0];
227 dpurdie 1534
    my @cmds;
261 dpurdie 1535
    my %seen;
227 dpurdie 1536
    while ( @scmds )
1537
    {
1538
        my $cmd = shift @scmds;
1539
        if ( exists $composite_commands{$cmd} )
1540
        {
261 dpurdie 1541
 
1542
            Error ("Internal. Recursion in composite command definitions: $cmd")
1543
                if ($seen{$cmd});
1544
 
227 dpurdie 1545
            @scmds = (@{$composite_commands{$cmd}}, @scmds);
261 dpurdie 1546
            $seen{$cmd} = 1;
227 dpurdie 1547
        }
1548
        else
1549
        {
1550
            push @cmds, $cmd;
1551
        }
1552
    }
1553
 
1554
    return @cmds;
1555
}
1556
 
1557
#-------------------------------------------------------------------------------
1558
#   Documentation
1559
#
1560
 
1561
=pod
1562
 
361 dpurdie 1563
=for htmltoc    JATS::make
1564
 
227 dpurdie 1565
=head1 NAME
1566
 
1567
jmake - JATS make support tool
1568
 
1569
=head1 SYNOPSIS
1570
 
1571
 Usage: jats make [options][targets][flags]
1572
 
1573
 Where options:
1574
    -h, -h -h, -man     - Help messages with increasing verbosity
1575
    -verbose            - Verbose operation
1576
    -debug              - Debug operation
1577
    -default=target     - Default 'target' if none is supplied
5695 dpurdie 1578
    -maxTime=duration   - Maximum allowed duration of any make command
367 dpurdie 1579
    -- make options     - [Advanced] Options passed directly to make
227 dpurdie 1580
 
1581
 Where flags are of the form Name=Value
1582
    SHOWENV=1           - Show make environment
1583
    LEAVETMP=1          - Leave temp working files
1584
    NODEPEND=1          - Ignore dependency checking
261 dpurdie 1585
    EXPERT=1            - Ignore dependency on makefiles
4782 dpurdie 1586
    UTF_POSTPROCESS=1   - Enable Unit Test Post Processing
227 dpurdie 1587
    OPTIONS=[opt]       - Maketime options [args,allargs,filter...]
1588
 
1589
 Valid targets include:
1590
    all                 - build and install everything(p*)
1591
    build               - build everything (pu)
1592
    debug               - build all things for debug (pu)
1593
    prod                - build all things for production (pu)
1594
    install             - install public components (pu*)
5073 dpurdie 1595
    ctags               - Generate ctags over the source (assumes debug)(p)
227 dpurdie 1596
    lint                - lints the source (assumes debug)(p)
1597
    package             - build all packages (pu*)
361 dpurdie 1598
    package-[set]       - build specific package (see below) (pu*)
227 dpurdie 1599
    run_tests           - Run the tests specified in the makefile
1600
    run_unit_tests      - Run the automatic unit tests specified in the makefile
1601
    deploy              - Run the deployment scripts (p*)
1602
    rebuild             - recursively rebuild makefiles
367 dpurdie 1603
    makefiles           - recursively rebuild makefiles, if needed (u)
227 dpurdie 1604
    depend              - construct the dependencies (u*)
1605
    rmlitter            - remove build litter (core, tmp and err) (*)
1606
    clean               - delete generate, obj, libraries and programs (p*)
1607
    clobber             - delete everything which can be remade (p*)
281 dpurdie 1608
    help                - A list of platforms and aliases
1609
    show                - A list of platforms, alias, and makefile paths
5073 dpurdie 1610
 Partial Builds
1611
    hdrs                - build to the headers phase (p*)
1612
    libs                - build to the static library stage (p*)
1613
    slibs               - build to the shared librray stage (p*)
1614
    progs               - build to the progs stage (p*)
227 dpurdie 1615
 
1616
      (u) undo target available (ie uninstall)
1617
      (p) optional [platform_] prefix targets (ie XXX_build)
1618
      (*) optional [_debug|_prod] postfix targets (ie clean_debug)
1619
 
1620
=head1 OPTIONS
1621
 
1622
=over 8
1623
 
1624
=item B<-help>
1625
 
1626
Print a brief help message and exits.
1627
 
1628
=item B<-help -help>
1629
 
1630
Print a detailed help message with an explanation for each option.
1631
 
1632
=item B<-man>
1633
 
1634
Prints the manual page and exits.
1635
 
1636
=item B<-verbose>
1637
 
1638
Increase the level of verbosity of the program execution
1639
 
1640
=item B<-debug>
1641
 
1642
Increase the debug output during program execution
1643
 
1644
=item B<-default=target>
1645
 
1646
This options specifies the default target if none is provided on the command
1647
line. Used by the jats wrapper to simplify processing.
1648
 
5695 dpurdie 1649
=item B<-maxTime=duration>
1650
 
1651
This option specifies the maximum allowed duration of any make sub command.
1652
 
1653
Some commands are composed of several subcommands, as are the production and 
1654
debug variants. The time lime is imposed on a sub commands and not the total
1655
collection of commands. The intent of the time limit is to prevent stalled builds 
1656
from hijacking the build process.
1657
 
5859 dpurdie 1658
The default value will be taken from the EnvVar L<GBE_MAXMAKE>, if present, or 4 hours
5695 dpurdie 1659
if the EnvVar is not present. A value of 0 (zero) will disable this feature.
1660
 
1661
The duration is specified as a positive floating point number with an optional
1662
modifing character. Valid modifiers are:
1663
 
1664
=over 4
1665
 
1666
=item   
1667
 
1668
B<s> - Seconds (default)
1669
 
1670
=item   
1671
 
1672
B<m> - Minutes
1673
 
1674
=item   
1675
 
1676
B<h> - hours
1677
 
1678
=item   
1679
 
1680
B<d> - Days
1681
 
1682
=back
1683
 
1684
Example: C<-MaxTime=5.h>. Will set a Maximum make time of 30 minutes.
1685
 
335 dpurdie 1686
=item B<-- Make Options>
1687
 
1688
Command line arguments that follow a '--' are passed directly to the GNU make
1689
program. This may be useful for advanced debugging of makefiles. These options
1690
include:
1691
 
1692
=over 8
1693
 
361 dpurdie 1694
=item
335 dpurdie 1695
 
361 dpurdie 1696
B<-h>     - Display Make's own help
335 dpurdie 1697
 
361 dpurdie 1698
=item
335 dpurdie 1699
 
361 dpurdie 1700
B<-d>     - Display diagnostic information
335 dpurdie 1701
 
361 dpurdie 1702
=item
1703
 
1704
B<-p>     - Print make's internal database.
1705
 
1706
=item
1707
 
1708
B<-k>     - Keep going when some targets can't be made.
1709
 
227 dpurdie 1710
=back
1711
 
335 dpurdie 1712
=back
1713
 
261 dpurdie 1714
=head1 TARGETS
227 dpurdie 1715
 
261 dpurdie 1716
Targets are described above.
1717
 
1718
Most targets support three modifiers. These can be used in conjunction with each
1719
other.
1720
 
227 dpurdie 1721
=over 8
1722
 
261 dpurdie 1723
=item undo
1724
 
1725
Many target operation can be undone by prefixing the tarhet with 'un' ie:
1726
uninstall.
1727
 
1728
=item platform prefix
1729
 
1730
Many target operations can be limited to one platform by prefixing the target
1731
with a valid platform name and an underscore. ie WIN32_all
1732
 
1733
=item build postfix. prod or debug
1734
 
1735
Many targets operations can be limited toi either production of debug by
1736
adding '_prod' or '_debug' to the target. ie 'install_debug'
1737
 
1738
=back
1739
 
5073 dpurdie 1740
=head1 PARTIAL BUILDS
1741
 
1742
Partial build targets allow the build process to be partialy completed. This may be of use during development.
1743
 
1744
The partial build phases are:
1745
 
1746
=over 4
1747
 
1748
=item hdrs
1749
 
1750
Generate header files. Install header files locally.
1751
 
1752
=item libs
1753
 
1754
Previous step plus build static libraries, merge static librarys and install static libraries locally.
1755
 
1756
=item slib
1757
 
1758
Previous step plus build shared libraries and install shared libraries.
1759
 
1760
=item progs
1761
 
1762
Previous step plus build programs and install programs (including test programs). This step is the same as 'build'.
1763
 
1764
=back
1765
 
261 dpurdie 1766
=head1 FLAGS
1767
 
227 dpurdie 1768
Flags are in the form TAG=value. This is a format that it used as they will be
1769
passed directly to the underlying makefiles. The recognised flags are:
1770
 
261 dpurdie 1771
=over 8
1772
 
227 dpurdie 1773
=item B<SHOWENV=1>
1774
 
1775
This flag will force the 'Environment' to be displayed before commands are executed
1776
 
1777
=item B<LEAVETMP=1>
1778
 
1779
This flag will cause temp files, created by the build process, to notr be deleted.
1780
 
1781
=item B<NODEPEND=1>
1782
 
1783
This flag will supress dependency checking. Makefiles will not be created when
1784
the makefile.pl is changed. Source files will not be scanned for header files.
1785
 
261 dpurdie 1786
=item B<EXPERT=1>
1787
 
1788
This flag will supress dependency checking between object files and the
1789
generated makefile. This option can be used while test building a large build
1790
when the makefile has been rebuilt but the user does not wish all the object
1791
files to be rebuilt.
1792
 
4782 dpurdie 1793
=item B<UTF_POSTPROCESS=1>
1794
 
1795
This flag will enable post processing of test results.
1796
 
1797
Post processing allows the details of the test results to be captured by the build system.
1798
 
1799
Post processing is normally only performed within the automated build environment. This flag 
1800
will force the processing within a user development environment.
1801
 
1802
UTF_POSTPROCESS=1   - Enable Unit Test Post Processing
1803
 
227 dpurdie 1804
=item B<OPTIONS=list,list>
1805
 
1806
This flags passes a list of comma seperated options into the makefile. The exact
1807
set of available options is target specific. Refer to the JATS manual.
1808
 
361 dpurdie 1809
=back
227 dpurdie 1810
 
361 dpurdie 1811
=head1 EXAMPLES
1812
 
1813
=over 4
1814
 
1815
=item jats all
1816
 
1817
This command will perform a B<jats build> if the build.pl file has been modified
1818
since the last build. It will then C<make> all the build targets.
1819
 
1820
=item jats make all
1821
 
1822
Same as C<jats all>
1823
 
1824
=item jats make debug
1825
 
1826
This command will create the B<debug> version of the make
1827
components in the current directory - and referenced sub components.
1828
 
1829
=item jats make debug NODEPEND=1
1830
 
1831
Same as C<jats make debug> but the dependency generation phase will be
1832
skipped. In a large build this will speed up the build, but there is an implicit
1833
assumption that file changes do not result in more header or library files being
1834
required. It will use the results of the previous C<make depend> phase.
1835
 
1836
=item jats make clean
1837
 
1838
This command will remove all object files, libraries, programs and any other
1839
build artifacts created by the B<make> process.
1840
 
1841
=item jats make clobber
1842
 
1843
Similar to C<jats make clean> but it will also delete build artifacts from the
1844
packaging directory.
1845
 
227 dpurdie 1846
=back
361 dpurdie 1847
 
1848
=cut
1849