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