illinkanalyzer(1)

πŸ’– illinkanalyzer β€” Mono's linker analyzer tool πŸ’–

okay bestie, pull up a chair, because we're about to get into illinkanalyzer, aka Mono's linker analyzer tool. it's a little command-line gremlin that reads a dependency graph and tells you why the linker decided to keep something. yes, the linker is a whole main character and this is how we get its receipts. πŸ•΅οΈβ™€οΈβœ¨


✨ SYNOPSIS ✨

illinkanalyzer [options] <linker-dependency-file.xml.gz>

like, one file in, whole truth out. that's the vibe. πŸ’…


🌸 DESCRIPTION 🌸

so, the Linker analyzer is a command line tool, and what it does is analyze dependencies β€” the ones that got recorded while the linker was doing its processing, the ones that made the linker mark an item so it gets kept in the resulting linked assembly. no cap, that's the whole job.

it works on an oriented graph of dependencies. that graph gets collected and dumped while the linker runs. and what's in it?

  • the vertices are the items of interest: assemblies, types, methods, fields, linker steps, etc. πŸ‘‘
  • the edges represent the dependencies.

so basically, vertices = the people, edges = the drama between them. and illinkanalyzer is here to explain the drama. πŸ’€


πŸ¦‹ HOW TO DUMP DEPENDENCIES πŸ¦‹

bestie, first things first: the analyzer needs a linker dependencies file as its input. you can't just show up empty-handed. so where do you get one? you get it by enabling dependencies dumping while linking a Xamarin.Android or a Xamarin.iOS project.

and how do you do that? on the command line, by setting the LinkerDumpDependencies property to true and building the project. (and make sure the LinkAssemblies task is actually called β€” sometimes it needs the project cleaned first, that's just the situation, don't fight it.)

usually it's enough to build the project like this:

rm -f obj/Release/link.flag
msbuild /p:LinkerDumpDependencies=true /p:Configuration=Release YourAppProject.csproj

after a successful build, there will be a linker-dependencies.xml.gz file created, and that file holds the info for the analyzer. that's the golden ticket, keep it safe. πŸŽ€


✨ OPTIONS ✨

  • -a, --alldeps β€” show all dependencies. all of them. every single one. πŸ‘€
  • --csvoutput=VALUE β€” outputs types and optionally size analysis to CSV file
  • -h, --help β€” show this message and exit.
  • -l, --linkedpath=VALUE β€” sets the linked assemblies directory path. also enables displaying size estimates.
  • -r, --rawdeps=VALUE β€” show raw vertex dependencies. the raw vertex VALUE is in the raw format written by linker to the dependency XML file. VALUE can be a regular expression.
  • --roots β€” show root dependencies.
  • --stat β€” show statistic of loaded dependencies.
  • --tree β€” reduce the dependency graph to the tree.
  • --types β€” show all types dependencies.
  • -t, --typedeps=VALUE β€” show type dependencies. the VALUE can be a regular expression.
  • -f, --flat β€” show all dependencies per vertex and their distance
  • -v, --verbose β€” be more verbose. enables stat and roots options.

🌈 EXAMPLES 🌈

okay so let's say you wanna know why a type got marked by the linker. take Android.App.Activity for example. run the analyzer like this:

illinkanalyzer -t Android.App.Activity linker-dependencies.xml.gz

and the output:

Loading dependency tree from: linker-dependencies.xml.gz

--- Type dependencies: 'Android.App.Activity' -----------------------

--- TypeDef:Android.App.Activity dependencies -----------------------
Dependency #1
     TypeDef:Android.App.Activity
     | TypeDef:XA.App.MainActivity [2 deps]
     | Assembly:XA.App, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null [3 deps]
     | Other:Mono.Linker.Steps.ResolveFromAssemblyStep

so the output contains dependencies string(s), starting with the type and continuing with the item of interest, which depends on the type. and heads up: the dependency could be the result of multiple reasons. for example, the type was referenced from a method, or the type was listed in the linker xml file to be protected. either way, it's giving receipts. πŸ”₯

in our example there's only one dependency string, called Dependency #1. it shows us that the type Android.App.Activity was marked during processing of type XA.App.MainActivity by the linker. in this case, it's because the MainActivity type is based on the Activity type, and so the linker marked it and kept it in the linked assembly. we can also see that there are 2 dependencies for the MainActivity class. note that in the string (above) we only see the 1st dependency of the 2 β€” the dependency on the assembly XA.App. and finally, the assembly vertex depends on the ResolveFromAssemblyStep vertex. so we see that the assembly was processed in the ResolveFromAssembly linker step. πŸ•΅οΈβ™€οΈ

now, maybe we wanna see the MainActivity dependencies. that's this run:

illinkanalyzer -r TypeDef:XA.App.MainActivity linker-dependencies.xml.gz

output:

Loading dependency tree from: linker-dependencies.xml.gz

--- Raw dependencies: 'TypeDef:XA.App.MainActivity' -----------------

--- TypeDef:XA.App.MainActivity dependencies ------------------------
Dependency #1
     TypeDef:XA.App.MainActivity
     | Assembly:XA.App, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null [3 deps]
     | Other:Mono.Linker.Steps.ResolveFromAssemblyStep
Dependency #2
     TypeDef:XA.App.MainActivity
     | TypeDef:XA.App.MainActivity/<>c__DisplayClass1_0 [2 deps]
     | TypeDef:XA.App.MainActivity [2 deps]
     | Assembly:XA.App, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null [3 deps]
     | Other:Mono.Linker.Steps.ResolveFromAssemblyStep

obsessed. literally the whole story, laid out like a group chat transcript. πŸ’œ


πŸ‘‘ SEE ALSO πŸ‘‘


one rule, bestie: the vibes are cute but the flags are sacred. don't go renaming anything, fr fr. πŸ’…

and that's the whole page! this came from the illinkanalyzer(1) page in the General Commands Manual section. mwah, go analyze some dependencies, you absolute icon. πŸ«ΆπŸŽ€πŸ¦‹βœ¨