Hide Show 32 lines of Pod
use
Mpp::Text
qw(index_ignoring_quotes split_on_whitespace requote
unquote unquote_split_on_whitespace format_exec_args)
;
our
(
$makefile
,
$makefile_line
);
sub
eval_or_die($$$) {
my
$code
=
$_
[0];
local
(
undef
,
$makefile
,
$makefile_line
) =
@_
;
(
my
$line
=
$makefile_line
) =~ s/(.+):(\d+)(?:\(.+\))?$/
&touched_filesystem
;
$code
=
qq{
no strict; package $makefile->{PACKAGE}
;
\
@Cxt
=(\
$Mpp::Subs::makefile
, \
$Mpp::Subs::makefile_line
);
$line
$code
};
if
(
wantarray
) {
my
@result
=
eval
$code
;
&touched_filesystem
;
die
$@
if
$@;
@result
;
}
elsif
(
defined
wantarray
) {
my
$result
=
eval
$code
;
&touched_filesystem
;
die
$@
if
$@;
$result
;
}
else
{
eval
$code
;
&touched_filesystem
;
die
$@
if
$@;
}
}
our
$rule
;
our
@system_include_dirs
=
grep
-d,
qw(/usr/local/include /usr/include)
;
our
@system_lib_dirs
=
grep
-d,
qw(/usr/local/lib /usr/lib /lib)
;
sub
p_gcc_compilation {
shift
;
Mpp::CommandParser::Gcc->new(
@_
);
}
*scanner_gcc_compilation
= \
&p_gcc_compilation
;
sub
p_c_compilation {
shift
;
Mpp::CommandParser::Gcc->new_no_gcc(
@_
);
}
*scanner_c_compilation
= \
&p_c_compilation
;
sub
p_esql_compilation {
shift
;
Mpp::CommandParser::Esql->new(
@_
);
}
*scanner_esql_compilation
= \
&p_esql_compilation
;
sub
p_vcs_compilation {
shift
;
Mpp::CommandParser::Vcs->new(
@_
);
}
*scanner_vcs_compilation
= \
&p_vcs_compilation
;
sub
p_swig {
shift
;
Mpp::CommandParser::Swig->new(
@_
);
}
*scanner_swig
= \
&p_swig
;
sub
scanner_none {
$_
[1]{SCANNER_NONE} = 1;
shift
;
Mpp::CommandParser->new(
@_
);
}
sub
scanner_skip_word {
my
(
$action
) =
@_
;
$action
=~ s/^\s+//;
while
(
$action
=~ s/^\S+\s+//) {
$action
=~ s/^([\"\
'\(])//; # Strip off leading quotes in case it'
s
if
(
defined
$1 ) {
my
$compl
= ${{
qw!" " ' ' ( \)!
}}{$1};
$action
=~ s/
$compl
//;
}
next
if
$action
=~ /^-/;
local
$_
[1]{LEXER}
if
$_
[1]{LEXER};
local
$_
[1]{LEXER_OBJ}
if
$_
[1]{LEXER_OBJ};
my
$lexer
= new Mpp::Lexer;
$_
[1]{SCANNER_NONE} = 1
if
Mpp::Lexer::parse_command(
$lexer
,
$action
,
$_
[1],
$_
[2],
$_
[1]{MAKEFILE}{ENVIRONMENT} );
last
;
}
new Mpp::Lexer;
}
(
*p_none
,
*p_skip_word
,
*p_shell
) =
@Mpp::Text::N
;
our
%parsers
=
(
ash
=> \
&p_shell
,
bash
=> \
&p_shell
,
csh
=> \
&p_shell
,
ksh
=> \
&p_shell
,
sh
=> \
&p_shell
,
tcsh
=> \
&p_shell
,
zsh
=> \
&p_shell
,
eval
=> \
&p_shell
,
ccache
=> \
&p_skip_word
,
condor_compile
=> \
&p_skip_word
,
cpptestscan
=> \
&p_skip_word
,
diet
=> \
&p_skip_word
,
distcc
=> \
&p_skip_word
,
fast_cc
=> \
&p_skip_word
,
libtool
=> \
&p_skip_word
,
purecov
=> \
&p_skip_word
,
purify
=> \
&p_skip_word
,
quantify
=> \
&p_skip_word
,
time
=> \
&p_skip_word
,
aCC
=> \
&p_c_compilation
,
bcc32
=> \
&p_c_compilation
,
c89
=> \
&p_c_compilation
,
c99
=> \
&p_c_compilation
,
cc
=> \
&p_c_compilation
,
CC
=> \
&p_c_compilation
,
ccppc
=> \
&p_c_compilation
,
clang
=> \
&p_c_compilation
,
cl
=> \
&p_c_compilation
,
'c++'
=> \
&p_c_compilation
,
cpp
=> \
&p_c_compilation
,
cxppc
=> \
&p_c_compilation
,
cxx
=> \
&p_c_compilation
,
icc
=> \
&p_c_compilation
,
icl
=> \
&p_c_compilation
,
ingcc
=> \
&p_c_compilation
,
insure
=> \
&p_c_compilation
,
kcc
=> \
&p_c_compilation
,
lsbcc
=> \
&p_c_compilation
,
'lsbc++'
=> \
&p_c_compilation
,
pcc
=> \
&p_c_compilation
,
xlC
=> \
&p_c_compilation
,
xlc
=> \
&p_c_compilation
,
xlc_r
=> \
&p_c_compilation
,
xlC_r
=> \
&p_c_compilation
,
vcs
=> \
&p_vcs_compilation
,
apre
=> \
&p_esql_compilation
,
db2
=> \
&p_esql_compilation
,
dmppcc
=> \
&p_esql_compilation
,
ecpg
=> \
&p_esql_compilation
,
esql
=> \
&p_esql_compilation
,
esqlc
=> \
&p_esql_compilation
,
gpre
=> \
&p_esql_compilation
,
proc
=> \
&p_esql_compilation
,
yardpc
=> \
&p_esql_compilation
,
swig
=> \
&p_swig
);
@parsers
{
map
"$_.exe"
,
keys
%parsers
} =
values
%parsers
if
Mpp::is_windows;
sub
relative_filenames {
my
@ret_vals
;
my
$cwd
=
$rule
->build_cwd;
foreach
(
@_
) {
next
unless
defined
;
push
@ret_vals
, (
ref
() eq
'ARRAY'
) ? relative_filenames(
@$_
) : relative_filename
$_
,
$cwd
;
}
@ret_vals
;
}
our
%perl_unfriendly_symbols
=
(
'@'
=> \
&f_target
,
'<'
=> \
&f_dependency
,
'^'
=> \
&f_dependencies
,
'?'
=> \
&f_changed_dependencies
,
'+'
=> \
&f_sorted_dependencies
,
'*'
=> \
&f_stem
,
'&'
=>
''
,
'/'
=> Mpp::is_windows > 1 ?
'\\'
:
'/'
,
'@D'
=> \
&f_target
,
'@F'
=> \
&f_target
,
'*D'
=> \
&f_stem
,
'*F'
=> \
&f_stem
,
'<D'
=> \
&f_dependency
,
'<F'
=> \
&f_dependency
,
'^D'
=> \
&f_dependencies
,
'^F'
=> \
&f_dependencies
);
sub
arg {
$_
[1] &&
ref
$_
[0] ?
$_
[1]->expand_text( ${
$_
[0]},
$_
[2] ) :
$_
[0] }
sub
args {
local
$_
=
ref
$_
[0] ? ${
$_
[0]} :
$_
[0];
my
$max
=
$_
[3] || 2;
my
$min
= (
$_
[4] or
$max
== ~0 ? 1 :
$max
) - 1;
pos
= 0;
while
(
length
() >
pos
) {
/\G[^,\$]+/gc;
if
( /\G,/gc ) {
--
$min
if
$min
;
last
unless
--
$max
;
my
$pos
=
pos
;
substr
$_
,
$pos
- 1, 1,
"\01"
;
pos
=
$pos
;
}
elsif
( /\G\$/gc ) {
&Mpp::Text::skip_over_make_expression
;
}
}
tr
/\01/,/,
die
$_
[2] ||
'somewhere'
,
': $('
, (
caller
1)[3],
" $_) $min more arguments expected\n"
if
$min
;
$_
=
$_
[1]->expand_text(
$_
,
$_
[2] )
if
$_
[1] &&
ref
$_
[0] && /\$/;
$_
[5] ?
split
"\01"
,
$_
, -1 :
split
/\s*\01\s*/,
$_
, -1;
}
sub
f_absolute_filename {
my
$cwd
=
$_
[1] &&
$_
[1]{CWD};
join
' '
,
map
absolute_filename( file_info unquote(),
$cwd
),
split_on_whitespace
&arg
;
}
*f_abspath
= \
&f_absolute_filename
;
sub
f_absolute_filename_nolink {
my
$cwd
=
$_
[1]{CWD};
join
' '
,
map
absolute_filename_nolink( file_info unquote(),
$cwd
),
split_on_whitespace
&arg
;
}
*f_realpath
= \
&f_absolute_filename_nolink
;
sub
f_addprefix {
my
(
$prefix
,
$text
) = args
$_
[0],
$_
[1],
$_
[2], 2, 2, 1;
join
' '
,
map
"$prefix$_"
,
split
' '
,
$text
;
}
sub
f_addsuffix {
my
(
$suffix
,
$text
) = args
$_
[0],
$_
[1],
$_
[2], 2, 2, 1;
join
' '
,
map
"$_$suffix"
,
split
' '
,
$text
;
}
sub
f_and {
my
$ret
=
''
;
for
my
$cond
( args
$_
[0],
undef
,
$_
[2], ~0 ) {
$ret
=
$_
[1] &&
ref
$_
[0] ?
$_
[1]->expand_text(
$cond
,
$_
[2] ) :
$cond
;
return
''
unless
length
$ret
;
}
$ret
;
}
sub
f_or {
for
my
$cond
( args
$_
[0],
undef
,
$_
[2], ~0 ) {
$cond
=
$_
[1]->expand_text(
$cond
,
$_
[2] )
if
$_
[1] &&
ref
$_
[0];
return
$cond
if
length
$cond
;
}
''
;
}
sub
f_basename {
join
' '
,
map
{ s!\.[^./,]*$!!;
$_
}
split
' '
,
&arg
;
}
our
$call_args
= 1;
sub
f_call {
my
@args
= args
$_
[0],
$_
[1],
$_
[2], ~0, 1, 1;
local
@perl_unfriendly_symbols
{0..(
$#args
>
$call_args
?
$#args
:
$call_args
)} =
@args
; # assign to $0, $1, $2...
local
$call_args
=
$#args
;
$_
[1]->expand_variable(
$args
[0],
$_
[2] );
}
sub
f_dir {
join
' '
,
map
{ m@^(.*/)@ ? $1 :
'./'
}
split
' '
,
&arg
;
}
sub
f_dir_noslash {
join
' '
,
map
{ m@^(.*)/@ ? $1 :
'.'
}
split
' '
,
&arg
;
}
sub
f_error {
die
"$_[2]: *** "
.
&arg
.
"\n"
;
}
sub
f_filesubst {
my
(
$src
,
$dest
,
$words
) = args
$_
[0],
$_
[1],
$_
[2], 3;
my
$cwd
=
$_
[1]{CWD};
my
$startdir
= (
$src
=~ s@^/+@@) ?
$Mpp::File::root
:
$cwd
;
while
(
$src
=~ s@([^%/]+)/+@@) {
$startdir
= dereference file_info $1,
$startdir
;
}
my
@words
;
foreach
(
split
' '
,
$words
) {
my
$thisdir
= (s@^/+@@) ?
$Mpp::File::root
:
$cwd
;
$thisdir
= dereference file_info $1,
$thisdir
while
$thisdir
!=
$startdir
&& s@([^/]+)/+@@;
push
@words
, case_sensitive_filenames ?
$_
:
lc
;
}
join
' '
, Mpp::Text::pattern_substitution( case_sensitive_filenames ?
$src
:
lc
$src
,
$dest
,
@words
);
}
sub
f_filter {
my
(
$filters
,
$words
) = args
$_
[0],
$_
[1],
$_
[2];
my
@filters
=
split
' '
,
$filters
;
foreach
(
@filters
) {
s/([.+()])/\\$1/g;
s/[*%]/\.\*/g;
$_
=
qr/^$_$/
;
}
my
@ret_words
;
wordloop:
foreach
(
split
' '
,
$words
) {
foreach
my
$filter
(
@filters
) {
if
(/
$filter
/) {
push
@ret_words
,
$_
;
next
wordloop;
}
}
}
join
' '
,
@ret_words
;
}
sub
f_filter_out {
my
(
$filters
,
$words
) = args
$_
[0],
$_
[1],
$_
[2];
my
@filters
=
split
' '
,
$filters
;
foreach
(
@filters
) {
s/([.+()])/\\$1/g;
s/[*%]/\.\*/g;
$_
=
qr/^$_$/
;
}
my
@ret_words
;
wordloop:
foreach
(
split
' '
,
$words
) {
foreach
my
$filter
(
@filters
) {
next
wordloop
if
/
$filter
/;
}
push
@ret_words
,
$_
;
}
join
' '
,
@ret_words
;
}
sub
f_filter_out_dirs {
join
' '
,
grep
{ !is_or_will_be_dir file_info
$_
,
$_
[1]{CWD} }
split
' '
,
&arg
;
}
sub
f_find_program {
my
$mkfile
=
$_
[1];
my
@pathdirs
;
my
$first_round
= 1;
foreach
my
$name
(
split
' '
,
&arg
) {
if
(
$name
=~ /\// || Mpp::is_windows > 1 &&
$name
=~ /\\/ ) {
my
$finfo
= path_file_info
$name
,
$mkfile
->{CWD};
my
$exists
= Mpp::File::exists_or_can_be_built
$finfo
;
if
( Mpp::is_windows &&
$name
!~ /\.exe$/ ) {
my
(
$exists_exe
,
$finfo_exe
);
$exists_exe
= Mpp::File::exists_or_can_be_built
$finfo_exe
= Mpp::File::path_file_info
"$name.exe"
,
$mkfile
->{CWD}
if
!
$exists
||
$_
[3] &&
$Mpp::File::stat_exe_separate
? !
exists
$finfo
->{xEXISTS} : !
open
my
$fh
,
'<'
, absolute_filename
$finfo
;
return
$_
[3] ? absolute_filename(
$finfo_exe
) :
$name
if
$exists_exe
;
}
return
$_
[3] ? absolute_filename(
$finfo
) :
$name
if
$exists
;
next
;
}
@pathdirs
= Mpp::Text::split_path(
$mkfile
->{EXPORTS} )
unless
@pathdirs
;
foreach
my
$dir
(
@pathdirs
) {
if
(
$first_round
) {
$dir
= path_file_info
$dir
,
$mkfile
->{CWD};
undef
$dir
unless
is_or_will_be_dir
$dir
;
}
next
unless
$dir
;
my
$finfo
= file_info
$name
,
$dir
;
my
$exists
= Mpp::File::exists_or_can_be_built
$finfo
,
undef
,
undef
, 1;
if
( Mpp::is_windows &&
$name
!~ /\.exe$/ ) {
my
(
$exists_exe
,
$finfo_exe
);
$exists_exe
= Mpp::File::exists_or_can_be_built
$finfo_exe
= file_info(
"$name.exe"
,
$dir
),
undef
,
undef
, 1
if
!
$exists
||
$_
[3] &&
$Mpp::File::stat_exe_separate
? !
exists
$finfo
->{xEXISTS} : !
open
my
$fh
,
'<'
, absolute_filename
$finfo
;
return
$_
[3] ? absolute_filename(
$finfo_exe
) :
$name
if
$exists_exe
;
}
return
$_
[3] ? absolute_filename(
$finfo
) :
$name
if
$exists
;
}
$first_round
= 0;
}
Mpp::
log
NOT_FOUND
=>
ref
$_
[0] ? ${
$_
[0]} :
$_
[0],
$_
[2];
'not-found'
;
}
sub
f_findfile {
my
(
$name
,
$path
) = args
$_
[0],
$_
[1],
$_
[2];
my
$mkfile
=
$_
[1];
my
@pathdirnames
=
$path
?
split
( /\s+|:/,
$path
) :
Mpp::Text::split_path(
$mkfile
->{EXPORTS} );
my
@names
=
split
' '
,
$name
;
foreach
$name
(
@names
) {
foreach
my
$dir
(
@pathdirnames
) {
my
$finfo
= file_info
$name
, file_info
$dir
,
$mkfile
->{CWD};
if
( file_exists
$finfo
) {
$name
= absolute_filename
$finfo
;
last
;
}
}
}
join
' '
,
@names
;
}
sub
f_find_upwards {
my
$cwd
=
$_
[1] &&
$_
[1]{CWD};
my
@ret_names
;
my
$cwd_devid
;
for
( split_on_whitespace
&arg
) {
$_
= unquote;
my
$found
;
my
$dirinfo
=
$cwd
;
while
( 1 ) {
my
$finfo
= file_info
$_
,
$dirinfo
;
if
( Mpp::File::exists_or_can_be_built
$finfo
) {
$found
= 1;
push
@ret_names
, relative_filename
$finfo
,
$cwd
;
last
;
}
last
unless
$dirinfo
=
$dirinfo
->{
'..'
};
last
if
(stat_array
$dirinfo
)->[Mpp::File::STAT_DEV] !=
(
$cwd_devid
||= (stat_array
$cwd
)->[Mpp::File::STAT_DEV]);
}
$found
or
die
"find_upwards: cannot find file $_\n"
;
}
join
' '
,
@ret_names
;
}
sub
f_find_first_upwards {
my
@fnames
= unquote_split_on_whitespace
&arg
;
my
$cwd
=
$_
[1] &&
$_
[1]{CWD};
my
$cwd_devid
;
my
$dirinfo
=
$cwd
;
while
( 1 ) {
for
(
@fnames
) {
my
$finfo
= file_info
$_
,
$dirinfo
;
return
$_
[3] ?
$finfo
: relative_filename
$finfo
,
$cwd
if
ref
$_
[3] ?
file_exists
$finfo
:
Mpp::File::exists_or_can_be_built
$finfo
;
}
last
unless
$dirinfo
=
$dirinfo
->{
'..'
};
last
if
(stat_array
$dirinfo
)->[Mpp::File::STAT_DEV] !=
(
$cwd_devid
||= (stat_array
$cwd
)->[Mpp::File::STAT_DEV]);
}
return
if
$_
[3];
die
"find_first_upwards cannot find any of the requested files: @fnames\n"
;
}
sub
f_findstring {
my
(
$find
,
$in
) = args
$_
[0],
$_
[1],
$_
[2], 2, 2, 1;
(
index
(
$in
,
$find
) >= 0) ?
$find
:
''
;
}
sub
f_firstword {
(
split
' '
,
&arg
, 2)[0] ||
''
;
}
sub
f_first_available {
foreach
my
$fname
(
split
' '
,
&arg
) {
Mpp::File::exists_or_can_be_built( file_info
$fname
,
$_
[1]->{CWD} ) and
return
$fname
;
}
''
;
}
sub
f_if {
my
(
$cond
,
$then
,
$else
) = args
$_
[0],
undef
,
$_
[2], 3, 2, 1;
my
(
undef
,
$mkfile
,
$mkfile_line
,
$iftrue
) =
@_
;
$cond
=
ref
$_
[0] ?
$mkfile
->expand_text(
$cond
,
$mkfile_line
) :
$cond
;
$cond
=~ s/^\s+//;
$cond
=~ s/\s+$//;
if
(
$cond
|| !
$iftrue
&&
$cond
ne
""
) {
ref
$_
[0] ?
$mkfile
->expand_text(
$then
,
$mkfile_line
) :
$then
;
}
elsif
(
defined
$else
) {
ref
$_
[0] ?
$mkfile
->expand_text(
$else
,
$mkfile_line
) :
$else
;
}
else
{
''
;
}
}
sub
f_iftrue {
$_
[3] = 1;
goto
&f_if
;
}
sub
f_infer_linker {
my
@objs
=
split
' '
,
&arg
;
my
(
undef
,
$mkfile
,
$mkfile_line
) =
@_
;
my
@build_handles
;
&Mpp::maybe_stop
;
foreach
my
$obj
(
@objs
) {
$obj
= file_info(
$obj
,
$mkfile
->{CWD});
my
$bh
= prebuild(
$obj
,
$mkfile
,
$mkfile_line
);
$bh
and
push
@build_handles
,
$bh
;
}
my
$status
= wait_for
@build_handles
;
$status
and
die
"Error while compiling\n"
;
my
$linker
;
foreach
my
$obj
(
@objs
) {
foreach
my
$source_name
(
split
/\01/, Mpp::File::build_info_string(
$obj
,
'SORTED_DEPS'
) ||
''
) {
$source_name
=~ /\.f(?:77)?$/ and
$linker
=
'$(FC)'
;
$source_name
=~ /\.(?:c\+\+|cc|cxx|C|cpp|moc)$/ and
$linker
||=
'$(CXX)'
;
}
}
$linker
||=
'$(CC)'
;
$mkfile
->expand_text(
$linker
,
$mkfile_line
);
}
sub
f_infer_objects {
my
(
$seed_objs
,
$candidate_list
) = args
$_
[0],
$_
[1],
$_
[2];
my
(
undef
,
$mkfile
,
$mkfile_line
) =
@_
;
my
$build_cwd
=
$rule
?
$rule
->build_cwd :
$mkfile
->{CWD};
my
%candidate_objs
;
foreach
my
$candidate_obj
(
map
Mpp::Glob::zglob_fileinfo_atleastone(
$_
,
$build_cwd
),
split
' '
,
$candidate_list
) {
my
$objname
=
$candidate_obj
->{NAME};
$objname
=~ s/\.[^\.]+$//;
if
(
$candidate_objs
{
$objname
}) {
ref
(
$candidate_objs
{
$objname
}) eq
'ARRAY'
or
$candidate_objs
{
$objname
} = [
$candidate_objs
{
$objname
} ];
push
@{
$candidate_objs
{
$objname
}},
$candidate_obj
;
}
else
{
$candidate_objs
{
$objname
} =
$candidate_obj
;
}
}
my
%source_names
;
my
@build_handles
;
my
@deps
=
map
zglob_fileinfo(
$_
,
$build_cwd
),
split
' '
,
$seed_objs
;
@deps
or
die
"infer_objects called with no seed objects that exist or can be built\n"
;
Mpp::
log
INFER_SEED
=> \
@deps
if
$Mpp::log_level
;
foreach
(
@deps
) {
my
$name
=
$_
->{NAME};
$name
=~ s/\.[^\.]+$//;
$source_names
{
$name
}++;
}
my
$dep_idx
= 0;
&Mpp::maybe_stop
;
for
(;;) {
while
(
$dep_idx
<
@deps
) {
my
$o_info
=
$deps
[
$dep_idx
];
my
$bh
= prebuild(
$o_info
,
$mkfile
,
$mkfile_line
);
my
$handle
= when_done
$bh
,
sub
{
defined
(
$bh
) &&
$bh
->status and
return
$bh
->status;
my
@this_sources
=
split
/\01/, Mpp::File::build_info_string(
$o_info
,
'SORTED_DEPS'
) ||
''
;
foreach
(
@this_sources
) {
my
$name
=
$_
;
$name
=~ s@.*/@@;
$name
=~ s/\.[^\.]+$//;
unless
(
$source_names
{
$name
}++) {
if
(
ref
(
$candidate_objs
{
$name
}) eq
'Mpp::File'
) {
Mpp::
log
INFER_DEP
=>
$candidate_objs
{
$name
},
$_
if
$Mpp::log_level
;
push
@deps
,
$candidate_objs
{
$name
};
}
elsif
(
ref
(
$candidate_objs
{
$name
}) eq
'ARRAY'
) {
Mpp::print_error(
'`'
,
$mkfile_line
,
"' in infer_objects: more than one possible object for include file $_:\n "
,
join
(
"\n "
,
map
absolute_filename(
$_
), @{
$candidate_objs
{
$name
}}),
"\n"
);
}
}
}
};
if
(
defined
(
$handle
)) {
$handle
->{STATUS} && !
$Mpp::keep_going
and
die
"$mkfile_line: infer_objects failed because dependencies could not be built\n"
;
push
@build_handles
,
$handle
;
}
++
$dep_idx
;
}
last
unless
@build_handles
;
my
$status
= wait_for
@build_handles
;
@build_handles
= ();
$status
and
last
;
}
join
' '
,
map
relative_filename(
$_
,
$build_cwd
),
@deps
;
}
sub
f_info {
print
&arg
.
"\n"
;
''
;
}
sub
f_join {
my
(
$words1
,
$words2
) = args
$_
[0],
$_
[1],
$_
[2], 2, 2, 1;
my
@words1
=
split
' '
,
$words1
;
my
@words2
=
split
' '
,
$words2
;
for
my
$word
(
@words1
) {
last
unless
@words2
;
$word
.=
shift
@words2
;
}
push
@words1
,
@words2
;
join
' '
,
@words1
;
}
sub
f_makemap {
my
(
$list
,
$code
) = args
$_
[0],
$_
[1],
$_
[2];
$code
= eval_or_die
"sub {$code\n;defined}"
,
$_
[1],
$_
[2];
$_
[1]->cd;
join
' '
,
grep
&$code
, split_on_whitespace
$list
;
}
sub
f_map {
my
(
$list
,
$code
) = args
$_
[0],
undef
,
$_
[2];
$code
= eval_or_die
"sub {$code\n;defined}"
,
$_
[1],
$_
[2];
$_
[1]->cd;
join
' '
,
grep
&$code
, split_on_whitespace
ref
$_
[0] ?
$_
[1]->expand_text(
$list
,
$_
[2] ) :
$list
;
}
our
@temp_files
;
END { Mpp::File::
unlink
$_
for
@temp_files
}
sub
f_mktemp {
my
$template
=
&arg
;
my
$mkfile
=
$_
[1];
$mkfile
||= \
%Mpp::Subs::
;
return
$mkfile
->{LAST_TEMP_FILE} ||
die
"No previous call to \$(mktemp)\n"
if
$template
eq
'/'
;
$template
||=
'tmp.'
;
my
$Xmax
= 9;
$Xmax
=
length
( $1 ) - 1
if
$template
=~ s/(X+)$//;
my
$finfo
;
for
( 0..999 ) {
my
$X
=
''
;
for
( 0..
$Xmax
) {
my
$chr
= (!
$_
&&
$Xmax
) ? $$ % (26 + 26 + 10) :
int
rand
26 + 26 + 10;
$X
.=
$chr
< 10 ?
$chr
:
chr
$chr
- 10 + (
$chr
< 26 + 10 ?
ord
'a'
:
-26 +
ord
'A'
);
}
$mkfile
->{LAST_TEMP_FILE} =
$template
.
$X
;
$finfo
= file_info
$mkfile
->{LAST_TEMP_FILE},
$mkfile
->{CWD};
unless
(
$finfo
->{MKTEMP}++ || file_exists
$finfo
) {
push
@temp_files
,
$finfo
;
return
$mkfile
->{LAST_TEMP_FILE};
}
}
die
"$_[2]: too many tries necessary to make unique filename for $_[0]\n"
;
}
sub
f_prebuild {
my
$names
=
&arg
;
my
(
undef
,
$mkfile
,
$mkfile_line
) =
@_
;
my
@build_handles
;
&Mpp::maybe_stop
;
for
( split_on_whitespace
$names
) {
push
@build_handles
, prebuild( file_info( unquote(),
$mkfile
->{CWD} ),
$mkfile
,
$mkfile_line
);
}
my
$status
= wait_for
@build_handles
;
$status
and
die
"\$(prebuild $names) failed\n"
;
$names
;
}
*f_make
= \
&f_prebuild
;
sub
f_notdir {
join
' '
,
map
{ m@^.*/([^/]+)@ ? $1 :
$_
}
split
' '
,
&arg
;
}
sub
f_only_targets {
my
$phony
=
$_
[3];
my
$cwd
=
$_
[1] &&
$_
[1]{CWD};
my
@ret_files
;
foreach
(
split
' '
,
&arg
) {
foreach
my
$finfo
(zglob_fileinfo(
$_
,
$cwd
, 0,
$phony
)) {
$phony
||
exists
(
$finfo
->{RULE}) and
push
@ret_files
, relative_filename
$finfo
,
$cwd
;
}
}
join
' '
,
@ret_files
;
}
sub
f_only_phony_targets {
$_
[3] = \1;
goto
&f_only_targets
;
}
sub
f_only_nontargets {
my
$cwd
=
$_
[1] &&
$_
[1]{CWD};
my
@ret_files
;
foreach
(
split
' '
,
&arg
) {
foreach
my
$finfo
(Mpp::Glob::zglob_fileinfo_atleastone(
$_
,
$cwd
)) {
exists
(
$finfo
->{RULE}) or
push
@ret_files
, relative_filename
$finfo
,
$cwd
;
}
}
join
' '
,
@ret_files
;
}
sub
f_only_generated {
my
$cwd
=
$_
[1] &&
$_
[1]{CWD};
my
@ret_files
;
foreach
(
split
' '
,
&arg
) {
foreach
my
$finfo
(Mpp::Glob::zglob_fileinfo_atleastone(
$_
,
$cwd
, 0,0,1)) {
Mpp::File::was_built_by_makepp(
$finfo
) and
push
@ret_files
, relative_filename
$finfo
,
$cwd
;
}
}
join
' '
,
@ret_files
;
}
sub
f_only_stale {
my
$cwd
=
$_
[1] &&
$_
[1]{CWD};
my
@ret_files
;
foreach
(
split
' '
,
&arg
) {
foreach
my
$finfo
(Mpp::Glob::zglob_fileinfo_atleastone(
$_
,
$cwd
, 0,0,1)) {
Mpp::File::is_stale(
$finfo
) and
push
@ret_files
, relative_filename
$finfo
,
$cwd
;
}
}
join
' '
,
@ret_files
;
}
sub
f_origin {
my
$varname
=
&arg
;
my
$mkfile
=
$_
[1];
$perl_unfriendly_symbols
{
$varname
} ?
'automatic'
:
$Mpp::Makefile::private
&&
defined
$Mpp::Makefile::private
->{PRIVATE_VARS}{
$varname
} ?
'file'
:
defined
${
$mkfile
->{PACKAGE} .
"::$varname"
} ?
'file'
:
defined
${
"Mpp::global::$varname"
} ?
'global'
:
$mkfile
->{COMMAND_LINE_VARS}{
$varname
} ?
'command line'
:
$mkfile
->{ENVIRONMENT}{
$varname
} ?
'environment'
:
!
defined
( *{
$mkfile
->{PACKAGE} .
"::f_$varname"
}{CODE} ) ?
'undefined'
:
$varname
=~ /^(?:
foreach
|targets?|dependenc(?:y|ies)|inputs?|outputs?)$/ ?
'automatic'
:
'default'
;
}
sub
f_patsubst {
my
(
$src
,
$dest
,
$words
) = args
$_
[0],
$_
[1],
$_
[2], 3;
join
' '
, Mpp::Text::pattern_substitution(
$src
,
$dest
,
split_on_whitespace
$words
);
}
sub
f_makeperl {
$_
[1]->cd;
join
' '
,
grep
{
defined
} eval_or_die
&arg
,
$_
[1],
$_
[2];
}
sub
f_perl {
if
(
ref
$_
[0] ) {
f_makeperl ${
$_
[0]},
$_
[1],
$_
[2];
}
else
{
goto
&f_makeperl
}
}
sub
f_phony {
my
$text
=
&arg
;
undef
file_info( unquote(),
$_
[1]{CWD} )->{xPHONY}
for
split_on_whitespace
$text
;
$text
;
}
sub
f_print {
my
$text
=
&arg
;
print
"$text\n"
;
$text
;
}
sub
f_relative_filename {
my
(
$files
,
$slash
) = args
$_
[0],
$_
[1],
$_
[2], 2, 1;
my
$cwd
=
$_
[1]{CWD};
join
' '
,
map
{
$_
= relative_filename file_info( unquote(),
$cwd
),
$cwd
;
!
$slash
|| m@/@ ?
$_
:
"./$_"
} split_on_whitespace
$files
;
}
sub
f_relative_to {
my
(
$files
,
$dir
,
$slash
) = args
$_
[0],
$_
[1],
$_
[2], 3, 2;
my
$cwd
=
$_
[1]{CWD};
defined
$dir
or
die
"wrong number of arguments to \$(relative_to file, dir)\n"
;
$dir
=~ s/^\s+//;
$dir
=~ s/\s+$//;
my
$dirinfo
= file_info unquote(
$dir
),
$cwd
;
join
' '
,
map
{
$_
= relative_filename file_info( unquote(),
$cwd
),
$dirinfo
;
!
$slash
|| m@/@ ?
$_
:
"./$_"
} split_on_whitespace
$files
;
}
sub
f_shell {
my
$str
=
&arg
;
my
(
undef
,
$mkfile
,
$mkfile_line
) =
@_
;
local
%ENV
;
$mkfile
->setup_environment;
$mkfile
->cd;
my
$shell_output
=
''
;
if
( Mpp::is_windows ) {
if
( Mpp::is_windows != 1 ) {
$shell_output
= `
$str
`;
}
else
{
my
@cmd
= format_exec_args
$str
;
if
(
@cmd
== 3 ) {
substr
$cmd
[2], 0, 0,
'"'
;
$cmd
[2] .=
'"'
;
}
$shell_output
= `
@cmd
`;
}
$? == 0 or
warn
"shell command `$str' returned `$?' at `$mkfile_line'\n"
;
}
else
{
local
(
*INHANDLE
,
*OUTHANDLE
);
pipe
(INHANDLE, OUTHANDLE) or
die
"can't make pipe--$!\n"
;
my
$proc_handle
= new Mpp::Event::Process
sub
{
close
INHANDLE;
close
STDOUT;
open
(STDOUT,
'>&OUTHANDLE'
) ||
die
"can't redirect stdout--$!\n"
;
exec
format_exec_args
$str
;
die
"exec $str failed--$!\n"
;
},
ERROR
=>
sub
{
warn
"shell command `$str' returned `$_[0]' at `$mkfile_line'\n"
;
};
close
OUTHANDLE;
my
$line
;
my
$n_errors_remaining
= 3;
for
(;;) {
my
$n_chars
=
sysread
(INHANDLE,
$line
, 8192);
unless
(
defined
$n_chars
) {
$n_errors_remaining
-- > 0 and
next
;
die
"read error--$!\n"
;
}
last
if
$n_chars
== 0;
$shell_output
.=
$line
;
}
wait_for
$proc_handle
;
close
INHANDLE;
}
$shell_output
=~ s/\r?\n/ /g
unless
$Mpp::Makefile::s_define
;
$shell_output
=~ s/\s+$//s;
$shell_output
;
}
sub
f_sort {
my
$last
=
''
;
join
' '
,
map
{
$last
eq
$_
? () : (
$last
=
$_
) }
sort
split
' '
,
&arg
;
}
sub
f_stem {
unless
(
defined
$rule
) {
warn
"\$(stem) or \$* used outside of rule at `$_[2]'\n"
;
return
''
;
}
defined
$rule
->{PATTERN_STEM} and
return
$rule
->{PATTERN_STEM};
f_basename
&f_target
;
}
sub
f_strip {
join
' '
,
split
' '
,
&arg
;
}
sub
f_subst {
my
(
$from
,
$to
,
$text
) = args
$_
[0],
$_
[1],
$_
[2], 3, 3, 1;
$from
=
quotemeta
(
$from
);
join
' '
,
map
{ s/
$from
/
$to
/g;
$_
}
split
' '
,
$text
;
}
sub
f_suffix {
join
' '
,
map
{ m@(\.[^\./]*)$@ ? $1 : () }
split
' '
,
&arg
;
}
sub
f_temporary {
my
$text
=
&arg
;
undef
file_info( unquote(),
$_
[1]{CWD} )->{xTEMP}
for
split_on_whitespace
$text
;
$text
;
}
sub
f_wildcard {
my
$cwd
=
$rule
?
$rule
->build_cwd :
$_
[1]{CWD};
join
' '
,
map
zglob(
$_
,
$cwd
),
split
' '
,
&arg
;
}
sub
f_wordlist {
my
(
$startidx
,
$endidx
,
$text
) = args
$_
[0],
$_
[1],
$_
[2], 3, 2;
if
(
defined
$text
) {
my
@wordlist
=
split
' '
,
$text
;
$_
< 0 and
$_
+=
@wordlist
+ 1
for
$startidx
,
$endidx
;
return
''
if
$startidx
>
$endidx
;
$endidx
=
@wordlist
if
$endidx
>
@wordlist
;
join
' '
,
@wordlist
[
$startidx
-1 ..
$endidx
-1];
}
else
{
join
' '
, (
split
' '
,
$endidx
)[
map
{
$_
> 0 ?
$_
- 1 :
$_
}
split
' '
,
$startidx
];
}
}
*f_word
= \
&f_wordlist
;
sub
f_words {
scalar
map
undef
,
split
' '
,
&arg
;
}
sub
f_target {
unless
(
defined
$rule
) {
warn
"\$(output), \$(target) or \$\@ used outside of rule at `$_[2]'\n"
;
return
''
;
}
my
$arg
=
defined
$_
[0] ?
&arg
: 0;
relative_filename
$rule
->{EXPLICIT_TARGETS}[
$arg
? (
$arg
> 0 ?
$arg
- 1 :
$arg
) : 0],
$rule
->build_cwd;
}
*f_output
= \
&f_target
;
sub
f_targets {
unless
(
defined
$rule
) {
warn
"\$(outputs) or \$(targets) used outside of rule at `$_[2]'\n"
;
return
''
;
}
my
$arg
=
defined
$_
[0] ?
&arg
: 0;
join
' '
, relative_filenames
$arg
?
[@{
$rule
->{EXPLICIT_TARGETS}}[
map
{
$_
> 0 ?
$_
- 1 :
$_
}
split
' '
,
$arg
]] :
$rule
->{EXPLICIT_TARGETS};
}
*f_outputs
=
*f_targets
;
sub
f_dependency {
unless
(
defined
$rule
) {
warn
"\$(dependency) or \$(input) or \$< used outside of rule at `$_[2]'\n"
;
return
''
;
}
my
$arg
=
defined
$_
[0] ?
&arg
: 0;
my
$finfo
=
$rule
->{EXPLICIT_DEPENDENCIES}[
$arg
? (
$arg
> 0 ?
$arg
- 1 :
$arg
) : 0];
$finfo
or
return
''
;
relative_filename
$finfo
,
$rule
->build_cwd;
}
*f_input
=
*f_dependency
;
sub
f_dependencies {
unless
(
defined
$rule
) {
warn
"\$(dependencies) or \$(inputs) or \$^ used outside of rule at `$_[2]'\n"
;
return
''
;
}
my
$arg
=
defined
$_
[0] ?
&arg
: 0;
join
' '
, relative_filenames
$arg
?
[@{
$rule
->{EXPLICIT_DEPENDENCIES}}[
map
{
$_
> 0 ?
$_
- 1 :
$_
}
split
' '
,
$arg
]] :
$rule
->{EXPLICIT_DEPENDENCIES};
}
*f_inputs
=
*f_dependencies
;
sub
f_changed_inputs {
unless
(
defined
$rule
&&
defined
$rule
->{EXPLICIT_TARGETS} ) {
warn
"\$(changed_dependencies) or \$(changed_inputs) or \$? used outside of rule at `$_[2]'\n"
;
return
''
;
}
my
@changed_dependencies
=
$rule
->build_check_method->changed_dependencies
(
$rule
->{EXPLICIT_TARGETS}[0],
$rule
->signature_method,
$rule
->build_cwd,
@{
$rule
->{EXPLICIT_DEPENDENCIES}});
my
@filenames
= relative_filenames
@changed_dependencies
;
join
' '
,
sort
@filenames
;
}
*f_changed_dependencies
= \
&f_changed_inputs
;
sub
f_sorted_dependencies {
unless
(
defined
$rule
) {
warn
"\$(sorted_dependencies) or \$(sorted_inputs) or \$+ used outside of rule at `$_[2]'\n"
;
return
''
;
}
Mpp::Subs::f_sort
join
' '
, relative_filenames
$rule
->{EXPLICIT_DEPENDENCIES};
}
*f_sorted_inputs
=
*f_sorted_dependencies
;
sub
f_foreach {
my
(
undef
,
$mkfile
,
$mkfile_line
) =
@_
;
unless
(
$_
[0] ) {
defined
$rule
&&
defined
$rule
->{FOREACH} or
die
"\$(foreach) used outside of rule, or in a rule that has no :foreach clause at `$_[2]'\n"
;
return
relative_filename
$rule
->{FOREACH},
$rule
->build_cwd;
}
my
(
$var
,
$list
,
$text
) = args
$_
[0],
undef
,
$_
[2], 3, 3, 1;
$var
=
ref
$_
[0] ?
$mkfile
->expand_text(
$var
,
$mkfile_line
) :
$var
;
my
$ret_str
=
''
;
my
$sep
=
''
;
$Mpp::Makefile::private
?
(
local
$Mpp::Makefile::private
->{PRIVATE_VARS}{
$var
}) :
(
local
$Mpp::Makefile::private
);
local
$Mpp::Makefile::private
->{VAR_REEXPAND}{
$var
} = 0
if
$Mpp::Makefile::private
->{VAR_REEXPAND};
for
(
split
' '
,
ref
$_
[0] ?
$mkfile
->expand_text(
$list
,
$mkfile_line
) :
$list
) {
$Mpp::Makefile::private
->{PRIVATE_VARS}{
$var
} =
$_
;
$ret_str
.=
$sep
. (
ref
$_
[0] ?
$mkfile
->expand_text(
$text
,
$mkfile_line
) :
$text
);
$sep
=
' '
;
}
$ret_str
;
}
sub
f_warning {
warn
&arg
.
" at `$_[2]'\n"
;
''
;
}
sub
f_xargs {
my
(
$command
,
$list
,
$postfix
,
$max_length
) = args
$_
[0],
$_
[1],
$_
[2], 3, 2;
$postfix
=
''
unless
defined
$postfix
;
$max_length
||= 1000;
$max_length
-=
length
$postfix
;
my
(
$piece
,
@pieces
) =
$command
;
for
my
$elt
(
split
' '
,
$list
) {
if
(
length
(
$piece
) +
length
(
$elt
) <
$max_length
) {
$piece
.=
" $elt"
;
}
else
{
push
@pieces
,
"$piece $postfix"
;
$piece
=
$command
;
redo
;
}
}
push
@pieces
,
"$piece $postfix"
if
$piece
ne
$command
;
join
"\n"
,
@pieces
;
}
*f__exe_phony_
=
sub
{
my
$cwd
=
$rule
->build_cwd;
my
$phony
=
substr
relative_filename(
$rule
->{FOREACH},
$cwd
), 0, -4;
file_info(
$phony
,
$cwd
)->{_IS_EXE_PHONY_} = 1;
$phony
;
}
if
Mpp::is_windows;
sub
f_MAKE {
goto
&f_MAKE
;
}
*f_MAKE_COMMAND
= \
&f_MAKE
;
sub
s_build_cache {
my
(
$fname
,
$mkfile
,
$mkfile_line
) =
@_
;
my
$var
=
delete
$_
[3]{global} ? \
$Mpp::BuildCache::global
: \
$mkfile
->{BUILD_CACHE};
$fname
=
$mkfile
->expand_text(
$fname
,
$mkfile_line
)
if
$mkfile
;
$fname
=~ s/^\s+//;
$fname
=~ s/\s+$//;
if
(
$fname
eq
'none'
) {
undef
$$var
;
}
else
{
$fname
= absolute_filename file_info
$fname
,
$mkfile
->{CWD}
if
$mkfile
;
warn
$mkfile_line
?
"$mkfile_line: "
:
''
,
"Setting another build cache.\n"
if
$$var
;
$$var
= new Mpp::BuildCache(
$fname
);
}
}
sub
s_build_check {
my
(
undef
,
$mkfile
,
$mkfile_line
) =
@_
;
my
$name
=
$mkfile
->expand_text(
$_
[0],
$mkfile_line
);
$name
=~ s/^\s*(\w+)\s*$/$1/ or
die
"$mkfile_line: invalid build_check statement\n"
;
if
(
$name
eq
'default'
) {
delete
$mkfile
->{DEFAULT_BUILD_CHECK_METHOD};
return
;
}
$mkfile
->{DEFAULT_BUILD_CHECK_METHOD} =
eval
"use Mpp::BuildCheck::$name; \$Mpp::BuildCheck::${name}::$name"
||
eval
"use BuildCheck::$name; warn qq!$mkfile_line: name BuildCheck::$name is deprecated, rename to Mpp::BuildCheck::$name\n!; \$BuildCheck::${name}::$name"
or
die
"$mkfile_line: invalid build_check method $name\n"
;
}
sub
s_no_implicit_load {
my
(
$text_line
,
$mkfile
,
$mkfile_line
) =
@_
;
$text_line
=
$mkfile
->expand_text(
$text_line
,
$mkfile_line
);
my
$cwd
=
$rule
?
$rule
->build_cwd :
$mkfile
->{CWD};
local
$Mpp::implicitly_load_makefiles
;
my
@dirs
=
map
zglob_fileinfo(
$_
,
$cwd
),
split
' '
,
$mkfile
->expand_text(
$text_line
,
$mkfile_line
);
foreach
my
$dir
(
@dirs
) {
undef
$dir
->{xNO_IMPLICIT_LOAD}
if
is_or_will_be_dir
$dir
;
}
}
our
(
$defer_include
,
@defer_include
);
sub
s_include {
my
(
undef
,
$mkfile
,
$mkfile_line
,
$keyword
) =
@_
;
if
(
$defer_include
) {
push
@defer_include
,
$keyword
->{ignore} ? \
&s__include
: \
&s_include
,
@_
[0..2];
return
;
}
for
my
$file
(
split
' '
,
$mkfile
->expand_text(
$_
[0],
$mkfile_line
)) {
my
$finfo
= f_find_first_upwards
$Mpp::Makefile::c_preprocess
?
$file
:
"$file.makepp $file"
,
$mkfile
,
$mkfile_line
, 1;
if
(
$Mpp::Makefile::c_preprocess
) {
eval
{
$mkfile
->read_makefile(
$finfo
) };
die
$@
if
$@ and
$keyword
->{ignore} ? !/^can't
read
makefile/ : 1;
}
else
{
$finfo
and
wait_for prebuild(
$finfo
,
$mkfile
,
$mkfile_line
) and
die
"can't build "
. absolute_filename(
$finfo
) .
", needed at $mkfile_line\n"
;
unless
(
$finfo
) {
foreach
(@{
$mkfile
->{INCLUDE_PATH}}) {
$finfo
= file_info(
$file
,
$_
);
last
if
file_exists
$finfo
;
}
unless
( file_exists
$finfo
) {
next
if
$keyword
->{ignore};
die
"makepp: can't find include file `$file'\n"
;
}
}
Mpp::
log
LOAD_INCL
=>
$finfo
,
$mkfile_line
if
$Mpp::log_level
;
$mkfile
->read_makefile(
$finfo
);
}
}
}
sub
s__include {
s_include
@_
[0..2], {
ignore
=> 1};
}
sub
s_load_makefile {
my
(
$text_line
,
$mkfile
,
$mkfile_line
) =
@_
;
my
@words
= split_on_whitespace
$mkfile
->expand_text(
$text_line
,
$mkfile_line
);
$mkfile
->cleanup_vars;
my
%command_line_vars
= %{
$mkfile
->{COMMAND_LINE_VARS}};
my
@include_path
= @{
$mkfile
->{INCLUDE_PATH}};
my
@makefiles
;
while
(
defined
(
$_
=
shift
@words
)) {
if
(/^(\w+)=(.*)/) {
$command_line_vars
{$1} = unquote($2);
}
elsif
(/^-I(\S*)/) {
unshift
@include_path
, ($1 ||
shift
@words
);
}
else
{
push
@makefiles
,
$_
;
}
}
my
$set_do_build
=
$Mpp::File::root
->{DONT_BUILD} &&
$Mpp::File::root
->{DONT_BUILD} == 2 &&
!Mpp::File::dont_build(
$mkfile
->{CWD} );
foreach
(
@makefiles
) {
s/^-F//;
my
$mfile
= file_info
$_
,
$mkfile
->{CWD};
my
$mdir
=
$mfile
;
is_or_will_be_dir
$mfile
or
$mdir
=
$mfile
->{
'..'
};
if
(
$set_do_build
&& Mpp::File::dont_build(
$mdir
) &&
$mdir
->{DONT_BUILD} == 2 ) {
my
@descend
=
$mdir
;
while
(
@descend
) {
my
$finfo
=
shift
@descend
;
next
unless
$finfo
->{DONT_BUILD} &&
$finfo
->{DONT_BUILD} == 2;
undef
$finfo
->{DONT_BUILD};
push
@descend
,
values
%{
$finfo
->{DIRCONTENTS}}
if
$finfo
->{DIRCONTENTS};
}
}
Mpp::Makefile::load(
$mfile
,
$mdir
, \
%command_line_vars
,
''
, \
@include_path
,
$mkfile
->{ENVIRONMENT} );
}
}
sub
s_makeperl { s_perl(
@_
[0..2], {
make
=> 1} ) }
sub
s_makesub { s_sub(
@_
[0..2], {
make
=> 1} ) }
sub
s_perl {
my
(
$perl_code
,
$mkfile
,
$mkfile_line
,
$keyword
) =
@_
;
$perl_code
= Mpp::Makefile::read_block(
$keyword
->{make} ?
'makeperl'
:
'perl'
,
$perl_code
);
$perl_code
=
$mkfile
->expand_text(
$perl_code
,
$mkfile_line
)
if
$keyword
->{make};
$mkfile
->cd;
eval_or_die
$perl_code
,
$mkfile
,
$mkfile_line
;
}
sub
s_perl_begin {
my
(
$perl_code
,
$mkfile
,
$mkfile_line
) =
@_
;
warn
"$mkfile_line: trailing cruft after statement: `$perl_code'\n"
if
$perl_code
;
$perl_code
= Mpp::Makefile::read_block(
perl_begin
=>
$perl_code
,
qr/perl[-_]end/
);
$mkfile
->cd;
eval_or_die
$perl_code
,
$mkfile
,
$mkfile_line
;
}
sub
s_prebuild {
my
(
$text_line
,
$mkfile
,
$mkfile_line
) =
@_
;
my
(
@words
) = split_on_whitespace
$mkfile
->expand_text(
$text_line
,
$mkfile_line
);
&Mpp::maybe_stop
;
for
my
$target
(
@words
) {
my
$finfo
= file_info
$target
,
$mkfile
->{CWD};
wait_for prebuild(
$finfo
,
$mkfile
,
$mkfile_line
) and
die
"failed to prebuild $target\n"
;
}
}
sub
prebuild {
my
(
$finfo
,
$mkfile
,
$mkfile_line
) =
@_
;
my
$myrule
= Mpp::File::get_rule(
$finfo
);
Mpp::
log
PREBUILD
=>
$finfo
,
$mkfile_line
if
$Mpp::log_level
;
if
(
$myrule
&& !UNIVERSAL::isa(
$myrule
,
'Mpp::DefaultRule'
) &&
!
exists
(
$finfo
->{BUILD_HANDLE})
) {
unless
(
$myrule
->makefile ==
$mkfile
||
$myrule
->makefile->{INITIALIZED}) {
warn
'Attempting to build '
. absolute_filename(
$finfo
) .
" before its makefile is completely loaded\n"
;
}
}
Mpp::build(
$finfo
);
}
sub
s_autoload {
my
(
$text_line
,
$mkfile
,
$mkfile_line
) =
@_
;
++
$Mpp::File::n_last_chance_rules
;
my
(
@fields
) = split_on_whitespace
$mkfile
->expand_text(
$text_line
,
$mkfile_line
);
push
@{
$mkfile
->{AUTOLOAD} ||= []},
@fields
;
}
sub
s_register_scanner {
my
(
undef
,
$mkfile
,
$mkfile_line
) =
@_
;
warn
"$mkfile_line: register-scanner deprecated, please use register-parser at `$_[2]'\n"
;
my
(
@fields
) = split_on_whitespace
$mkfile
->expand_text(
$_
[0],
$mkfile_line
);
@fields
== 2 or
die
"$mkfile_line: register_scanner needs 2 arguments\n"
;
my
$command_word
= unquote
$fields
[0];
$fields
[1] =~
tr
/-/_/;
my
$scanner_sub
=
$fields
[1] =~ /^(?:scanner_)?none$/ ?
undef
: (*{
"$mkfile->{PACKAGE}::$fields[1]"
}{CODE} || *{
"$mkfile->{PACKAGE}::scanner_$fields[1]"
}{CODE});
$mkfile
->register_parser(
$command_word
,
$scanner_sub
);
}
sub
s_register_parser {
my
(
undef
,
$mkfile
,
$mkfile_line
) =
@_
;
my
(
@fields
) = unquote_split_on_whitespace
$mkfile
->expand_text(
$_
[0],
$mkfile_line
);
@fields
== 2 or
die
"$mkfile_line: register_command_parser needs 2 arguments at `$_[2]'\n"
;
$fields
[1] =~
tr
/-/_/;
$fields
[1] =
*{
"$mkfile->{PACKAGE}::p_$fields[1]"
}{CODE} ||
*{
"$fields[1]::factory"
}{CODE} ||
*{
"Mpp::CommandParser::$fields[1]::factory"
}{CODE} ||
*{
"$fields[1]::factory"
}{CODE} ||
die
"$mkfile_line: invalid command parser $fields[1]\n"
;
$mkfile
->register_parser(
@fields
);
}
*s_register_command_parser
= \
&s_register_parser
;
sub
s_register_input_suffix {
my
(
$text_line
,
$mkfile
,
$mkfile_line
) =
@_
;
my
(
$command_word
,
@fields
) =
unquote_split_on_whitespace(
$mkfile
->expand_text(
$text_line
,
$mkfile_line
));
no
strict
'refs'
;
my
$hashref
= \%{
$mkfile
->{PACKAGE} .
'::input_suffix_hash'
};
push
@{
$hashref
->{
$command_word
} ||= []},
@fields
;
}
sub
s_repository {
goto
&s_repository
;
}
sub
s_vpath {
goto
&s_vpath
;
}
sub
s_runtime {
my
(
$text
,
$mkfile
,
$mkfile_line
) =
@_
;
(
my
$comma
= index_ignoring_quotes
$text
,
','
) >= 0 or
die
"$mkfile_line: runtime EXE,LIST called with only one argument\n"
;
my
$exelist
=
$mkfile
->expand_text(
substr
(
$text
, 0,
$comma
),
$mkfile_line
);
substr
$text
, 0,
$comma
+1,
''
;
my
@deps
=
map
file_info(
$_
,
$mkfile
->{CWD}), split_on_whitespace
$mkfile
->expand_text(
$text
,
$mkfile_line
);
for
my
$exe
(
map
file_info(
$_
,
$mkfile
->{CWD}), split_on_whitespace
$exelist
) {
for
my
$dep
(
@deps
) {
$exe
->{RUNTIME_DEPS}{
$dep
} =
$dep
;
}
}
}
sub
s_signature {
my
(
undef
,
$mkfile
,
$mkfile_line
) =
@_
;
my
$name
=
$mkfile
->expand_text(
$_
[0],
$mkfile_line
);
$name
=~ s/^\s*(\w+)\s*$/$1/ or
die
"$mkfile_line: invalid signature statement\n"
;
if
(
$name
eq
'default'
) {
delete
$mkfile
->{DEFAULT_SIGNATURE_METHOD};
return
;
}
$mkfile
->{DEFAULT_SIGNATURE_METHOD} =
eval
"use Mpp::Signature::$name; \$Mpp::Signature::${name}::$name"
||
eval
"use Signature::$name; warn qq!$mkfile_line: name Signature::$name is deprecated, rename to Mpp::Signature::$name\n!; \$Signature::${name}::$name"
;
unless
(
defined
$mkfile
->{DEFAULT_SIGNATURE_METHOD} ) {
$mkfile
->{DEFAULT_BUILD_CHECK_METHOD} =
eval
"use Mpp::BuildCheck::$name; \$Mpp::BuildCheck::${name}::$name"
||
eval
"use BuildCheck::$name; warn qq!$mkfile_line: name BuildCheck::$name is deprecated, rename to Mpp::BuildCheck::$name\n!; \$BuildCheck::${name}::$name"
;
if
(
defined
$mkfile
->{DEFAULT_BUILD_CHECK_METHOD} ) {
warn
"$mkfile_line: requesting build check method $name via signature is deprecated.\n"
;
}
else
{
die
"$mkfile_line: invalid signature method $name\n"
;
}
}
}
sub
s_sub {
my
(
$subr_text
,
$mkfile
,
$mkfile_line
,
$keyword
) =
@_
;
$subr_text
= Mpp::Makefile::read_block(
$keyword
->{make} ?
'makesub'
:
'sub'
,
$subr_text
);
$subr_text
=
$mkfile
->expand_text(
$subr_text
,
$mkfile_line
)
if
defined
$keyword
->{make};
eval_or_die
"sub $subr_text"
,
$mkfile
,
$mkfile_line
;
}
sub
s_unexport {
my
(
$text_line
,
$mkfile
,
$mkfile_line
) =
@_
;
delete
@{
$mkfile
->{EXPORTS}}{
split
' '
,
$mkfile
->expand_text(
$text_line
,
$mkfile_line
)}
if
$mkfile
->{EXPORTS};
}
sub
run(@) {
local
( $0,
@ARGV
) =
@_
;
$0 = f_find_program $0,
$rule
?
$rule
->{MAKEFILE} :
$makefile
,
$rule
?
$rule
->{RULE_SOURCE} :
$makefile_line
unless
-f $0;
local
$SIG
{__WARN__} =
local
$SIG
{__DIE__} =
'DEFAULT'
;
die
$@ ||
"$0 failed--$!\n"
if
!
defined
do
$0 and $@ || $!;
}
sub
f_AR() {
'ar'
}
sub
f_ARFLAGS() {
'rv'
}
sub
f_AS() {
'as'
}
my
$CC
;
sub
f_CC {
$CC
||= f_find_program
'gcc egcc pgcc c89 cc'
. (Mpp::is_windows?
' cl bcc32'
:
''
),
$_
[1],
$_
[2] }
sub
f_CFLAGS { f_if \(
'$(filter %gcc, $(CC)), -g -Wall, '
. (Mpp::is_windows?
' $(if $(filter %cl %cl.exe %bcc32 %bcc32.exe, $(CC)), , -g)'
:
'-g'
)),
$_
[1],
$_
[2] }
sub
f_CURDIR { absolute_filename
$_
[1]{CWD} }
my
$CXX
;
sub
f_CXX {
$CXX
||= f_find_program
'g++ c++ pg++ cxx '
. (Mpp::is_windows?
'cl bcc32'
:
'CC aCC'
),
$_
[1],
$_
[2] }
sub
f_CXXFLAGS { f_if \(
'$(filter %g++ %c++, $(CXX)), -g -Wall, '
. (Mpp::is_windows?
'$(if $(filter %cl %cl.exe %bcc32 %bcc32.exe, $(CXX)), , -g)'
:
'-g'
)),
$_
[1],
$_
[2] }
my
$F77
;
sub
f_F77 {
$F77
||= f_find_program
'f77 g77 fort77'
,
$_
[1],
$_
[2] }
sub
f_FC {
$_
[1]->expand_variable(
'F77'
,
$_
[2]) }
my
$LEX
;
sub
f_LEX {
$LEX
||= f_find_program
'lex flex'
,
$_
[1],
$_
[2] }
sub
f_LIBTOOL() {
'libtool'
}
sub
f_LD() {
'ld'
}
sub
f_MAKEINFO() {
'makeinfo'
}
*f_PWD
= \
&f_CURDIR
;
sub
f_RM() {
'rm -f'
}
my
$YACC
;
sub
f_YACC {
$YACC
||= f_if \
'$(filter bison, $(find_program yacc bison)), bison -y, yacc'
,
$_
[1],
$_
[2] }
sub
f_ROOT {
$_
[1]{CWD}{ROOT} ? relative_filename(
$_
[1]{CWD}{ROOT},
$_
[1]{CWD} ) :
''
}
sub
import
() {
my
$package
=
caller
;
no
warnings
'redefine'
;
for
(
keys
%Mpp::Subs::
) {
$_
[1] ? /^(?:
$_
[1])/ : /^[fps]_/ or
/^args?$/ or
/^run/ or
/^scanner_/ or
next
;
my
$coderef
= *{
"Mpp::Subs::$_"
}{CODE};
*{
$package
.
"::$_"
} =
$coderef
if
$coderef
;
}
}
1;