Subversion Repositories DevTools

Rev

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

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