File Coverage

lib/Panotools/Makefile/Rule.pm
Criterion Covered Total %
statement 43 48 89.5
branch 2 6 33.3
condition 2 5 40.0
subroutine 8 8 100.0
pod 0 5 0.0
total 55 72 76.3


line stmt bran cond sub pod time code
1             package Panotools::Makefile::Rule;
2              
3             =head1 NAME
4              
5             Panotools::Makefile::Rule - Assemble Makefile rules
6              
7             =head1 SYNOPSIS
8              
9             Simple interface for generating Makefile syntax
10              
11             =head1 DESCRIPTION
12              
13             Writing Makefiles directly from perl scripts with print and "\t" etc... is
14             prone to error, this library provides a simple perl interface for assembling
15             Makefile rules.
16              
17             =cut
18              
19 3     3   225756 use strict;
  3         31  
  3         85  
20 3     3   14 use warnings;
  3         4  
  3         94  
21              
22 3     3   1125 use Panotools::Makefile::Utils qw/quotetarget quoteprerequisite quoteshell/;
  3         8  
  3         1655  
23              
24             =head1 USAGE
25              
26             my $rule = new Panotools::Makefile::Rule;
27              
28             ..or additionally specify targets at creation time
29              
30             my $rule = new Panotools::Makefile::Rule ('all');
31              
32             =cut
33              
34             sub new
35             {
36 62     62 0 502738 my $class = shift;
37 62   33     1139 $class = ref $class || $class;
38 62         436 my $self = bless {targets => [@_], prerequisites => [], command => []}, $class;
39 62         191 return $self;
40             }
41              
42             =pod
43              
44             A Makefile rule always has one or more 'targets', these are typically
45             filenames, but can be 'phony' non-files.
46              
47             (phony targets should be listed as perequisites of the special .PHONY target)
48              
49             $rule->Targets ('output1.txt', 'output2.txt');
50              
51             ..or equivalently:
52              
53             $rule->Targets ('output1.txt');
54             $rule->Targets ('output2.txt');
55              
56             =cut
57              
58             sub Targets
59             {
60 62     62 0 241 my $self = shift;
61 62         85 push @{$self->{targets}}, @_;
  62         232  
62             #warn 'Error: unescapable =;:% in targets: '. join (' ', @_) if grep /[=;:%]/, @_;
63             #warn 'Warning: non-portable target name: '. join (' ', @_) if grep /[?<>:*|"^]/, @_;
64             }
65              
66             =pod
67              
68             Rules can have zero or more 'prerequisites', again these are typically
69             filenames, but can be 'phony' non-files.
70              
71             $rule->Prerequisites ('input1.txt', 'input2.txt');
72              
73             ..or equivalently:
74              
75             $rule->Prerequisites ('input1.txt');
76             $rule->Prerequisites ('input2.txt');
77              
78             =cut
79              
80             sub Prerequisites
81             {
82 62     62 0 193 my $self = shift;
83 62         78 push @{$self->{prerequisites}}, @_;
  62         150  
84             #warn 'Error: unescapable =;:% in prerequisites: '. join (' ', @_) if grep /[=;:%]/, @_;
85             #warn 'Warning: non-portable target name: '. join (' ', @_) if grep /[?<>:*|"^]/, @_;
86             }
87              
88             =pod
89              
90             Rules zero or more 'commands':
91              
92             $rule->Command ('cp', 'input1.txt', 'output1.txt');
93             $rule->Command ('cp', 'input2.txt', 'output2.txt');
94              
95             =cut
96              
97             sub Command
98             {
99 65     65 0 1120 my $self = shift;
100 65         175 push @{$self->{command}}, [@_];
  65         277  
101             }
102              
103             =pod
104              
105             Assemble all this into string that can be written to a Makefile:
106              
107             my $string = $rule->Assemble;
108              
109             =cut
110              
111             sub Assemble
112             {
113 72     72 0 47234 my $self = shift;
114 72   50     961 my $opts = shift || {};
115 72 50       163 return '' unless scalar @{$self->{targets}};
  72         460  
116              
117 72         381 my $text;
118 72         143 $text .= join ' ', (map { quotetarget ($_)} @{$self->{targets}});
  76         432  
  72         198  
119 72         140 $text .= ' : ';
120 72         101 $text .= join ' ', (map { quoteprerequisite ($_)} @{$self->{prerequisites}});
  76         161  
  72         134  
121 72         142 for my $command (@{$self->{command}})
  72         169  
122             {
123 86         122 $text .= "\n\t";
124 86         121 $text .= join ' ', (map { quoteshell ($_)} @{$command});
  358         638  
  86         132  
125 86 50       326 next unless defined $opts->{warnings};
126 0         0 for my $token (@{$command})
  0         0  
127             {
128 0         0 my @vars = $token =~ /\$\([[:alnum:]_]+\)/g;
129 0         0 for my $var (@vars)
130             {
131 0 0       0 warn "underquoted \"$token\"" unless $var =~ /\$\([[:alnum:]_]+_SHELL\)/;
132             }
133             }
134             }
135 72         134 $text .= "\n\n";
136 72         1068 return $text;
137             }
138              
139             1;