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