--- /dev/null
+//
+// ConsoleDependencyGraph.cs: text output related code for dependency graph
+//
+// Author:
+// Radek Doulik (rodo@xamarin.com)
+//
+// Copyright 2015 Xamarin Inc (http://www.xamarin.com).
+//
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using LinkerAnalyzer.Core;
+
+namespace LinkerAnalyzer
+{
+ public class ConsoleDependencyGraph : DependencyGraph
+ {
+ public bool Tree = false;
+
+ public void ShowDependencies (string raw, List<VertexData> verticesList, string searchString)
+ {
+ VertexData vertex = Vertex (raw);
+ if (vertex == null) {
+ Regex regex = new Regex (searchString);
+ int count = 0;
+
+ foreach (var v in verticesList) {
+ if (regex.Match (v.value) != Match.Empty) {
+ ShowDependencies (v);
+ count++;
+ }
+ }
+
+ if (count == 0)
+ Console.WriteLine ("\nUnable to find vertex: {0}", raw);
+ else
+ Console.WriteLine ("\nFound {0} matches", count);
+ } else
+ ShowDependencies (vertex);
+ }
+
+ public void ShowDependencies (VertexData vertex)
+ {
+ Header ("{0} dependencies", vertex.value);
+ if (vertex.parentIndexes == null) {
+ Console.WriteLine ("Root dependency");
+ } else {
+ int i = 0;
+ foreach (int index in vertex.parentIndexes) {
+ Console.WriteLine ("Dependency #{0}", ++i);
+ Console.WriteLine ("\t{0}", vertex.value);
+ var childVertex = Vertex (index);
+ Console.WriteLine ("\t| {0}{1}", childVertex.value, childVertex.DepsCount);
+ while (childVertex.parentIndexes != null) {
+ childVertex = Vertex (childVertex.parentIndexes [0]);
+ Console.WriteLine ("\t| {0}{1}", childVertex.value, childVertex.DepsCount);
+ }
+ if (Tree)
+ break;
+ }
+ }
+ }
+
+ public void ShowAllDependencies ()
+ {
+ Header ("All dependencies");
+ Console.WriteLine ("Types count: {0}", vertices.Count);
+ foreach (var vertex in vertices)
+ ShowDependencies (vertex);
+ }
+
+ public void ShowTypesDependencies ()
+ {
+ Header ("All types dependencies");
+ Console.WriteLine ("Deps count: {0}", Types.Count);
+ foreach (var type in Types)
+ ShowDependencies (type);
+ }
+
+ string Tabs (string key)
+ {
+ int count = Math.Max (1, 2 - key.Length / 8);
+
+ if (count == 1)
+ return "\t";
+ else
+ return "\t\t";
+ }
+
+ public void ShowStat (bool verbose = false)
+ {
+ Header ("Statistics");
+ if (verbose) {
+ foreach (var key in counts.Keys)
+ Console.WriteLine ("Vertex type:\t{0}{1}count:{2}", key, Tabs (key), counts [key]);
+ } else {
+ Console.WriteLine ("Assemblies:\t{0}", counts ["Assembly"]);
+ Console.WriteLine ("Modules:\t{0}", counts ["Module"]);
+ Console.WriteLine ("Types:\t\t{0}", counts ["TypeDef"]);
+ Console.WriteLine ("Fields:\t\t{0}", counts ["Field"]);
+ Console.WriteLine ("Methods:\t{0}", counts ["Method"]);
+ }
+
+ Console.WriteLine ();
+ Console.WriteLine ("Total vertices: {0}", vertices.Count);
+ }
+
+ public void ShowRoots ()
+ {
+ Header ("Root vertices");
+
+ int count = 0;
+ foreach (var vertex in vertices) {
+ if (vertex.parentIndexes == null) {
+ Console.WriteLine ("{0}", vertex.value);
+ count++;
+ }
+ }
+
+ Console.WriteLine ();
+ Console.WriteLine ("Total root vertices: {0}", count);
+ }
+
+ public void ShowRawDependencies (string raw)
+ {
+ Header ("Raw dependencies: '{0}'", raw);
+ ShowDependencies (raw, vertices, raw);
+ }
+
+ public void ShowTypeDependencies (string raw)
+ {
+ Header ("Type dependencies: '{0}'", raw);
+ ShowDependencies ("TypeDef:" + raw, Types, raw);
+ }
+
+ void Header (string header, params object[] values)
+ {
+ string formatted = string.Format (header, values);
+ Console.WriteLine ();
+ Console.Write ("--- {0} ", formatted);
+ for (int i=0; i< Math.Max (3, 64 - formatted.Length); i++)
+ Console.Write ('-');
+ Console.WriteLine ();
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDisplayName</key>
+ <string>LinkerAnalyzer</string>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.your-company.LinkerAnalyzer</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>LinkerAnalyzer</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>10.8</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>rodo</string>
+ <key>NSMainNibFile</key>
+ <string>MainMenu</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectTypeGuids>{A3F8F2AB-B479-4A4A-A458-A89E7DC349F1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <ProjectGuid>{B64F51B1-2D82-479C-B8F5-8875CDF06D95}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>LinkerAnalyzer</RootNamespace>
+ <MonoMacResourcePrefix>Resources</MonoMacResourcePrefix>
+ <AssemblyName>LinkerAnalyzer</AssemblyName>
+ <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
+ <TargetFrameworkIdentifier>Xamarin.Mac</TargetFrameworkIdentifier>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ <UseRefCounting>true</UseRefCounting>
+ <UseSGen>true</UseSGen>
+ <IncludeMonoRuntime>false</IncludeMonoRuntime>
+ <EnablePackageSigning>false</EnablePackageSigning>
+ <CodeSigningKey>Mac Developer</CodeSigningKey>
+ <EnableCodeSigning>false</EnableCodeSigning>
+ <CreatePackage>false</CreatePackage>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>full</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ <LinkMode>SdkOnly</LinkMode>
+ <UseRefCounting>true</UseRefCounting>
+ <UseSGen>true</UseSGen>
+ <IncludeMonoRuntime>true</IncludeMonoRuntime>
+ <CreatePackage>true</CreatePackage>
+ <CodeSigningKey>Developer ID Application</CodeSigningKey>
+ <EnableCodeSigning>true</EnableCodeSigning>
+ <EnablePackageSigning>false</EnablePackageSigning>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="Xamarin.Mac" />
+ </ItemGroup>
+ <ItemGroup>
+ <Folder Include="Resources\" />
+ <Folder Include="Mono.Options\" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Info.plist" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Main.cs" />
+ <Compile Include="ConsoleDependencyGraph.cs" />
+ <Compile Include="..\..\class\Mono.Options\Mono.Options\Options.cs">
+ <Link>Mono.Options\Options.cs</Link>
+ </Compile>
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath)\Xamarin\Mac\Xamarin.Mac.CSharp.targets" />
+ <ItemGroup>
+ <ProjectReference Include="LinkerAnalyzerCore\LinkerAnalyzerCore.csproj">
+ <Project>{E1B8F203-5251-470E-A573-C9E79B60781B}</Project>
+ <Name>LinkerAnalyzerCore</Name>
+ </ProjectReference>
+ </ItemGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+\r
+Microsoft Visual Studio Solution File, Format Version 12.00\r
+# Visual Studio 2012\r
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinkerAnalyzer", "LinkerAnalyzer.csproj", "{B64F51B1-2D82-479C-B8F5-8875CDF06D95}"\r
+EndProject\r
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinkerAnalyzerCore", "LinkerAnalyzerCore\LinkerAnalyzerCore.csproj", "{E1B8F203-5251-470E-A573-C9E79B60781B}"\r
+EndProject\r
+Global\r
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+ Debug|Any CPU = Debug|Any CPU\r
+ Release|Any CPU = Release|Any CPU\r
+ EndGlobalSection\r
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+ {B64F51B1-2D82-479C-B8F5-8875CDF06D95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r
+ {B64F51B1-2D82-479C-B8F5-8875CDF06D95}.Debug|Any CPU.Build.0 = Debug|Any CPU\r
+ {B64F51B1-2D82-479C-B8F5-8875CDF06D95}.Release|Any CPU.ActiveCfg = Release|Any CPU\r
+ {B64F51B1-2D82-479C-B8F5-8875CDF06D95}.Release|Any CPU.Build.0 = Release|Any CPU\r
+ {E1B8F203-5251-470E-A573-C9E79B60781B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r
+ {E1B8F203-5251-470E-A573-C9E79B60781B}.Debug|Any CPU.Build.0 = Debug|Any CPU\r
+ {E1B8F203-5251-470E-A573-C9E79B60781B}.Release|Any CPU.ActiveCfg = Release|Any CPU\r
+ {E1B8F203-5251-470E-A573-C9E79B60781B}.Release|Any CPU.Build.0 = Release|Any CPU\r
+ EndGlobalSection\r
+EndGlobal\r
--- /dev/null
+//
+// DependencyGraph.cs: linker dependencies graph
+//
+// Author:
+// Radek Doulik (rodo@xamarin.com)
+//
+// Copyright 2015 Xamarin Inc (http://www.xamarin.com).
+//
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Xml;
+
+namespace LinkerAnalyzer.Core
+{
+ public class VertexData {
+ public string value;
+ public List<int> parentIndexes;
+ public int index;
+
+ public string DepsCount {
+ get {
+ if (parentIndexes == null || parentIndexes.Count < 1)
+ return "";
+ return string.Format (" [{0} deps]", parentIndexes.Count);
+ }
+ }
+ };
+
+ public class DependencyGraph
+ {
+ protected List<VertexData> vertices = new List<VertexData> ();
+ public List<VertexData> Types = new List<VertexData> ();
+ Dictionary<string, int> indexes = new Dictionary<string, int> ();
+ protected Dictionary<string, int> counts = new Dictionary<string, int> ();
+
+ public void Load (string filename)
+ {
+ Console.WriteLine ("Loading dependency tree from: {0}", filename);
+
+ using (var fileStream = File.OpenRead (filename))
+ using (var zipStream = new GZipStream (fileStream, CompressionMode.Decompress)) {
+ try {
+ Load (zipStream);
+ } catch (Exception) {
+ Console.WriteLine ("Unable to open and read the dependecies.");
+ Environment.Exit (1);
+ }
+ }
+ }
+
+ void Load (GZipStream zipStream) {
+ using (XmlReader reader = XmlReader.Create (zipStream)) {
+ while (reader.Read ()) {
+ switch (reader.NodeType) {
+ case XmlNodeType.Element:
+ //Console.WriteLine (reader.Name);
+ if (reader.Name == "edge" && reader.IsStartElement ()) {
+ string b = reader.GetAttribute ("b");
+ string e = reader.GetAttribute ("e");
+ //Console.WriteLine ("edge value " + b + " --> " + e);
+
+ if (e != b) {
+ VertexData begin = Vertex (b, true);
+ VertexData end = Vertex (e, true);
+
+ if (end.parentIndexes == null)
+ end.parentIndexes = new List<int> ();
+ if (!end.parentIndexes.Contains (begin.index)) {
+ end.parentIndexes.Add (begin.index);
+ //Console.WriteLine (" end parent index: {0}", end.parentIndexes);
+ }
+ }
+ }
+ break;
+ default:
+ //Console.WriteLine ("node: " + reader.NodeType);
+ break;
+ }
+ }
+ }
+ }
+
+ public VertexData Vertex (string vertexName, bool create = false)
+ {
+ VertexData vertex;
+
+ try {
+ vertex = vertices [indexes [vertexName]];
+ } catch (KeyNotFoundException) {
+ if (create) {
+ int index = vertices.Count;
+ vertex = new VertexData () { value = vertexName, index = index };
+ vertices.Add (vertex);
+ indexes.Add (vertexName, index);
+ string prefix = vertexName.Substring (0, vertexName.IndexOf (':'));
+ if (counts.ContainsKey (prefix))
+ counts [prefix]++;
+ else
+ counts [prefix] = 1;
+ //Console.WriteLine ("prefix " + prefix + " count " + counts[prefix]);
+ if (prefix == "TypeDef") {
+ Types.Add (vertex);
+ }
+ } else
+ return null;
+ }
+
+ return vertex;
+ }
+
+ public VertexData Vertex (int index)
+ {
+ return vertices [index];
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectTypeGuids>{A3F8F2AB-B479-4A4A-A458-A89E7DC349F1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <ProjectGuid>{E1B8F203-5251-470E-A573-C9E79B60781B}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <RootNamespace>LinkerAnalyzer.Core</RootNamespace>
+ <MonoMacResourcePrefix>Resources</MonoMacResourcePrefix>
+ <AssemblyName>LinkerAnalyzerCore</AssemblyName>
+ <UseXamMacFullFramework>true</UseXamMacFullFramework>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug</OutputPath>
+ <DefineConstants>DEBUG;</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ <UseRefCounting>false</UseRefCounting>
+ <UseSGen>false</UseSGen>
+ <IncludeMonoRuntime>false</IncludeMonoRuntime>
+ <CreatePackage>false</CreatePackage>
+ <EnableCodeSigning>false</EnableCodeSigning>
+ <EnablePackageSigning>false</EnablePackageSigning>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>full</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release</OutputPath>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <ConsolePause>false</ConsolePause>
+ <UseRefCounting>false</UseRefCounting>
+ <UseSGen>false</UseSGen>
+ <IncludeMonoRuntime>false</IncludeMonoRuntime>
+ <CreatePackage>false</CreatePackage>
+ <EnableCodeSigning>false</EnableCodeSigning>
+ <EnablePackageSigning>false</EnablePackageSigning>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="Xamarin.Mac" />
+ <Reference Include="System.Xml" />
+ <Reference Include="Mono.Cecil">
+ <HintPath>..\..\..\git\upstream\cecil\bin\net_4_0_Debug\Mono.Cecil.dll</HintPath>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Folder Include="Resources\" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="DependencyGraph.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildExtensionsPath)\Xamarin\Mac\Xamarin.Mac.CSharp.targets" />
+</Project>
\ No newline at end of file
--- /dev/null
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle ("LinkerAnalyzerCore")]
+[assembly: AssemblyDescription ("")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("")]
+[assembly: AssemblyProduct ("")]
+[assembly: AssemblyCopyright ("rodo")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion ("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
--- /dev/null
+//
+// Main.cs: Main program file of command line utility.
+//
+// Author:
+// Radek Doulik (rodo@xamarin.com)
+//
+// Copyright 2015 Xamarin Inc (http://www.xamarin.com).
+//
+using System;
+using Mono.Options;
+using LinkerAnalyzer.Core;
+
+namespace LinkerAnalyzer
+{
+ static class MainClass
+ {
+ static void Main (string[] args)
+ {
+ bool showUsage = true;
+ bool showAllDeps = false;
+ bool showTypeDeps = false;
+ string typeName = null;
+ bool showRawDeps = false;
+ string rawName = null;
+ bool showRoots = false;
+ bool showSpaceUsage = false;
+ bool showStat = false;
+ bool showTypes = false;
+ bool reduceToTree = false;
+ bool verbose = false;
+
+ var optionsParser = new OptionSet () {
+ { "a|alldeps", "show all dependencies", v => { showAllDeps = v != null; } },
+ { "h|help", "show this message and exit.", v => showUsage = v != null },
+ { "r|rawdeps=", "show raw vertex dependencies. Raw vertex VALUE is in the raw format written by linker to the dependency XML file. VALUE can be regular expression", v => { showRawDeps = v != null; rawName = v; } },
+ { "roots", "show root dependencies.", v => showRoots = v != null },
+ { "stat", "show statistic of loaded dependencies.", v => showStat = v != null },
+ { "tree", "reduce the dependency graph to the tree.", v => reduceToTree = v != null },
+ { "types", "show all types dependencies.", v => showTypes = v != null },
+ { "t|typedeps=", "show type dependencies. The VALUE can be regular expression", v => { showTypeDeps = v != null; typeName = v; } },
+ //{ "u|spaceusage", "show space analysis.", v => showSpaceUsage = v != null },
+ { "v|verbose", "be more verbose. Enables stat and roots options.", v => verbose = v != null },
+ };
+
+ if (args.Length > 0) {
+ showUsage = false;
+ optionsParser.Parse (args);
+ }
+
+ if (showUsage) {
+ Console.WriteLine ("Usage:\n\n\tlinkeranalyzer [Options] <linker-dependency-file.xml.gz>\n\nOptions:\n");
+ optionsParser.WriteOptionDescriptions (Console.Out);
+ Console.WriteLine ();
+ return;
+ }
+
+ string dependencyFile = args [args.Length - 1];
+
+ ConsoleDependencyGraph deps = new ConsoleDependencyGraph () { Tree = reduceToTree };
+ deps.Load (dependencyFile);
+
+ if (showSpaceUsage) {
+// SpaceAnalyzer sa = new SpaceAnalyzer (System.IO.Path.GetDirectoryName (dependencyFile));
+// sa.LoadAssemblies (verbose);
+ }
+
+ if (verbose) {
+ showStat = true;
+ showRoots = true;
+ }
+
+ if (showStat)
+ deps.ShowStat (verbose);
+ if (showRoots)
+ deps.ShowRoots ();
+ if (showRawDeps)
+ deps.ShowRawDependencies (rawName);
+ if (showTypeDeps)
+ deps.ShowTypeDependencies (typeName);
+ if (showAllDeps)
+ deps.ShowAllDependencies ();
+ else if (showTypes)
+ deps.ShowTypesDependencies ();
+ }
+ }
+}
--- /dev/null
+thisdir = tools/linker-analyzer
+SUBDIRS =
+include ../../build/rules.make
+
+PROGRAM = linkeranalyzer.exe
+
+include ../../build/executable.make
--- /dev/null
+ConsoleDependencyGraph.cs
+Main.cs
+
+LinkerAnalyzerCore/DependencyGraph.cs
+../../class/Mono.Options/Mono.Options/Options.cs