Skip to content

Commit

Permalink
[mono-api-info] Add mono-api-info -L, mono-api-info -r
Browse files Browse the repository at this point in the history
**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.
  • Loading branch information
jonpryor committed Dec 16, 2015
1 parent cd62639 commit 4e45904
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 8 deletions.
2 changes: 1 addition & 1 deletion mcs/tools/corcompare/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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:$@ $^
27 changes: 20 additions & 7 deletions mcs/tools/corcompare/mono-api-info.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,31 @@ public static int Main (string [] args)
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;
Expand Down

0 comments on commit 4e45904

Please sign in to comment.