]> git.draconx.ca Git - dxcommon.git/commitdiff
Integrate Gnulib non-recursively.
authorNick Bowler <nbowler@draconx.ca>
Mon, 19 Sep 2011 01:46:14 +0000 (21:46 -0400)
committerNick Bowler <nbowler@draconx.ca>
Wed, 21 Sep 2011 23:25:09 +0000 (19:25 -0400)
With a little bit of mangling, it's possible to make the makefile
fragment produced by gnulib-tool suitable for use in our non-recursive
makefile.

scripts/fix-gnulib.pl [new file with mode: 0755]

diff --git a/scripts/fix-gnulib.pl b/scripts/fix-gnulib.pl
new file mode 100755 (executable)
index 0000000..6663e6e
--- /dev/null
@@ -0,0 +1,154 @@
+#!/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;
+}