File Coverage

blib/lib/Make.pm
Criterion Covered Total %
statement 445 468 95.0
branch 154 178 86.5
condition 25 38 65.7
subroutine 54 57 94.7
pod 21 41 51.2
total 699 782 89.3


line stmt bran cond sub pod time code
1             package Make;
2              
3 1     1   89326 use strict;
  1         14  
  1         30  
4 1     1   5 use warnings;
  1         12  
  1         42  
5              
6             our $VERSION = '2.011';
7              
8 1     1   5 use Carp qw(confess croak);
  1         2  
  1         46  
9 1     1   5 use Config;
  1         2  
  1         49  
10 1     1   7 use Cwd;
  1         2  
  1         96  
11 1     1   8 use File::Spec;
  1         2  
  1         21  
12 1     1   456 use Make::Target ();
  1         2  
  1         19  
13 1     1   430 use Make::Rule ();
  1         3  
  1         21  
14 1     1   801 use File::Temp;
  1         22027  
  1         69  
15 1     1   677 use Text::Balanced qw(extract_bracketed);
  1         10292  
  1         98  
16 1     1   489 use Text::ParseWords qw(parse_line);
  1         1271  
  1         62  
17 1     1   499 use File::Spec::Functions qw(file_name_is_absolute);
  1         890  
  1         78  
18             ## no critic (ValuesAndExpressions::ProhibitConstantPragma)
19 1     1   7 use constant DEBUG => $ENV{MAKE_DEBUG};
  1         1  
  1         7606  
20             ## use critic
21             require Make::Functions;
22              
23             my $DEFAULTS_AST;
24             my %date;
25             my %fs_function_map = (
26             glob => sub { glob $_[0] },
27             fh_open => sub { open my $fh, $_[0], $_[1] or confess "open @_: $!"; $fh },
28             fh_write => sub { my $fh = shift; print {$fh} @_ },
29             file_readable => sub { -r $_[0] },
30             mtime => sub { ( stat $_[0] )[9] },
31             is_abs => sub { goto &file_name_is_absolute },
32             );
33             my @RECMAKE_FINDS = ( \&_find_recmake_cd, );
34              
35             sub _find_recmake_cd {
36 10     10   18 my ($cmd) = @_;
37 10 100       69 return unless $cmd =~ /\bcd\s+([^\s;&]+)\s*(?:;|&&)\s*make\s*(.*)/;
38 5         21 my ( $dir, $makeargs ) = ( $1, $2 );
39 5         855 require Getopt::Long;
40 5         11042 local @ARGV = Text::ParseWords::shellwords($makeargs);
41 5         131 Getopt::Long::GetOptions( "f=s" => \my $makefile );
42 5         660 my ( $vars, $targets ) = parse_args(@ARGV);
43 5         26 return ( $dir, $makefile, $vars, $targets );
44             }
45              
46             ## no critic (Subroutines::RequireArgUnpacking Subroutines::RequireFinalReturn)
47             sub load_modules {
48 11     11 0 31 for (@_) {
49 11         33 my $pkg = $_; # to not mutate inputs
50 11         114 $pkg =~ s#::#/#g;
51             ## no critic (Modules::RequireBarewordIncludes)
52 11 50       26 eval { require "$pkg.pm"; 1 } or die;
  11         148  
  11         57  
53             ## use critic
54             }
55             }
56              
57             sub phony {
58 157     157 0 266 my ( $self, $name ) = @_;
59 157         572 return exists $self->{PHONY}{$name};
60             }
61              
62             sub suffixes {
63 11     11 0 19 my ($self) = @_;
64             ## no critic (Subroutines::ProhibitReturnSort)
65 11         14 return sort keys %{ $self->{'SUFFIXES'} };
  11         82  
66             ## use critic
67             }
68              
69             sub target {
70 241     241 1 2895 my ( $self, $target ) = @_;
71 241 100       583 unless ( exists $self->{Depend}{$target} ) {
72 131         429 my $t = $self->{Depend}{$target} = Make::Target->new( $target, $self );
73 131 100       540 if ( $target =~ /%/ ) {
    100          
74 33         80 $self->{Pattern}{$target} = $t;
75             }
76             elsif ( $target =~ /^\./ ) {
77 61         134 $self->{Dot}{$target} = $t;
78             }
79             }
80 241         640 return $self->{Depend}{$target};
81             }
82              
83             sub has_target {
84 43     43 1 91 my ( $self, $target ) = @_;
85 43 50       95 confess "Trying to has_target undef value" unless defined $target;
86 43         166 return exists $self->{Depend}{$target};
87             }
88              
89             sub targets {
90 15     15 1 1780 my ($self) = @_;
91             ## no critic ( BuiltinFunctions::RequireBlockGrep )
92 15         25 return grep !/%|^\./, keys %{ $self->{Depend} };
  15         464  
93             ## use critic
94             }
95              
96             # Utility routine for patching %.o type 'patterns'
97             my %pattern_cache;
98              
99             sub patmatch {
100 117     117 0 241 my ( $pat, $target ) = @_;
101 117 100       300 return $target if $pat eq '%';
102             ## no critic (BuiltinFunctions::RequireBlockMap)
103             $pattern_cache{$pat} = join '(.*)', map quotemeta, split /%/, $pat
104 85 100       156 if !exists $pattern_cache{$pat};
105             ## use critic
106 85         126 $pat = $pattern_cache{$pat};
107 85 100       1140 if ( $target =~ /^$pat$/ ) {
108 27         150 return $1;
109             }
110 58         191 return;
111             }
112              
113             sub in_dir {
114 114     114 0 233 my ( $fsmap, $dir, $file ) = @_;
115 114 100 66     368 return $file if defined $file and $fsmap->{is_abs}->($file);
116 109 100       1220 my @dir = defined($dir) ? split /\//, $dir : ();
117 109         240 my @file = split /\//, $file;
118 109   66     478 while ( @dir and @file and $file[0] eq '..' ) {
      100        
119              
120             # normalise out ../ in $file - no account taken of symlinks
121 2         3 shift @file;
122 2         5 pop @dir;
123             }
124 109         493 join '/', @dir, @file;
125             }
126              
127             sub locate {
128 41     41 0 85 my ( $self, $file ) = @_;
129 41         78 my $fsmap = $self->fsmap;
130 41         65 my $readable = $fsmap->{file_readable};
131 41         61 foreach my $key ( sort keys %{ $self->{Vpath} } ) {
  41         175  
132 21 100       47 next unless defined( my $Pat = patmatch( $key, $file ) );
133 15         36 foreach my $dir ( @{ $self->{Vpath}{$key} } ) {
  15         39  
134 15         65 ( my $maybe_file = $dir ) =~ s/%/$Pat/g;
135 15 100       47 return $maybe_file if $readable->( in_dir $fsmap, $self->{InDir}, $maybe_file );
136             }
137             }
138 38         120 return;
139             }
140              
141             # Convert traditional .c.o rules into GNU-like into %.o : %.c
142             sub dotrules {
143 11     11 0 26 my ($self) = @_;
144 11         33 my @suffix = $self->suffixes;
145 11         37 my $Dot = delete $self->{Dot};
146 11         44 foreach my $f (@suffix) {
147 66         103 foreach my $t ( '', @suffix ) {
148 462         660 delete $self->{Depend}{ $f . $t };
149 462 100       883 next unless my $r = delete $Dot->{ $f . $t };
150 44         61 DEBUG and print STDERR "Pattern %$t : %$f\n";
151 44         103 my $target = $self->target( '%' . $t );
152 44         97 my $thisrule = $r->rules->[-1]; # last-specified
153             die "Failed on pattern rule for '$f$t', no prereqs allowed"
154 44 50       66 if @{ $thisrule->prereqs };
  44         81  
155 44         118 my $rule = Make::Rule->new( '::', [ '%' . $f ], $thisrule->recipe, $thisrule->recipe_raw );
156 44         113 $self->target( '%' . $t )->add_rule($rule);
157             }
158             }
159 11         30 return;
160             }
161              
162             #
163             # Return modified date of name if it exists
164             #
165             sub date {
166 67     67 0 117 my ( $self, $name ) = @_;
167 67         121 my $fsmap = $self->fsmap;
168 67 100       147 unless ( exists $date{$name} ) {
169 48         122 $date{$name} = $self->fsmap->{mtime}->( in_dir $fsmap, $self->{InDir}, $name );
170             }
171 67         544 return $date{$name};
172             }
173              
174             #
175             # See if we can find a %.o : %.c rule for target
176             # .c.o rules are already converted to this form
177             #
178             sub patrule {
179 47     47 1 106 my ( $self, $target, $kind ) = @_;
180 47         64 DEBUG and print STDERR "Trying pattern for $target\n";
181 47         55 foreach my $key ( sort keys %{ $self->{Pattern} } ) {
  47         236  
182 96         127 DEBUG and print STDERR " Pattern $key trying\n";
183 96 100       157 next unless defined( my $Pat = patmatch( $key, $target ) );
184 44         65 DEBUG and print STDERR " Pattern $key matched ($Pat)\n";
185 44         71 my $t = $self->{Pattern}{$key};
186 44         107 foreach my $rule ( @{ $t->rules } ) {
  44         129  
187 44         106 my @dep = @{ $rule->prereqs };
  44         91  
188 44         55 DEBUG and print STDERR " Try rule : @dep\n";
189 44 50       86 next unless @dep;
190 44         56 my @failed;
191 44         70 for my $this_dep (@dep) {
192 44         169 $this_dep =~ s/%/$Pat/g;
193 44 100 66     96 next if $self->date($this_dep) or $self->has_target($this_dep);
194 41         109 my $maybe = $self->locate($this_dep);
195 41 100       95 if ( defined $maybe ) {
196 3         11 $this_dep = $maybe;
197 3         7 next;
198             }
199 38         84 push @failed, $this_dep;
200             }
201 44         61 DEBUG and print STDERR " " . ( @failed ? "Failed: (@failed)" : "Matched (@dep)" ) . "\n";
202 44 100       123 next if @failed;
203 6         19 return Make::Rule->new( $kind, \@dep, $rule->recipe, $rule->recipe_raw );
204             }
205             }
206 41         118 return;
207             }
208              
209             sub evaluate_macro {
210 64     64 0 136 my ( $key, @args ) = @_;
211 64         115 my ( $function_packages, $vars_search_list, $fsmap ) = @args;
212 64         108 my $value;
213 64 100       156 return '' if !length $key;
214 62 100       355 if ( $key =~ /^([\w._]+|\S)(?::(.*))?$/ ) {
    100          
    50          
215 51         127 my ( $var, $subst ) = ( $1, $2 );
216 51         116 foreach my $hash (@$vars_search_list) {
217 70 100       244 last if defined( $value = $hash->{$var} );
218             }
219 51 100       117 $value = '' if !defined $value;
220 51 100       98 if ( defined $subst ) {
221 1         6 my @parts = split /=/, $subst, 2;
222 1 50       6 die "Syntax error: expected form x=y in '$subst'" if @parts != 2;
223 1         10 $value = join ' ', Make::Functions::patsubst( $fsmap, @parts, $value );
224             }
225             }
226             elsif ( $key =~ /([\w._]+)\s+(.*)$/ ) {
227 10         47 my ( $func, $args ) = ( $1, $2 );
228 10         17 my $code;
229 10         31 foreach my $package (@$function_packages) {
230 10 50       121 last if $code = $package->can($func);
231             }
232 10 50       28 die "'$func' not found in (@$function_packages)" if !defined $code;
233             ## no critic (BuiltinFunctions::RequireBlockMap)
234 10         52 $value = join ' ', $code->( $fsmap, map subsvars( $_, @args ), split /\s*,\s*/, $args );
235             ## use critic
236             }
237             elsif ( $key =~ /^\S*\$/ ) {
238              
239             # something clever, expand it
240 1         4 $key = subsvars( $key, @args );
241 1         3 return evaluate_macro( $key, @args );
242             }
243 61         435 return subsvars( $value, @args );
244             }
245              
246             sub subsvars {
247 272     272 1 26863 my ( $remaining, $function_packages, $vars_search_list, $fsmap ) = @_;
248 272 50       517 confess "Trying to expand undef value" unless defined $remaining;
249 272         391 my $ret = '';
250 272         371 my $found;
251 272         362 while (1) {
252 336 100       1039 last unless $remaining =~ s/(.*?)\$//;
253 66         179 $ret .= $1;
254 66         179 my $char = substr $remaining, 0, 1;
255 66 100       291 if ( $char eq '$' ) {
    100          
256 1         3 $ret .= $char; # literal $
257 1         3 substr $remaining, 0, 1, '';
258 1         2 next;
259             }
260             elsif ( $char =~ /[\{\(]/ ) {
261 50         279 ( $found, my $tail ) = extract_bracketed $remaining, '{}()', '';
262 50 100       7460 die "Syntax error in '$remaining'" if !defined $found;
263 48         119 $found = substr $found, 1, -1;
264 48         119 $remaining = $tail;
265             }
266             else {
267 15         33 $found = substr $remaining, 0, 1, '';
268             }
269 63         170 my $value = evaluate_macro( $found, $function_packages, $vars_search_list, $fsmap );
270 63 50       148 if ( !defined $value ) {
271 0         0 warn "Cannot evaluate '$found'\n";
272 0         0 $value = '';
273             }
274 63         101 $ret .= $value;
275             }
276 270         997 return $ret . $remaining;
277             }
278              
279             # Perhaps should also understand "..." and '...' ?
280             # like GNU make will need to understand \ to quote spaces, for deps
281             # also C:\xyz as a non-target (overlap with parse_makefile)
282             sub tokenize {
283 169     169 1 5670 my ( $string, @extrasep ) = @_;
284             ## no critic ( BuiltinFunctions::RequireBlockGrep BuiltinFunctions::RequireBlockMap)
285 169         383 my $pat = join '|', '\s+', map quotemeta, @extrasep;
286 169   100     536 my @toks = grep defined && length, parse_line $pat, 1, $string;
287             ## use critic
288 169         8217 s/\\(\s)/$1/g for @toks;
289 169         514 return \@toks;
290             }
291              
292             sub get_full_line {
293 114     114 0 2560 my ($fh) = @_;
294 114         346 my $final = my $line = <$fh>;
295 114 100       294 return if !defined $line;
296 92         122 my $raw = $line;
297 92         199 $raw =~ s/^\t//;
298 92         423 $final =~ s/\r?\n\z//;
299 92         260 while ( $final =~ /\\$/ ) {
300 4         21 $final =~ s/\s*\\\z//;
301 4         11 $line = <$fh>;
302 4 50       10 last if !defined $line;
303 4         7 my $raw_line = $line;
304 4         49 $raw_line =~ s/^\t//;
305 4         10 $raw .= $raw_line;
306 4         20 $line =~ s/\s*\z//;
307 4         10 $line =~ s/^\s*/ /;
308 4         19 $final .= $line;
309             }
310 92         277 $raw =~ s/\r?\n\z//;
311 92         327 return ( $final, $raw );
312             }
313              
314             sub set_var {
315 48     48 1 495 my ( $self, $name, $value ) = @_;
316 48         214 $self->{Vars}{$name} = $value;
317             }
318              
319             sub vars {
320 178     178 1 264 my ($self) = @_;
321 178         466 $self->{Vars};
322             }
323              
324             sub function_packages {
325 197     197 1 319 my ($self) = @_;
326 197         476 $self->{FunctionPackages};
327             }
328              
329             sub fsmap {
330 343     343 1 518 my ($self) = @_;
331 343         678 $self->{FSFunctionMap};
332             }
333              
334             sub expand {
335 156     156 1 277 my ( $self, $text ) = @_;
336 156         255 return subsvars( $text, $self->function_packages, [ $self->vars, \%ENV ], $self->fsmap );
337             }
338              
339             sub process_ast_bit {
340 99     99 0 370 my ( $self, $type, @args ) = @_;
341 99 50       227 return if $type eq 'comment';
342 99 100       324 if ( $type eq 'include' ) {
    100          
    100          
    50          
343 6         11 my $opt = $args[0];
344 6         16 my ($tokens) = tokenize( $self->expand( $args[1] ) );
345 6         18 foreach my $file (@$tokens) {
346 6 100 50     27 eval {
347 3         11 my $fsmap = $self->fsmap;
348 3         21 $file = in_dir $fsmap, $self->{InDir}, $file;
349 3         11 my $mf = $fsmap->{fh_open}->( '<', $file );
350 3         97 my $ast = parse_makefile($mf);
351 3         12 close($mf);
352 3         48 $self->process_ast_bit(@$_) for @$ast;
353 3         29 1;
354             } or warn $@ if $opt ne '-';
355             }
356             }
357             elsif ( $type eq 'var' ) {
358 15 50       56 $self->set_var( $args[0], defined $args[1] ? $args[1] : "" );
359             }
360             elsif ( $type eq 'vpath' ) {
361 3         7 my ( $pattern, @vpath ) = @args;
362 3         16 $self->{Vpath}{$pattern} = \@vpath;
363             }
364             elsif ( $type eq 'rule' ) {
365 75         187 my ( $targets, $kind, $prereqs, $cmnds, $cmnds_raw ) = @args;
366 75         173 ($prereqs) = tokenize( $self->expand($prereqs) );
367 75         227 ($targets) = tokenize( $self->expand($targets) );
368 75 100 66     409 $self->{Vars}{'.DEFAULT_GOAL'} ||= $targets->[0]
369             if $targets->[0] !~ /%|^\./;
370 75 100 66     377 unless ( @$targets == 1 and $targets->[0] =~ /^\.[A-Z]/ ) {
371 60         134 $self->target($_) for @$prereqs; # so "exist or can be made"
372             }
373 75         371 my $rule = Make::Rule->new( $kind, $prereqs, $cmnds, $cmnds_raw );
374 75         221 $self->target($_)->add_rule($rule) for @$targets;
375             }
376 99         332 return;
377             }
378              
379             #
380             # read makefile (or fragment of one) either as a result
381             # of a command line, or an 'include' in another makefile.
382             #
383             sub parse_makefile {
384 22     22 1 7528 my ($fh) = @_;
385 22         68 my @ast;
386             my $raw;
387 22         55 ( local $_, $raw ) = get_full_line($fh);
388 22         39 while (1) {
389 83 100       196 last unless ( defined $_ );
390 61         146 s/^\s+//;
391 61 100       128 next if !length;
392 58 100       502 if (/^(-?)include\s+(.*)$/) {
    100          
    100          
    100          
    50          
393 6         46 push @ast, [ 'include', $1, $2 ];
394             }
395             elsif (s/^#+\s*//) {
396 1         4 push @ast, [ 'comment', $_ ];
397             }
398             elsif (/^\s*([\w._]+)\s*:?=\s*(.*)$/) {
399 17         96 push @ast, [ 'var', $1, $2 ];
400             }
401             elsif (/^vpath\s+(\S+)\s+([^#]*)/) {
402 4         33 my ( $pattern, $path ) = ( $1, $2 );
403 4         8 my @path = @{ tokenize $path, $Config{path_sep} };
  4         21  
404 4         23 push @ast, [ 'vpath', $pattern, @path ];
405             }
406             elsif (
407             /^
408             \s*
409             ([^:\#]*?)
410             \s*
411             (::?)
412             \s*
413             ((?:[^;\#]*\#.*|.*?))
414             (?:\s*;\s*(.*))?
415             $/sx
416             )
417             {
418 30         173 my ( $target, $kind, $prereqs, $maybe_cmd ) = ( $1, $2, $3, $4 );
419 30 100       83 my @cmnds = defined $maybe_cmd ? ($maybe_cmd) : ();
420 30         53 my @cmnds_raw = @cmnds;
421 30         56 $prereqs =~ s/\s*#.*//;
422 30         63 while ( ( $_, $raw ) = get_full_line($fh) ) {
423 42 100       143 next if /^\s*#/;
424 41 100       113 next if /^\s*$/;
425 33 100       96 last unless /^\t/;
426 19 50       47 next if /^\s*$/;
427 19         48 s/^\s+//;
428 19         43 push @cmnds, $_;
429 19         39 push @cmnds_raw, $raw;
430             }
431 30         123 push @ast, [ 'rule', $target, $kind, $prereqs, \@cmnds, \@cmnds_raw ];
432 30         87 redo;
433             }
434             else {
435 0         0 warn "Ignore '$_'\n";
436             }
437             }
438             continue {
439 31         83 ( $_, $raw ) = get_full_line($fh);
440             }
441 22         81 return \@ast;
442             }
443              
444             sub pseudos {
445 11     11 0 23 my $self = shift;
446 11         60 foreach my $key (qw(SUFFIXES PHONY PRECIOUS PARALLEL)) {
447 44         123 delete $self->{Depend}{ '.' . $key };
448 44         84 my $t = delete $self->{Dot}{ '.' . $key };
449 44 100       99 if ( defined $t ) {
450 15         64 $self->{$key} = {};
451             ## no critic (BuiltinFunctions::RequireBlockMap)
452 15         35 foreach my $dep ( map @{ $_->prereqs }, @{ $t->rules } ) {
  15         44  
  15         81  
453             ## use critic
454 70         225 $self->{$key}{$dep} = 1;
455             }
456             }
457             }
458 11         24 return;
459             }
460              
461             sub find_makefile {
462 12     12 0 45 my ( $self, $file, $dir ) = @_;
463             ## no critic ( BuiltinFunctions::RequireBlockGrep )
464 12         85 my @dirs = grep defined, $self->{InDir}, $dir;
465 12 100       73 $dir = join '/', @dirs if @dirs;
466             ## use critic
467 12         30 my $fsmap = $self->fsmap;
468 12 100       59 return in_dir $fsmap, $dir, $file if defined $file;
469 11         50 my @search = qw(makefile Makefile);
470 11 100       48 unshift @search, 'GNUmakefile' if $self->{GNU};
471             ## no critic (BuiltinFunctions::RequireBlockMap)
472 11         40 @search = map in_dir( $fsmap, $dir, $_ ), @search;
473             ## use critic
474 11         45 for (@search) {
475 20 100       75 return $_ if $fsmap->{file_readable}->($_);
476             }
477 0         0 return;
478             }
479              
480             sub parse {
481 11     11 1 90 my ( $self, $file ) = @_;
482 11         19 my $fh;
483 11 100       41 if ( ref $file eq 'SCALAR' ) {
484 3         57 open my $tfh, "+<", $file;
485 3         10 $fh = $tfh;
486             }
487             else {
488 8         38 $file = $self->find_makefile($file);
489 8         61 $fh = $self->fsmap->{fh_open}->( '<', $file );
490             }
491 11         318 my $ast = parse_makefile($fh);
492 11         58 $self->process_ast_bit(@$_) for @$ast;
493 11         59 undef $fh;
494              
495             # Next bits should really be done 'lazy' on need.
496              
497 11         37 $self->pseudos; # Pull out .SUFFIXES etc.
498 11         58 $self->dotrules; # Convert .c.o into %.o : %.c
499 11         50 return $self;
500             }
501              
502             sub PrintVars {
503 0     0 0 0 my $self = shift;
504 0         0 local $_;
505 0         0 my $vars = $self->vars;
506 0         0 foreach ( sort keys %$vars ) {
507 0         0 print "$_ = ", $vars->{$_}, "\n";
508             }
509 0         0 print "\n";
510 0         0 return;
511             }
512              
513             sub parse_cmdline {
514 13     13 0 5811 my ($line) = @_;
515 13         193 $line =~ s/^([\@\s-]*)//;
516 13         101 my $prefix = $1;
517 13         77 my %parsed = ( line => $line );
518 13 100       101 $parsed{silent} = 1 if $prefix =~ /\@/;
519 13 100       42 $parsed{can_fail} = 1 if $prefix =~ /-/;
520 13         44 return \%parsed;
521             }
522              
523             ## no critic (BuiltinFunctions::RequireBlockMap)
524             my %NAME_QUOTING = map +( $_ => sprintf "%%%02x", ord $_ ), qw(% :);
525             my $NAME_QUOTE_CHARS = join '', '[', ( map quotemeta, sort keys %NAME_QUOTING ), ']';
526              
527             sub name_encode {
528             join ':', map {
529 93         117 my $s = $_;
530 93         264 $s =~ s/($NAME_QUOTE_CHARS)/$NAME_QUOTING{$1}/gs;
531 93         293 $s
532 42     42 1 1696 } @{ $_[0] };
  42         99  
533             }
534              
535             sub name_decode {
536 13     13 1 1075 my ($s) = @_;
537             [
538             map {
539 13         40 my $s = $_;
  27         38  
540 27         42 $s =~ s/%(..)/chr hex $1/ges;
  2         10  
541 27         73 $s
542             } split ':',
543             $_[0]
544             ];
545             }
546             ## use critic
547              
548             ## no critic (Subroutines::ProhibitBuiltinHomonyms)
549             sub exec {
550 8     8 0 44 my ( $self, $line ) = @_;
551 8         50 undef %date;
552 8         59 my $parsed = parse_cmdline($line);
553 8 50       28 print "$parsed->{line}\n" unless $parsed->{silent};
554 8         50317 my $code = system $parsed->{line};
555 8 50 33     188 if ( $code && !$parsed->{can_fail} ) {
556 0         0 $code >>= 8;
557 0         0 die "Code $code from $parsed->{line}";
558             }
559 8         672 return;
560             }
561             ## use critic
562              
563             ## no critic (Subroutines::RequireFinalReturn)
564 5     5 0 16 sub NextPass { shift->{Pass}++ }
565 20     20 0 37 sub pass { shift->{Pass} }
566             ## use critic
567              
568             ## no critic (RequireArgUnpacking)
569             sub parse_args {
570 11     11 0 23 my ( @vars, @targets );
571 11         35 foreach (@_) {
572 6 100       58 if (/^(\w+)=(.*)$/) {
573 1         21 push @vars, [ $1, $2 ];
574             }
575             else {
576 5         24 push @targets, $_;
577             }
578             }
579 11         60 return \@vars, \@targets;
580             }
581             ## use critic
582              
583             sub _rmf_search_rule {
584 10     10   29 my ( $rule, $target_obj, $target, $rule_no, $rmfs ) = @_;
585 10         12 my @found;
586 10         16 my $line = -1;
587 10         27 for my $cmd ( $rule->exp_recipe($target_obj) ) {
588 10         17 $line++;
589 10         13 my @rec_vars;
590 10         20 for my $rf (@$rmfs) {
591 10 100       19 last if @rec_vars = $rf->($cmd);
592             }
593 10 100       25 next unless @rec_vars;
594 5         20 push @found, [ $target, $rule_no, $line, @rec_vars ];
595             }
596 10         32 return @found;
597             }
598              
599             sub find_recursive_makes {
600 1     1 1 3495 my ($self) = @_;
601 1         4 my @found;
602 1         2 my $rmfs = $self->{RecursiveMakeFinders};
603 1         4 for my $target ( sort $self->targets ) {
604 3         9 my $target_obj = $self->target($target);
605 3         5 my $rule_no = 0;
606             ## no critic (BuiltinFunctions::RequireBlockMap)
607 3         7 push @found, map _rmf_search_rule( $_, $target_obj, $target, $rule_no++, $rmfs ), @{ $target_obj->rules };
  3         8  
608             ## use critic
609             }
610 1         5 return @found;
611             }
612              
613             sub as_graph {
614 8     8 1 13299 my ( $self, %options ) = @_;
615 8         25 my ( $no_rules, $recursive_make ) = @options{qw(no_rules recursive_make)};
616 8         1058 require Graph;
617 8 100       33605 my $g = Graph->new( $no_rules ? ( multiedged => 1 ) : () );
618 8         6844 my ( %recipe_cache, %seen );
619 8         17 my $rmfs = $self->{RecursiveMakeFinders};
620 8         20 my $fsmap = $self->fsmap;
621 8         14 my $fr = $fsmap->{file_readable};
622 8         19 my %make_args = (
623             FunctionPackages => $self->function_packages,
624             FSFunctionMap => $fsmap,
625             );
626 8         15 my $InDir = $self->{InDir};
627              
628 8         17 for my $target ( sort $self->targets ) {
629 22 100       932 my $node_name = $no_rules ? $target : name_encode( [ 'target', $target ] );
630 22         69 $g->add_vertex($node_name);
631 22         913 my $rule_no = -1;
632 22         54 my $target_obj = $self->target($target);
633 22         35 for my $rule ( @{ $target_obj->rules } ) {
  22         58  
634 12         19 $rule_no++;
635 12         37 my $recipe = $rule->recipe;
636 12         29 my $recipe_hash = { recipe => $recipe, recipe_raw => $rule->recipe_raw };
637 12         21 my $from_id;
638 12 100       24 if ($no_rules) {
639 6         10 $from_id = $node_name;
640             }
641             else {
642             $from_id = $recipe_cache{$recipe}
643 6   33     46 || ( $recipe_cache{$recipe} = name_encode( [ 'rule', $target, $rule_no ] ) );
644 6         25 $g->set_vertex_attributes( $from_id, $recipe_hash );
645 6         1133 $g->add_edge( $node_name, $from_id );
646             }
647 12         1027 my $prereqs = $rule->prereqs;
648 12 100 100     56 my @to_nodes = ( $no_rules && !@$prereqs ) ? $node_name : @$prereqs;
649 12         25 for my $dep (@to_nodes) {
650 18 100       2050 my $dep_node = $no_rules ? $dep : name_encode( [ 'target', $dep ] );
651 18         54 $g->add_vertex($dep_node);
652 18 100       1074 if ($no_rules) {
653 10         21 my @edge = ( $from_id, $dep_node, $rule_no );
654 10         24 $g->set_edge_attributes_by_id( @edge, $recipe_hash );
655             }
656             else {
657 8         18 $g->add_edge( $from_id, $dep_node );
658             }
659             }
660 12 100       2647 next if !$recursive_make;
661 8         23 for my $t ( _rmf_search_rule( $rule, $target_obj, $target, $rule_no, $rmfs ) ) {
662 4         14 my ( undef, $rule_index, $line, $dir, $makefile, $vars, $targets ) = @$t;
663 4 100       14 my $from = $no_rules ? $target : name_encode( [ 'rule', $target, $rule_index ] );
664 4         18 my $indir_makefile = $self->find_makefile( $makefile, $dir );
665 4 50 33     37 next unless $indir_makefile && $fr->($indir_makefile);
666             ## no critic (BuiltinFunctions::RequireBlockMap)
667 4         32 my $cache_key = join ' ', $indir_makefile, sort map join( '=', @$_ ), @$vars;
668             ## use critic
669 4 50       18 if ( !$seen{$cache_key}++ ) {
670 4         17 my $make2 = ref($self)->new( %make_args, InDir => in_dir( $fsmap, $InDir, $dir ) );
671 4         15 $make2->parse($makefile);
672 4         9 $make2->set_var(@$_) for @$vars;
673 4 50       15 $targets = [ $make2->{Vars}{'.DEFAULT_GOAL'} ] unless @$targets;
674 4         30 my $g2 = $make2->as_graph(%options);
675             $g2->rename_vertices(
676             sub {
677 19 100   19   772 return in_dir( $fsmap, $dir, $_[0] ) if $no_rules;
678 11         16 my ( $type, $name, @other ) = @{ name_decode( $_[0] ) };
  11         19  
679 11         26 name_encode( [ $type, in_dir( $fsmap, $dir, $name ), @other ] );
680             }
681 4         43 );
682 4         180 $g->ingest($g2);
683             }
684 4 100       23818 if ($no_rules) {
685             ## no critic (BuiltinFunctions::RequireBlockMap)
686 2         15 $g->add_edge( $from, $_ ) for map "$dir/$_", @$targets;
687             ## use critic
688             }
689             else {
690             ## no critic (BuiltinFunctions::RequireBlockMap)
691             $g->set_edge_attribute( $from, $_, fromline => $line )
692 2         12 for map name_encode( [ 'target', "$dir/$_" ] ), @$targets;
693             ## use critic
694             }
695             }
696             }
697             }
698 8         863 return $g;
699             }
700              
701             sub apply {
702 5     5 0 47 my ( $self, $method, @args ) = @_;
703 5         37 $self->NextPass;
704 5         17 my ( $vars, $targets ) = parse_args(@args);
705 5         18 $self->set_var(@$_) for @$vars;
706 5 100       22 $targets = [ $self->{Vars}{'.DEFAULT_GOAL'} ] unless @$targets;
707             ## no critic (BuiltinFunctions::RequireBlockGrep BuiltinFunctions::RequireBlockMap)
708 5         25 my @bad_targets = grep !$self->{Depend}{$_}, @$targets;
709 5 50       25 die "Cannot '$method' (@args) - no target @bad_targets" if @bad_targets;
710 5         19 return map $self->target($_)->recurse($method), @$targets;
711             ## use critic
712             }
713              
714             # Spew a shell script to perfom the 'make' e.g. make -n
715             sub Script {
716 0     0 1 0 my ( $self, @args ) = @_;
717 0 0       0 my $com = ( $^O eq 'MSWin32' ) ? 'rem ' : '# ';
718 0         0 my @results;
719 0         0 for ( $self->apply( Make => @args ) ) {
720 0         0 my ( $name, @cmd ) = @$_;
721 0         0 push @results, $com . $name . "\n";
722             ## no critic (BuiltinFunctions::RequireBlockMap)
723 0         0 push @results, map parse_cmdline($_)->{line} . "\n", @cmd;
724             ## use critic
725             }
726 0         0 return @results;
727             }
728              
729             sub Print {
730 0     0 1 0 my ( $self, @args ) = @_;
731 0         0 return $self->apply( Print => @args );
732             }
733              
734             sub Make {
735 5     5 1 1669 my ( $self, @args ) = @_;
736 5         22 for ( $self->apply( Make => @args ) ) {
737 12         114 my ( $name, @cmd ) = @$_;
738 12         96 $self->exec($_) for @cmd;
739             }
740 5         260 return;
741             }
742              
743             sub new {
744 11     11 1 19433 my ( $class, %args ) = @_;
745 11         325 my $self = bless {
746             Pattern => {}, # GNU style %.o : %.c
747             Dot => {}, # Trad style .c.o
748             Vpath => {}, # vpath %.c info
749             Vars => {}, # Variables defined in makefile
750             Depend => {}, # hash of targets
751             Pass => 0, # incremented each sweep
752             Done => {},
753             FunctionPackages => [qw(Make::Functions)],
754             FSFunctionMap => \%fs_function_map,
755             RecursiveMakeFinders => \@RECMAKE_FINDS,
756             %args,
757             }, $class;
758 11         189 $self->set_var( 'CC', $Config{cc} );
759 11         50 $self->set_var( 'AR', $Config{ar} );
760 11         44 $self->set_var( 'CFLAGS', $Config{optimize} );
761 11         23 load_modules( @{ $self->function_packages } );
  11         54  
762 11   66     64 $DEFAULTS_AST ||= parse_makefile( \*DATA );
763 11         97 $self->process_ast_bit(@$_) for @$DEFAULTS_AST;
764 11         52 return $self;
765             }
766              
767             =head1 NAME
768              
769             Make - Pure-Perl implementation of a somewhat GNU-like make.
770              
771             =head1 SYNOPSIS
772              
773             require Make;
774             my $make = Make->new;
775             $make->parse($file)->Make(@ARGV);
776              
777             # to see what it would have done
778             print $make->Script(@ARGV);
779              
780             # to see an expanded version of the makefile
781             $make->Print(@ARGV);
782              
783             my $targ = $make->target($name);
784             my $rule = Make::Rule->new(':', \@prereqs, \@recipe, \@recipe_raw);
785             $targ->add_rule($rule);
786             my @rules = @{ $targ->rules };
787              
788             my @prereqs = @{ $rule->prereqs };
789             my @commands = @{ $rule->recipe };
790              
791             =head1 DESCRIPTION
792              
793             Implements in pure Perl a somewhat GNU-like make, intended to be highly
794             customisable.
795              
796             Via pure-perl-make Make has built perl/Tk from the C generated
797             Makefiles...
798              
799             =head1 MAKEFILE SYNTAX
800              
801             Broadly, there are macros, directives, and rules (including recipes).
802              
803             Macros:
804              
805             varname = value
806              
807             Directives:
808              
809             vpath %.c src/%.c
810             [-]include otherfile.mk # - means no warn on failure to include
811              
812             Please note the C does not have the GNU-make behaviour of
813             discarding the found path if an inferred target must be rebuilt, since
814             this is too non-deterministic / confusing behaviour for this author.
815              
816             Rules:
817              
818             target : prerequisite1 prerequisite2[; immediate recipe]
819             (tab character)follow-on recipe...
820              
821             Recipe lines can start with C<@> (do not echo), C<-> (continue on failure).
822              
823             In addition to traditional
824              
825             .c.o :
826             $(CC) -c ...
827              
828             GNU make's 'pattern' rules e.g.
829              
830             %.o : %.c
831             $(CC) -c ...
832              
833             The former gets internally translated to the latter.
834              
835             =head1 METHODS
836              
837             There are other methods (used by parse) which can be used to add and
838             manipulate targets and their prerequites.
839              
840             =head2 new
841              
842             Class method, takes pairs of arguments in name/value form. Arguments:
843              
844             =head3 Vars
845              
846             A hash-ref of values that sets variables, overridable by the makefile.
847              
848             =head3 Jobs
849              
850             Number of concurrent jobs to run while building. Not implemented.
851              
852             =head3 GNU
853              
854             If true, then F is looked for first.
855              
856             =head3 FunctionPackages
857              
858             Array-ref of package names to search for GNU-make style
859             functions. Defaults to L.
860              
861             =head3 FSFunctionMap
862              
863             Hash-ref of file-system functions by which to access the
864             file-system. Created to help testing, but might be more widely useful.
865             Defaults to code accessing the actual local filesystem. The various
866             functions are expected to return real Perl filehandles. Relevant keys:
867             C, C, C, C, C,
868             C.
869              
870             =head3 InDir
871              
872             Optional. If supplied, will be treated as the current directory instead
873             of the default which is the real current directory.
874              
875             =head3 RecursiveMakeFinders
876              
877             Array-ref of functions to be called in order, searching an expanded
878             recipe line for a recursive make invocation (cf
879             L)
880             that would run a C in a subdirectory. Each returns either an empty
881             list, or
882              
883             ($dir, $makefile, $vars, $targets)
884              
885             The C<$makefile> might be , in which case the default will be
886             searched for. C<$vars> and C<$targets> are array-refs of pairs and
887             strings, respectively. The C<$targets> can be empty.
888              
889             Defaults to a single, somewhat-suitable, function.
890              
891             =head2 parse
892              
893             Parses the given makefile. If none or C, these files will be tried,
894             in order: F if L, F, F.
895              
896             If a scalar-ref, will be makefile text.
897              
898             Returns the make object for chaining.
899              
900             =head2 Make
901              
902             Given a target-name, builds the target(s) specified, or the first 'real'
903             target in the makefile.
904              
905             =head2 Print
906              
907             Print to current C
908             variables expanded.
909              
910             =head2 Script
911              
912             Print to current C
913             that a make would perform i.e. the output of C.
914              
915             =head2 set_var
916              
917             Given a name and value, sets the variable to that.
918              
919             May gain a "type" parameter to distinguish immediately-expanded from
920             recursively-expanded (the default).
921              
922             =head2 expand
923              
924             Uses L to return its only arg with any macros expanded.
925              
926             =head2 target
927              
928             Find or create L for given target-name.
929              
930             =head2 has_target
931              
932             Returns boolean on whether the given target-name is known to this object.
933              
934             =head2 targets
935              
936             List all "real" (non-dot, non-inference) target-names known to this object
937             at the time called, unsorted. Note this might change when C is
938             called, as targets will be added as part of the dependency-search process.
939              
940             =head2 patrule
941              
942             Search registered pattern-rules for one matching given
943             target-name. Returns a L for that of the given kind, or false.
944              
945             Uses GNU make's "exists or can be made" algorithm on each rule's proposed
946             requisite to see if that rule matches.
947              
948             =head2 find_recursive_makes
949              
950             my @found = $make->find_recursive_makes;
951              
952             Iterate over all the rules, expanding them for their targets, and find
953             any recursive make invocations using the L.
954              
955             Returns a list of array-refs with:
956              
957             [ $from_target, $rule_index, $line_index, $dir, $makefile, $vars, $targets ]
958              
959             =head1 ATTRIBUTES
960              
961             These are read-only.
962              
963             =head2 vars
964              
965             Returns a hash-ref of the current set of variables.
966              
967             =head2 function_packages
968              
969             Returns an array-ref of the packages to search for macro functions.
970              
971             =head2 fsmap
972              
973             Returns a hash-ref of the L.
974              
975             =head2 as_graph
976              
977             Returns a L object representing the makefile.
978             Takes options as a hash:
979              
980             =head3 recursive_make
981              
982             If true (default false), uses L to find recursive
983             make invocations in the current makefile, parses those, then includes
984             them, with an edge created to the relevant target.
985              
986             =head3 no_rules
987              
988             If true, the graph will only have target vertices, but will be
989             "multiedged". The edges will have an ID of the zero-based index of the
990             rule on the predecessor target, and will have attributes C
991             and C. Rules with no prerequisites will be indicated with
992             an edge back to the same target.
993              
994             If false (the default), the vertices are named either C
995             (representing Ls) or C (representing
996             Ls). The names encoded with L. Rules are named
997             according to the first (alphabetically) target they are attached to.
998              
999             The rule vertices have attributes with the same values as the
1000             L attributes:
1001              
1002             =over
1003              
1004             =item recipe
1005              
1006             =item recipe_raw
1007              
1008             =back
1009              
1010             =head1 FUNCTIONS
1011              
1012             =head2 name_encode
1013              
1014             =head2 name_decode
1015              
1016             my $encoded = Make::name_encode([ 'target', 'all' ]);
1017             my $tuple = Make::name_decode($encoded); # [ 'target', 'all' ]
1018              
1019             Uses C<%>-encoding and -decoding to allow C<%> and C<:> characters in
1020             components without problems.
1021              
1022             =head2 parse_makefile
1023              
1024             Given a file-handle, returns array-ref of Abstract Syntax-Tree (AST)
1025             fragments, representing the contents of that file. Each is an array-ref
1026             whose first element is the node-type (C, C, C,
1027             C, C), followed by relevant data.
1028              
1029             =head2 tokenize
1030              
1031             Given a line, returns array-ref of the space-separated "tokens". Also
1032             splits on any further args.
1033              
1034             =head2 subsvars
1035              
1036             my $expanded = Make::subsvars(
1037             'hi $(shell echo there)',
1038             \@function_packages,
1039             [ \%vars ],
1040             $fsmap,
1041             );
1042             # "hi there"
1043              
1044             Given a piece of text, will substitute any macros in it, either a
1045             single-character macro, or surrounded by either C<{}> or C<()>. These
1046             can be nested. Uses the array-ref as a list of hashes to search
1047             for values.
1048              
1049             If the macro is of form C<$(varname:a=b)>, then this will be a GNU
1050             (and others) make-style "substitution reference". First "varname" will
1051             be expanded. Then all occurrences of "a" at the end of words within
1052             the expanded text will be replaced with "b". This is intended for file
1053             suffixes.
1054              
1055             For GNU-make style functions, see L.
1056              
1057             =head1 DEBUGGING
1058              
1059             To see debugging messages on C, set environment variable
1060             C to a true value;
1061              
1062             =head1 BUGS
1063              
1064             More attention needs to be given to using the package to I makefiles.
1065              
1066             The rules for matching 'dot rules' e.g. .c.o and/or pattern rules e.g. %.o : %.c
1067             are suspect. For example give a choice of .xs.o vs .xs.c + .c.o behaviour
1068             seems a little odd.
1069              
1070             =head1 SEE ALSO
1071              
1072             L
1073              
1074             L POSIX standard for make
1075              
1076             L GNU make docs
1077              
1078             =head1 AUTHOR
1079              
1080             Nick Ing-Simmons
1081              
1082             =head1 COPYRIGHT AND LICENSE
1083              
1084             Copyright (c) 1996-1999 Nick Ing-Simmons.
1085              
1086             This program is free software; you can redistribute it and/or
1087             modify it under the same terms as Perl itself.
1088              
1089             =cut
1090              
1091             1;
1092             #
1093             # Remainder of file is in makefile syntax and constitutes
1094             # the built in rules
1095             #
1096             __DATA__