#!/usr/bin/perl -w
our
$VERSION
=
'@VERSION@'
;
our
$datadir
;
BEGIN {
eval
"sub ARCHITECTURE() { '$Config{archname}' }"
;
$datadir
= $0;
unless
(
$datadir
=~ s@/[^/]+$@@ ) {
foreach
(
split
( /:/,
$ENV
{
'PATH'
} ),
'.'
) {
if
( -d
"$_/Mpp"
) {
$datadir
=
$_
;
last
;
}
}
}
$datadir
or
die
"makeppreplay: can't find library files\n"
;
$datadir
=
eval
"use Cwd; cwd . '/$datadir'"
if
$datadir
=~ /^\./;
unshift
@INC
,
$datadir
;
}
our
$progname
;
my
$temporary
;
use
FileInfo
qw(file_info chdir absolute_filename file_exists relative_filename $CWD_INFO)
;
my
@targets
;
my
$target_cwd
=
$CWD_INFO
;
Makefile::find_root_makefile_upwards
$target_cwd
;
my
$modules
=
''
;
my
%command_line_vars
;
my
$tmp
;
sub
load_build_info_file($) {
my
$build_info
=
&FileInfo::load_build_info_file
or
return
;
unless
(
exists
$build_info
->{SIGNATURE} ) {
my
$sig
=
&FileInfo::signature
;
my
$count
=
keys
%$build_info
;
delete
@{
$build_info
}{
qw(FROM_REPOSITORY LINKED_TO_CACHE)
}
unless
$sig
;
while
(
my
(
$key
,
$value
) =
each
%$build_info
) {
delete
$build_info
->{
$key
}
if
$key
ne
'DEP_SIGS'
&& Signature::is_content_based
$value
or
$key
eq
'LINKED_TO_CACHE'
&&
$_
[0]{LSTAT}[FileInfo::STAT_NLINK] == 1 or
$key
eq
'FROM_REPOSITORY'
&& (
readlink
(
&FileInfo::absolute_filename_nolink
) ||
''
) ne
$value
;
}
if
(
$sig
) {
&FileInfo::mark_build_info_for_update
if
$count
!=
keys
%$build_info
;
$build_info
->{RESCAN} ||= 1;
$build_info
->{SIGNATURE} =
$sig
;
}
}
$build_info
;
}
@ARGV
=
'.'
unless
@ARGV
;
my
$nothing_in_dir
;
my
$found_in_dir
= 0;
perform
eval
{
while
(
@ARGV
) {
TextSubs::getopts \
%command_line_vars
, 1,
[
'c'
,
qr/root(?:[-_]?dir(?:ectory)?)?/
, \
$tmp
,
undef
,
sub
{
Makefile::find_root_makefile_upwards
$target_cwd
;
$target_cwd
=
$target_cwd
->{ROOT}
or
die
"$0: No RootMakeppfile(.mk) found above `"
, absolute_filename(
$target_cwd
),
"'.\n"
;
chdir
$target_cwd
;
}],
[
qw(C directory)
, \
$tmp
, 1,
sub
{
$target_cwd
= file_info
$tmp
,
$target_cwd
;
chdir
$target_cwd
;
Makefile::find_root_makefile_upwards
$target_cwd
;
}],
[
'I'
,
qr/include(?:[-_]?dir)?/
, \
$tmp
, 1,
sub
{
unshift
@INC
, absolute_filename file_info
$tmp
}],
[
qw(M module)
, \
$tmp
, 1,
sub
{
$tmp
=~ s/=(.*)/
qw($1)
/ and
$tmp
=~
tr
/,/ /;
$modules
.=
"use $tmp;"
}],
[
qw(t temporary)
, \
$temporary
],
@::common_options;
@ARGV
=
'.'
unless
@ARGV
||
@targets
;
my
$finfo
= file_info
shift
,
$target_cwd
;
if
( is_dir
$finfo
) {
::
log
RULE_ALL
=>
$finfo
if
$::log_level;
my
$build_info_subdir
= file_info relative_filename(
$finfo
) .
"/$FileInfo::build_info_subdir"
;
$nothing_in_dir
= absolute_filename
$finfo
;
unshift
@ARGV
,
grep
{
$_
= relative_filename
$_
;
s!
$FileInfo::build_info_subdir
/!! &&
s!\.mk$!! &&
++
$found_in_dir
;
} Mpp::Glob::zglob_fileinfo
'*.mk'
,
$build_info_subdir
;
next
;
}
my
$build_info
=
$finfo
->{BUILD_INFO} = load_build_info_file
$finfo
;
if
(
$found_in_dir
) {
$found_in_dir
--;
next
unless
exists
$build_info
->{COMMAND};
undef
$nothing_in_dir
;
}
else
{
die
"$progname: No files built by makepp in `$nothing_in_dir'.\n"
if
$nothing_in_dir
;
die
"$progname: Nothing known about `"
. absolute_filename(
$finfo
) .
"'.\n"
unless
defined
$build_info
;
die
"$progname: File `"
. absolute_filename(
$finfo
) .
"' not built by makepp.\n"
unless
exists
$build_info
->{COMMAND};
}
(
my
$cmd
=
$build_info
->{COMMAND}) =~ s/\A\|FAILED\|//;
$cmd
=~
tr
/\cC/\n/;
(
my
$deps
=
$build_info
->{SORTED_DEPS} ||
''
) =~
tr
/\cA/ /;
my
$dinfo
= file_info
$build_info
->{CWD},
$finfo
->{
'..'
};
my
$makefile
=
$dinfo
->{MAKEINFO};
unless
(
$makefile
) {
$makefile
= Makefile::load
$dinfo
,
$dinfo
, \
%command_line_vars
,
''
, [], \
%ENV
;
if
(
$modules
) {
$makefile
->cd;
Mpp::Subs::eval_or_die
$modules
,
$makefile
, absolute_filename(
$dinfo
) .
':0'
;
}
}
my
$target
= relative_filename
$finfo
,
$dinfo
;
my
$rule_cache
=
"$deps\01$cmd"
;
if
(
$dinfo
->{
$rule_cache
} ) {
::
log
RULE_EXTEND
=>
$finfo
,
$dinfo
->{
$rule_cache
}{TARGETS}
if
$::log_level;
$dinfo
->{
$rule_cache
}{TARGET_STRING} .=
" $target"
;
push
@{
$dinfo
->{
$rule_cache
}{TARGETS}},
$finfo
;
}
else
{
::
log
RULE_NEW
=>
$finfo
if
$::log_level;
$dinfo
->{
$rule_cache
} = new Mpp::Rule
$target
,
$deps
,
$cmd
,
$makefile
, FileInfo::build_info_fname(
$finfo
) .
':0'
;
push
@targets
,
$finfo
;
$dinfo
->{
$rule_cache
}{TARGETS} = [
$finfo
];
@{
$dinfo
->{
$rule_cache
}{ENV_DEPS}}{
split
"\cA"
,
$build_info
->{ENV_DEPS}} =
split
"\cA"
,
$build_info
->{ENV_VALS}
if
exists
$build_info
->{ENV_DEPS};
}
$finfo
->{RULE} =
$dinfo
->{
$rule_cache
};
}
@::common_options = ();
close
DATA;
die
"$progname: No files built by makepp in `$nothing_in_dir'.\n"
if
$nothing_in_dir
;
for
my
$target
(
@targets
) {
my
$build_info
=
$target
->{BUILD_INFO};
if
(
delete
$build_info
->{FROM_REPOSITORY} ||
delete
$build_info
->{LINKED_TO_CACHE} ) {
::
log
REMOVE
=>
$target
if
$::log_level;
FileInfo::
unlink
$target
;
}
my
$rule
=
$target
->{RULE};
my
$n_files
= @{
$rule
->{TARGETS}};
local
$rule
->{MAKEFILE}{EXPORTS} =
$rule
->{ENV_DEPS}
if
exists
$rule
->{ENV_DEPS};
if
( $::dry_run ) {
$rule
->print_command(
$rule
->{COMMAND_STRING} );
}
elsif
(
my
$status
= wait_for
$rule
->execute(
$rule
->{COMMAND_STRING},
$rule
->{TARGETS},
[
map
file_info(
$_
,
$target
->{
'..'
} ),
split
' '
,
$rule
->{DEPENDENCY_STRING}] ) ) {
print_error
"Failed to build target"
, (@{
$rule
->{TARGETS}}>1 ?
's'
:
''
),
map
(
' `'
.absolute_filename(
$_
).
"'"
, @{
$rule
->{TARGETS}} ),
" [$status]"
;
::
log
RULE_FAILED
=>
$rule
if
$::log_level;
$::error_found =
$status
if
$status
=~ /^signal (?:$::int_signo|$::quit_signo)$/os;
$::error_found ||=
$status
unless
$::keep_going;
$rule
->{TARGET_STRING} =~ s/ /' `/g;
$::failed_count +=
$n_files
;
unless
(
$temporary
||
$build_info
->{COMMAND} =~ /\A\|FAILED\|/ ) {
for
my
$tinfo
( @{
$rule
->{TARGETS}} ) {
substr
$tinfo
->{BUILD_INFO}{COMMAND}, 0, 0,
'|FAILED|'
;
FileInfo::mark_build_info_for_update
$tinfo
;
}
&FileInfo::update_build_infos
;
}
last
unless
$::keep_going;
}
else
{
::
log
SUCCESS
=>
$rule
,
$rule
->{TARGETS}
if
$::log_level;
$::n_files_changed +=
$n_files
;
next
if
$temporary
;
my
$sig
=
$build_info
->{SIG_METHOD_NAME};
$sig
&&=
$rule
->set_signature_method_scanner(
$sig
);
my
$dep_sigs
=
''
;
my
$sep
=
''
;
for
my
$dep
(
split
/\cA/,
$build_info
->{SORTED_DEPS} ) {
$dep
= FileInfo::path_file_info
$dep
,
$rule
->{MAKEFILE}{CWD};
$dep
->{BUILD_INFO} ||= load_build_info_file
$dep
;
$dep_sigs
.=
$sep
.
((
$sig
?
$sig
->signature(
$dep
) : FileInfo::signature
$dep
) ||
''
);
$sep
=
"\cA"
;
}
for
my
$tinfo
( @{
$rule
->{TARGETS}} ) {
$build_info
=
$tinfo
->{BUILD_INFO};
delete
$tinfo
->{LSTAT};
$build_info
->{SIGNATURE} = FileInfo::signature
$tinfo
;
if
(
$tinfo
->{LINK_DEREF} &&
$tinfo
->{LSTAT}[FileInfo::STAT_NLINK] == 1 ) {
$build_info
->{SYMLINK} =
readlink
FileInfo::absolute_filename
$tinfo
;
}
else
{
delete
$build_info
->{SYMLINK};
}
$build_info
->{DEP_SIGS} =
$dep_sigs
;
$build_info
->{BUILD_SIGNATURE} =
$sig
?
$sig
->signature(
$tinfo
) :
$build_info
->{SIGNATURE};
$build_info
->{RESCAN} = 2;
FileInfo::mark_build_info_for_update
$tinfo
;
}
&FileInfo::update_build_infos
;
}
}
};