1# $Id: Signature.pm,v 1.14 2012/03/04 13:56:35 pfeiffer Exp $
2package Mpp::Signature;
3
4=head1 NAME
5
6Mpp::Signature -- Interface definition for various signature classes
7
8=head1 USAGE
9
10Derive a package from this package.
11
12=head1 DESCRIPTION
13
14Makepp is quite flexible in the algorithm it uses for deciding whether
15a target is out of date with respect to its dependencies.  Most of this
16flexibility is due to various different implementations of the Mpp::Signature
17class.
18
19Each rule can have a different signature class associated with it,
20if necessary.  In the makefile, the signature class is specified by
21using the :signature modifier, like this:
22
23   %.o : %.c
24	   : signature special_build
25	   $(CC) $(CFLAGS) -c $(FIRST_DEPENDENCY) -o $(TARGET)
26
27This causes the signature class C<Mpp::Signature::special_build> to be used for
28this particular rule.
29
30Only one object from each different signature class is actually created; the
31object has no data, and its only purpose is to contain a blessed reference to
32the package that actually implements the functions.  Each rule contains a
33reference to the Mpp::Signature object that is appropriate for it.  The object is
34found by the name of the Mpp::Signature class.  For example, the above rule uses
35the object referenced by C<$Mpp::Signature::special_build::special_build>.  (The
36purpose of this naming scheme is to make it impossible to inherit accidentally a
37singleton object, which would cause the wrong Mpp::Signature class to be used.)
38
39
40=head2 signature
41
42   $signature = $sigobj->signature($objinfo);
43
44This function returns a signature for the given object (usually a
45Mpp::File class, but possibly some other kind of object).  A signature is
46simply an ASCII string that will change if the object is modified.
47
48$sigobj is the dummy Mpp::Signature class object.
49
50$objinfo is the a reference to B<makepp>'s internal description of that object
51and how it is to be built.  See L<makepp_extending> for details.
52
53The default signature function simply calls $objinfo->signature, i.e., it uses
54the default signature function for objects of that class.  For files, this is
55the file date concatenated with the file size.
56
57=cut
58
59our $signature = bless [];	# Make the singleton object.
60
61sub get {
62  my( $fullname, $mkfile_line ) = @_;
63  my( $name, $sep, $re ) = split /(\.\(?|\()/, $fullname, 2;
64  $name =~ tr/-/_/;
65  $name = 'c_compilation_md5' if $name eq 'C'; # Alias
66  my $sig = eval "use Mpp::Signature::$name; \$Mpp::Signature::${name}::$name" ||
67    eval "use Signature::$name; warn qq!$mkfile_line: name Signature::$name is deprecated, rename to Mpp::Signature::$name\n!; \$Signature::${name}::$name";
68  if( defined $re ) {
69    die "$mkfile_line: Can't add suffixes to inexistent signature $name\n" unless $sig;
70    die "$mkfile_line: Signature $name doesn't support adding suffixes\n" unless UNIVERSAL::can( $sig, 'recognizes_file' );
71
72    my $class = ref( $sig ) . '::_'; # Make an unlikely-to-exist subclass name.
73    unless( keys %{$class.'::'} ) {
74      my $super = $sig;
75      @{$class.'::ISA'} = ref $sig;
76      *{$class.'::recognizes_file'} = sub {
77	($_[0][1] ? Mpp::File::absolute_filename $_[1] : $_[1]{NAME}) =~ $_[0][0] or
78	    $super->recognizes_file( $_[1] );
79      };
80    }
81
82    if( $sep eq '.' ) {
83      my $orig = $re;
84      $re = quotemeta $re;
85      $re =~ s/\\,/|/g and $re = "(?:$re)";
86      $sig = ${$class."::$orig"} ||= bless [qr/\.$re$/], $class;
87    } else {
88      $re =~ s/\)$// or die "$mkfile_line: No final parenthesis in $fullname\n";
89      $sep eq '.(' && $re =~ /\|/ and $re = "(?:$re)";
90      $sig = ${$class."::$re"} ||=
91	bless $sep eq '.(' ? [qr/\.$re$/] : [qr/$re/, $re =~ /\//], $class;
92    }
93  }
94  $sig;
95}
96
97
98sub signature {
99  return $_[1]->signature;
100}
101
102# This is used to determine whether the signature is file content based, as
103# opposed to timestamp based.  This is used to determine whether the signature
104# can be used in a build cache key, because we never want to use
105# timestamp-based signatures for that.
106sub is_content_based {
107  # A heuristic that works for all the current Mpp::Signature subclasses, but
108  # not necessarily for all possible subclasses.
109  return $_[0] =~ m|^[+/A-Za-z\d]{22}$|;
110}
111
112=head1 BUGS
113
114A signature must not contain 22 consecutive characters that are alphanumeric
115or '+' or '/', unless the signature is dependent only on file content and
116expected to be alias-free.
117Otherwise, aliases can cause corruption when you use build caches.
118There probably ought to be a more robust way to determine whether a signature
119was generated by a method that is prone to aliasing.
120
121=cut
122
1231;
124