Subversion Repositories DevTools

Rev

Rev 4778 | Rev 4889 | 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
########################################################################
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
 
4781 dpurdie 401
sub SectionDef
402
{
403
    my $self = shift;
404
    $self->{SDEF} = $_[0];
405
}
406
 
407
 
227 dpurdie 408
#-------------------------------------------------------------------------------
409
# Function        : Print
410
#
411
# Description     : Print the entry
412
#
413
# Inputs          : None
414
#
415
# Returns         : Nothing
416
#
417
sub Print
418
{
419
    my $self = shift;
420
 
421
    #
422
    #   Set the default print stream to the desired stream
423
    #   This greatly simplifies the use of print
424
    #
425
    my $fh = $self->{FH};
426
    my $old_fh = select($fh);
427
 
271 dpurdie 428
 
227 dpurdie 429
    #
430
    #   A nice comment header
431
    #
432
    if ( @{$self->{COMMENT}} )
433
    {
434
        print( "#\n" );
435
        print map {"# $_\n"} @{$self->{COMMENT}};
436
        print( "#\n" );
437
    }
438
 
439
    #
440
    #   Print the targets
441
    #   Print PHONY information
442
    #   Print on multiple lines if multiple targets are very long
443
    #
444
    if ( $self->{PHONY} )
445
    {
446
        my $phony_string = ".PHONY: ";
447
        my $tstring = join $;, @{$self->{NAME}};
448
        my $join = length ($tstring) < $llength ? ' ' : "\n$phony_string";
449
        $tstring =~ s~$;~$join~g;
450
        print "$phony_string$tstring\n";
451
    }
452
 
453
    #
454
    #   Print any definitions
455
    #       target: DEFN = VALUE
456
    #
457
    if ( $self->{DEFN}  )
458
    {
459
        my $tstring = join $;, @{$self->{NAME}};
460
        my $join = length ($tstring) < $llength ? ' ' : " \\\n    ";
461
        $tstring =~ s~$;~$join~g;
462
        foreach  ( keys %{$self->{DEFN}}  )
463
        {
464
            my $value = $self->{DEFN} {$_};
465
            print( "$tstring: $_ = $value\n" );
466
        }
467
    }
468
 
4344 dpurdie 469
    if ( $self->{RAW}  )
227 dpurdie 470
    {
4778 dpurdie 471
        if ( $self->{PHONY} )
472
        {
473
            my $tstring = $self->{NAME}[0];
474
            print($tstring . ":\n");
475
        }
4344 dpurdie 476
        my $tstring = join ("\n", @{$self->{RECIPE}});
477
        print $tstring;
227 dpurdie 478
    }
4344 dpurdie 479
    elsif ( $self->{DEFINE}  )
480
    {
227 dpurdie 481
 
4344 dpurdie 482
        my $tstring = $self->{NAME}[0];
483
        print "define $tstring";
484
        print_list ( '', '', $self->{RECIPE}, '');
485
        print "\nendef";
486
    }
487
    else
488
    {
489
        #
490
        #   Print the main target name
491
        #   Print on multiple lines if multiple targets are very long
492
        #
493
        my $tstring = join $;, @{$self->{NAME}};
494
        my $join = length ($tstring) < $llength ? ' ' : " \\\n";
495
        $tstring =~ s~$;~$join~g;
496
        my $nlength = length $tstring;
497
        print "$tstring:";
498
 
499
        #
500
        #   Print the prerequisites
501
        #   Print on multiple lines if long
502
        #
503
        $tstring = join $;, @{$self->{DEPENDANCY}};
504
        $join = $nlength + length ($tstring) < $llength ? ' ' : " \\\n\t";
505
        $tstring =~ s~$;~$join~g;
506
        print $join . $tstring;
227 dpurdie 507
 
4344 dpurdie 508
        #
4778 dpurdie 509
        #   Push the current section onto the stack
510
        #   This will simplify processing of all sections
4344 dpurdie 511
        #
4778 dpurdie 512
        $self->NewSection();
513
        foreach my $recipeEntry (@{$self->{STACK}})
4344 dpurdie 514
        {
4778 dpurdie 515
            my $comment = $recipeEntry->{RECIPE_COMMENT};
516
            my $prefix =  $recipeEntry->{RECIPE_PREFIX};
517
            my $recipe =  $recipeEntry->{RECIPE};
518
            my $shell =   $recipeEntry->{SHELL};
4781 dpurdie 519
            my $sdef =    $recipeEntry->{SDEF};
520
 
521
            if ($sdef)
522
            {
523
                print "\nifdef $sdef";
524
            }
525
 
4778 dpurdie 526
            #
527
            #   Print the Recipe runtime comment
528
            #
529
            if ( $comment )
530
            {
531
                print "\n\t\@echo \"$comment\"";
532
            }
533
 
534
            #
535
            #   Print the recipe
536
            #
537
            print_list ( '', '', $recipe, '');
538
 
539
            #
540
            #   Print the recipe as a shell command
541
            #   Bracket the recipes with ( .. ) and place semi colons between lines
542
            #   Use the current recipe prefix
543
            #
544
            print_list ( $prefix . '(', ';\\', $shell, ')');
4781 dpurdie 545
 
546
            if ($sdef)
547
            {
548
                print "\nendif";
549
            }
4344 dpurdie 550
        }
551
    }
552
 
227 dpurdie 553
    print "\n\n";
554
 
555
    #
556
    #   Flag the entry as having been printed
557
    #   Used as a sanity test when the object is destroyed
558
    #
559
    $self->{PRINT} = 1;
560
 
561
    #
562
    #   Restore default output stream handle
563
    #
564
    select($old_fh);
565
}
566
 
567
#-------------------------------------------------------------------------------
568
# Function        : print_list
569
#
570
# Description     : Internal helper rouitine
571
#
572
# Inputs          : $prefix     - Optional prefix to wrap the list
573
#                                 If present will cause extra indentation
574
#                   $linesep    - Line seperator string
575
#                   $ref        - Ref to the list to display
576
#                                 Each element will be a line of text, or an
577
#                                 array of arguments which will be displayed on
578
#                                 new lines for pretty printing
579
#                   $suffix     - Optional suffix.
580
#
581
# Returns         :
582
#
583
sub print_list
584
{
585
    my ($prefix, $linesep ,$ref, $suffix) = @_;
586
    my @entry = @{$ref};
587
    my $leadin = "\t";
588
 
589
    if ( @entry  )
590
    {
591
        if ( $prefix )
592
        {
593
            print( "\n" . $leadin . $prefix . "\\" );
594
            $leadin .= "\t";
595
        }
596
 
597
        foreach ( @entry )
598
        {
599
            if (ref($_) eq "ARRAY")
600
            {
601
                my @array = @{$_};
602
                my $indent = '';
603
                my $tail = '';
604
                foreach ( @array )
605
                {
606
                    print( $tail . "\n" . $leadin . $indent . $_ );
607
                    $indent = "\t";
608
                    $tail = " \\";
609
                }
610
                print $linesep;
611
            }
612
            else
613
            {
614
                print( "\n" . $leadin . $_ . $linesep );
615
            }
616
        }
617
 
618
        if ( $suffix )
619
        {
4778 dpurdie 620
            $leadin = chop($leadin) if ($prefix);
227 dpurdie 621
            print( "\n" . $leadin . $suffix );
622
        }
623
    }
624
}
625
 
626
#-------------------------------------------------------------------------------
627
# Function        : DESTROY
628
#
629
# Description     : Sanity test
630
#
631
# Inputs          :
632
#
633
# Returns         :
634
#
635
sub DESTROY
636
{
637
    my $self = shift;
638
    unless ($self->{PRINT} )
639
    {
640
        $self->{PRINT} = 1;
641
        Error ("Destroying MakeEntry before printing.",
642
               "Name: @{$self->{NAME}}");
643
    }
271 dpurdie 644
 
645
    #
646
    #   If using an in-memory file close the handle
647
    #
648
    close $self->{FH} if ( $self->{FH_inmemory} );
227 dpurdie 649
}
650
 
651
1;
652
 
653