package Makefile::AST::Rule; use strict; use warnings; #use Smart::Comments; use base 'Makefile::AST::Rule::Base'; use Makefile::AST::Command; use List::MoreUtils; __PACKAGE__->mk_accessors(qw{ stem target other_targets shell }); # XXX: generate description for the rule sub as_str ($) { my $self = shift; my $order_part = ''; ## as_str: order_prereqs: $self->order_prereqs if (@{ $self->order_prereqs }) { $order_part = " | " . join(" ",@{ $self->order_prereqs }); } ### colon: $self->colon my $str = $self->target . " " . $self->colon . " " . join(" ", @{ $self->normal_prereqs }) . "$order_part ; " . join("", map { "[$_]" } @{ $self->commands }); $str =~ s/\n+//g; $str =~ s/ +/ /g; $str; } sub prepare_command ($$) { my ($self, $ast, $raw_cmd, $silent, $tolerant, $critical) = @_; ## $raw_cmd my @tokens = $raw_cmd->elements; # try to recognize modifiers: my $modifier; while (@tokens) { if ($tokens[0]->class eq 'MDOM::Token::Whitespace') { shift @tokens; next; } last unless $tokens[0]->class eq 'MDOM::Token::Modifier'; $modifier = shift @tokens; if ($modifier eq '+') { # XXX is this the right thing to do? $critical = 1; } elsif ($modifier eq '-') { $tolerant = 1; } elsif ($modifier eq '@') { $silent = 1; } else { die "Unknown modifier: $modifier"; } } local $. = $raw_cmd->lineno; ## TOKENS (BEFORE): @tokens my $cmd = $ast->solve_refs_in_tokens(\@tokens); ### cmd after solve (1): $cmd $cmd =~ s/^\s+|\s+$//gs; return () if $cmd =~ /^(\\\n)*\\?$/s; ### cmd after modifier extraction: $cmd ### critical (+): $critical ### tolerant (-): $tolerant ### silent (@): $silent if ($cmd =~ /(?new; $cmd->__add_elements(@tokens); # XXX upper-level's modifiers should take in # effect in the recursive calls: push @ast_cmds, $self->prepare_command($ast, $cmd, $silent, $tolerant, $critical); } return @ast_cmds; } while (1) { if ($cmd =~ s/^\s*\+//) { # XXX is this the right thing to do? $critical = 1; } elsif ($cmd =~ s/^\s*-//) { $tolerant = 1; } elsif ($cmd =~ s/^\s*\@//) { $silent = 1; } else { last; } } $cmd =~ s/^\s+|\s+$//gs; return () if $cmd =~ /^(\\\n)*\\?$/s; return Makefile::AST::Command->new({ silent => $silent, tolerant => $tolerant, critical => $critical, content => $cmd, target => $self->target, }); } sub prepare_commands ($$) { my ($self, $ast) = @_; my @normal_prereqs = @{ $self->normal_prereqs }; my @order_prereqs = @{ $self->order_prereqs }; ## @normal_prereqs ## @order_prereqs ### run_commands: target: $self->target ### run_commands: Stem: $self->stem $self->shell($ast->eval_var_value('SHELL')); $ast->enter_pad; $ast->add_auto_var( '@' => [$self->target], '<' => [$normal_prereqs[0]], # XXX better solutions? '*' => [$self->stem], '^' => [join(" ", List::MoreUtils::uniq(@normal_prereqs))], '+' => [join(" ", @normal_prereqs)], '|' => [join(" ", List::MoreUtils::uniq(@order_prereqs))], # XXX add more automatic vars' defs here ); ### auto $*: $ast->get_var('*') my @ast_cmds; for my $cmd (@{ $self->commands }) { $Makefile::AST::Evaluator::CmdRun = 1; push @ast_cmds, $self->prepare_command($ast, $cmd); } $ast->leave_pad; return @ast_cmds; } sub run_command ($$) { my ($self, $ast_cmd) = @_; my $cmd = $ast_cmd->content; if (!$Makefile::AST::Evaluator::Quiet && (!$ast_cmd->silent || $Makefile::AST::Evaluator::JustPrint)) { print "$cmd\n"; } if (! $Makefile::AST::Evaluator::JustPrint) { system($self->shell, '-c', $cmd); if ($? != 0) { my $retval = $? >> 8; my $target = $ast_cmd->target; if (!$Makefile::AST::Evaluator::IgnoreErrors && (!$ast_cmd->tolerant || $ast_cmd->critical)) { # XXX better handling for tolerance die "$::MAKE: *** [$target] Error $retval\n"; } else { warn "$::MAKE: [$target] Error $retval (ignored)\n"; } } } } sub run_commands ($@) { my $self = shift; for my $ast_cmd (@_) { $self->run_command($ast_cmd); } } 1;