[mono-api-info] Add `mono-api-info -L`, `mono-api-info -r`
authorJonathan Pryor <jonpryor@vt.edu>
Wed, 16 Dec 2015 15:59:06 +0000 (10:59 -0500)
committerJonathan Pryor <jonpryor@vt.edu>
Wed, 16 Dec 2015 18:02:19 +0000 (13:02 -0500)
**The Scenario**: `mono-api-info` and `mono-api-html`, together, are a
useful way to track API changes over time, specifically to check for
accidental API breakage:

# Have a "known good" assembly version;
# keep reference/assembly.xml in version control
$ mono-api-info assembly.dll > reference/assembly.xml

# ...then on every new build, check for breakage:
$ mono-api-info assembly.dll > new-assembly.xml
$ mono-api-html reference/assembly.xml new-assembly.xml > assembly-diff.html
$ if grep '<p>Removed' assembly-diff.html > /dev/null ; then \
echo "ABI BREAK IN assembly.dll" ; \
cat assembly-diff.html ; \
fi

This is a very nice workflow, and has been used in Xamarin.Android to
track accidental API breakage for some time.

**The problem** with the above workflow are *implicit* references:
`mono-api-info` will happily look for dependencies in the same
directory as `assembly`, but it will *also* look for assembly
references in various system-specific directories, which is fine...

...until it *isn't* fine, e.g. if you have your own version of
mscorlib.dll that you need to use, *not* the system one, as your own
version may have API differences from the system mscorlib.dll which
are "percolated" into `mono-api-info` output. For example, on
"desktop" profiles, System.Attribute implements
System.Runtime.InteropServices._Attribute, and thus *all* custom
attribute types will have _Attribute listed as an implemented
interface. The Xamarin.iOS and Xamarin.Android mscorlib.dll,
meanwhile, does *not* have System.Attribute implementing _Attribute.
Consequently, changing the mscorlib.dll which is used while processing
an assembly will change `mono-api-info` output, resulting in "API
breakage" which doens't actually exist, because the wrong mscorlib.dll
was used to generate the original API description in the first place.

We need a way to control which mscorlib.dll/etc. are used. This can be
done by allowing specification of the assembly search directories, so
that we can "override" the default system-specific directory location.

**The solution**: Add a `mono-api-info -L PATH` option which adds PATH
to the list of directories that `mono-api-info` will search when
resolving assembly references. This allows "overriding" the system
directory location, as PATH will be searched for mscorlib.dll before
the system directory location.

Additionally, add a `mono-api-info -r ASSEMBLY` option, which will
pre-process ASSEMBLY (and all dependencies) and add the directory
which contains ASSEMBLY to the assembly search paths.

These two options are conceptually similar to `mcs -L` and `mcs -r`.

Finally, while adding support for these options, add support for
`mono-api-info --help`, so that we don't need to use only the man page
to get option information.

mcs/tools/corcompare/Makefile
mcs/tools/corcompare/mono-api-info.cs

index d84398c8df69a51f3afc4595d3b7cb7d8c171769..4b9478c045ec9640b5b97ba6f4f9c8fb1f28180c 100644 (file)
@@ -42,5 +42,5 @@ clean-local:
 
 dist-local: dist-default
 
-mono-api-info.exe: $(APIINFO_SOURCES)
+mono-api-info.exe: $(APIINFO_SOURCES) ../../class/Mono.Options/Mono.Options/Options.cs
        $(CSCOMPILE) -r:Mono.Cecil.dll -out:$@ $^
index 6194bb30ef7fffa23e3c392db8b745b5654f2b09..c43437fe40d869165c5b7d20f02eaa036c58a85f 100644 (file)
@@ -35,18 +35,31 @@ namespace CorCompare
                        var acoll = new AssemblyCollection ();
 
                        var options = new Mono.Options.OptionSet {
-                               { "h|help", "Show this help", v => showHelp = true },
-                               { "abi", _ => AbiMode = true},
-                               { "f|follow-forwarders", _ => FollowForwarders = true },
-                               { "d|search-directory=", v => TypeHelper.Resolver.AddSearchDirectory (v) },
+                               "usage: mono-api-info [OPTIONS+] ASSEMBLY+",
+                               "",
+                               "Expose IL structure of CLR assemblies as XML.",
+                               "",
+                               "Available Options:",
+                               { "abi",
+                                       "Generate ABI, not API; contains only classes with instance fields which are not [NonSerialized].",
+                                       v => AbiMode = v != null },
+                               { "f|follow-forwarders",
+                                       "Follow type forwarders.",
+                                       v => FollowForwarders = v != null },
+                               { "d|L|lib|search-directory=",
+                                       "Check for assembly references in {DIRECTORY}.",
+                                       v => TypeHelper.Resolver.AddSearchDirectory (v) },
+                               { "r=",
+                                       "Read and register the file {ASSEMBLY}, and add the directory containing ASSEMBLY to the search path.",
+                                       v => TypeHelper.Resolver.ResolveFile (v) },
+                               { "h|?|help",
+                                       "Show this message and exit.",
+                                       v => showHelp = v != null },
                        };
 
                        var asms = options.Parse (args);
 
                        if (showHelp || asms.Count == 0) {
-                               Console.WriteLine (@"Usage: mono-api-info [options] <assemblies>");
-                               Console.WriteLine ();
-                               Console.WriteLine ("Available options:");
                                options.WriteOptionDescriptions (Console.Out);
                                Console.WriteLine ();
                                return showHelp? 0 :1;