Subversion Repositories DevTools

Rev

Rev 5708 | Rev 5986 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
#! perl
2
########################################################################
5710 dpurdie 3
# Copyright (c) VIX TECHNOLOGY (AUST) LTD
227 dpurdie 4
#
5
# Module name   : jats.sh
6
# Module type   : Perl Package
7
# Compiler(s)   : n/a
8
# Environment(s): jats
9
#
10
# Description   : This package contains functions to create a makefile entry
11
#                 The entry may consist of the following (optional) fields
12
#
13
#                 .PHONY <targets>
14
#                 <targets> : VARAIBLE = VALUE
15
#                 <targets> : <prerequisites>
16
#                       @echo "Run time comment"
17
#                       Recipe
18
#                       ( ShellRecipe )
19
#
20
#                 The order that information is added is not important
21
#                 Recipes and prerequisites may be mixed to simplify
22
#                 programming.
23
#
4344 dpurdie 24
#                 The --Define option creates
25
#                 define <name>
26
#                   Recipe
27
#                 endef
28
#
29
#                The --Raw option creates
30
#                   Recipe
31
#
4778 dpurdie 32
#                The --Raw with --Phony option creates
33
#                   .PHONY <targets>
34
#                   <targets>:
35
#                       Recipe
4344 dpurdie 36
#
4778 dpurdie 37
#
38
#
227 dpurdie 39
#......................................................................#
40
 
255 dpurdie 41
use 5.006_001;
227 dpurdie 42
use strict;
43
use warnings;
44
 
45
package MakeEntry;
46
use JatsError;
47
use ArrayHashUtils;
48
 
49
#
50
#   Global variables
51
#
52
my $llength = 80;                           # Target line length
53
 
54
 
55
#-------------------------------------------------------------------------------
56
# Function        : New
57
#
58
# Description     : Create a new empty entry
59
#
271 dpurdie 60
# Inputs          : handle              - FILEHANDLE or variable ref
61
#                                         eg: *MAKEFILE     - print to handle
62
#                                              \$var        - print to variable
63
#
64
#                   name                - Primary target name
65
#                   options             - Preload the fields
227 dpurdie 66
#                           --Target=name,name,name
67
#                           --Comment=text
68
#                           --Prereq=name,name,name
69
#                           --Recipe=text
70
#                           --Phony
4344 dpurdie 71
#                           --Define
72
#                           --Raw
227 dpurdie 73
#                           --Print
74
#
75
# Returns         : Ref to a an object that can be manipulated
76
#
77
sub New
78
{
79
    my ($handle, $name, @args ) = @_;
80
    my $self  = {};
81
    $self->{DEPENDANCY}     = [];
82
    $self->{NAME}           = [];
83
    $self->{RECIPE}         = [];
84
    $self->{SHELL}          = [];
85
    $self->{PRINTED}        = 0;
86
    $self->{COMMENT}        = [];
87
    $self->{DEFN}           = {};
88
    $self->{PHONY}          = 0;
4344 dpurdie 89
    $self->{DEFINE}         = 0;
90
    $self->{RAW}            = 0;
227 dpurdie 91
    $self->{FH}             = $handle;
271 dpurdie 92
    $self->{FH_inmemory}    = 0;
227 dpurdie 93
    $self->{RECIPE_PREFIX}  = '';
5708 dpurdie 94
    $self->{RECIPE_WRAPPER}  = ['(', ')'];
227 dpurdie 95
    $self->{RECIPE_COMMENT} = '';
4778 dpurdie 96
    $self->{STACK}          = [];
4781 dpurdie 97
    $self->{SDEF}           = '';
227 dpurdie 98
 
99
    push @{$self->{NAME}}, split(/,/,$name) if ( $name );
100
 
101
    bless ($self, __PACKAGE__);
102
 
103
    #
104
    #   Process any argument
105
    #
106
    my $print = 0;
107
    foreach ( @args )
108
    {
109
        if ( m/^--Target=(.*)/ ) {
110
            $self->AddName(split(/,/,$1));
111
 
112
        } elsif ( m/^--Comment=(.*)/ ) {
113
            $self->AddComment($1);
114
 
115
        } elsif ( m/^--Prereq=(.*)/ ) {
116
            $self->AddDependancy(split(/,/,$1));
117
 
118
        } elsif ( m/^--Phony/ ) {
119
            $self->Phony();
120
 
4344 dpurdie 121
        } elsif ( m/^--Define/ ) {
122
            $self->Define();
123
 
124
        } elsif ( m/^--Raw/ ) {
125
            $self->Raw();
126
 
227 dpurdie 127
        } elsif ( m/^--Recipe=(.*)/ ) {
128
            $self->AddRecipe($1);
129
 
130
        } elsif ( m/^--Print/ ) {
131
            $print = 1;
132
 
133
        } elsif ( m/^--/ ) {
134
            Error ("MakeEntry: Unknown option: $_");
135
 
136
        } else {
137
            $self->AddDependancy( $_ );
138
 
139
        }
140
    }
141
 
271 dpurdie 142
    #
143
    #   Set up the printer handle
144
    #   May be
145
    #       Empty           - use stderr
146
    #       ref to a scalar - use in memory file
147
    #       typeglob        - normal handle
148
    #
149
    if ( ref $handle eq 'SCALAR' )
150
    {
151
        $$handle = '' if ( ! defined $$handle );
152
        open(MEMORY,'>>', $handle) || Error ("Cannot open in-memory file");
153
        $self->{FH_inmemory} = $handle;
154
        $self->{FH} = \*MEMORY;
155
 
156
    } elsif ( ! $handle ) {
157
       $self->{FH} = \*STDERR;
158
    }
159
 
160
    #
161
    #   Print simple entry if required
162
    #
227 dpurdie 163
    $self->Print() if ( $print );
164
    return $self;
165
}
166
 
167
#-------------------------------------------------------------------------------
168
# Function        : AddName
169
#
4778 dpurdie 170
# Description     : Add a target name to the entry
227 dpurdie 171
#
172
# Inputs          : An array of names to add
173
#
174
# Returns         :
175
#
176
sub AddName
177
{
178
    my $self = shift;
179
    push @{$self->{NAME}}, @_
180
}
181
 
182
#-------------------------------------------------------------------------------
183
# Function        : Phony
184
#
185
# Description     : Flag the entry as a phony
186
#
187
# Inputs          :
188
#
189
# Returns         :
190
#
191
sub Phony
192
{
193
    my $self = shift;
194
    $self->{PHONY} = 1;
195
}
196
 
4344 dpurdie 197
#-------------------------------------------------------------------------------
198
# Function        : Define
199
#
200
# Description     : Flag the entry as a define, rather than a normal target
201
#                   Many of the other commands are not supported
202
#                   Only AddComment and AddRecipe
203
#
204
# Inputs          :
205
#
206
# Returns         :
207
#
208
sub Define
209
{
210
    my $self = shift;
211
    $self->{DEFINE} = 1;
212
}
227 dpurdie 213
 
214
#-------------------------------------------------------------------------------
4344 dpurdie 215
# Function        : Raw
216
#
217
# Description     : Flag the entry as raw text
218
#                   Many of the other commands are not supported
219
#                   Only AddComment and AddRecipe
220
#
221
# Inputs          :
222
#
223
# Returns         :
224
#
225
sub Raw
226
{
227
    my $self = shift;
228
    $self->{RAW} = 1;
229
}
230
 
231
#-------------------------------------------------------------------------------
227 dpurdie 232
# Function        : AddComment
233
#
234
# Description     : Add a comment to the entry
235
#
236
# Inputs          : An array of names to add
237
#
238
# Returns         :
239
#
240
sub AddComment
241
{
242
    my $self = shift;
243
    push @{$self->{COMMENT}}, @_
244
}
245
 
246
#-------------------------------------------------------------------------------
247
# Function        : AddDependancy
248
#
249
# Description     : Add a dependancy to the entry
250
#
251
# Inputs          : An array of dependacies to add
252
#
253
# Returns         :
254
#
255
sub AddDependancy
256
{
257
    my $self = shift;
258
    UniquePush $self->{DEPENDANCY}, @_ ;
259
}
260
 
261
#-------------------------------------------------------------------------------
262
# Function        : AddDefn
263
#
264
# Description     : Add a definition to the entry
265
#
266
# Inputs          : A hash of definitions to add
267
#                   The Hash gets lost in the subcall. Its simply a list
268
#                   of NAME, VALUE pairs
269
#
270
# Returns         :
271
#
272
sub AddDefn
273
{
274
    my $self = shift;
275
    while ( @_ )
276
    {
277
        my $defn = shift;
278
        my $value = shift || '';
279
        $self->{DEFN}{$defn} = $value;
280
    }
281
}
282
 
283
#-------------------------------------------------------------------------------
284
# Function        : RecipePrefix
285
#
286
# Description     : Set the recipe prefix
287
#                   This will be added to ALL recipe entries
288
#
289
# Inputs          :
290
#
291
# Returns         :
292
#
293
sub RecipePrefix
294
{
295
    my $self = shift;
296
    my $prefix = shift || '';
297
    $self->{RECIPE_PREFIX} = $prefix;
298
}
299
 
300
#-------------------------------------------------------------------------------
301
# Function        : RecipeComment
302
#
303
# Description     : Add a runtime comment to the entry
304
#
305
# Inputs          : String to print at runtime
306
#
307
# Returns         :
308
#
309
sub RecipeComment
310
{
311
    my $self = shift;
312
    $self->{RECIPE_COMMENT} = join( ' ', @_);
313
}
314
 
315
 
5708 dpurdie 316
#-------------------------------------------------------------------------------
317
# Function        : RecipeWrapper
318
#
319
# Description     : Add a wrapper around the recipe
320
#
321
# Inputs          : begin   - Start of wrapper
322
#                   end     - End of wrapper
323
#
324
# Returns         :
325
#
326
sub RecipeWrapper
327
{
328
    my $self = shift;
329
    Error("RecipeWrapper requires exacly two arguments") unless scalar @_ == 2;
330
    my ($begin, $end) = @_;
331
    $self->{RECIPE_WRAPPER}[0] = $begin;
332
    $self->{RECIPE_WRAPPER}[1] = $end;
333
}
227 dpurdie 334
 
335
#-------------------------------------------------------------------------------
336
# Function        : AddRecipe
337
#
338
# Description     : Add a line to the line-by-line recipe
339
#
340
# Inputs          : One or more recipe lines
341
#                   Each line of the recipe will be prefixed with the current
342
#                   recipe prefix.
343
#
344
#                   An array will be treated as a recipe with implicit line
4344 dpurdie 345
#                   breaks for formatting purposes.
227 dpurdie 346
#
347
# Returns         :
348
#
349
sub AddRecipe
350
{
351
    my $self = shift;
352
    my $prefix = $self->{RECIPE_PREFIX};
353
    foreach ( @_ )
354
    {
355
        if (ref($_) eq "ARRAY")
356
        {
357
            $_->[0] = $prefix . $_->[0];
358
            push @{$self->{RECIPE}}, $_;
359
        }
360
        else
361
        {
362
            push @{$self->{RECIPE}}, $prefix . $_;
363
        }
364
    }
365
}
366
 
367
#-------------------------------------------------------------------------------
368
# Function        : AddShellRecipe
369
#
370
# Description     : Add recipe lines that will be processed within a 'shell'
371
#
372
# Inputs          : One or more recipe lines
373
#
374
#                   An array will be treated as a recipe with implicit line
4778 dpurdie 375
#                   breaks for formatting purposes.
227 dpurdie 376
#
377
# Returns         :
378
#
379
sub AddShellRecipe
380
{
381
    my $self = shift;
382
    push @{$self->{SHELL}}, @_
383
}
384
 
4778 dpurdie 385
#-------------------------------------------------------------------------------
386
# Function        : NewSection 
387
#
388
# Description     : Create a new section within the current recipe
389
#                   Only used within a standard recipe (not raw or defined)
390
#                   Used to create multiple sections in cases with multiple shell
391
#                   and recipe sections.
392
#
393
#                   Save existing entries and start again
394
#
395
# Inputs          : None 
396
#
397
# Returns         : 
398
#
399
sub NewSection
400
{
401
    my $self = shift;
402
    my %data;
227 dpurdie 403
 
4778 dpurdie 404
    $data{RECIPE}           = $self->{RECIPE};
405
    $data{SHELL}            = $self->{SHELL};
406
    $data{RECIPE_PREFIX}    = $self->{RECIPE_PREFIX};
407
    $data{RECIPE_COMMENT}   = $self->{RECIPE_COMMENT};
5708 dpurdie 408
    $data{RECIPE_WRAPPER}   = $self->{RECIPE_WRAPPER};
4781 dpurdie 409
    $data{SDEF}             = $self->{SDEF};
410
 
4778 dpurdie 411
 
412
    push @{$self->{STACK}}, \%data;
413
 
414
    $self->{RECIPE}         = []; 
415
    $self->{SHELL}          = [];
416
    $self->{RECIPE_PREFIX}  = '';
417
    $self->{RECIPE_COMMENT} = '';
5708 dpurdie 418
    $self->{RECIPE_WRAPPER} = ['(', ')'];
4781 dpurdie 419
    $self->{SDEF}           = '';
4778 dpurdie 420
}
421
 
4889 dpurdie 422
#-------------------------------------------------------------------------------
423
# Function        : SectionIfDef 
424
#
425
# Description     : Place the current section within a ifdef ... endif block
426
#
427
# Inputs          : defn        - Definition to use within the ifdef construct 
428
#
429
# Returns         : Nothing
430
#
431
 
432
sub SectionIfDef
4781 dpurdie 433
{
434
    my $self = shift;
435
    $self->{SDEF} = $_[0];
436
}
437
 
227 dpurdie 438
#-------------------------------------------------------------------------------
439
# Function        : Print
440
#
441
# Description     : Print the entry
442
#
443
# Inputs          : None
444
#
445
# Returns         : Nothing
446
#
447
sub Print
448
{
449
    my $self = shift;
450
 
451
    #
452
    #   Set the default print stream to the desired stream
453
    #   This greatly simplifies the use of print
454
    #
455
    my $fh = $self->{FH};
456
    my $old_fh = select($fh);
457
 
271 dpurdie 458
 
227 dpurdie 459
    #
460
    #   A nice comment header
461
    #
462
    if ( @{$self->{COMMENT}} )
463
    {
464
        print( "#\n" );
465
        print map {"# $_\n"} @{$self->{COMMENT}};
466
        print( "#\n" );
467
    }
468
 
469
    #
470
    #   Print the targets
471
    #   Print PHONY information
472
    #   Print on multiple lines if multiple targets are very long
473
    #
474
    if ( $self->{PHONY} )
475
    {
476
        my $phony_string = ".PHONY: ";
477
        my $tstring = join $;, @{$self->{NAME}};
478
        my $join = length ($tstring) < $llength ? ' ' : "\n$phony_string";
479
        $tstring =~ s~$;~$join~g;
480
        print "$phony_string$tstring\n";
481
    }
482
 
483
    #
484
    #   Print any definitions
485
    #       target: DEFN = VALUE
486
    #
487
    if ( $self->{DEFN}  )
488
    {
489
        my $tstring = join $;, @{$self->{NAME}};
490
        my $join = length ($tstring) < $llength ? ' ' : " \\\n    ";
491
        $tstring =~ s~$;~$join~g;
492
        foreach  ( keys %{$self->{DEFN}}  )
493
        {
494
            my $value = $self->{DEFN} {$_};
495
            print( "$tstring: $_ = $value\n" );
496
        }
497
    }
498
 
4344 dpurdie 499
    if ( $self->{RAW}  )
227 dpurdie 500
    {
4778 dpurdie 501
        if ( $self->{PHONY} )
502
        {
503
            my $tstring = $self->{NAME}[0];
504
            print($tstring . ":\n");
505
        }
4344 dpurdie 506
        my $tstring = join ("\n", @{$self->{RECIPE}});
507
        print $tstring;
227 dpurdie 508
    }
4344 dpurdie 509
    elsif ( $self->{DEFINE}  )
510
    {
227 dpurdie 511
 
4344 dpurdie 512
        my $tstring = $self->{NAME}[0];
513
        print "define $tstring";
514
        print_list ( '', '', $self->{RECIPE}, '');
515
        print "\nendef";
516
    }
517
    else
518
    {
519
        #
520
        #   Print the main target name
521
        #   Print on multiple lines if multiple targets are very long
522
        #
523
        my $tstring = join $;, @{$self->{NAME}};
524
        my $join = length ($tstring) < $llength ? ' ' : " \\\n";
525
        $tstring =~ s~$;~$join~g;
526
        my $nlength = length $tstring;
527
        print "$tstring:";
528
 
529
        #
530
        #   Print the prerequisites
531
        #   Print on multiple lines if long
532
        #
533
        $tstring = join $;, @{$self->{DEPENDANCY}};
534
        $join = $nlength + length ($tstring) < $llength ? ' ' : " \\\n\t";
535
        $tstring =~ s~$;~$join~g;
536
        print $join . $tstring;
227 dpurdie 537
 
4344 dpurdie 538
        #
4778 dpurdie 539
        #   Push the current section onto the stack
540
        #   This will simplify processing of all sections
4344 dpurdie 541
        #
4778 dpurdie 542
        $self->NewSection();
543
        foreach my $recipeEntry (@{$self->{STACK}})
4344 dpurdie 544
        {
4778 dpurdie 545
            my $comment = $recipeEntry->{RECIPE_COMMENT};
5708 dpurdie 546
            my $wrapper = $recipeEntry->{RECIPE_WRAPPER};
4778 dpurdie 547
            my $prefix =  $recipeEntry->{RECIPE_PREFIX};
548
            my $recipe =  $recipeEntry->{RECIPE};
549
            my $shell =   $recipeEntry->{SHELL};
4781 dpurdie 550
            my $sdef =    $recipeEntry->{SDEF};
551
 
552
            if ($sdef)
553
            {
554
                print "\nifdef $sdef";
555
            }
556
 
4778 dpurdie 557
            #
558
            #   Print the Recipe runtime comment
559
            #
560
            if ( $comment )
561
            {
562
                print "\n\t\@echo \"$comment\"";
563
            }
564
 
565
            #
566
            #   Print the recipe
567
            #
568
            print_list ( '', '', $recipe, '');
569
 
570
            #
571
            #   Print the recipe as a shell command
572
            #   Bracket the recipes with ( .. ) and place semi colons between lines
573
            #   Use the current recipe prefix
574
            #
5708 dpurdie 575
            print_list ( $prefix . $wrapper->[0], ';\\', $shell, $wrapper->[1]);
4781 dpurdie 576
 
577
            if ($sdef)
578
            {
579
                print "\nendif";
580
            }
4344 dpurdie 581
        }
582
    }
583
 
227 dpurdie 584
    print "\n\n";
585
 
586
    #
587
    #   Flag the entry as having been printed
588
    #   Used as a sanity test when the object is destroyed
589
    #
590
    $self->{PRINT} = 1;
591
 
592
    #
593
    #   Restore default output stream handle
594
    #
595
    select($old_fh);
596
}
597
 
598
#-------------------------------------------------------------------------------
599
# Function        : print_list
600
#
601
# Description     : Internal helper rouitine
602
#
603
# Inputs          : $prefix     - Optional prefix to wrap the list
604
#                                 If present will cause extra indentation
605
#                   $linesep    - Line seperator string
606
#                   $ref        - Ref to the list to display
607
#                                 Each element will be a line of text, or an
608
#                                 array of arguments which will be displayed on
609
#                                 new lines for pretty printing
610
#                   $suffix     - Optional suffix.
611
#
612
# Returns         :
613
#
614
sub print_list
615
{
616
    my ($prefix, $linesep ,$ref, $suffix) = @_;
617
    my @entry = @{$ref};
618
    my $leadin = "\t";
619
 
620
    if ( @entry  )
621
    {
622
        if ( $prefix )
623
        {
624
            print( "\n" . $leadin . $prefix . "\\" );
625
            $leadin .= "\t";
626
        }
627
 
628
        foreach ( @entry )
629
        {
630
            if (ref($_) eq "ARRAY")
631
            {
632
                my @array = @{$_};
633
                my $indent = '';
634
                my $tail = '';
635
                foreach ( @array )
636
                {
637
                    print( $tail . "\n" . $leadin . $indent . $_ );
638
                    $indent = "\t";
639
                    $tail = " \\";
640
                }
641
                print $linesep;
642
            }
643
            else
644
            {
645
                print( "\n" . $leadin . $_ . $linesep );
646
            }
647
        }
648
 
649
        if ( $suffix )
650
        {
4778 dpurdie 651
            $leadin = chop($leadin) if ($prefix);
227 dpurdie 652
            print( "\n" . $leadin . $suffix );
653
        }
654
    }
655
}
656
 
657
#-------------------------------------------------------------------------------
658
# Function        : DESTROY
659
#
660
# Description     : Sanity test
661
#
662
# Inputs          :
663
#
664
# Returns         :
665
#
666
sub DESTROY
667
{
668
    my $self = shift;
669
    unless ($self->{PRINT} )
670
    {
671
        $self->{PRINT} = 1;
672
        Error ("Destroying MakeEntry before printing.",
673
               "Name: @{$self->{NAME}}");
674
    }
271 dpurdie 675
 
676
    #
677
    #   If using an in-memory file close the handle
678
    #
679
    close $self->{FH} if ( $self->{FH_inmemory} );
227 dpurdie 680
}
681
 
682
1;
683
 
684