Subversion Repositories DevTools

Rev

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