Subversion Repositories DevTools

Rev

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