{
my
(
%signo
,
@signame
);
if
(
defined
(
my
$sig_name
=
$Config
{sig_name})) {
my
$i
=0;
for
my
$name
(
split
(
' '
,
$sig_name
)) {
$signo
{
$name
} ||=
$i
;
$signame
[
$i
] =
$name
;
$i
++;
}
}
sub
signo {
$signo
{
$_
[0]} ||
$_
[0];
}
sub
signame {
$signame
[
$_
[0]] ||
$_
[0];
}
}
our
$int_signo
= signo
'INT'
;
our
$quit_signo
= signo
'QUIT'
;
my
$logfh
;
our
@close_fhs
= \(
*STDOUT
,
*STDERR
);
our
$critical_sections
= 0;
our
$n_files_changed
= 0;
our
$n_phony_targets_built
= 0;
our
$error_found
= 0;
our
$failed_count
= 0;
our
$build_cache_hits
= 0;
our
$rep_hits
= 0;
our
$log_level
= 2;
sub
log
($@);
my
@signals_to_handle
= is_windows > 0 && is_perl_5_6 ?
() :
qw/INT QUIT HUP TERM/
;
{
my
%pending_signals
;
sub
suicide {
my
(
$sig
) =
@_
;
$SIG
{
$sig
} =
'DEFAULT'
;
$sig
=
'INT'
if
$sig
eq
'QUIT'
&&
!(
require
BSD::Resource && BSD::Resource::setrlimit(
&BSD::Resource::RLIMIT_CORE
, 0, 0 ));
kill
$sig
, $$;
POSIX::_exit(0x80 | signo(
$sig
));
}
sub
handle_signal {
my
$sig
=
$_
[0];
return
if
$Mpp::Event::n_external_processes
&&
(
$sig
eq
'INT'
||
$sig
eq
'QUIT'
);
$pending_signals
{
$sig
} = 1;
exit
unless
$critical_sections
;
&Mpp::Event::Process::terminate_all_processes
;
}
sub
propagate_pending_signals {
die
if
$critical_sections
<0;
return
if
$critical_sections
;
exit
2
if
grep
$_
,
values
%pending_signals
;
}
sub
reset_signal_handlers {
@SIG
{
@signals_to_handle
} = (
'DEFAULT'
) x
@signals_to_handle
;
}
@pending_signals
{
@signals_to_handle
} = ( 0 ) x
@signals_to_handle
;
END {
::
log
N_REP_HITS
=>
$rep_hits
if
$log_level
&&
$rep_hits
;
::
log
N_CACHE_HITS
=>
$build_cache_hits
if
$log_level
&&
$build_cache_hits
;
::
log
N_FILES
=>
$n_files_changed
,
$n_phony_targets_built
,
$failed_count
if
defined
$logfh
;
if
(
exists
$Devel::DProf::
{VERSION} ) {
warn
"Doing slow exit, needed for profiler.\n"
;
}
else
{
close
$_
for
@close_fhs
;
$pending_signals
{
$_
} && suicide
$_
for
keys
%pending_signals
;
POSIX::_exit $?;
}
}
}
@SIG
{
@signals_to_handle
} = ( \
&handle_signal
) x
@signals_to_handle
;
my
$invocation
= join_with_protection($0,
@ARGV
);
our
$progname
;
for
(
qw(/usr/xpg4/bin/sh /sbin/xpg4/sh /bin/sh)
) {
if
( -x ) {
$ENV
{SHELL} =
$_
;
last
;
}
}
delete
$ENV
{PWD};
our
$indent_level
= 0;
our
$keep_going
= 0;
my
$logfile
;
our
$parallel_make
= 0;
our
$profile
= 0;
our
$verbose
;
our
$silent_execution
;
$SIG
{__WARN__} =
sub
{
my
$level
= (
$_
[0] =~ /^(?:error|info): /s) ?
''
:
'warning: '
;
print
STDERR
"$progname: $level$_[0]"
;
if
(
$log_level
== 2 ) {
&::
log
()
unless
defined
$logfh
;
print
$logfh
"*** $level$_[0]"
;
}
};
my
$last_indent_level
= 0;
sub
log
($@) {
unless
(
defined
$logfh
) {
if
(
$log_level
== 1 ) {
(
my
$mppl
= $0) =~ s/\w+$/makepplog/;
-f
$mppl
or
substr
$mppl
, 0, 0, Mpp::File::absolute_filename( $::original_cwd ) .
'/'
;
open
$logfh
,
'|'
. PERL .
" $mppl -pl-"
or
die
"$progname: can't pipe to `makepplog' for verbose option--$!\n"
;
}
else
{
if
( !
$logfile
) {
mkdir
'.makepp'
;
$logfile
=
'.makepp/log'
;
}
open
$logfh
,
'>'
,
$logfile
or
die
"$progname: can't create log file ./$logfile--$!\n"
;
}
push
@close_fhs
,
$logfh
;
print
$logfh
"2\01$invocation\n"
;
Mpp::Rule::print_build_cwd(
$Mpp::File::CWD_INFO
)
if
defined
$Mpp::Recursive::traditional
;
return
unless
@_
;
}
print
$logfh
join
"\01"
,
$indent_level
==
$last_indent_level
?
shift
() :
(
$indent_level
<
$last_indent_level
?
"\02"
:
"\03"
) .
shift
,
map
( {
if
( !
ref
) {
$_
;
}
elsif
(
'ARRAY'
eq
ref
) {
join
"\02"
,
map
{
if
(
exists
$_
->{LOGGED} ) {
int
;
}
elsif
( !
exists
$_
->{
'..'
} ) {
$_
->name;
}
elsif
(
exists
$_
->{
'..'
}{LOGGED} ) {
undef
$_
->{LOGGED};
int
() .
"\03$_->{NAME}\03"
.
int
$_
->{
'..'
};
}
else
{
undef
$_
->{LOGGED};
undef
$_
->{
'..'
}{LOGGED};
int
() .
"\03$_->{NAME}\03"
.
int
(
$_
->{
'..'
} ) .
"\03"
. (
$_
->{
'..'
}{FULLNAME} || Mpp::File::absolute_filename(
$_
->{
'..'
} ));
}
}
@$_
;
}
elsif
(
exists
$_
->{LOGGED} ) {
int
;
}
elsif
( !
exists
$_
->{
'..'
} ) {
$_
->name;
}
elsif
(
exists
$_
->{
'..'
}{LOGGED} ) {
undef
$_
->{LOGGED};
int
() .
"\03$_->{NAME}\03"
.
int
$_
->{
'..'
};
}
else
{
undef
$_
->{LOGGED};
undef
$_
->{
'..'
}{LOGGED};
int
() .
"\03$_->{NAME}\03"
.
int
(
$_
->{
'..'
} ) .
"\03"
. (
$_
->{
'..'
}{FULLNAME} || Mpp::File::absolute_filename(
$_
->{
'..'
} ));
}
}
@_
),
"\n"
;
$last_indent_level
=
$indent_level
;
}
sub
flush_log {
my
$fh
=
select
STDOUT;
local
$| = 1;
select
STDERR; $| = 1;
if
(
defined
$logfh
) {
select
$logfh
; $| = 1 }
select
$fh
;
}
my
$hires_time
;
sub
print_profile {
print
$profile
?
"$progname: Begin \@"
.
&$hires_time
() .
" $_[0]\n"
:
"$_[0]\n"
;
}
sub
print_profile_end {
print
"$progname: End \@"
.
&$hires_time
() .
" $_[0]\n"
;
}
sub
print_error {
my
(
$log
,
$stderr
) =
$log_level
&&
'*** '
;
my
$str
=
''
;
if
(
$_
[0] =~ /^error()/ ||
$_
[0] !~ /^\S+?:/ ) {
$stderr
=
"$progname: "
;
$str
=
'error: '
unless
defined
$1;
}
$str
.=
ref
() ?
$_
->name :
$_
for
@_
;
$str
.=
"\n"
if
$str
!~ /\n\z/;
print
STDERR
$stderr
?
$stderr
.
$str
:
$str
;
if
(
$log_level
== 2 ) {
&::
log
()
unless
defined
$logfh
;
print
$logfh
$log
.
$str
;
}
&flush_log
;
}
sub
perform(@) {
my
$status
;
my
$start_pid
= $$;
my
$error_message
= $@ ||
''
;
$error_message
or
eval
{
$status
=
&wait_for
};
$error_message
.= $@
if
$@;
{
my
$orig
=
''
;
if
(
$error_message
) {
chomp
(
$orig
=
$error_message
);
$orig
=
" (Original error was $orig)"
;
}
if
( $$ !=
$start_pid
) {
print
STDERR
qq{makepp internal error: sub-process died or returned to outer scope.
If we had not caught this, it would cause exit blocks to run multiple times.
Use POSIX::_exit instead.$orig Stopped}
;
close
$_
for
@close_fhs
;
POSIX::_exit 3;
}
&Mpp::Event::event_loop
while
$Mpp::Event::n_external_processes
;
die
qq{makepp internal error: dangling critical section.
This means that there was a live process in the background when makepp
died, so makepp did not have a chance to create build info files for
targets generated by that process. It also means that makepp can't
propagate signals. This could instead mean that you need an extra 'eval'
somewhere to prevent an exception from bypassing process accounting and
signal propagation.$orig Stopped}
if
$critical_sections
;
if
(
$error_found
&&
$error_found
=~ /^signal (
$int_signo
|
$quit_signo
)$/ ) {
my
$sig
= $1;
handle_signal signame(
$sig
);
}
}
if
(
$n_files_changed
||
$rep_hits
||
$build_cache_hits
||
$n_phony_targets_built
||
$failed_count
) {
print
"$progname: $n_files_changed file"
. (
$n_files_changed
== 1 ?
''
:
's'
) .
' updated'
.
(
$rep_hits
?
", $rep_hits repository import"
. (
$rep_hits
== 1 ?
''
:
's'
) :
''
) .
(
$build_cache_hits
?
", $build_cache_hits build cache import"
. (
$build_cache_hits
== 1 ?
''
:
's'
) :
''
) .
(
$error_found
?
','
:
' and'
) .
" $n_phony_targets_built phony target"
. (
$n_phony_targets_built
== 1 ?
''
:
's'
) .
' built'
.
(
$failed_count
?
" and $failed_count target"
. (
$failed_count
== 1 ?
''
:
's'
) .
" failed\n"
:
"\n"
);
}
elsif
( !
$error_message
) {
print
"$progname: no update necessary\n"
;
}
print
"$progname: Ending \@"
.
&$hires_time
() .
"\n"
if
$profile
;
print_error
$error_message
if
$error_message
;
exit
1
if
$error_message
||
$status
|| !MAKEPP &&
$failed_count
;
exit
0;
}
our
@common_options
=
(
[
qr/[h?]/
,
'help'
,
undef
,
undef
,
sub
{
local
$/;
print
<DATA>;
exit
0 }],
[
'n'
,
qr/(?:just[-_]?print|dry[-_]?run|recon)/
, \$::dry_run],
[
'k'
,
qr/keep[-_]?going/
, \
$keep_going
],
[
undef
,
qr/log(?:[-_]?file)?/
, \
$logfile
, 1],
[
undef
,
qr/no[-_]?log/
, \
$log_level
,
undef
, 0],
[
undef
,
'profile'
, \
$profile
,
undef
,
sub
{
if
( !
$hires_time
) {
$hires_time
= $@ ?
sub
{
time
} : \
&Time::HiRes::time
;
print
"$progname: Beginning \@"
.
&$hires_time
() .
"\n"
;
}
}],
[
qw(s silent)
, \
$silent_execution
],
[
qw(v verbose)
,
undef
,
undef
,
sub
{
$verbose
= 2;
$log_level
= 1;
}],
[
undef
,
'version'
,
undef
,
undef
, \
&Mpp::File::version
],
);
1;