Subversion Repositories DevTools

Rev

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

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