package Signature::exact_match;

use strict;

use Signature;

@Signature::exact_match::ISA = qw(Signature);

=head1 NAME

Signature::exact_match -- a signature class that requires that dependencies have exactly the same signature they did on the last build

=head1 USAGE

This is the default signature class.  You don't have to do anything to use it
unless you override it from the command line.  You can specify it explicitly
in the Makefile using

   target : dependencies
	  : signature exact_match
	$(commands_to_build)


=head1 DESCRIPTION

This class forces a recompilation if any of the following are different from
the last time this particular rule was executed:

=over 4

=item *

The build command or the directory from which it is executed.

=item *

The architecture this is running on (e.g., i386, sparc, alpha, etc.).

=item *

The signatures of each dependency.

=back

Returns undef if no build is necessary, or a true value if a build is
necessary.

=cut

my $last_compilation_warning_x86 = 0;

$Signature::exact_match::exact_match = bless {}; # Make the singleton object.

sub build_check {
  shift @_;			# Get rid of dummy argument.

  my ($tinfo, $command_string, $cwd, $sorted_dep_str, $dep_sig_str) = @_;

#
# Do the default, which is exact matching.  Note that we don't have to
# check the signature, because if it doesn't match, the build info file
# will be invalid anyway.  See FileInfo::load_build_info.
#  
  if ($command_string ne ($tinfo->build_info_string("COMMAND") || '')) {
    if ($main::log_level) {
      my ($last_cmd, $this_cmd);
      ($last_cmd = $tinfo->build_info_string("COMMAND") || '') =~ s/\n/\\n/g;
      ($this_cmd = $command_string) =~ s/\n/\\n/g;
				# Make the strings more printable.
      main::print_log("Rebuild ", $tinfo->name, " because last build command (\"$last_cmd\") differs from current command (\"$this_cmd\")");
    }	
    return 1;
  }

  if ($cwd ne ($tinfo->build_info_string("CWD") || '')) {
    $main::log_level and
      main::print_log("Rebuild ", $tinfo->name, " because build cwd changed\n");
    return 1;
  }

  if ($main::architecture ne ($tinfo->build_info_string("ARCH") || '')) {
#
# The pentium architectures are all more or less equivalent, but have different
# architecture flags.  Give a warning (so at least the user isn't surprised
# about recompilation).
#
    if ($main::architecture =~ /^i[34567]86-linux/ &&
	$tinfo->build_info_string("ARCH") =~ /^i[34567]86-linux/) {
      unless ($last_compilation_warning_x86++) {
	$main::warn_level and
	  main::print_error("warning: last compilation was on the ",
			    $tinfo->build_info_string("ARCH"),
			    " architecture, and this is on $main::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.");
      }
    }
    $main::log_level and
      main::print_log("Rebuild ", $tinfo->name, " because last build was on ",
		      $tinfo->build_info_string("ARCH") || '',
		      " and this is on ", $main::architecture);
    return 1;
  }

  my $last_dep_sigs = $tinfo->build_info_string("DEP_SIGS") || '';

  if ($last_dep_sigs ne $dep_sig_str) {
				# Is anything different?  (This will be
				# different not only if a file has changed,
				# but also if the dependency list has changed,
				# so we don't want to check the dependency
				# list directly.  In fact, checking it can
				# cause problems when we get files out of
				# a repository.)
    if ($main::log_level) {	# Do we have to figure out what is different?
      my $last_dep_str = $tinfo->build_info_string("SORTED_DEPS") || '';
      my (%cur_deps, %last_deps);
      @cur_deps{split(/\01/, $sorted_dep_str)} = split(/\01/, $dep_sig_str);
      @last_deps{split(/\01/, $last_dep_str)} = split(/\01/, $last_dep_sigs);

      foreach (keys %cur_deps, keys %last_deps) {
	next if (($cur_deps{$_} || '') eq ($last_deps{$_} || ''));
	
	main::print_log("Rebuild ", $tinfo->name, " because $_ ",
			($cur_deps{$_} ? 
			 ($last_deps{$_} ? "changed" :
			  "was not previously a dependency") :
			 "is no longer a dependency"));
      }
    }
    return 1;
  }

  return undef;		# No build necessary.
 
}

1;
