Subversion Repositories DevTools

Rev

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

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