+#!/usr/bin/env perl
+#
+# Copyright © 2011 Nick Bowler
+#
+# Prepare the Gnulib tree for inclusion into a non-recursive automake build.
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+use strict;
+use List::Compare;
+use Getopt::Long;
+
+my $output = undef;
+my $input = undef;
+my $m4output = undef;
+my $m4macro = "DX_FIX_GNULIB";
+
+Getopt::Long::Configure("gnu_getopt", "no_auto_abbrev");
+GetOptions(
+ "o|output=s" => \$output,
+ "i|input=s" => \$input,
+ "m|m4output=s" => \$m4output,
+ "M|m4macro=s" => \$m4macro,
+);
+
+open STDOUT, ">", $output or die "$output: $!\n" if (defined $output);
+open STDIN, "<", $input or die "$input: $!\n" if (defined $input);
+
+my $printed_header = 0;
+my (%allvars, %sourcevars);
+
+sub drop {
+ undef $_;
+ next;
+}
+
+sub basename {
+ my $file = shift;
+ $file =~ m|(?:.+/)?([^/]+)/?|;
+ return $1;
+}
+
+sub mangle_file {
+ my $word = shift;
+
+ if ($word =~ /^\$\(([[:word:].]+)\)$/) {
+ # Don't touch variables now, but record them for later.
+ $sourcevars{$1} = 1;
+ } elsif ($word =~ /^\$\((?:top_)?(?:srcdir|builddir)\)/) {
+ # Do nothing. Generic transformation will take care of
+ # $(srcdir) and $(builddir).
+ } elsif ($word =~ /^[[:word:].+\/-]+$/) {
+ # Fix up things that look like filenames.
+ $word = "lib/$word";
+ } else {
+ print STDERR "$0: warning: unrecognized source file: $word\n";
+ }
+
+ return "$word";
+}
+
+sub mangle_variable {
+ my $raw = shift;
+
+ $raw =~ /([^=]+=)[[:space:]]*(.*)/;
+ my ($left, @right) = ($1, split(/[[:space:]]+/, $2));
+
+ return join(" ", ($left, map(mangle_file($_), @right))) . "\n";
+}
+
+sub mangle_target {
+ my $raw = shift;
+
+ $raw =~ /([^:]+):[[:space:]]*(.*)/;
+ my @left = split(/[[:space:]]+/, $1);
+ my @right = split(/[[:space:]]+/, $2);
+
+ @left = map(mangle_file($_), @left);
+ @right = map(mangle_file($_), @right);
+
+ return join(" ", @left) . ": " . join(" ", @right) . "\n";
+}
+
+while (<STDIN>) {
+ next if (/^#/);
+
+ if (!$printed_header) {
+ print "# Postprocessed by ", basename($0), "\n";
+ $printed_header = 1;
+ drop;
+ }
+
+ # For some reason, gnulib-tool adds core dumps to "make mostlyclean".
+ # Since these files are (hopefully!) not created by make, they should
+ # not be cleaned.
+ drop if (/^MOSTLYCLEANFILES.*core/);
+
+ # Some modules set AM_CPPFLAGS/AM_CFLAGS/etc. in a manner that is not
+ # useful for non-recursive builds. Strip them out.
+ drop if (/^(AM_CPPFLAGS|AM_CFLAGS)/);
+
+ # Rewrite automake hook targets to be more generic.
+ if (s/^(.*)-local:/\1-gnulib:/) {
+ print ".PHONY: $1-gnulib\n";
+ print "$1-local: $1-gnulib\n";
+ s/$1-generic//;
+
+ # Don't let these targets get confused with filenames below.
+ next;
+ }
+
+ # We need to mangle filenames in make variables; prepending a lib/ on
+ # relative paths. The following should catch all variable assignments
+ # that need mangling.
+ if (/^([[:word:]]+)[[:space:]]*\+?=/) {
+ $allvars{$1} = 1;
+
+ if (/_SOURCES|CLEANFILES|EXTRA_DIST|[[:upper:]]+_H/) {
+ $_ = mangle_variable($_);
+ }
+ }
+
+ # Targets are similar to variables: the target and its dependencies
+ # need to be mangled.
+ if (/:/) {
+ $_ = mangle_target($_);
+ }
+
+ # Finally, references to $(srcdir) and $(builddir) need to be fixed up.
+ s:\$\(srcdir\):\$\(top_srcdir\)/lib:g;
+ s:\$\(builddir\):\$\(top_builddir\)/lib:g;
+} continue { print };
+
+# Some filenames are AC_SUBSTed by the Gnulib macros, and thus we need to
+# prepend lib/ if and only if they're not empty. Unfortunately, make is not
+# powerful to do this, so we need to put this transformation into configure
+# itself by defining a new autoconf macro.
+if (defined $m4output) {
+ my $lc = List::Compare->new('-u', '-a', \%sourcevars, \%allvars);
+ my @vars = $lc->get_unique;
+
+ open(M4OUT, '>', $m4output) or die "$m4output: $!\n";
+
+ print M4OUT "dnl This file was generated by fix-gnulib.pl\n";
+ print M4OUT "AC_DEFUN([$m4macro], [dnl\n";
+ foreach (@vars) {
+ print M4OUT "$_=\${$_:+lib/\$$_}\n";
+ }
+ print M4OUT "])\n";
+
+ close M4OUT;
+}