Subversion Repositories DevTools

Rev

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