Subversion Repositories DevTools

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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