our
@ISA
=
'BuildCheck'
;
my
$last_compilation_warning_x86
= 0;
our
$exact_match
=
bless
\
@ISA
;
sub
_check_env {
my
(
$tinfo
,
$env
,
$log_level
) =
@_
;
my
(
$env_deps
,
$env_vals
) =
FileInfo::build_info_string(
$tinfo
,
qw(ENV_DEPS ENV_VALS)
);
my
(
@old_env_list
,
@old_env_vals
);
if
(
defined
$env_deps
) {
@old_env_list
=
split
/\01/,
$env_deps
, -1;
@old_env_vals
=
split
/\01/,
$env_vals
, -1;
}
@old_env_vals
=
''
if
!
@old_env_vals
&&
@old_env_list
== 1;
my
@new_env_list
=
sort
keys
%$env
;
my
@new_env_vals
= @{
$env
}{
@new_env_list
};
my
@save_env_list
=
@new_env_list
;
while
(
@old_env_list
||
@new_env_list
) {
my
(
$old
,
$new
) = (
shift
(
@old_env_list
),
shift
(
@new_env_list
));
if
(
$old
&&
$new
) {
if
(
$old
lt
$new
) {
undef
$new
;
}
elsif
(
$old
gt
$new
) {
undef
$old
;
}
}
if
(
$log_level
) {
::
log
BUILD_ENV_DEL
=>
$tinfo
,
$old
if
!
$new
;
::
log
BUILD_ENV_ADD
=>
$tinfo
,
$new
if
!
$old
;
}
return
1
if
!
$new
|| !
$old
;
}
die
unless
@new_env_vals
==
@old_env_vals
&&
@old_env_vals
==
@save_env_list
;
while
(
@save_env_list
) {
my
$name
=
shift
(
@save_env_list
);
my
(
$old
,
$new
) = (
shift
(
@old_env_vals
),
shift
(
@new_env_vals
));
if
(
$old
ne
$new
) {
::
log
BUILD_ENV
=>
$tinfo
,
$name
,
$new
,
$old
if
$log_level
;
return
1;
}
}
return
;
}
sub
build_check {
my
(
undef
,
$tinfo
,
$sorted_dependencies
,
$command_string
,
$build_cwd
,
$sig_method
,
$env
,
$ignore_action
,
$ignore_architecture
,
$only_action
) =
@_
;
my
(
$last_cmd
,
$arch
,
$sorted_deps
,
$dep_sigs
,
$symlink
) =
FileInfo::build_info_string(
$tinfo
,
qw(COMMAND ARCH SORTED_DEPS DEP_SIGS SYMLINK)
);
unless
(
defined
$tinfo
->{BUILD_INFO} ) {
::
log
BUILD_NONE
=>
$tinfo
if
$::log_level;
return
1;
}
unless
( %{
$tinfo
->{BUILD_INFO}} ||
$only_action
) {
::
log
BUILD_INVALID
=>
$tinfo
if
$::log_level;
return
1;
}
unless
(
$ignore_action
||
$last_cmd
&&
$command_string
eq
$last_cmd
) {
::
log
BUILD_CMD
=>
$tinfo
,
$last_cmd
||
''
,
$command_string
if
$::log_level;
return
1;
}
$arch
||=
''
;
if
( !
$symlink
&& !
$ignore_architecture
&& ::ARCHITECTURE ne
$arch
) {
warn
"
last
compilation was on the
$arch
architecture,
and this is on
" . ::ARCHITECTURE . "
.
These are technically different and force a recompilation of everything,
but this may not be what you want. The difference is most likely caused
by running a different copy of perl.\n"
if
$::warn_level &&
::ARCHITECTURE =~ /^i[34567]86-linux/ &&
$arch
=~ // &&
!
$last_compilation_warning_x86
++;
::
log
BUILD_ARCH
=>
$tinfo
,
$arch
, ::ARCHITECTURE
if
$::log_level;
return
1;
}
return
undef
if
$only_action
||
$symlink
;
return
1
if
_check_env
$tinfo
,
$env
, $::log_level;
my
@old_dep_list
=
map
exists
$build_cwd
->{DIRCONTENTS} &&
$build_cwd
->{DIRCONTENTS}{
$_
} || FileInfo::path_file_info(
$_
,
$build_cwd
),
split
/\01/,
$sorted_deps
;
if
(
@old_dep_list
!=
@$sorted_dependencies
) {
report_changed_dependencies(
\
@old_dep_list
,
$sorted_dependencies
,
$tinfo
,
$build_cwd
);
return
1;
}
my
$changed_dependencies
;
my
@old_dep_sigs
=
split
/\01/,
$dep_sigs
, -1;
for
(
my
$depidx
= 0;
$depidx
<
@$sorted_dependencies
; ++
$depidx
) {
my
$dep
=
$sorted_dependencies
->[
$depidx
];
next
if
FileInfo::assume_unchanged(
$dep
);
if
(
$dep
->{ASSUME_CHANGED}) {
::
log
BUILD_MARK_NEW
=>
$tinfo
,
$dep
if
$::log_level;
return
1;
}
if
(
$old_dep_list
[
$depidx
] !=
$dep
) {
report_changed_dependencies(
\
@old_dep_list
,
$sorted_dependencies
,
$tinfo
,
$build_cwd
);
return
1;
}
next
if
$changed_dependencies
;
my
$sig
=
$sig_method
->signature(
$dep
);
if
(!
defined
(
$sig
) ||
$sig
ne (
$old_dep_sigs
[
$depidx
] ||
''
)) {
::
log
BUILD_CHANGED
=>
$tinfo
,
$dep
if
$::log_level;
$changed_dependencies
= 1;
}
}
$changed_dependencies
?
'DEPENDENCIES'
:
undef
;
}
sub
report_changed_dependencies {
$::log_level or
return
;
my
(
$old_deps
,
$new_deps
,
$tinfo
) =
@_
;
my
%old_deps
=
map
+(
int
,
$_
),
@$old_deps
;
my
@not_in_old_deps
;
foreach
(
@$new_deps
) {
push
@not_in_old_deps
,
$_
if
!
delete
$old_deps
{
int
()};
}
::
log
BUILD_DEP_DEL
=>
$tinfo
, [
values
%old_deps
]
if
%old_deps
;
::
log
BUILD_DEP_ADD
=>
$tinfo
, \
@not_in_old_deps
if
@not_in_old_deps
;
}
sub
build_check_from_build_info {
my
(
undef
,
$bc_entry
,
$sorted_dependencies
,
$command_string
,
undef
,
$sig_method
,
$env
,
$ignore_action
,
$ignore_architecture
,
$only_action
) =
@_
;
my
(
$last_cmd
,
$arch
,
$dep_sigs
) =
FileInfo::build_info_string(
$bc_entry
,
qw(COMMAND ARCH DEP_SIGS)
);
!
$ignore_action
and !
$last_cmd
||
$command_string
ne
$last_cmd
and
return
1;
return
undef
if
$only_action
;
!
$ignore_architecture
and ::ARCHITECTURE ne (
$arch
||
''
)
and
return
1;
return
1
if
_check_env
$bc_entry
,
$env
;
my
@old_dep_sigs
=
split
/\01/,
$dep_sigs
, -1;
return
1
if
@old_dep_sigs
!=
@$sorted_dependencies
;
for
(
my
$depidx
= 0;
$depidx
<
@old_dep_sigs
; ++
$depidx
) {
return
1
if
$old_dep_sigs
[
$depidx
] ne
$sig_method
->signature(
$sorted_dependencies
->[
$depidx
]);
}
undef
;
}
sub
build_cache_key {
$::has_md5_signatures or
return
undef
;
my
(
undef
,
$tinfo
,
$sorted_dependencies
,
$key
,
$build_cwd
,
$sig_method
,
$env
,
$ignore_action
,
$ignore_architecture
,
$only_action
) =
@_
;
$key
=
''
if
$ignore_action
;
$key
.=
$ignore_architecture
?
"\01"
:
"\01"
. ::ARCHITECTURE;
if
( !
$only_action
) {
for
(
@$sorted_dependencies
) {
my
$content_based_signature
=
$sig_method
->signature(
$_
);
unless
( Signature::is_content_based(
$content_based_signature
) ) {
$content_based_signature
= Signature::md5::signature(
$Signature::md5::md5
,
$_
);
}
$key
.=
"\01$content_based_signature"
;
}
$key
.=
"\01$_\02$env->{$_}"
for
sort
keys
%$env
;
}
$key
.=
"\01"
. FileInfo::relative_filename
$tinfo
->{
'..'
},
$build_cwd
if
$tinfo
->{
'..'
} !=
$build_cwd
;
if
( FileInfo::case_sensitive_filenames ) {
$key
= Digest::MD5::md5_base64(
$key
);
$key
=~
tr
|/|%|;
}
else
{
$key
= Digest::MD5::md5_hex(
$key
);
}
$key
.
"_"
.
$tinfo
->{NAME};
}
sub
update_dep_sigs {
my
(
undef
,
$output_finfo
,
$rule
) =
@_
;
my
%deps
;
my
(
$sorted_deps
,
$dep_sigs
) =
FileInfo::build_info_string(
$output_finfo
,
qw(SORTED_DEPS DEP_SIGS)
);
my
@deps
=
split
/\01/,
$sorted_deps
;
@deps
{
@deps
} =
split
/\01/,
$dep_sigs
, -1;
my
$sig_method
=
$rule
->signature_method;
my
$dir
=
$rule
->makefile->{CWD};
for
my
$dep
(
@deps
) {
unless
( Signature::is_content_based(
$deps
{
$dep
}) ) {
$deps
{
$dep
} =
$sig_method
->signature(file_info(
$dep
,
$dir
));
}
}
FileInfo::set_build_info_string(
$output_finfo
,
'DEP_SIGS'
,
join
(
"\01"
,
map
$deps
{
$_
},
@deps
) );
}
sub
changed_dependencies {
my
(
undef
,
$tinfo
,
$signature_method
,
$build_cwd
,
@dep_list
) =
@_
;
my
(
$old_dep_str
,
$dep_sigs
) =
FileInfo::build_info_string(
$tinfo
,
qw(SORTED_DEPS DEP_SIGS)
);
return
@dep_list
unless
$old_dep_str
;
my
%old_deps
;
@old_deps
{
map
file_info(
$_
,
$build_cwd
),
split
/\01/,
$old_dep_str
} =
split
/\01/,
$dep_sigs
, -1;
my
@changed_deps
;
foreach
my
$dep
(
@dep_list
) {
next
if
FileInfo::assume_unchanged
$dep
;
my
$old_sig
=
$old_deps
{
$dep
};
!
defined
(
$old_sig
) ||
$dep
->{ASSUME_CHANGED} ||
$old_sig
ne (
$signature_method
->signature(
$dep
) ||
''
) and
push
@changed_deps
,
$dep
;
}
@changed_deps
;
}
1;