[Pkg-mono-svn-commits] rev 1558 - cli-common/trunk

Mirco Bauer meebey-guest@costa.debian.org
Sat, 09 Apr 2005 16:15:55 +0000


Author: meebey-guest
Date: 2005-04-09 16:15:54 +0000 (Sat, 09 Apr 2005)
New Revision: 1558

Added:
   cli-common/trunk/dh_clideps
   cli-common/trunk/dh_makeclilibs
   cli-common/trunk/ildasm-monodis
Log:
- removed egrep call, using perl now! :)



Added: cli-common/trunk/dh_clideps
===================================================================
--- cli-common/trunk/dh_clideps	2005-04-09 15:32:55 UTC (rev 1557)
+++ cli-common/trunk/dh_clideps	2005-04-09 16:15:54 UTC (rev 1558)
@@ -0,0 +1,271 @@
+#!/usr/bin/perl -w
+
+=head1 NAME
+
+dh_clideps - calculates CLI (.NET) dependencies
+
+=cut
+
+use strict;
+use File::Find;
+use Debian::Debhelper::Dh_Lib;
+
+#eval 'use Debian::Debhelper::Dh_Lib';
+#print "You need to install the debhelper package in order to use this program!" if $@;
+
+=head1 SYNOPSIS
+
+B<dh_clideps> [S<I<debhelper options>>]
+
+=head1 DESCRIPTION
+
+dh_clideps is a debhelper program that is responsible for generating the
+${cli:Depends} substitutions and adding them to substvars files.
+
+The program will look at .dll/.exe and .config files in your package, and
+will use the embedded dependency information to generate a dependency
+string on assembly and shared libs packages, including the setting of
+version ranges (as declared by the shlibs/clilibs files of the used
+packages). The dependency on a certain CLR (.NET runtime) version will be
+also added to the final variable.
+
+Note: the dependencies on shared libraries may be not resolved correctly
+if there are no .config files associated with the the .exe/.dll file
+which refers to the particular shared library (by its SONAME).
+
+If you use this program, your package should build-depend on cli-common
+(>= 0.1).
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-d>
+
+Attempt to predict and avoid duplicates that may appear if you package
+both, native shared libraries and DLL assemblies in one package.
+The list of possibly duplicating candidates is expected to be in the
+variable shlib:Depends from debian/package.substvars.
+
+=item B<-r>
+
+Don't set a strong versioned dependency on mono-jit or other CLR packages.
+This option can be used to specify a relaxed dependency on the VM
+by-hand in the control file, eg. "mono-jit | cli-virtual-machine".
+
+=cut
+
+init();
+
+my $clr;
+my $cli = '/usr/bin/cli';
+my $cli_version = `$cli --version 2>&1`;
+my $cli_parser;
+
+if (-x "/usr/bin/monodis" ) {
+    $clr = "mono";
+    $cli_parser = "/usr/bin/monodis";
+    verbose_print("Will use Mono (/usr/bin/monodis) for CIL parsing.");
+} elsif (-x "/usr/bin/ildasm") {
+    $clr = "pnet";
+    $cli_parser = "/usr/share/cli-common/ildasm-monodis";
+    verbose_print("Will use Portable.NET (/usr/bin/ildasm) for CIL parsing.");
+} else {
+    error("Could not find a CIL disassembler, aborting.");
+}
+
+{
+  local $/="";
+  open(FILE, 'debian/control');
+  @filedata = <FILE>;
+  close FILE;
+  if (!($filedata[0] =~ /Build-Depends: .*cli-common \(>= 0\.1\)/)) {
+      warning("Warning! No Build-Depends on cli-common (>= 0.1)!");
+  }
+}
+
+if (!defined $cli_version || $cli_version eq "" ) {
+    error( "No CLR is installed, aborting. (Probably forgot to Build-Depend on cli-virtual-machine.)");
+} elsif ($clr eq "mono") {
+    if ($cli_version =~ /(mint|version)\ ([\d\.]+)/) {
+      $cli_version = "$2";
+    } else {
+      error("Unable to parse Mono version out of \"$cli_version\".");
+    }
+} elsif ($clr eq "pnet") {
+    if ($cli_version =~ /ILRUN\ ([\d\.]+)/) {
+      $cli_version = "$1";
+    } else {
+      error("Unable to parse Portable.NET version out of \"$cli_version\".");
+    }
+} else {
+    error("Unable to detect CLR, aborting.");
+}
+
+# Cleaning the paths given on the command line
+foreach (@ARGV) {
+    s#/$##;
+    s#^/##;
+}
+
+my $fh;
+my %libdata;
+open($fh, "cat /var/lib/dpkg/info/*.clilibs debian/*/DEBIAN/clilibs 2>/dev/null |");
+while (<$fh>) {
+    /(\S+)\s+(\S+)\s+(\w.*)\n?/;
+    $libdata{"$1/$2"} = $3;
+}
+
+my %shlibdata;
+
+foreach my $package (@{$dh{DOPACKAGES}}) {
+    my $tmp = tmpdir($package);
+    my %deps;
+    my @depkgs;
+
+    delsubstvar($package, "cli:Depends");    # for idempotency
+
+    # find binaries
+    find (sub {
+        my $vers;
+        return unless -f and /\.(exe|dll)$/;
+        local *F;
+        my $file = $_;
+        return unless open F, "LANG=C $cli_parser --assemblyref $file 2>&1 |";
+        
+        if (my $extra = extraDeps ($file)) {
+           push(@depkgs, $extra);
+        }
+        our($vers, $name, $key);
+        while (<F>) {
+            $vers = $1 if /Version=(.*)\n/;
+            $name = $1 if /Could not find assembly ([^,]+),/;
+            $name = $1 if /Name=(.*)\n/;
+            $vers = "$1.$2" if /Major\/Minor:\s*(\d+),(\d+)/;
+            $vers .= ".$1.$2" if /Build:\s*(\d+),(\d+)/;
+
+            if (/0x\S+:.([ABCDEF0123456789 ]+)\n/ || /Token:\s*(\w+)/) {
+                $key = $1;
+                $key =~ s/\ //g;
+                $key = $vers . "__" . lc($key);
+                my $compat = "$name/$key";
+                if (!defined($libdata{$compat})) {
+                    # reuse the key variable
+                    #if ( resolveShlib( $file, $name, \$key ) ) {
+                    #    push ( @depkgs, $key );
+                    #}
+                    #else
+                    {
+                        warning("Warning! No Debian dependency data for $name ($key)!");
+                    }
+                } else {
+                    push(@depkgs, $libdata{$compat});
+                }
+                #print "ok, ".$deps{ "$name/$vers" . "__" . lc($key) };
+            }
+        }
+        close F;
+     }, $tmp);
+
+    my %depkgsFiltered;
+    for (@depkgs) {
+       for (split(/\s*,\s*/, $_ )) {
+          # filter dupes and don't depend on this package
+          /^(\S+)/;
+          $depkgsFiltered{$_} = 1 if($1 ne $package);
+       }
+    }
+    # now filter the dupes coming from shlibs
+    if (defined($dh{D_FLAG})) {
+       if(open($fh, "<debian/$package.substvars" )) {
+          while (<$fh>) {
+             if (/^shlibs:Depends=(.*)\n?/) {
+                for (split(/\s*,\s*/, $1)) {
+                   delete $depkgsFiltered{$_};
+                }
+             }
+          }
+       } else {
+          verbose_print("Could not read debian/$package.substvars");
+       }
+    }
+
+    my $deps;
+    if (defined($dh{R_FLAG})) {
+        if ($clr eq "mono") {
+          $deps = "mono-jit (>= $cli_version)";
+        } elsif ($clr eq "pnet") {
+          $deps = "pnet-interpreter (>= $cli_version)";
+        }
+    }
+    
+    $deps .= join(", ", "",
+        sort {
+            # beautify the sort order, requested by meebey
+            my $apkg;
+            $a=~/^\S+/;
+            $apkg=$&;
+            $b=~/^\S+/;
+            if($apkg eq $&) {
+               return -1 if( ($a=~/>=/) && ($b=~/<</));
+               return 1 if( ($b=~/>=/) && ($a=~/<</));
+            }
+            $a cmp $b;
+        } (keys %depkgsFiltered)
+    );
+
+    addsubstvar($package, "cli:Depends", $deps);
+}
+
+sub resolveShlib {
+    our($file, $name, $outRef) = @_;
+    if (!%shlibdata) {
+        open($fh, "cat /var/lib/dpkg/info/*.shlibs debian/shlibs.local debian/*/DEBIAN/shlibs 2>/dev/null |");
+        while (<$fh>) {
+            /(\S+)\s+(\S+)\s+(\w.*)\n?/;
+            $shlibdata{"$1.so.$2"} = $3;
+        }
+    }
+    
+    if (-r "$file.config" &&
+        `cat $file.config` =~ /dll=\W*$name[^>]+\Wtarget\W*=\W*(\w[\w.\-_\d]+)/ &&
+        defined( $shlibdata{$1})) {
+        $$outRef = $shlibdata{$1};
+        return 1;
+    }
+    return 0;
+}
+
+sub extraDeps {
+   my $config=$_[0].".config";
+   return undef if (! -r $config);
+   my $ret=undef;
+
+   if (!%shlibdata) {
+      open($fh, "cat /var/lib/dpkg/info/*.shlibs debian/shlibs.local debian/*/DEBIAN/shlibs 2>/dev/null |");
+      while (<$fh>) {
+         /(\S+)\s+(\S+)\s+(\w.*)\n?/;
+         $shlibdata{"$1.so.$2"} = $3;
+      }
+   }
+
+   $config = `cat $config`;
+   while ($config=~s/\Wtarget\W*=\W*(\w[\w.\-\d]+)//) {
+      $ret.= (", ".$shlibdata{$1}) if(defined($shlibdata{$1}));
+   }
+   $ret =~ s/^, // if $ret;
+   return $ret;
+}
+
+=head1 SEE ALSO
+
+L<debhelper(7)>
+
+This program is a part of cli-common.
+
+=head1 AUTHOR
+
+Mirco Bauer <meebey@meebey.net>, Eduard Bloch <blade@debian.org>,
+partialy based on code from Brendan O'Dea <bod@debian.org>.
+
+=cut


Property changes on: cli-common/trunk/dh_clideps
___________________________________________________________________
Name: svn:executable
   + *

Added: cli-common/trunk/dh_makeclilibs
===================================================================
--- cli-common/trunk/dh_makeclilibs	2005-04-09 15:32:55 UTC (rev 1557)
+++ cli-common/trunk/dh_makeclilibs	2005-04-09 16:15:54 UTC (rev 1558)
@@ -0,0 +1,308 @@
+#!/usr/bin/perl -w
+
+=head1 NAME
+
+dh_makeclilibs - automatically create clilibs file
+
+=cut
+
+use strict;
+use Debian::Debhelper::Dh_Lib;
+
+=head1 SYNOPSIS
+
+B<dh_makeclilibs> [S<I<debhelper options>>] [B<-r>] [B<-V>I<[dependancies]>] [B<-m>I<minversion>] [B<-l>I<nextincompatible>] [B<-X>I<item>]
+
+=head1 DESCRIPTION
+
+dh_makeclilibs is a debhelper program that automatically scans for
+versioned CIL (.NET) assemblies, and generates a clilibs file for the
+libraries it finds.
+
+By default, dh_makeclilibs scans the .dll files in the package
+directories and writes the discovered compatibility data (major/minor,
+build, token) to "clilibs" files in the appropriate packages.
+ 
+However, if a file like debian/package.clilibs is found, this one will
+be installed and no scanning is performed.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-V>, B<-V>I<dependancies>
+
+=item B<--version-info>, B<--version-info=>I<dependancies>
+
+By default, the clilibs file generated by this program does not make packages
+depend on any particular version of the package containing the assembly.
+It may be necessary for you to add some version dependency
+information to the clilibs file. If -V is specified with no dependency
+information, the current version of the package is plugged into a
+dependency that looks like "packagename (>= packageversion)". If -V is
+specified with parameters, the parameters can be used to specify the exact
+dependency information needed (be sure to include the package name).
+
+Beware of using -V without any parameters; this is a conservative setting
+that always ensures that other packages' shared library dependencies are at
+least as tight as they need to be, so that if the maintainer screws up then
+they won't break. The flip side is that packages might end up with
+dependencies that are too tight and so find it harder to be upgraded.
+
+=item B<-m>I<minversion>
+
+Like -V, but specifies only the version string, the package name comes
+from the package that is actually processed. This option is more
+flexible if you try to set a range of valid versions for different
+assembly packages coming from one source package.
+
+=item B<-l>I<nextincompatible>
+
+Specifies the (expected) version of this package when the compatibility
+to the current assemblies will break.
+
+=item B<-r>
+
+An experimental option to automaticaly guess the next incompatible
+upstream version and insert them (like working with -l and -m options,
+see above). Do not expect the guessed values to be always correct -
+normally, the usualy assumed version string has the form
+generation.major.minor where versions with changes in "minor" are
+compatible and "major" versions break with compatibility.
+
+=item B<-X>I<item>, B<--exclude=>I<item>
+
+Exclude files that contain "item" anywhere in their filename or directory 
+from being treated as shared libraries.
+
+=back
+
+=head1 EXAMPLES
+
+ dh_makeclilibs
+
+Assuming this is a package named libfoobar0.9x-cil, generates a clilibs file that
+looks something like:
+ libfoobar  1.0.2345.0_23a12f34  libfoobar0.9x-cil
+
+ dh_makeclilibs -V
+
+Assuming the current version of the package is 0.93-3, generates a clilibs
+file that looks something like:
+ libfoobar 1.0.2345.0_23a12f34 libfoobar0.9x-cil (>= 0.93-3)
+
+ dh_makeclilibs -V 'libfoobar0.9x-cil (>= 0.92)'
+
+Generates a clilibs file that looks something like:
+  libfoobar 1.0.2345.0_23a12f34 libfoobar0.9x-cil (>= 0.92)
+
+Assuming that your package creates libfoobar-cil and liblafasel-cil,
+which are compatible to 0.92 versions but the upstream is going to break
+compatibility in the next version, 0.94:
+
+ dh_makeclilibs -m 0.92 -l 0.94
+
+Generates clilibs file that looks something like:
+
+  libfoobar 1.0.2345.0_23a12f34 libfoobar-cil (>= 0.92), libfoobar-cil (<< 0.94)
+
+and
+
+  liblafasel 1.0.2345.0_23a12f34 liblafasel-cil (>= 0.92), liblafasel-cil (<< 0.94)
+
+=cut
+
+init();
+
+my $clr;
+my $cli = '/usr/bin/cli';
+my $cli_version = `$cli --version 2>&1`;
+my $cli_parser;
+
+if (-x "/usr/bin/monodis") {
+    $clr = "mono";
+    $cli_parser = "/usr/bin/monodis";
+    verbose_print("Will use Mono (/usr/bin/monodis) for CIL parsing.");
+} elsif (-x "/usr/bin/ildasm") {
+    $clr = "pnet";
+    $cli_parser = "/usr/share/cli-common/ildasm-monodis";
+    verbose_print("Will use Portable.NET (/usr/bin/ildasm) for CIL parsing.");
+} else {
+    error("Could not find a CIL disassembler, aborting.");
+}
+
+{
+  local $/="";
+  open(FILE, 'debian/control');
+  @filedata = <FILE>;
+  close FILE;
+  if (!($filedata[0] =~ /Build-Depends: .*cli-common \(>= 0\.1\)/)) {
+      warning("Warning! No Build-Depends on cli-common (>= 0.1)!");
+  }
+}
+
+my $fh;
+my %shlibdata;
+
+foreach my $package (@{$dh{DOPACKAGES}}) {
+    next if is_udeb($package);
+
+    my $tmp = tmpdir($package);
+
+    my %seen;
+    my $need_ldconfig = 0;
+
+    doit("rm", "-f", "$tmp/DEBIAN/clilibs");
+    if (-e "debian/$package.clilibs" ) {
+        complex_doit("cat debian/$package.clilibs > $tmp/DEBIAN/clilibs");
+    } else {
+        # So, we look for files or links to existing files with names that
+        # match "*.so*". Matching *.so.* is not good enough because of
+        # broken crap like db3. And we only look at real files not
+        # symlinks, so we don't accidentually add clilibs data to -dev
+        # packages. This may have a few false positives, which is ok,
+        # because only if we can get a library name and a major number from
+        # objdump is anything actually added.
+        my $exclude = '';
+        if (defined($dh{EXCLUDE_FIND}) && $dh{EXCLUDE_FIND} ne '') {
+            $exclude = "! \\( $dh{EXCLUDE_FIND} \\) ";
+        }
+        open(FIND, "find $tmp -type f \\( -name '*.dll' \\) $exclude |");
+        
+        dll:
+        while (<FIND>) {
+            chomp;
+            my ($library, $ver, $libfile);
+            $libfile = $_;
+            my $sig = `sn -T $_ 2>/dev/null`;
+            $sig =~ s/.*key token: (\w+).*/$1/is;
+            if ($sig=~/\s/) {
+               warning "$libfile has no valid signature, ignoring";
+               next dll;
+            }
+            my $dis = `$cli_parser --assembly $libfile 2>&1`;
+            if ($dis =~ m/Name:\s+(\S+)/) {
+               $library = $1;
+               $dis =~ m/Version:\s+(\S+)/;
+               $ver = $1;
+            } else {
+               # completely broken code, we need a mature app not
+               # depending on assembly loading
+               # verbose_print("trouble parsing monodis output, components not installed? Fallback to parsing the pure monodis output.");
+               # $dis = `monodis $libfile 2>&1`;
+               # $dis =~ /^module (\S+)/is;
+               # $library = $1;
+               # $library =~ s/'|"//;
+               warning("$cli_parser could not open $libfile, maybe some components not installed yet. Using filename to guess the assembly name :(");
+               $libfile=~ m,/(\d+\.\d+.\d+.\d+)__(\w+)/([^/]+)\.dll$,is;
+               next dll if (!($1 && $2 && $3));
+               $ver=$1;
+               $sig=$2;
+               $library=$3;
+            }
+
+            if (!-d "$tmp/DEBIAN") {
+                doit("install", "-d", "$tmp/DEBIAN");
+            }
+            my $deps = $package;
+
+            # Call isnative becuase it sets $dh{VERSION}
+            # as a side effect.
+            isnative($package);
+            my $version = $dh{VERSION};
+
+            # Old compatibility levels include the
+            # debian revision, while new do not.
+            if (!compat(3)) {
+                # Remove debian version, if any.
+                $version =~ s/-[^-]+$//;
+            }
+
+            if (defined($dh{M_PARAMS}) && $dh{M_PARAMS} ne '') {
+                $version = $dh{M_PARAMS};
+            }
+            if ($dh{V_FLAG_SET}) {
+                if ( $dh{V_FLAG} ne '' ) {
+                    $deps = $dh{V_FLAG};
+                } else {
+                    $deps = "$package (>= $version)";
+                }
+            }
+            if (defined( $dh{R_FLAG})) {
+                $version =~ s/-[^-]+$//;
+                my @uvers = split ( /\./, $version );
+                $uvers[1]++;
+                $deps = "$package (>= $version), $package (<< ".join(".", @uvers).")";
+            }
+            if (defined( $dh{M_PARAMS})) {
+                $deps = "$package (>= ".$dh{M_PARAMS}.")";
+            }
+            if (defined( $dh{L_PARAMS})) {
+                $deps .= ", $package (<< ".$dh{L_PARAMS}.")";
+            }
+            if (defined($library) &&
+                defined($ver) &&
+                defined($deps) &&
+                $library ne '' &&
+                $ver ne '' &&
+                $deps ne '') {
+                # Prevent duplicate lines from entering the file.
+                my $line = "$library $ver" . "__$sig $deps";
+
+                # extra dependencies are to be resolved by dh_clideps,
+                # don't forward the dependency libs to the apps where it
+                # does not belong to
+#                if ( my $extra = extraDeps ($libfile) )   { $line .= ", $extra";  }
+                if (!$seen{$line}) {
+                    $seen{$line} = 1;
+                    complex_doit("echo '$line' >> $tmp/DEBIAN/clilibs");
+                }
+            }
+        }
+    }
+    close FIND;
+
+    if (-e "$tmp/DEBIAN/clilibs") {
+        doit("chmod", 644,   "$tmp/DEBIAN/clilibs");
+        doit("chown", "0:0", "$tmp/DEBIAN/clilibs");
+    }
+}
+
+sub extraDeps {
+   my $config=$_[0].".config";
+   my $ret=undef;
+
+   if (!%shlibdata) {
+      open($fh, "cat /var/lib/dpkg/info/*.shlibs debian/shlibs.local debian/*/DEBIAN/shlibs 2>/dev/null |");
+      while (<$fh>) {
+         /(\S+)\s+(\S+)\s+(\w.*)\n?/;
+         $shlibdata{"$1.so.$2"} = $3;
+      }
+   }
+
+   if (-r $config) {
+      $config = `cat $config`;
+      while($config=~s/\Wtarget\W*=\W*(\w[\w.\-\d]+)//) {
+         $ret.= (", ".$shlibdata{$1}) if(defined($shlibdata{$1}));
+      }
+   }
+   $ret=~s/^, // if $ret;
+   return $ret;
+}
+
+=head1 SEE ALSO
+
+L<debhelper(7)>
+
+This program is a part of cli-common.
+
+=head1 KNOWN BUGS
+
+Will possibly not work correctly with DH_COMPAT levels 1 and 2.
+
+=head1 AUTHOR
+
+Mirco Bauer <meebey@meebey.net>, Eduard Bloch <blade@debian.org>,
+inspired by dh_makeshlibs by Joey Hess <joeyh@debian.org>
+
+=cut


Property changes on: cli-common/trunk/dh_makeclilibs
___________________________________________________________________
Name: svn:executable
   + *

Added: cli-common/trunk/ildasm-monodis
===================================================================
--- cli-common/trunk/ildasm-monodis	2005-04-09 15:32:55 UTC (rev 1557)
+++ cli-common/trunk/ildasm-monodis	2005-04-09 16:15:54 UTC (rev 1558)
@@ -0,0 +1,136 @@
+#!/usr/bin/perl
+
+#
+# Setup
+#
+
+# Directives
+use strict;
+use warnings;
+
+# Modules
+use Getopt::Long;
+
+#
+# Variables
+#
+
+# Filenames
+my $assemblyref;
+
+# Get the mode
+GetOptions(
+	   "assemblyref!" => \$assemblyref,
+	   );
+
+# Get the filenames
+my $dll_filename = shift;
+
+usage() if (!defined $dll_filename);
+
+# Figure out what to do
+if ($assemblyref)
+{
+    parse_assemblyref($dll_filename);
+}
+else
+{
+    # As per meeby, do assemblyref
+    parse_assemblyref($dll_filename);
+}
+
+#
+# Create a pipe to the 'ildasm' program and give it the given
+# DLL. Then, take the results, parse them, and write it out to stdout.
+#
+
+sub parse_assemblyref
+{
+    # Get the parameters
+    my $dll_filename = shift;
+
+    # Open the pipe
+    open PIPE, "/usr/bin/ildasm $dll_filename |"
+	or die "Cannot open /usr/bin/ildasm $dll_filename ($!)";
+    
+    # Print out the header
+    print "AssemblyRef Table\n";
+    
+    # Go through the results
+    my $count = 0;
+    while (<PIPE>)
+    {
+	# Clean up the line
+	chomp;
+	
+	# Check for assembly ref
+	if (/^\.assembly extern (.*?)$/)
+	{
+	    # We have an assembly reference
+	    my $name = $1;
+	    my $version = undef;
+	    my $key = "\tZero sized public key";
+	    $count++;
+
+	    # On occasion, the name has quotes around it, but monodis
+	    # doesn't.
+	    $name =~ s/\'//g;
+	    $name =~ s/\"//g;
+
+	    # Go through and parse the rest of the variables until we
+	    # get to a } which signals the end of the block.
+	    while (<PIPE>)
+	    {
+		# Stop if we get a }
+		last if /^\}/;
+		s/^\s+//;
+
+		# Check for the keys
+		if (/\.ver (\d+):(\d+):(\d+):(\d+)/)
+		{
+		    # Make it look like mono
+		    $version = "$1.$2.$3.$4";
+		    next;
+		}
+
+		# Check for public key
+		if (/\.publickeytoken = \((.*?)\)/)
+		{
+		    # Monodis adds a space at the end of this next line
+		    $key = "\tPublic Key:\n0x00000000: $1 ";
+		}
+	    }
+
+	    # Emit it
+	    print join("\n",
+		       "$count: Version=$version",
+		       "\tName=$name",
+		       $key,
+		       ), "\n";
+	}
+    }
+    
+    # Mono also has an extra space at the end
+    print "\n";
+
+    # Close the pipe
+    close PIPE;
+}
+
+#
+# Usage. Just your typical complain function that automatically exits
+# out of perl after complaining.
+#
+
+sub usage
+{
+    print STDERR join("\n",
+		      "USAGE: $0 [options] /path/to/something.dll",
+		      "",
+		      "Options:",
+		      sprintf("%-20.20s  %s",
+			      "--assemblyref",
+			      "Dumps output like 'monodis --assemblyref'"),
+		      ), "\n";
+    exit 1;
+}