Subversion Repositories DevTools

Rev

Rev 4700 | 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
74
#   A hash of known commands an information about the commands
75
#       common      - Command is not executed for Debug and Production
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'] ,
4700 alewis 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
    #
4700 alewis 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},
4725 dpurdie 161
    'preprocess_tests'      => { 'nomakecheck' => 1, 'tag' => 'process_tests'},
162
    'postprocess_tests'     => { 'nomakecheck' => 1, 'tag' => 'process_tests'},
163
    'collate_test_results'  => { 'nomakecheck' => 1, 'tag' => 'process_tests'},
4700 alewis 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
 
550
    if ( $commands{$cmd}{'common'} )
551
    {
552
        InvokeSubMake( $::Cwd, $platform_ref ,$cmd, $tag, 1 );
553
    }
554
    else
555
    {
556
        InvokeSubMake( $::Cwd, $platform_ref ,$cmd, $tag, 1 ) if $do_debug;
557
        InvokeSubMake( $::Cwd, $platform_ref ,$cmd, $tag, 0 ) if $do_prod;
558
    }
559
}
560
 
561
#-------------------------------------------------------------------------------
562
# Function        : InvokeSubMake
563
#
564
# Description     : Build recursion
565
#                   Determine if there is anything to be done for the current
566
#                   target within a specified directory
567
#
568
# Inputs          : $dir
569
#                   $pref                   - Ref to an array of platforms
570
#                   $cmd
571
#                   $tag
572
#                   $do_prod
573
#
574
# Returns         : 
575
#
576
sub InvokeSubMake
577
{
578
    my ( $dir, $pref, $cmd, $tag, $do_debug) = @_;
579
 
580
    #
581
    #   Ensure the current directory is known to the Tags database
582
    #
583
    $Tags = ReadMaketags( $dir );
584
    Error ("Directory not in tag database", $dir ) unless ( $Tags );
585
 
586
    #
587
    #   Process commands in the current directory
588
    #   If the command is tagged, then we may be able to skip it
589
    #   Otherwise we need to do it
590
    #
591
    InvokeMake( $dir, $pref, $cmd, $tag, $do_debug );
592
 
593
    #
594
    #   Recurse into any subdirectories that may be a part of the build
595
    #
596
    unless ( exists $defs{NORECURSE} && $defs{NORECURSE}  )
597
    {
598
        #
599
        #   Process subdirectories for the current command
600
        #   If the command is tagged, then we may be able to skip it
601
        #   Otherwise we need to do it
602
        #
603
        foreach my $subdir (@{$Tags->{$dir}{subdirs}} )
604
        {
605
 
606
            InvokeSubMake( CleanDirName( "$dir/$subdir"), $pref, $cmd, $tag, $do_debug );
607
        }
608
    }
609
}
610
 
611
#-------------------------------------------------------------------------------
612
# Function        : InvokeMake
613
#
614
# Description     : Actually invoke the make for debug and production as required
615
#
616
# Inputs          : $dir
617
#                   $pref
618
#                   $cmd
619
#                   $tag
620
#                   $do_debug
621
#
622
#
623
# Returns         : 
624
#
625
sub InvokeMake
626
{
627
    my ( $dir, $pref, $cmd, $tag, $do_debug ) = @_;
628
    my $text = 'C';
629
 
279 dpurdie 630
    Verbose2 ("InvokeMake: $dir");
227 dpurdie 631
    #
632
    #   Ensure that the current directory actually has makefile targets
633
    #   Not all makefile.pl create .mk files
634
    #       1) Top-level makefile.pl
635
    #       2) Makefiles that use --NoPlatformBuilds
636
    #
637
    if ( $Tags->{$dir}{root} )
638
    {
639
        Verbose2 "Root directory has no makefiles: $dir";
640
        return;
641
    }
642
 
643
    if ( $Tags->{$dir}{noplatforms} )
644
    {
645
        Verbose2 "No make targets in $dir";
646
        return;
647
    }
648
 
649
    #
650
    #   Process each platform
651
    #
652
    foreach my $target ( @{$pref} )
653
    {
654
        unless ( exists $Tags->{$dir}{platforms}{$target} )
655
        {
656
            Verbose2 "No make targets in $dir, for $target";
657
            next;
658
        }
659
 
660
        #
661
        #   Do we need to do any thing for this target / tag
662
        #
663
        if ( $tag )
664
        {
665
            unless ( exists $Tags->{$dir}{full}{$target}{'%MakeTags'}{$tag} )
666
            {
261 dpurdie 667
                Verbose2 ("Skipping $cmd in $dir for $tag");
227 dpurdie 668
                next;
669
            }
670
        }
671
 
672
        #
673
        #   common mode == 2
674
        #   Only process target ONCE for each platform
675
        #   Don't care when its used
676
        #
261 dpurdie 677
        if ( exists $commands{$cmd}{'common'} && $commands{$cmd}{'common'} & 2 )
227 dpurdie 678
        {
679
            if ( $common_cmd{$cmd}{$target} )
680
            {
681
                Verbose2 "Already performed $cmd for $target";
682
                next;
683
            }
684
            $common_cmd{$cmd}{$target} = 1;
685
        }
686
 
687
        #
688
        #   Is the build limited to only debug or production
689
        #
261 dpurdie 690
        unless ( exists $commands{$cmd}{'common'} )
227 dpurdie 691
        {
692
            if ( $do_debug == 0 ) {
693
                next unless ( $Tags->{$dir}{platforms}{$target}{prod} );
694
                $text = 'P';
695
 
696
            } elsif  ( $do_debug == 1 ) {
697
                next unless ( $Tags->{$dir}{platforms}{$target}{debug} );
698
                $text = 'D';
699
            }
700
        }
701
 
702
        #
703
        #   Final sanity test
704
        #   Must have the makefile. We should have detected this error before now
705
        #
706
        Error ("Makefile not found - $target") unless ( -f "$dir/$target.mk" );
707
 
708
        #
275 dpurdie 709
        #   Export data into the user environment
710
        #   Allows underlying tools to locate data files with little effort
711
        #
712
        $ENV{'GBE_MAKE_TYPE'} = $text;                  # P or D or C
713
        $ENV{'GBE_MAKE_TARGET'} = $target;              # Target platform
714
        $ENV{'GBE_MAKE_CFG'} = $Tags->{$dir}{config};   # Ref to config data
715
        $ENV{'GBE_MAKE_CMD'} = $cmd;                    # Make phase
716
 
717
        #
227 dpurdie 718
        #   Build up the make command line
719
        #   Examine command specfic flags
720
        #
721
        my @args = @defs;
722
        push @args, "IFLAG=$commands{$cmd}{IFLAG}" if ( exists $commands{$cmd}{IFLAG} );
723
 
724
        my $cdir = CleanDirName ($dir);
725
        my @make_command;
726
        push @make_command, "$ENV{GBE_BIN}/xmake";
727
        push @make_command, "-s" if $opt_silent;
728
        push @make_command, "--no-print-directory";
729
        push @make_command, "-C", $cdir unless ( $cdir eq $::Cwd );
730
        push @make_command, "-f", "$target.mk";
731
        push @make_command, @args;
732
        push @make_command, 'make_dir' unless exists $commands{$cmd}{nomakecheck} ;
733
        push @make_command, $cmd;
734
 
735
        Message ( sprintf ("[$text] %-${tlen}s, $cmd, $cdir", $target ));
736
        System (@make_command, "DEBUG=$do_debug" );
737
    }
738
}
739
 
740
#-------------------------------------------------------------------------------
741
# Function        : TestMakeFiles
742
#
743
# Description     : Test all the makefile dependent files to see if any of the
744
#                   makefiles need to be rebuilt.
745
#
746
#                   Walk the directory tree looking for makefiles to be
747
#                   rebuilt.
748
#
749
# Inputs          : $cmd            - Current command
750
#                   $pref           - Ref to an array of platforms
751
#
752
# Returns         : 
753
#
754
sub TestMakeFiles
755
{
756
    my ( $cmd, $pref ) = @_;
757
    Verbose ("Test makefile dependencies");
758
 
759
    #
760
    #   Read in the Tag file for the current directory
761
    #   This will provide the current list of subdirectories
762
    #
763
    #   Process Test the current makefiles, then test any subdirs
764
    #
765
    TestSubMake( $cmd, $Cwd, $pref );
766
 
767
    #
768
    #   Report build errors
769
    #   Done after all makefiles have been processed
770
    #
771
    if ( $build_error )
772
    {
773
        Error ("Error creating makefiles. Errors previously reported");
774
    }
775
 
776
    #
777
    #   Post makefile build processing
778
    #   Only required if a files have been re-built
779
    #
780
    if ( $update )
781
    {
782
        #
783
        #   Sanity test the makefile structure
784
        #   Ensure that makefiles have only one parent.
785
        #
786
        TestParents();
787
 
788
        #
789
        #   Sanity test the installed and packaged files
790
        #   Generate warnings and errors if a file if packaged from two
791
        #   locations
792
        #
793
        TestPackages();
794
 
795
        #
796
        #   Generate DPACKAGE file if required
797
        #
798
        JatsDPackage::DPackageGenerate( $::ScmRoot, $::ScmInterface  );
799
    }
800
 
801
    #
802
    #
803
    #   Check that the build.pl file is not newer that the tags file
804
    #   This will not be an error, but it will be a nagging warning
805
    #
806
    my @build_warn;
807
    my $bstamp = -M "$::ScmRoot/$ScmBuildSrc";
808
    my $tstamp = -M "$::ScmRoot/Makefile.gbe";
809
 
810
    push @build_warn, "Missing: Makefile.gbe" unless ( defined $tstamp );
811
    push @build_warn, "Modified build file ($ScmBuildSrc)" if ( $tstamp && $bstamp < $tstamp );
812
    if ( @build_warn )
813
    {
814
        Warning ("The build file is newer than the generated files",
815
                 "The project needs to be built for these changes to be included",
816
                 @build_warn );
817
    }
818
}
819
 
820
#-------------------------------------------------------------------------------
821
# Function        : TestSubMake
822
#
823
# Description     : Test the makefiles in the current directory
824
#                   Recurse into subdirectories
825
#
826
# Inputs          : $cmd            - Current command
827
#                   $dir            - Directory to test
828
#                   $pref           - Ref to an array of platforms
829
#
830
# Returns         : 
831
#
832
sub TestSubMake
833
{
834
    my ($cmd, $dir, $pref ) = @_;
835
 
836
    $Tags = ReadMaketags( $dir, 1 );
837
    unless ( $Tags )
838
    {
839
        Verbose2 ("TestSubMake :Directory not in tag database", $dir );
840
        MakeBuild( $dir);
841
    }
842
    else
843
    {
844
        TestMake( $cmd, $dir, $pref );
845
    }
846
 
847
    #
848
    #   Recurse into any subdirectories that may be a part of the build
849
    #
850
    unless ( exists $defs{NORECURSE} && $defs{NORECURSE}  )
851
    {
852
        foreach my $subdir (@{$Tags->{$dir}{subdirs}} )
853
        {
854
            TestSubMake( $cmd, CleanDirName( "$dir/$subdir"), $pref );
855
        }
856
    }
857
}
858
 
859
#-------------------------------------------------------------------------------
281 dpurdie 860
# Function        : ShowMakefiles
861
#
862
# Description     : Show the makefiles used in the build
863
#
864
# Inputs          : $cmd            - Current command
865
#                   $pref           - Ref to an array of platforms
866
#
867
# Returns         : 
868
#
869
sub ShowMakefiles
870
{
871
    my ( $cmd, $pref ) = @_;
872
    Verbose ("Show makefiles");
363 dpurdie 873
    ShowTargetsAlaises();
281 dpurdie 874
 
875
    #
876
    #   Read in the Tag file for the current directory
877
    #   This will provide the current list of subdirectories
878
    #
879
    #   Process Test the current makefiles, then any subdirs
880
    #
881
    ShowSubMake( $cmd, $Cwd, $pref, 0 );
882
}
883
 
884
#-------------------------------------------------------------------------------
885
# Function        : ShowSubMake
886
#
887
# Description     : Test the makefiles in the current directory
888
#                   Recurse into subdirectories
889
#
890
# Inputs          : $cmd            - Current command
891
#                   $dir            - Directory to test
892
#                   $pref           - Ref to an array of platforms
893
#                   $level          - Recursion depth
894
#
895
# Returns         : 
896
#
897
sub ShowSubMake
898
{
899
    my ($cmd, $dir, $pref, $level ) = @_;
900
 
901
    $Tags = ReadMaketags( $dir, 1 );
902
    unless ( $Tags )
903
    {
904
        Verbose2 ("ShowSubMake :Directory not in tag database", $dir );
905
        MakeBuild( $dir);
906
    }
907
    elsif ( $level )
908
    {
909
        print ("Makefile : " . ' ' x (4 * ($level - 1) ) . DisplayPath(RelPath($dir)) ,"\n");
910
    } else {
911
        print ("\nBuildfile: ", DisplayPath($dir), "\n" );
912
    }
913
 
914
    #
915
    #   Recurse into any subdirectories that may be a part of the build
916
    #
917
    foreach my $subdir (@{$Tags->{$dir}{subdirs}} )
918
    {
919
        ShowSubMake( $cmd, CleanDirName( "$dir/$subdir"), $pref, $level + 1 );
920
    }
921
}
922
 
923
#-------------------------------------------------------------------------------
227 dpurdie 924
# Function        : TestMake
925
#
926
# Description     : Test the makefiles component files
927
#                   and determine if the makefile(s) need to be rebuilt
928
#
929
# Inputs          : $cmd            - Current command
930
#                   $dir            - Directory to test
931
#                   $pref           - Ref to an array of platforms
932
#
933
# Returns         : 
934
#
935
sub TestMake
936
{
937
    my ( $cmd, $dir, $pref ) = @_;
938
    my @must_rebuild;
939
 
940
    if ( $cmd eq 'rebuild' )
941
    {
942
        MakeBuild( $dir);
943
        return;
944
    }
945
 
946
    #
947
    #   Check that the local makefile.pl is not newer than
948
    #   the Tags file. Not all makefile.pl's create .mk files
949
    #
950
    my $mstamp = -M "$dir/makefile.pl";
951
    my $tstamp = -M "$dir/Makefile.gbe";
952
 
953
    unless ( defined $tstamp )
954
    {
955
        UniquePush (\@must_rebuild, "Missing: $dir/Makefile.gbe");
956
    }
957
 
958
    if ( $mstamp && $mstamp < $tstamp  )
959
    {
960
        UniquePush (\@must_rebuild, "Updated: $dir/makefile.pl");
961
    }
962
    else
963
    {
964
        if ( $Tags->{$dir}{root} )
965
        {
966
            Verbose2 "TestMake: Root directory has no makefiles: $dir";
967
            return;
968
        }
969
 
970
        if ( $Tags->{$dir}{noplatforms} )
971
        {
972
            Verbose2 "TestMake: No make targets in $dir";
973
            return;
974
        }
975
 
976
        #
977
        #   Process only the required build targets
978
        #
979
        foreach my $tgt ( keys %{$Tags->{$dir}{platforms}}   )
980
        {
285 dpurdie 981
            next if ( %gbe_platform && ! exists $gbe_platform{$tgt} );
227 dpurdie 982
            #
983
            #   Locate all the makefile dependent files
984
            #
985
            my $data = $Tags->{$dir}{full}{$tgt}{'@ScmDepends'};
986
            if ( $data )
987
            {
988
                Verbose2 ("Processing: $dir : $tgt");
989
                my $base_stamp = -M "$dir/$tgt.mk";
990
                unless ( defined $base_stamp )
991
                {
992
                    UniquePush (\@must_rebuild, "Missing: $dir/$tgt.mk");
993
                }
994
                else
995
                {
996
                    foreach my $file ( "$dir/makefile.pl" ,@$data )
997
                    {
325 dpurdie 998
                        $file = FullPath ( $file, $dir );
227 dpurdie 999
                        my $stamp = -M $file;
1000
                        if ( defined $stamp )
1001
                        {
1002
                            Verbose3 ("Timestamp: $stamp, $file");
1003
                            if ( $stamp < $base_stamp  )
1004
                            {
1005
                                UniquePush (\@must_rebuild, $file);
1006
                            }
1007
                        }
1008
                        else
1009
                        {
1010
                            UniquePush (\@must_rebuild, "Missing: $file");
1011
                        }
1012
                    }
1013
                }
1014
            }
1015
            else
1016
            {
1017
                Warning ("No dependency information for: $tgt in $dir");
1018
            }
1019
        }
1020
    }
1021
 
1022
    if ( @must_rebuild )
1023
    {
1024
        my @display;
1025
        push (@display, CleanDirName($_) ) foreach ( @must_rebuild );
1026
        Message ("One or more JATS source or internal files have changed, Makefiles will be rebuilt",
1027
                  "Target is: $dir",
1028
                  @display );
1029
        MakeBuild ($dir);
1030
    }
1031
    return;
1032
}
1033
 
1034
#-------------------------------------------------------------------------------
1035
# Function        : MakeBuild
1036
#
1037
# Description     : Rebuild the makefiles in the specified directory
1038
#                   This does not involve recursion - thats already been
1039
#                   done.
1040
#
1041
#                   Once the makefiles have been re-built the tags database
1042
#                   must be read in again as it may have changed.
1043
#
1044
# Inputs          : 
1045
#
1046
# Returns         : 
1047
#
1048
sub MakeBuild
1049
{
1050
    my ($dir) = @_;
1051
 
1052
    #
1053
    #   No makefiles to build in the root directory
1054
    #   Can't rebuild the top-level Makefile.gbe file
1055
    #
1056
    return if ( $Tags->{$dir}{root} );
1057
 
1058
    #
1059
    #   Try to rebuild the makefile
1060
    #
1061
    chdir $dir || Error ("Cannot change directory to $dir");
261 dpurdie 1062
    my $result = System ('--NoExit', $ENV{GBE_PERL}, 'makefile.pl',
1063
                            $::ScmRoot, $makelib, "--interface=$::ScmInterface" );
227 dpurdie 1064
    chdir $::Cwd || Error ("Cannot change directory to $::Cwd");
1065
 
1066
    #
1067
    #   Re-read the tags database
1068
    #
1069
    $Tags = ReadMaketags( $dir, 2 );
1070
 
1071
    #
1072
    #   Flag that makefiles have been modified
1073
    #
1074
    $update = 1;
261 dpurdie 1075
    $build_error = 1 if ( $result );
227 dpurdie 1076
}
1077
 
1078
#-------------------------------------------------------------------------------
1079
# Function        : UnMakeFiles
1080
#
1081
# Description     : Delete generated makefiles and control files
1082
#
1083
# Inputs          : $cmd            - Current command
1084
#                   $pref           - Ref to an array of platforms
1085
#
1086
# Returns         : 
1087
#
1088
sub UnMakeFiles
1089
{
1090
    #
1091
    #   Recurse down the tree
1092
    #   Recurse, then performs operations in the current directory
1093
    #
1094
    sub UnSubMakeFiles
1095
    {
1096
        my ($dir) = @_;
1097
        $Tags = ReadMaketags( $dir, 1 );
1098
        foreach my $subdir (@{$Tags->{$dir}{subdirs}} )
1099
        {
1100
            UnSubMakeFiles( CleanDirName( "$dir/$subdir") );
1101
        }
1102
        UnMake( $dir );
1103
    }
1104
 
1105
    #
1106
    #   Delete makefiles in the current directory
1107
    #
1108
    sub UnMake
1109
    {
1110
        my ($dir) = @_;
1111
        Verbose("Unmake in $dir");
1112
        foreach my $tgt ( keys %{$Tags->{$dir}{platforms}}   )
1113
        {
1114
            Verbose2("Unmake. Delete ${tgt}.mk");
1115
            unlink ("$dir/${tgt}.mk");
1116
        }
1117
        unlink ("$dir/Makefile.gbe");
1118
        Verbose2("Unmake. Delete Makefile.gbe");
1119
    }
1120
 
1121
    #
1122
    #   Depth first recursion through the tree
1123
    #
1124
    UnSubMakeFiles ( $Cwd );
1125
}
1126
 
1127
#-------------------------------------------------------------------------------
1128
# Function        : TestParents
1129
#
1130
# Description     : Ensure that each makefile node has exactly one parent
1131
#                   Prevent the user from creating recursive loops
1132
#
1133
# Inputs          : 
1134
#
1135
# Returns         : 
1136
#
1137
my %parents;
1138
sub TestParents
1139
{
1140
    Verbose ("Test makefile parents");
1141
    #
1142
    #   Init the hash. Command may be invoked multiple times
1143
    #
1144
    %parents = ();
1145
 
1146
    #
1147
    #   Recurse down the tree
1148
    #   Recurse, then performs operations in the current directory
1149
    #
1150
    sub RecurseDown
1151
    {
1152
        my ($dir) = @_;
1153
        $Tags = ReadMaketags( $dir, 1 );
1154
        Verbose2("TestParents in $dir");
1155
        foreach my $subdir (@{$Tags->{$dir}{subdirs}} )
1156
        {
1157
            my $subdir = CleanDirName( "$dir/$subdir");
1158
            push @{$parents{$subdir}}, $dir;
1159
            RecurseDown( $subdir );
1160
        }
1161
    }
1162
 
1163
    #
1164
    #   Depth first recursion through the tree
1165
    #
1166
    RecurseDown ( $Cwd );
1167
 
1168
    #
1169
    #   Test for only one parent
1170
    #   The root makefile won't have any
1171
    #
1172
    foreach my $dir ( sort keys %{$Tags} )
1173
    {
1174
        my $count = $#{$parents{$dir}};
1175
        if ( $count > 0 )
1176
        {
1177
            if ( defined($GBE_ABT) )
1178
            {
1179
                Warning ("Error supressed by ABT");
1180
                Warning ("makefile.pl with multiple parents",
1181
                         "makefile.pl in: $dir",
1182
                         "Parented by:", @{$parents{$dir}} );
1183
            }
1184
            else
1185
            {
1186
                unlink $Tags->{$dir}{config};
1187
                Error ("makefile.pl with multiple parents",
1188
                       "makefile.pl in: $dir",
1189
                       "Parented by:", @{$parents{$dir}} );
1190
            }
1191
        }
1192
    }
1193
}
1194
 
1195
#-------------------------------------------------------------------------------
1196
# Function        : TestPackages
1197
#
1198
# Description     : Ensure that files that are packaged and installed are
1199
#                   only done from one makefile. Warn if the same file
1200
#                   is being packaged from multiple makefiles.
1201
#
1202
# Inputs          : 
1203
#
1204
# Returns         : 
1205
#
1206
my %test_packages;
1207
sub TestPackages
1208
{
1209
    Verbose ("Test packaged files");
1210
    #
1211
    #   Init the hash. Command may be invoked multiple times
1212
    #
1213
    %test_packages = ();
1214
 
1215
    #
1216
    #   Recurse down the tree
1217
    #   Recurse, then performs operations in the current directory
1218
    #
1219
    sub TRecurseDown
1220
    {
1221
        my ($dir) = @_;
1222
        Verbose2("TestPackages in $dir");
1223
        $Tags = ReadMaketags( $dir, 1 );
1224
        #
1225
        #   Process makefile
1226
        #   Examine all the %PACKAGE_xxx and %INSTALL_xxx fields thare listed
1227
        #   in the @PACKAGE_VARS and @INSTALL_VARS array
1228
        #
1229
        foreach my $target ( keys %{$Tags->{$dir}{platforms}}   )
1230
        {
285 dpurdie 1231
            next if ( %gbe_platform && ! exists $gbe_platform{$target} );
227 dpurdie 1232
            foreach my $field ( @{$Tags->{$dir}{full}{$target}{'@PACKAGE_VARS'}},
1233
                                @{$Tags->{$dir}{full}{$target}{'@INSTALL_VARS'}} )
1234
            {
1235
                foreach my $entry ( keys %{$Tags->{$dir}{full}{$target}{$field}} )
1236
                {
1237
                    Verbose3("TestPackages: $target, File: $entry");
1238
                    push @{$test_packages{$target}{$entry}}, $dir;
1239
                }
1240
            }
1241
        }
1242
 
1243
        #
1244
        #   Process subdirectories too
1245
        #
1246
        foreach my $subdir (@{$Tags->{$dir}{subdirs}} )
1247
        {
1248
            TRecurseDown( CleanDirName( "$dir/$subdir") );
1249
        }
1250
    }
1251
 
1252
 
1253
 
1254
    #
1255
    #   Depth first recursion through the tree
1256
    #
1257
    TRecurseDown ( $Cwd );
1258
 
1259
    #
1260
    #   Test and report files that are packaged in different makefiles
1261
    #   There are two issues:
1262
    #       1) Not good practice
1263
    #       2) May be different files
1264
    #   The warning message is a bit ugly - but it shouldn't pop up often.
1265
    #
1266
#    DebugDumpData ("test_packages", \%test_packages);
1267
 
1268
    foreach my $target ( sort keys %test_packages )
1269
    {
1270
        foreach my $file ( sort keys %{$test_packages{$target}} )
1271
        {
1272
            #
1273
            #   The descpkg file is known to be packaged from multiple dirs
1274
            #
1275
            next if ( $file =~ m~/descpkg~ );
1276
            if ( $#{$test_packages{$target}{$file}} > 0 )
1277
            {
1278
                Warning ("File is packaged or installed from multiple makefiles",
1279
                         "Target: $target, Packaged file: $file",
1280
                         "Packaged from the following directories:", @{$test_packages{$target}{$file}} );
1281
            }
1282
        }
1283
    }
1284
}
1285
 
1286
 
1287
#-------------------------------------------------------------------------------
1288
# Function        : DoHelp
1289
#
1290
# Description     : Display basic help information
1291
#
1292
# Inputs          : None
1293
#
1294
# Returns         :
1295
#
1296
sub DoHelp
1297
{
1298
 
1299
#
1300
#   Display basic usage information
1301
#
1302
    pod2usage(-verbose => 0,
1303
              -message => "Version: $VERSION",
1304
              -exitval => 'NOEXIT');
1305
 
363 dpurdie 1306
    ShowTargetsAlaises();
1307
}
1308
 
1309
#-------------------------------------------------------------------------------
1310
# Function        : ShowTargetsAlaises
1311
#
1312
# Description     : Display make targets and aliases
1313
#                   Used by 'show' and 'help'
1314
#
1315
# Inputs          : None
1316
#
1317
# Returns         : Nothing
1318
#                   Output via 'print'
1319
#
1320
sub ShowTargetsAlaises
1321
{
1322
    my @targets = sort keys %BUILDINFO;
1323
    my @alias = sort keys %ScmBuildAliases;
1324
 
1325
    #
1326
    #   Determine the max length of target or alias
1327
    #   Used to make pretty display
1328
    #
1329
    my $flen = 6;
1330
    foreach ( @alias, @targets )
227 dpurdie 1331
    {
363 dpurdie 1332
        my $len = length $_;
1333
        $flen = $len if ( $len > $flen );
1334
    }
1335
 
1336
    print "\nActive Platform targets\n";
1337
    foreach (@targets)
1338
    {
227 dpurdie 1339
        print "    $_\n";
1340
    }
1341
 
1342
    if ( $#alias >=0 )
1343
    {
363 dpurdie 1344
        print "\nAlias targets\n";
1345
 
1346
        #   Display aliases
1347
        #   Indent list by 4 spaces
1348
        #
227 dpurdie 1349
        foreach ( @alias )
1350
        {
363 dpurdie 1351
            print PrintList("    $_",4+$flen, split(' ', $ScmBuildAliases{$_}));
227 dpurdie 1352
        }
1353
    }
1354
}
1355
 
1356
#-------------------------------------------------------------------------------
363 dpurdie 1357
# Function        : PrintList
1358
#
1359
# Description     : Pretty format an array to fit within 80 char line
1360
#                   Perform wrapping as required
1361
#
1362
# Inputs          : $title          - Title string
1363
#                   $len            - Desired length of title area
1364
#                   @list           - An array of items to print
1365
#
1366
# Returns         : string
1367
#
1368
sub PrintList
1369
{
1370
    my ($title, $llen, @list) = @_;
1371
    my $string = sprintf ("%-${llen}s :", $title);
1372
 
1373
    my $nlen = length($string);
1374
    my $nl = "\n" . (' ' x  $nlen );
1375
    $llen = $nlen;
1376
 
1377
    for my $k (sort @list)
1378
    {
1379
        my $klen = length($k);
1380
        if ($llen + $klen > 78 )
1381
        {
1382
            $string .= $nl;
1383
            $llen = $nlen;
1384
        }
1385
        $string .= ' ' .  $k;
1386
        $llen += $klen + 1;
1387
    }
1388
    return $string . "\n";
1389
}
1390
 
1391
#-------------------------------------------------------------------------------
227 dpurdie 1392
# Function        : ReadMaketags
1393
#
1394
# Description     : Read in the global make tags data base
1395
#                   This contains information on all the components within
1396
#                   the build. The tags allow recursive makes to be pruned.
1397
#
1398
#                   The file may change while the build is running
1399
#                   It can be read multiple times
1400
#
1401
# Inputs          : $dir            - Directory entry to read
321 dpurdie 1402
#                   $test           - 0: Read. Error if not available (default)
1403
#                                     1: Read if available
227 dpurdie 1404
#                                     2: Force read
1405
#
1406
# Returns         : Reference to the tag data for the requested directory
1407
#                   Will error if no available
1408
#
1409
our %cf_minfo;
1410
our %cf_minfo2;
1411
my %tag_data;
1412
sub ReadMaketags
1413
{
1414
    my ($dir, $test) = @_;
321 dpurdie 1415
    $test ||= 0;
227 dpurdie 1416
 
1417
    #
1418
    #   Force data re-aquisition
1419
    #
1420
    delete $tag_data{$dir}
321 dpurdie 1421
        if ( $test == 2 );
227 dpurdie 1422
 
1423
    #
1424
    #   Do we already have the entry
1425
    #
1426
    return \%tag_data
1427
        if ( exists ($tag_data{$dir} ));
1428
 
1429
    #
1430
    #   If the entry is not known, then re-read the index file
1431
    #
321 dpurdie 1432
#DebugDumpData ("ReadMaketags", \%::cf_filelist);
227 dpurdie 1433
    unless ( $::cf_filelist{$dir} )
1434
    {
1435
        my $index_file = "$::ScmRoot/$::ScmInterface/Makefile.cfg";
1436
        Error ("Makefile index missing. Rebuild required") unless ( -f $index_file );
1437
 
1438
        #
1439
        #   Kill the entry in %INC to force the file to be read in
1440
        #
1441
        $::cf_filelist = ();
1442
        delete $INC{ $index_file };
1443
        require $index_file;
1444
    }
1445
 
1446
    my $cfg_filen = $::cf_filelist{$dir};
1447
    unless ( $cfg_filen )
1448
    {
285 dpurdie 1449
        return if ( $test );
227 dpurdie 1450
        Error ("Makefile index entry missing: $dir. Rebuild required");
1451
    }
1452
 
1453
 
1454
    #
1455
    #   Read in all the Makefile_x.cfg files
1456
    #
1457
    %cf_minfo = ();
1458
    %cf_minfo2 = ();
1459
    my $cfg_file = "$::ScmRoot/$::ScmInterface/$cfg_filen";
1460
 
1461
    unless ( -f $cfg_file )
1462
    {
285 dpurdie 1463
        return if ( $test );
227 dpurdie 1464
        Error ("Make data file missing: $cfg_file. Rebuild required");
1465
    }
1466
 
1467
    delete $INC{ $cfg_file };
1468
    require $cfg_file;
1469
 
1470
    Error ("Makefile info2 not present")
1471
        unless ( keys %::cf_info2 );
1472
 
1473
    Error ("Makefile info2 incorrect version. Rebuild required")
285 dpurdie 1474
        unless ( exists $::cf_info2{version} && $::cf_info2{version} == 1 );
227 dpurdie 1475
 
1476
    %{$tag_data{$dir}} = %::cf_info2;
1477
    $tag_data{$dir}{config} = $cfg_file;
1478
    %{$tag_data{$dir}{full}} = %::cf_info;
1479
 
1480
#DebugDumpData ("ReadMaketags", $tag_data{$dir});
1481
    return \%tag_data;
1482
 
1483
}
1484
 
1485
#-------------------------------------------------------------------------------
1486
# Function        : ExpandComposite
1487
#
1488
# Description     : Expand a command via composite command expansion
1489
#                   A composite command may contain other composite commands
261 dpurdie 1490
#                   Detect, as an error, recursive expansions
227 dpurdie 1491
#
1492
# Inputs          : $cmd    - command to expand
1493
#
1494
# Returns         : An array of commands
1495
#
1496
sub ExpandComposite
1497
{
285 dpurdie 1498
    my @scmds = $_[0];
227 dpurdie 1499
    my @cmds;
261 dpurdie 1500
    my %seen;
227 dpurdie 1501
    while ( @scmds )
1502
    {
1503
        my $cmd = shift @scmds;
1504
        if ( exists $composite_commands{$cmd} )
1505
        {
261 dpurdie 1506
 
1507
            Error ("Internal. Recursion in composite command definitions: $cmd")
1508
                if ($seen{$cmd});
1509
 
227 dpurdie 1510
            @scmds = (@{$composite_commands{$cmd}}, @scmds);
261 dpurdie 1511
            $seen{$cmd} = 1;
227 dpurdie 1512
        }
1513
        else
1514
        {
1515
            push @cmds, $cmd;
1516
        }
1517
    }
1518
 
1519
    return @cmds;
1520
}
1521
 
1522
 
1523
#-------------------------------------------------------------------------------
1524
#   Documentation
1525
#
1526
 
1527
=pod
1528
 
361 dpurdie 1529
=for htmltoc    JATS::make
1530
 
227 dpurdie 1531
=head1 NAME
1532
 
1533
jmake - JATS make support tool
1534
 
1535
=head1 SYNOPSIS
1536
 
1537
 Usage: jats make [options][targets][flags]
1538
 
1539
 Where options:
1540
    -h, -h -h, -man     - Help messages with increasing verbosity
1541
    -verbose            - Verbose operation
1542
    -debug              - Debug operation
1543
    -default=target     - Default 'target' if none is supplied
367 dpurdie 1544
    -- make options     - [Advanced] Options passed directly to make
227 dpurdie 1545
 
1546
 Where flags are of the form Name=Value
1547
    SHOWENV=1           - Show make environment
1548
    LEAVETMP=1          - Leave temp working files
1549
    NODEPEND=1          - Ignore dependency checking
261 dpurdie 1550
    EXPERT=1            - Ignore dependency on makefiles
227 dpurdie 1551
    OPTIONS=[opt]       - Maketime options [args,allargs,filter...]
1552
 
1553
 Valid targets include:
1554
    all                 - build and install everything(p*)
1555
    build               - build everything (pu)
1556
    debug               - build all things for debug (pu)
1557
    prod                - build all things for production (pu)
1558
    install             - install public components (pu*)
1559
    lint                - lints the source (assumes debug)(p)
1560
    package             - build all packages (pu*)
361 dpurdie 1561
    package-[set]       - build specific package (see below) (pu*)
227 dpurdie 1562
    run_tests           - Run the tests specified in the makefile
1563
    run_unit_tests      - Run the automatic unit tests specified in the makefile
1564
    deploy              - Run the deployment scripts (p*)
1565
    rebuild             - recursively rebuild makefiles
367 dpurdie 1566
    makefiles           - recursively rebuild makefiles, if needed (u)
227 dpurdie 1567
    depend              - construct the dependencies (u*)
1568
    rmlitter            - remove build litter (core, tmp and err) (*)
1569
    clean               - delete generate, obj, libraries and programs (p*)
1570
    clobber             - delete everything which can be remade (p*)
281 dpurdie 1571
    help                - A list of platforms and aliases
1572
    show                - A list of platforms, alias, and makefile paths
227 dpurdie 1573
 
1574
      (u) undo target available (ie uninstall)
1575
      (p) optional [platform_] prefix targets (ie XXX_build)
1576
      (*) optional [_debug|_prod] postfix targets (ie clean_debug)
1577
 
1578
=head1 OPTIONS
1579
 
1580
=over 8
1581
 
1582
=item B<-help>
1583
 
1584
Print a brief help message and exits.
1585
 
1586
=item B<-help -help>
1587
 
1588
Print a detailed help message with an explanation for each option.
1589
 
1590
=item B<-man>
1591
 
1592
Prints the manual page and exits.
1593
 
1594
=item B<-verbose>
1595
 
1596
Increase the level of verbosity of the program execution
1597
 
1598
=item B<-debug>
1599
 
1600
Increase the debug output during program execution
1601
 
1602
=item B<-default=target>
1603
 
1604
This options specifies the default target if none is provided on the command
1605
line. Used by the jats wrapper to simplify processing.
1606
 
335 dpurdie 1607
=item B<-- Make Options>
1608
 
1609
Command line arguments that follow a '--' are passed directly to the GNU make
1610
program. This may be useful for advanced debugging of makefiles. These options
1611
include:
1612
 
1613
=over 8
1614
 
361 dpurdie 1615
=item
335 dpurdie 1616
 
361 dpurdie 1617
B<-h>     - Display Make's own help
335 dpurdie 1618
 
361 dpurdie 1619
=item
335 dpurdie 1620
 
361 dpurdie 1621
B<-d>     - Display diagnostic information
335 dpurdie 1622
 
361 dpurdie 1623
=item
1624
 
1625
B<-p>     - Print make's internal database.
1626
 
1627
=item
1628
 
1629
B<-k>     - Keep going when some targets can't be made.
1630
 
227 dpurdie 1631
=back
1632
 
335 dpurdie 1633
=back
1634
 
261 dpurdie 1635
=head1 TARGETS
227 dpurdie 1636
 
261 dpurdie 1637
Targets are described above.
1638
 
1639
Most targets support three modifiers. These can be used in conjunction with each
1640
other.
1641
 
227 dpurdie 1642
=over 8
1643
 
261 dpurdie 1644
=item undo
1645
 
1646
Many target operation can be undone by prefixing the tarhet with 'un' ie:
1647
uninstall.
1648
 
1649
=item platform prefix
1650
 
1651
Many target operations can be limited to one platform by prefixing the target
1652
with a valid platform name and an underscore. ie WIN32_all
1653
 
1654
=item build postfix. prod or debug
1655
 
1656
Many targets operations can be limited toi either production of debug by
1657
adding '_prod' or '_debug' to the target. ie 'install_debug'
1658
 
1659
=back
1660
 
1661
=head1 FLAGS
1662
 
227 dpurdie 1663
Flags are in the form TAG=value. This is a format that it used as they will be
1664
passed directly to the underlying makefiles. The recognised flags are:
1665
 
261 dpurdie 1666
=over 8
1667
 
227 dpurdie 1668
=item B<SHOWENV=1>
1669
 
1670
This flag will force the 'Environment' to be displayed before commands are executed
1671
 
1672
=item B<LEAVETMP=1>
1673
 
1674
This flag will cause temp files, created by the build process, to notr be deleted.
1675
 
1676
=item B<NODEPEND=1>
1677
 
1678
This flag will supress dependency checking. Makefiles will not be created when
1679
the makefile.pl is changed. Source files will not be scanned for header files.
1680
 
261 dpurdie 1681
=item B<EXPERT=1>
1682
 
1683
This flag will supress dependency checking between object files and the
1684
generated makefile. This option can be used while test building a large build
1685
when the makefile has been rebuilt but the user does not wish all the object
1686
files to be rebuilt.
1687
 
227 dpurdie 1688
=item B<OPTIONS=list,list>
1689
 
1690
This flags passes a list of comma seperated options into the makefile. The exact
1691
set of available options is target specific. Refer to the JATS manual.
1692
 
361 dpurdie 1693
=back
227 dpurdie 1694
 
361 dpurdie 1695
=head1 EXAMPLES
1696
 
1697
=over 4
1698
 
1699
=item jats all
1700
 
1701
This command will perform a B<jats build> if the build.pl file has been modified
1702
since the last build. It will then C<make> all the build targets.
1703
 
1704
=item jats make all
1705
 
1706
Same as C<jats all>
1707
 
1708
=item jats make debug
1709
 
1710
This command will create the B<debug> version of the make
1711
components in the current directory - and referenced sub components.
1712
 
1713
=item jats make debug NODEPEND=1
1714
 
1715
Same as C<jats make debug> but the dependency generation phase will be
1716
skipped. In a large build this will speed up the build, but there is an implicit
1717
assumption that file changes do not result in more header or library files being
1718
required. It will use the results of the previous C<make depend> phase.
1719
 
1720
=item jats make clean
1721
 
1722
This command will remove all object files, libraries, programs and any other
1723
build artifacts created by the B<make> process.
1724
 
1725
=item jats make clobber
1726
 
1727
Similar to C<jats make clean> but it will also delete build artifacts from the
1728
packaging directory.
1729
 
227 dpurdie 1730
=back
361 dpurdie 1731
 
1732
=cut
1733