[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;
+}