makepp
view release on metacpan or search on metacpan
Mpp/Lexer.pm view on Meta::CPAN
my $ix = find_unquoted $command, ' ';
# Look for the next whitespace.
$ix >= 0 or $ix = find_unquoted $command, "\t";
# Oops, it must be a tab.
$ix >= 0 or last; # Can't find the end. It must be a simple assignment.
$env{$var} = substr $command, 0, $ix, ''; # Chop off the environment variable's value.
$command =~ s/^\s+//;
}
# TBD: expand and/or parse back-quotes
# Deal with cd commands and set $dir
if( my( $reldir ) = $command =~ m|^\s*cd\s+([-+=@%^\w:,./]+)\s*|) {
$dir = $reldir =~ m|^/| ? $reldir : $dir . '/' . $reldir;
next;
}
unless($command =~ /^\s*$/) {
local $rule->{PARSER} if $p_shell; # Special recursion brake set by find_command_parser's p_shell handling.
my $found = $_[0]->parse_command( $command, $rule, $dir, \%env );
return undef unless defined $found;
$found == 1 and ++$parsers_found;
}
}
} continue {
last unless @actions;
($p_shell, undef, $command, $action) = splice @actions, 0, 4;
$p_shell = ref $p_shell;
}
#
# We want to try to avoid the case where because of some quirk in the command,
# we failed to find a scanner. Scanners are especially important for
# C/C++ compilation. See if this rule looks like it's some sort of a
# compile:
#
if( $parsers_found == 0 ) { # No parsers found at all?
my $tinfo = $rule->{EXPLICIT_TARGETS}[0];
if( ref($tinfo) eq 'Mpp::File' && # Target is a file?
$tinfo->{NAME} =~ /\.l?o$/ ) { # And it's an object file?
my $deps = $rule->{ALL_DEPENDENCIES};
if( grep { 'Mpp::File' eq ref && $_->{NAME} =~ /\.c(?:|xx|\+\+|c|pp)$/i } values %$deps ) {
# Looks like C source code?
warn $rule->source, ": no command parser found,\nalthough this seems to be a compilation command. This means that makepp will
not detect any include files. To specify a parser for the whole rule,
add a :parser modifier line to the rule actions, like this:
: parser gcc-compilation # Scans source for include files.
or
: parser none # Does not scan, but suppresses warning.
Or to do it on a per command basis, if you have such obscure commands:
register-parser my_obscure_cc_wrapper skip-word
register-parser my_obscure_cc c-compilation
" unless $parser_warnings{$rule->source}++;
}
}
}
1;
}
=head2 parse_command
$lexer->parse_command($command, $rule, $dir, $setenv_hash, \$found);
Parse $command as if it is executed in directory $dir (relative to
$rule->build_cwd), and update $rule accordingly.
$setenv_hash is the environmental settings that are set by the rule itself,
with shell variables I<not> expanded.
In this base class, calls find_command_parser to determine which command
parser to use.
If the result is FALSE, then do nothing more. (This can't
happen for an object of the base class, since we always use a
plain Mpp/CommandParser.)
Otherwise, the resulting object's parse_command method is called, and
we return that method's return value.
Return value is TRUE on success, zero if no meaningful command parsing was
performed, and undefined if a metadependency failed to build or if scanning
failed.
=cut
sub parse_command {
my $command = $_[1]; # modified by skip-word
my $found = 0;
if( my $command_parser = $_[0]->find_command_parser($command, $_[2], $_[3] || '.', \$found) ) {
return unless
defined( ref $command_parser ?
$command_parser->parse_command($command, $_[4] || {}) :
$command_parser );
}
$found;
}
=head2 find_command_parser
my $command_parser=$lexer->find_command_parser($command, $rule, $dir, \$found);
The first word of $command is looked up in %parsers from the Makeppfile's namespace.
If it isn't found, then undef is returned.
Otherwise, the resulting coderef is called with the command, rule and directory.
If the return value is a reference to an object of type Mpp::CommandParser,
then it is returned.
Otherwise, 0 is returned.
There is no way to indicate a scanning failure if 0 is returned, for
backward compatibility.
=cut
sub find_command_parser {
my( undef, $command, $rule, $dir, $found ) = @_;
my $parser;
my $from_rule = $rule->{PARSER};
my( $firstword, @rest ) = split_on_whitespace $command;
until( defined $parser ) {
if( $from_rule ) {
$parser = $from_rule;
$from_rule = 0; # Only 1st word, not again after skip-word
} else {
if( Mpp::is_windows < 2 && $firstword =~ /['"\\]/ ) {
$firstword = unquote $firstword;
} elsif( Mpp::is_windows > 1 && $firstword =~ /"/ ) {
$firstword =~ tr/"//d; # Don't unquote \, which is Win dir separator
}
if( defined $firstword ) {
no strict 'refs';
( run in 1.476 second using v1.01-cache-2.11-cpan-39bf76dae61 )