You've already forked linux-packaging-mono
Imported Upstream version 6.0.0.172
Former-commit-id: f3cc9b82f3e5bd8f0fd3ebc098f789556b44e9cd
This commit is contained in:
parent
8016999e4d
commit
64ac736ec5
49
external/linker/src/ILLink.CustomSteps/ClearInitLocals.cs
vendored
Normal file
49
external/linker/src/ILLink.CustomSteps/ClearInitLocals.cs
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Mono.Linker;
|
||||
using Mono.Linker.Steps;
|
||||
using Mono.Cecil;
|
||||
|
||||
namespace ILLink.CustomSteps
|
||||
{
|
||||
public class ClearInitLocalsStep : BaseStep
|
||||
{
|
||||
HashSet<string> _assemblies;
|
||||
|
||||
protected override void Process ()
|
||||
{
|
||||
string parameterName = "ClearInitLocalsAssemblies";
|
||||
|
||||
if (Context.HasParameter (parameterName)) {
|
||||
string parameter = Context.GetParameter (parameterName);
|
||||
_assemblies = new HashSet<string> (parameter.Split(','), StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ProcessAssembly (AssemblyDefinition assembly)
|
||||
{
|
||||
if ((_assemblies != null) && (!_assemblies.Contains (assembly.Name.Name))) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
|
||||
foreach (ModuleDefinition module in assembly.Modules) {
|
||||
foreach (TypeDefinition type in module.Types) {
|
||||
foreach (MethodDefinition method in type.Methods) {
|
||||
if (method.Body != null) {
|
||||
if (method.Body.InitLocals) {
|
||||
method.Body.InitLocals = false;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed && (Annotations.GetAction (assembly) == AssemblyAction.Copy))
|
||||
Annotations.SetAction (assembly, AssemblyAction.Save);
|
||||
}
|
||||
}
|
||||
}
|
49
external/linker/src/ILLink.CustomSteps/ILLink.CustomSteps.csproj
vendored
Normal file
49
external/linker/src/ILLink.CustomSteps/ILLink.CustomSteps.csproj
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<!-- net46 build is disabled until cecil uses SDK-style projects. -->
|
||||
<TargetFrameworks>netcoreapp2.0</TargetFrameworks>
|
||||
<DefineConstants>$(DefineConstants);FEATURE_ILLINK</DefineConstants>
|
||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="ClearInitLocals.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\linker\Mono.Linker.csproj">
|
||||
<SetConfiguration Condition=" '$(Configuration)' == 'illink_Debug' ">Configuration=illink_Debug</SetConfiguration>
|
||||
<SetConfiguration Condition=" '$(Configuration)' == 'illink_Release' ">Configuration=illink_Release</SetConfiguration>
|
||||
<Project>{DD28E2B1-057B-4B4D-A04D-B2EBD9E76E46}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\external\cecil\Mono.Cecil.csproj">
|
||||
<SetConfiguration Condition=" '$(Configuration)' == 'illink_Debug' ">Configuration=netstandard_Debug</SetConfiguration>
|
||||
<SetConfiguration Condition=" '$(Configuration)' == 'illink_Debug' And '$(TargetFramework)' == 'net46' ">Configuration=net_4_0_Debug</SetConfiguration>
|
||||
<SetConfiguration Condition=" '$(Configuration)' == 'illink_Release' ">Configuration=netstandard_Release</SetConfiguration>
|
||||
<SetConfiguration Condition=" '$(Configuration)' == 'illink_Release' And '$(TargetFramework)' == 'net46' ">Configuration=net_4_0_Release</SetConfiguration>
|
||||
<Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- The reference to the linker will cause Mono.Cecil.Pdb to be
|
||||
built in the wrong configuration unless we apply this
|
||||
workaround. -->
|
||||
<Target Name="SetCecilConfiguration"
|
||||
AfterTargets="AssignProjectConfiguration">
|
||||
<ItemGroup>
|
||||
<ProjectReferenceWithConfiguration Condition=" '%(Filename)%(Extension)' == 'Mono.Cecil.Pdb.csproj' ">
|
||||
<SetConfiguration Condition=" '$(TargetFramework)' == 'net46' And '$(Configuration)' == 'illink_Debug' ">Configuration=net_4_0_Debug</SetConfiguration>
|
||||
<SetConfiguration Condition=" '$(TargetFramework)' == 'netcoreapp2.0' And '$(Configuration)' == 'illink_Debug' ">Configuration=netstandard_Debug</SetConfiguration>
|
||||
<SetConfiguration Condition=" '$(TargetFramework)' == 'net46' And '$(Configuration)' == 'illink_Release' ">Configuration=net_4_0_Release</SetConfiguration>
|
||||
<SetConfiguration Condition=" '$(TargetFramework)' == 'netcoreapp2.0' And '$(Configuration)' == 'illink_Release' ">Configuration=netstandard_Release</SetConfiguration>
|
||||
</ProjectReferenceWithConfiguration>
|
||||
<ProjectReferenceWithConfiguration Condition=" '%(Filename)%(Extension)' == 'Mono.Cecil.Mdb.csproj' ">
|
||||
<SetConfiguration Condition=" '$(TargetFramework)' == 'net46' And '$(Configuration)' == 'illink_Debug' ">Configuration=net_4_0_Debug</SetConfiguration>
|
||||
<SetConfiguration Condition=" '$(TargetFramework)' == 'netcoreapp2.0' And '$(Configuration)' == 'illink_Debug' ">Configuration=netstandard_Debug</SetConfiguration>
|
||||
<SetConfiguration Condition=" '$(TargetFramework)' == 'net46' And '$(Configuration)' == 'illink_Release' ">Configuration=net_4_0_Release</SetConfiguration>
|
||||
<SetConfiguration Condition=" '$(TargetFramework)' == 'netcoreapp2.0' And '$(Configuration)' == 'illink_Release' ">Configuration=netstandard_Release</SetConfiguration>
|
||||
</ProjectReferenceWithConfiguration>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
37
external/linker/src/ILLink.Tasks/AdapterLogger.cs
vendored
Normal file
37
external/linker/src/ILLink.Tasks/AdapterLogger.cs
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace ILLink.Tasks
|
||||
{
|
||||
class AdapterLogger : Mono.Linker.ILogger
|
||||
{
|
||||
private TaskLoggingHelper log;
|
||||
|
||||
public AdapterLogger (TaskLoggingHelper log)
|
||||
{
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
public void LogMessage (Mono.Linker.MessageImportance importance, string message, params object[] values)
|
||||
{
|
||||
Microsoft.Build.Framework.MessageImportance msBuildImportance;
|
||||
switch (importance)
|
||||
{
|
||||
case Mono.Linker.MessageImportance.High:
|
||||
msBuildImportance = MessageImportance.High;
|
||||
break;
|
||||
case Mono.Linker.MessageImportance.Normal:
|
||||
msBuildImportance = MessageImportance.Normal;
|
||||
break;
|
||||
case Mono.Linker.MessageImportance.Low:
|
||||
msBuildImportance = MessageImportance.Low;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException ($"Unrecognized importance level {importance}", nameof(importance));
|
||||
}
|
||||
|
||||
log.LogMessageFromText (String.Format (message, values), msBuildImportance);
|
||||
}
|
||||
}
|
||||
}
|
37
external/linker/src/ILLink.Tasks/CheckEmbeddedRootDescriptor.cs
vendored
Normal file
37
external/linker/src/ILLink.Tasks/CheckEmbeddedRootDescriptor.cs
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
using Microsoft.Build.Utilities; // Task
|
||||
using Microsoft.Build.Framework; // ITaskItem
|
||||
using Mono.Cecil;
|
||||
|
||||
namespace ILLink.Tasks
|
||||
{
|
||||
public class CheckEmbeddedRootDescriptor : Task
|
||||
{
|
||||
/// <summary>
|
||||
/// Path to the assembly.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem AssemblyPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This will be set to true if the assembly has an embedded root descriptor.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public bool HasEmbeddedRootDescriptor { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
ModuleDefinition module = ModuleDefinition.ReadModule (AssemblyPath.ItemSpec);
|
||||
string assemblyName = module.Assembly.Name.Name;
|
||||
string expectedResourceName = assemblyName + ".xml";
|
||||
HasEmbeddedRootDescriptor = false;
|
||||
foreach (var resource in module.Resources) {
|
||||
if (resource.Name == expectedResourceName) {
|
||||
HasEmbeddedRootDescriptor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
117
external/linker/src/ILLink.Tasks/CompareSizes.cs
vendored
Normal file
117
external/linker/src/ILLink.Tasks/CompareSizes.cs
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace ILLink.Tasks
|
||||
{
|
||||
struct AssemblySizes
|
||||
{
|
||||
public long unlinkedSize;
|
||||
public long linkedSize;
|
||||
}
|
||||
public class CompareAssemblySizes : Task
|
||||
{
|
||||
/// <summary>
|
||||
/// Paths to managed assemblies before linking.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem[] UnlinkedAssemblies { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Paths to managed assemblies after linking. These
|
||||
/// assembly names should be a subset of the
|
||||
/// assembly names in UnlinkedAssemblies.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem[] LinkedAssemblies { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
string[] unlinkedFiles = UnlinkedAssemblies.Select (i => i.ItemSpec).ToArray();
|
||||
string[] linkedFiles = LinkedAssemblies.Select (i => i.ItemSpec).ToArray();
|
||||
|
||||
Dictionary<string, AssemblySizes> sizes = new Dictionary<string, AssemblySizes> ();
|
||||
|
||||
long totalUnlinked = 0;
|
||||
foreach (string unlinkedFile in unlinkedFiles) {
|
||||
if (!Utils.IsManagedAssembly (unlinkedFile)) {
|
||||
continue;
|
||||
}
|
||||
string fileName = Path.GetFileName (unlinkedFile);
|
||||
AssemblySizes assemblySizes = new AssemblySizes ();
|
||||
assemblySizes.unlinkedSize = new System.IO.FileInfo (unlinkedFile).Length;
|
||||
totalUnlinked += assemblySizes.unlinkedSize;
|
||||
sizes[fileName] = assemblySizes;
|
||||
}
|
||||
|
||||
long totalLinked = 0;
|
||||
foreach (string linkedFile in linkedFiles) {
|
||||
if (!Utils.IsManagedAssembly (linkedFile)) {
|
||||
continue;
|
||||
}
|
||||
string fileName = Path.GetFileName (linkedFile);
|
||||
if (!sizes.ContainsKey(fileName)) {
|
||||
Console.WriteLine ($"{linkedFile} was specified as an assembly kept by the linker, but {fileName} was not specified as a managed publish assembly.");
|
||||
continue;
|
||||
}
|
||||
AssemblySizes assemblySizes = sizes[fileName];
|
||||
assemblySizes.linkedSize = new System.IO.FileInfo (linkedFile).Length;
|
||||
totalLinked += assemblySizes.linkedSize;
|
||||
sizes[fileName] = assemblySizes;
|
||||
}
|
||||
|
||||
Console.WriteLine ("{0, -60} {1,-20:N0} {2, -20:N0} {3, -10:P}",
|
||||
"",
|
||||
"Before linking (B)",
|
||||
"After linking (B)",
|
||||
"Size decrease");
|
||||
Console.WriteLine ("{0, -60} {1,-20:N0} {2, -20:N0} {3, -10:P}",
|
||||
"-----------",
|
||||
"-----------",
|
||||
"-----------",
|
||||
"-----------"
|
||||
);
|
||||
|
||||
Console.WriteLine ("{0, -60} {1,-20:N0} {2, -20:N0} {3, -10:P}",
|
||||
"Total size of assemblies",
|
||||
totalUnlinked,
|
||||
totalLinked,
|
||||
((double)totalUnlinked - (double)totalLinked) / (double)totalUnlinked);
|
||||
|
||||
Console.WriteLine ("{0, -60} {1,-20:N0} {2, -20:N0} {3, -10:P}",
|
||||
"-----------",
|
||||
"-----------",
|
||||
"-----------",
|
||||
"-----------"
|
||||
);
|
||||
|
||||
foreach (string assembly in sizes.Keys) {
|
||||
Console.WriteLine ("{0, -60} {1,-20:N0} {2, -20:N0} {3, -10:P}",
|
||||
assembly,
|
||||
sizes[assembly].unlinkedSize,
|
||||
sizes[assembly].linkedSize,
|
||||
(double)(sizes[assembly].unlinkedSize - sizes[assembly].linkedSize)/(double)sizes[assembly].unlinkedSize);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static long DirSize(DirectoryInfo d)
|
||||
{
|
||||
long size = 0;
|
||||
// Add file sizes.
|
||||
FileInfo[] fis = d.GetFiles ();
|
||||
foreach (FileInfo fi in fis) {
|
||||
size += fi.Length;
|
||||
}
|
||||
// Add subdirectory sizes.
|
||||
DirectoryInfo[] dis = d.GetDirectories ();
|
||||
foreach (DirectoryInfo di in dis) {
|
||||
size += DirSize (di);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
31
external/linker/src/ILLink.Tasks/ComputeManagedAssemblies.cs
vendored
Normal file
31
external/linker/src/ILLink.Tasks/ComputeManagedAssemblies.cs
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
using System.Linq;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace ILLink.Tasks
|
||||
{
|
||||
public class ComputeManagedAssemblies : Task
|
||||
{
|
||||
/// <summary>
|
||||
/// Paths to assemblies.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem[] Assemblies { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This will contain the output list of managed
|
||||
/// assemblies. Metadata from the input parameter
|
||||
/// Assemblies is preserved.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ITaskItem[] ManagedAssemblies { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
ManagedAssemblies = Assemblies
|
||||
.Where(f => Utils.IsManagedAssembly(f.ItemSpec))
|
||||
.ToArray();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
44
external/linker/src/ILLink.Tasks/ComputeRemovedAssemblies.cs
vendored
Normal file
44
external/linker/src/ILLink.Tasks/ComputeRemovedAssemblies.cs
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace ILLink.Tasks
|
||||
{
|
||||
public class ComputeRemovedAssemblies : Task
|
||||
{
|
||||
/// <summary>
|
||||
/// The paths to the inputs to the linker.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem[] InputAssemblies { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The paths to the linked assemblies.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem[] KeptAssemblies { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The set of assemblies in the inputs that weren't kept by
|
||||
/// the linker. These items include the full metadata from
|
||||
/// the input assemblies, and only the filenames of the
|
||||
/// inputs are used to determine which assemblies were
|
||||
/// removed.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ITaskItem[] RemovedAssemblies { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
var keptAssemblyNames = new HashSet<string> (
|
||||
KeptAssemblies.Select(i => Path.GetFileName(i.ItemSpec))
|
||||
);
|
||||
RemovedAssemblies = InputAssemblies.Where(i =>
|
||||
!keptAssemblyNames.Contains(Path.GetFileName(i.ItemSpec))
|
||||
).ToArray();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
48
external/linker/src/ILLink.Tasks/CreateRootDescriptorFile.cs
vendored
Normal file
48
external/linker/src/ILLink.Tasks/CreateRootDescriptorFile.cs
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace ILLink.Tasks
|
||||
{
|
||||
public class CreateRootDescriptorFile : Task
|
||||
{
|
||||
/// <summary>
|
||||
/// Assembly names (without path or extension) to
|
||||
/// include in the generated root file.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem[] AssemblyNames { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The path to the file to generate.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem RootDescriptorFilePath { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
var roots = new XElement("linker");
|
||||
foreach (var assemblyItem in AssemblyNames) {
|
||||
var assemblyName = assemblyItem.ItemSpec;
|
||||
roots.Add(new XElement("assembly",
|
||||
new XAttribute("fullname", assemblyName),
|
||||
new XElement("type",
|
||||
new XAttribute("fullname", "*"),
|
||||
new XAttribute("required", "true"))));
|
||||
}
|
||||
|
||||
var xdoc = new XDocument(roots);
|
||||
|
||||
XmlWriterSettings xws = new XmlWriterSettings();
|
||||
xws.Indent = true;
|
||||
xws.OmitXmlDeclaration = true;
|
||||
|
||||
using (XmlWriter xw = XmlWriter.Create(RootDescriptorFilePath.ItemSpec, xws)) {
|
||||
xdoc.Save(xw);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
349
external/linker/src/ILLink.Tasks/CreateRuntimeRootDescriptorFile.cs
vendored
Normal file
349
external/linker/src/ILLink.Tasks/CreateRuntimeRootDescriptorFile.cs
vendored
Normal file
@ -0,0 +1,349 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Build.Utilities; // Task
|
||||
using Microsoft.Build.Framework; // ITaskItem
|
||||
|
||||
namespace ILLink.Tasks
|
||||
{
|
||||
public class CreateRuntimeRootILLinkDescriptorFile : Task
|
||||
{
|
||||
/// <summary>
|
||||
/// The path to namespace.h.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem NamespaceFilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The path to mscorlib.h.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem MscorlibFilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The path to cortypeinfo.h.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem CortypeFilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The path to rexcep.h.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem RexcepFilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The path to ILLinkTrim.xml.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem ILLinkTrimXmlFilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The path to the file to generate.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem RuntimeRootDescriptorFilePath { get; set; }
|
||||
|
||||
class ClassMembers
|
||||
{
|
||||
public bool keepAllFields;
|
||||
public HashSet<string> methods;
|
||||
public HashSet<string> fields;
|
||||
}
|
||||
|
||||
Dictionary<string, string> namespaceDictionary = new Dictionary<string, string> ();
|
||||
Dictionary<string, string> classIdsToClassNames = new Dictionary<string, string> ();
|
||||
Dictionary<string, ClassMembers> classNamesToClassMembers = new Dictionary<string, ClassMembers> ();
|
||||
|
||||
public override bool Execute ()
|
||||
{
|
||||
var namespaceFilePath = NamespaceFilePath.ItemSpec;
|
||||
if (!File.Exists (namespaceFilePath)) {
|
||||
Log.LogError ("File " + namespaceFilePath + " doesn't exist.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var mscorlibFilePath = MscorlibFilePath.ItemSpec;
|
||||
if (!File.Exists (mscorlibFilePath)) {
|
||||
Log.LogError ("File " + mscorlibFilePath + " doesn't exist.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var cortypeFilePath = CortypeFilePath.ItemSpec;
|
||||
if (!File.Exists (cortypeFilePath)) {
|
||||
Log.LogError ("File " + cortypeFilePath + " doesn't exist.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var rexcepFilePath = RexcepFilePath.ItemSpec;
|
||||
if (!File.Exists (rexcepFilePath)) {
|
||||
Log.LogError ("File " + rexcepFilePath + " doesn't exist.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var iLLinkTrimXmlFilePath = ILLinkTrimXmlFilePath.ItemSpec;
|
||||
if (!File.Exists (iLLinkTrimXmlFilePath)) {
|
||||
Log.LogError ("File " + iLLinkTrimXmlFilePath + " doesn't exist.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ProcessNamespaces (namespaceFilePath);
|
||||
|
||||
ProcessMscorlib (mscorlibFilePath);
|
||||
|
||||
ProcessCoreTypes (cortypeFilePath);
|
||||
|
||||
ProcessExceptionTypes (rexcepFilePath);
|
||||
|
||||
OutputXml (iLLinkTrimXmlFilePath, RuntimeRootDescriptorFilePath.ItemSpec);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ProcessNamespaces (string namespaceFile)
|
||||
{
|
||||
string [] namespaces = File.ReadAllLines (namespaceFile);
|
||||
|
||||
// Process definitions of the form
|
||||
// #define g_SystemNS "System"
|
||||
// from namespace.h
|
||||
foreach (string namespaceDef in namespaces) {
|
||||
if (namespaceDef.StartsWith ("#define")) {
|
||||
char [] separators = { '"', ' ', '\t' };
|
||||
string [] namespaceDefElements = namespaceDef.Split (separators, StringSplitOptions.RemoveEmptyEntries);
|
||||
int startIndex = "g_".Length;
|
||||
// E.g., if namespaceDefElements [1] is "g_RuntimeNS", lhs is "Runtime".
|
||||
string lhs = namespaceDefElements [1].Substring (startIndex, namespaceDefElements [1].LastIndexOf ('N') - startIndex);
|
||||
if (namespaceDefElements.Length == 3) {
|
||||
// E.G., #define g_SystemNS "System"
|
||||
// "System" --> "System"
|
||||
namespaceDictionary [lhs] = namespaceDefElements [2];
|
||||
}
|
||||
else {
|
||||
// E.g., #define g_RuntimeNS g_SystemNS ".Runtime"
|
||||
// "Runtime" --> "System.Runtime"
|
||||
string prefix = namespaceDefElements [2].Substring (startIndex, namespaceDefElements [2].LastIndexOf ('N') - startIndex);
|
||||
namespaceDictionary [lhs] = namespaceDictionary [prefix] + namespaceDefElements [3];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessMscorlib (string typeFile)
|
||||
{
|
||||
string [] types = File.ReadAllLines (typeFile);
|
||||
string classId = null;
|
||||
|
||||
foreach (string def in types) {
|
||||
string [] defElements = null;
|
||||
if (def.StartsWith ("DEFINE_") || def.StartsWith ("// DEFINE_")) {
|
||||
char [] separators = { ',', '(', ')', ' ', '\t', '/' };
|
||||
defElements = def.Split (separators, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
if (def.StartsWith ("DEFINE_CLASS(") || def.StartsWith ("// DEFINE_CLASS(")) {
|
||||
// E.g., DEFINE_CLASS(APP_DOMAIN, System, AppDomain)
|
||||
classId = defElements [1]; // APP_DOMAIN
|
||||
string classNamespace = defElements [2]; // System
|
||||
string className = defElements [3]; // AppDomain
|
||||
AddClass (classNamespace, className, classId);
|
||||
}
|
||||
else if (def.StartsWith ("DEFINE_CLASS_U(")) {
|
||||
// E.g., DEFINE_CLASS_U(System, AppDomain, AppDomainBaseObject)
|
||||
string classNamespace = defElements [1]; // System
|
||||
string className = defElements [2]; // AppDomain
|
||||
classId = defElements [3]; // AppDomainBaseObject
|
||||
// For these classes the sizes of managed and unmanaged classes and field offsets
|
||||
// are compared so we need to preserve all fields.
|
||||
const bool keepAllFields = true;
|
||||
AddClass (classNamespace, className, classId, keepAllFields);
|
||||
}
|
||||
else if (def.StartsWith ("DEFINE_FIELD(")) {
|
||||
// E.g., DEFINE_FIELD(ACCESS_VIOLATION_EXCEPTION, IP, _ip)
|
||||
classId = defElements [1]; // ACCESS_VIOLATION_EXCEPTION
|
||||
string fieldName = defElements [3]; // _ip
|
||||
AddField (fieldName, classId);
|
||||
}
|
||||
else if (def.StartsWith ("DEFINE_METHOD(")) {
|
||||
// E.g., DEFINE_METHOD(APP_DOMAIN, ON_ASSEMBLY_LOAD, OnAssemblyLoadEvent, IM_Assembly_RetVoid)
|
||||
string methodName = defElements [3]; // OnAssemblyLoadEvent
|
||||
classId = defElements [1]; // APP_DOMAIN
|
||||
AddMethod (methodName, classId);
|
||||
}
|
||||
else if (def.StartsWith ("DEFINE_PROPERTY(") || def.StartsWith ("DEFINE_STATIC_PROPERTY(")) {
|
||||
// E.g., DEFINE_PROPERTY(ARRAY, LENGTH, Length, Int)
|
||||
// or DEFINE_STATIC_PROPERTY(THREAD, CURRENT_THREAD, CurrentThread, Thread)
|
||||
string propertyName = defElements [3]; // Length or CurrentThread
|
||||
classId = defElements [1]; // ARRAY or THREAD
|
||||
AddMethod ("get_" + propertyName, classId);
|
||||
}
|
||||
else if (def.StartsWith ("DEFINE_SET_PROPERTY(")) {
|
||||
// E.g., DEFINE_SET_PROPERTY(THREAD, UI_CULTURE, CurrentUICulture, CultureInfo)
|
||||
string propertyName = defElements [3]; // CurrentUICulture
|
||||
classId = defElements [1]; // THREAD
|
||||
AddMethod ("get_" + propertyName, classId);
|
||||
AddMethod ("set_" + propertyName, classId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ProcessCoreTypes (string corTypeFile)
|
||||
{
|
||||
string [] corTypes = File.ReadAllLines (corTypeFile);
|
||||
|
||||
foreach (string def in corTypes) {
|
||||
// E.g., TYPEINFO(ELEMENT_TYPE_VOID, "System", "Void", 0, TYPE_GC_NONE, false, true, false, false, false) // 0x01
|
||||
if (def.StartsWith ("TYPEINFO(")) {
|
||||
char [] separators = { ',', '(', ')', '"', ' ', '\t' };
|
||||
string [] defElements = def.Split (separators, StringSplitOptions.RemoveEmptyEntries);
|
||||
string classId = null;
|
||||
string classNamespace = defElements [2]; // System
|
||||
string className = defElements [3]; // Void
|
||||
AddClass (classNamespace, className, classId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ProcessExceptionTypes (string excTypeFile)
|
||||
{
|
||||
string [] excTypes = File.ReadAllLines (excTypeFile);
|
||||
|
||||
foreach (string def in excTypes) {
|
||||
// E.g., DEFINE_EXCEPTION(g_InteropNS, MarshalDirectiveException, false, COR_E_MARSHALDIRECTIVE)
|
||||
if (def.StartsWith ("DEFINE_EXCEPTION(")) {
|
||||
char [] separators = { ',', '(', ')', ' ', '\t' };
|
||||
string [] defElements = def.Split (separators, StringSplitOptions.RemoveEmptyEntries);
|
||||
string classId = null;
|
||||
string classNamespace = defElements [1]; // g_InteropNS
|
||||
string className = defElements [2]; // MarshalDirectiveException
|
||||
AddClass (classNamespace, className, classId);
|
||||
AddMethod (".ctor", classId, classNamespace, className);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OutputXml (string iLLinkTrimXmlFilePath, string outputFileName)
|
||||
{
|
||||
XmlDocument doc = new XmlDocument ();
|
||||
doc.Load (iLLinkTrimXmlFilePath);
|
||||
XmlNode linkerNode = doc ["linker"];
|
||||
XmlNode assemblyNode = linkerNode ["assembly"];
|
||||
|
||||
foreach (string typeName in classNamesToClassMembers.Keys) {
|
||||
XmlNode typeNode = doc.CreateElement ("type");
|
||||
XmlAttribute typeFullName = doc.CreateAttribute ("fullname");
|
||||
typeFullName.Value = typeName;
|
||||
typeNode.Attributes.Append (typeFullName);
|
||||
|
||||
ClassMembers members = classNamesToClassMembers [typeName];
|
||||
|
||||
// We need to keep everyting in System.Runtime.InteropServices.WindowsRuntime and
|
||||
// System.Threading.Volatile.
|
||||
if (!typeName.StartsWith ("System.Runtime.InteropServices.WindowsRuntime") &&
|
||||
!typeName.StartsWith ("System.Threading.Volatile")) {
|
||||
if (members.keepAllFields) {
|
||||
XmlAttribute preserve = doc.CreateAttribute ("preserve");
|
||||
preserve.Value = "fields";
|
||||
typeNode.Attributes.Append (preserve);
|
||||
}
|
||||
else if ((members.fields == null) && (members.methods == null)) {
|
||||
XmlAttribute preserve = doc.CreateAttribute ("preserve");
|
||||
preserve.Value = "nothing";
|
||||
typeNode.Attributes.Append (preserve);
|
||||
}
|
||||
|
||||
if (!members.keepAllFields && (members.fields != null)) {
|
||||
foreach (string field in members.fields) {
|
||||
XmlNode fieldNode = doc.CreateElement ("field");
|
||||
XmlAttribute fieldName = doc.CreateAttribute ("name");
|
||||
fieldName.Value = field;
|
||||
fieldNode.Attributes.Append (fieldName);
|
||||
typeNode.AppendChild (fieldNode);
|
||||
}
|
||||
}
|
||||
|
||||
if (members.methods != null) {
|
||||
foreach (string method in members.methods) {
|
||||
XmlNode methodNode = doc.CreateElement ("method");
|
||||
XmlAttribute methodName = doc.CreateAttribute ("name");
|
||||
methodName.Value = method;
|
||||
methodNode.Attributes.Append (methodName);
|
||||
typeNode.AppendChild (methodNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
assemblyNode.AppendChild (typeNode);
|
||||
}
|
||||
doc.Save (outputFileName);
|
||||
}
|
||||
|
||||
void AddClass (string classNamespace, string className, string classId, bool keepAllFields = false)
|
||||
{
|
||||
string fullClassName = GetFullClassName (classNamespace, className);
|
||||
if (fullClassName != null) {
|
||||
if ((classId != null) && (classId != "NoClass")) {
|
||||
classIdsToClassNames [classId] = fullClassName;
|
||||
}
|
||||
ClassMembers members;
|
||||
if (!classNamesToClassMembers.TryGetValue (fullClassName, out members)) {
|
||||
members = new ClassMembers ();
|
||||
classNamesToClassMembers [fullClassName] = members;
|
||||
}
|
||||
members.keepAllFields |= keepAllFields;
|
||||
}
|
||||
}
|
||||
|
||||
void AddField (string fieldName, string classId)
|
||||
{
|
||||
string className = classIdsToClassNames [classId];
|
||||
|
||||
ClassMembers members = classNamesToClassMembers [className];
|
||||
|
||||
if (members.fields == null) {
|
||||
members.fields = new HashSet<string> ();
|
||||
}
|
||||
members.fields.Add (fieldName);
|
||||
}
|
||||
|
||||
void AddMethod (string methodName, string classId, string classNamespace = null, string className = null)
|
||||
{
|
||||
string fullClassName;
|
||||
if (classId != null) {
|
||||
fullClassName = classIdsToClassNames [classId];
|
||||
}
|
||||
else {
|
||||
fullClassName = GetFullClassName (classNamespace, className);
|
||||
}
|
||||
|
||||
ClassMembers members = classNamesToClassMembers [fullClassName];
|
||||
|
||||
if (members.methods == null) {
|
||||
members.methods = new HashSet<string> ();
|
||||
}
|
||||
members.methods.Add (methodName);
|
||||
}
|
||||
|
||||
string GetFullClassName (string classNamespace, string className)
|
||||
{
|
||||
string prefixToRemove = "g_";
|
||||
if (classNamespace.StartsWith (prefixToRemove)) {
|
||||
classNamespace = classNamespace.Substring (prefixToRemove.Length);
|
||||
}
|
||||
string suffixToRemove = "NS";
|
||||
if (classNamespace.EndsWith (suffixToRemove)) {
|
||||
classNamespace = classNamespace.Substring (0, classNamespace.Length - suffixToRemove.Length);
|
||||
}
|
||||
|
||||
if ((classNamespace == "NULL") && (className == "NULL")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!namespaceDictionary.ContainsKey (classNamespace)) {
|
||||
Log.LogError ("Unknown namespace: " + classNamespace);
|
||||
}
|
||||
|
||||
return namespaceDictionary [classNamespace] + "." + className;
|
||||
}
|
||||
}
|
||||
}
|
46
external/linker/src/ILLink.Tasks/FilterByMetadata.cs
vendored
Normal file
46
external/linker/src/ILLink.Tasks/FilterByMetadata.cs
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace ILLink.Tasks
|
||||
{
|
||||
public class FilterByMetadata : Task
|
||||
{
|
||||
/// <summary>
|
||||
/// Items to filter.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem[] Items { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of metadata to filter on.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public String MetadataName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The set of metadata values to include.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem[] MetadataValues { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Filtered items: the input items for which the
|
||||
/// specified metadata was one of the allowed
|
||||
/// values.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ITaskItem[] FilteredItems { get; set; }
|
||||
|
||||
public override bool Execute()
|
||||
{
|
||||
var metadataValues = new HashSet<string>(MetadataValues.Select(v => v.ItemSpec));
|
||||
FilteredItems = Items
|
||||
.Where(i => metadataValues.Contains(i.GetMetadata(MetadataName)))
|
||||
.ToArray();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
47
external/linker/src/ILLink.Tasks/FindDuplicatesByMetadata.cs
vendored
Normal file
47
external/linker/src/ILLink.Tasks/FindDuplicatesByMetadata.cs
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace ILLink.Tasks
|
||||
{
|
||||
public class FindDuplicatesByMetadata : Task
|
||||
{
|
||||
/// <summary>
|
||||
/// Items to scan.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem [] Items { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of metadata to scan for.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public String MetadataName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Duplicate items: the input items for which the
|
||||
/// specified metadata was shared by multiple input
|
||||
/// items.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ITaskItem [] DuplicateItems { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Duplicate representatives: includes one input
|
||||
/// item from each set of duplicates.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ITaskItem [] DuplicateRepresentatives { get; set; }
|
||||
|
||||
public override bool Execute ()
|
||||
{
|
||||
var duplicateGroups = Items.GroupBy (i => i.GetMetadata (MetadataName))
|
||||
.Where (g => g.Count () > 1);
|
||||
DuplicateItems = duplicateGroups.SelectMany (g => g).ToArray ();
|
||||
DuplicateRepresentatives = duplicateGroups.Select (g => g.First ()).ToArray ();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
91
external/linker/src/ILLink.Tasks/FindNativeDeps.cs
vendored
Normal file
91
external/linker/src/ILLink.Tasks/FindNativeDeps.cs
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace ILLink.Tasks
|
||||
{
|
||||
public class FindNativeDeps : Task
|
||||
{
|
||||
/// <summary>
|
||||
/// The managed assemblies to scan for references to native
|
||||
/// dependencies.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem [] ManagedAssemblyPaths { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The set of native dependencies to keep even if they
|
||||
/// aren't found to be referenced by a managed assembly.
|
||||
/// </summary>
|
||||
public ITaskItem [] NativeDepsToKeep { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The paths to the available native dependencies. We
|
||||
/// expect that all references found point to existing
|
||||
/// native files.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem [] NativeDepsPaths { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The set of native dependencies to keep, including those
|
||||
/// found in the analysis, and those explicitly marked keep
|
||||
/// by NativeDepsToKeep. This includes metadata from the
|
||||
/// input NativeDepsToKeep.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ITaskItem [] KeptNativeDepsPaths { get; set; }
|
||||
|
||||
public override bool Execute ()
|
||||
{
|
||||
var allNativeNames = new HashSet<string> ();
|
||||
foreach (var nativeDep in NativeDepsPaths)
|
||||
allNativeNames.Add (Path.GetFileName (nativeDep.ItemSpec));
|
||||
var keptNativeNames = new HashSet<string> ();
|
||||
foreach (var nativeDep in NativeDepsToKeep)
|
||||
keptNativeNames.Add (Path.GetFileName (nativeDep.ItemSpec));
|
||||
|
||||
var managedAssemblies = ManagedAssemblyPaths.Select (i => i.ItemSpec).ToArray ();
|
||||
foreach (string managedAssembly in managedAssemblies) {
|
||||
using (var peReader = new PEReader(new FileStream (managedAssembly, FileMode.Open, FileAccess.Read, FileShare.Read))) {
|
||||
if (peReader.HasMetadata) {
|
||||
var reader = peReader.GetMetadataReader ();
|
||||
for (int i = 1, count = reader.GetTableRowCount (TableIndex.ModuleRef); i <= count; i++) {
|
||||
var moduleRef = reader.GetModuleReference (MetadataTokens.ModuleReferenceHandle (i));
|
||||
var moduleName = reader.GetString (moduleRef.Name);
|
||||
|
||||
var moduleRefCandidates = new [] { moduleName, moduleName + ".dll", moduleName + ".so", moduleName + ".dylib" };
|
||||
|
||||
bool foundModuleRef = false;
|
||||
foreach (string moduleRefCandidate in moduleRefCandidates) {
|
||||
if (allNativeNames.Contains (moduleRefCandidate)) {
|
||||
keptNativeNames.Add (moduleRefCandidate);
|
||||
foundModuleRef = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundModuleRef)
|
||||
Log.LogMessage("unsatisfied DLLImport: " + managedAssembly + " -> " + moduleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var keptNativeDeps = new List<ITaskItem> ();
|
||||
foreach (var nativeDep in NativeDepsPaths) {
|
||||
var fileName = Path.GetFileName (nativeDep.ItemSpec);
|
||||
if (keptNativeNames.Contains (fileName))
|
||||
keptNativeDeps.Add (nativeDep);
|
||||
}
|
||||
|
||||
KeptNativeDepsPaths = keptNativeDeps.ToArray ();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
222
external/linker/src/ILLink.Tasks/ILLink.Tasks.csproj
vendored
Normal file
222
external/linker/src/ILLink.Tasks/ILLink.Tasks.csproj
vendored
Normal file
@ -0,0 +1,222 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(MSBuildThisFileDirectory)../../eng/Versions.props" Condition=" '$(ArcadeBuild)' != 'true' " />
|
||||
<PropertyGroup>
|
||||
<!-- net46 build is disabled until cecil uses SDK-style projects. -->
|
||||
<TargetFrameworks>netcoreapp2.0</TargetFrameworks>
|
||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||
<BaseOutputPath>bin/</BaseOutputPath>
|
||||
<PackageOutputPath>$(BaseOutputPath)nupkgs</PackageOutputPath>
|
||||
<IsPackable>true</IsPackable>
|
||||
<!-- IsTool true causes the build output to be placed in the
|
||||
package's tools folder. This allows projects to reference the
|
||||
tasks package without including the tasks dll in their
|
||||
output. -->
|
||||
<!-- TODO: This has no effect currently, because we are using a
|
||||
custom .nuspec with the tools path hardcoded. Uncomment this
|
||||
once we are able to remove the custom .nuspec workaround. -->
|
||||
<!-- <IsTool>true</IsTool> -->
|
||||
|
||||
<!-- We want to package the tasks package together with its
|
||||
package dependencies, the linker, and the linker's
|
||||
dependencies, in order to prevent projects that consume the
|
||||
tasks package from pulling in the linker. To do this, we need
|
||||
to include project references and package references in the
|
||||
package, and prevent any of these references from being
|
||||
marked as dependencies in the tasks package.
|
||||
|
||||
To include the linker in the package, we want to package the
|
||||
tasks project together with its project references. This is
|
||||
not supported by the pack targets
|
||||
(https://github.com/dotnet/cli/issues/1290,
|
||||
https://github.com/dotnet/cli/issues/3959), so we work around
|
||||
this by explicitly setting the package path to include the
|
||||
build output. Using the publish directory will also cause
|
||||
dependencies from package references to be packaged.
|
||||
|
||||
To prevent the linker from being marked as a package
|
||||
dependency, we can't use PrivateAssets="All", because this
|
||||
removes it from the publish output as well, due to an issue
|
||||
in the SDK (https://github.com/dotnet/sdk/issues/952). To
|
||||
work around this, we use a custom .nuspec that doesn't
|
||||
declare any dependencies. This also prevents package
|
||||
references from being marked as dependencies. -->
|
||||
<!-- TODO: Remove the custom .nuspec once the P2P PrivateAssets
|
||||
issue is fixed. -->
|
||||
<NuspecFileName>ILLink.Tasks.nuspec</NuspecFileName>
|
||||
<NuspecFile>$(BaseOutputPath)$(NuspecFileName)</NuspecFile>
|
||||
<NuspecProperties>id=$(AssemblyName);authors=$(AssemblyName);description=linker tasks;</NuspecProperties>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- TODO: Remove this workaround once we're able to avoid using a
|
||||
custom .nuspec. We may still need a similar workaround to
|
||||
dynamically include the publish output in the package contents.
|
||||
|
||||
We can't specify the output path to package in the static
|
||||
nuspec properties, because the project's output path gets set
|
||||
at a later point. To work around this, we add the output path
|
||||
to the nuspec properties dynamically as part of the pack
|
||||
target. We use the same workaround to set the version in the
|
||||
.nuspec file.
|
||||
|
||||
We can't insert this into the pack target by modifying
|
||||
PackDependsOn, since GenerateNuspec is always prepended to
|
||||
PackDependsOn, which would cause the nuspec file to be
|
||||
generated before our extra properties are added.
|
||||
|
||||
Instead, we use GenerateNuspecDependsOn. We could probably also
|
||||
use BeforeTargets="GenerateNuspec". -->
|
||||
<PropertyGroup>
|
||||
<GenerateNuspecDependsOn>SetDynamicNuspecProperties;BinPlacePackageDeps;$(GenerateNuspecDependsOn)</GenerateNuspecDependsOn>
|
||||
</PropertyGroup>
|
||||
<Target Name="SetDynamicNuspecProperties"
|
||||
DependsOnTargets="LayoutPackage">
|
||||
<PropertyGroup>
|
||||
<NuspecProperties>$(NuspecProperties)version=$(Version);</NuspecProperties>
|
||||
</PropertyGroup>
|
||||
</Target>
|
||||
|
||||
<!-- This target is necessary because the .nuspec includes the full
|
||||
path of the selected dlls in the package layout. We want the
|
||||
assets to be included in the package without the bin prefix, so
|
||||
we place the .nuspec and the included targets alongside the
|
||||
publish directories in the bin directory. -->
|
||||
<Target Name="BinPlacePackageDeps">
|
||||
<Copy SourceFiles="$(NuspecFileName)" DestinationFolder="$(BaseOutputPath)" />
|
||||
<Copy SourceFiles="ILLink.Tasks.targets" DestinationFolder="$(BaseOutputPath)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="LayoutPackage">
|
||||
<ItemGroup>
|
||||
<TFMsToPublish Include="$(TargetFrameworks)" />
|
||||
<ProjectsToPublish Include="$(MSBuildProjectFile)">
|
||||
<AdditionalProperties>TargetFramework=%(TFMsToPublish.Identity);PublishDir=$(BaseOutputPath)%(TFMsToPublish.Identity)</AdditionalProperties>
|
||||
</ProjectsToPublish>
|
||||
</ItemGroup>
|
||||
<MSBuild Projects="@(ProjectsToPublish)" Targets="Publish" />
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="AdapterLogger.cs" />
|
||||
<Compile Include="LinkTask.cs" />
|
||||
<Compile Include="CheckEmbeddedRootDescriptor.cs" />
|
||||
<Compile Include="CompareSizes.cs" />
|
||||
<Compile Include="ComputeManagedAssemblies.cs" />
|
||||
<Compile Include="ComputeRemovedAssemblies.cs" />
|
||||
<Compile Include="CreateRootDescriptorFile.cs" />
|
||||
<Compile Include="CreateRuntimeRootDescriptorFile.cs" />
|
||||
<Compile Include="FilterByMetadata.cs" />
|
||||
<Compile Include="FindDuplicatesByMetadata.cs" />
|
||||
<Compile Include="FindNativeDeps.cs" />
|
||||
<Compile Include="SetAssemblyActions.cs" />
|
||||
<Compile Include="Utils.cs" />
|
||||
<Content Include="Sdk\Sdk.props">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- TODO: Uncomment this once we can avoid hard-coding this in a
|
||||
custom .nuspec. -->
|
||||
<!-- Targets under the build directory of the package automatically
|
||||
get included in the consumer's build.
|
||||
-->
|
||||
<!--
|
||||
<ItemGroup>
|
||||
<Content Include="ILLink.Tasks.targets">
|
||||
<PackagePath>build</PackagePath>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
-->
|
||||
|
||||
<!-- TODO: Use this to set the package contents once we can avoid
|
||||
using a custom .nuspec. -->
|
||||
<!-- We can't glob everything in the output path for two reasons:
|
||||
|
||||
1. Content gets expanded before "Build" is called during
|
||||
"Pack". We could work around this by creating our own target to
|
||||
call build and then pack, but it would be nice to avoid
|
||||
changing the build/package pipeline.
|
||||
|
||||
2. We'll try to include the tasks dll twice. This only causes a
|
||||
warning during pack, but should be avoided.
|
||||
|
||||
<Content Include="$(OutputPath)*.dll;$(OutputPath)*.json">
|
||||
<PackagePath>tools</PackagePath>
|
||||
</Content>
|
||||
|
||||
There may also be a better ItemGroup to use than
|
||||
Content. Content semantics mean to output with the build, which
|
||||
isn't our goal. Instead, we want to include these dependencies
|
||||
in the package without necessarily including them in the build.
|
||||
-->
|
||||
<!--
|
||||
<ItemGroup>
|
||||
<Content Include="$(OutputPath)illink.dll;$(OutputPath)Mono.Cecil.dll">
|
||||
<PackagePath>tools</PackagePath>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
-->
|
||||
|
||||
<ItemGroup>
|
||||
<!-- TODO: Once https://github.com/dotnet/sdk/issues/952 is fixed,
|
||||
use PrivateAssets="All" to prevent this project reference
|
||||
from being marked as a dependency of the tasks package (while
|
||||
still including it in the publish output). -->
|
||||
<ProjectReference Include="../linker/Mono.Linker.csproj">
|
||||
<!-- SetConfiguration isn't required when the configuration is
|
||||
already set in the solution. Setting it here allows packing
|
||||
the tasks csproj on its own. This lets us avoid some of the
|
||||
strange behavior that shows up when trying to build from a
|
||||
.sln file.
|
||||
|
||||
There is a nuget bug that prevents this from working
|
||||
properly during restore
|
||||
(https://github.com/NuGet/Home/issues/4873). For the
|
||||
moment, the linker has a workaround for this issue.
|
||||
|
||||
However, this still won't work properly because the build
|
||||
target doesn't propagate this information properly either -
|
||||
this is probably another bug. Building from the .csproj
|
||||
would cause cecil to be built twice, once through the
|
||||
linker with the netstandard configuration and once directly
|
||||
from the tasks project in the default configuration info
|
||||
(because some target gets its reference information from
|
||||
the lock file, which doesn't have configuration info).
|
||||
-->
|
||||
<SetConfiguration>Configuration=illink_$(Configuration)</SetConfiguration>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="../../external/cecil/Mono.Cecil.csproj" />
|
||||
|
||||
<ProjectReference Include="../ILLink.CustomSteps/ILLink.CustomSteps.csproj">
|
||||
<SetConfiguration>Configuration=illink_$(Configuration)</SetConfiguration>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Workaround for the SetConfiguration issue described above. -->
|
||||
<Target Name="SetCecilConfiguration"
|
||||
AfterTargets="AssignProjectConfiguration">
|
||||
<ItemGroup>
|
||||
<ProjectReferenceWithConfiguration Condition=" '%(Filename)%(Extension)' == 'Mono.Cecil.csproj' Or '%(Filename)%(Extension)' == 'Mono.Cecil.Pdb.csproj' Or '%(Filename)%(Extension)' == 'Mono.Cecil.Mdb.csproj' ">
|
||||
<SetConfiguration Condition=" '$(TargetFramework)' == 'net46' ">Configuration=net_4_0_$(Configuration)</SetConfiguration>
|
||||
<SetConfiguration Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">Configuration=netstandard_$(Configuration)</SetConfiguration>
|
||||
</ProjectReferenceWithConfiguration>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
<!-- TODO: Once we can avoid using a custom .nuspec, we should be
|
||||
able to set PrivateAssets="All" on these packages to prevent
|
||||
them from becoming package dependencies, and use an msbuild
|
||||
itemgroup to include their assets in the package instead of
|
||||
passing the publish path to the .nuspec. -->
|
||||
<!-- We use private assets for the Microsoft.Build packages to
|
||||
prevent them from being published with the tasks dll, because
|
||||
these are already a part of the SDK. -->
|
||||
<PackageReference Include="Microsoft.Build.Framework" Version="15.1.1012"
|
||||
PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="15.1.1012"
|
||||
PrivateAssets="All" />
|
||||
<PackageReference Include="System.Reflection.Metadata" Version="1.3.0"
|
||||
PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
</Project>
|
15
external/linker/src/ILLink.Tasks/ILLink.Tasks.nuspec
vendored
Normal file
15
external/linker/src/ILLink.Tasks/ILLink.Tasks.nuspec
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>$id$</id>
|
||||
<version>$version$</version>
|
||||
<authors>$authors$</authors>
|
||||
<description>$description$</description>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="ILLink.Tasks.targets" target="build" />
|
||||
<file src="netcoreapp2.0/**/*.dll" target="tools" />
|
||||
<file src="netcoreapp2.0/**/*.json" target="tools" />
|
||||
<file src="netcoreapp2.0/Sdk/Sdk.props" target="Sdk/Sdk.props" />
|
||||
</files>
|
||||
</package>
|
509
external/linker/src/ILLink.Tasks/ILLink.Tasks.targets
vendored
Normal file
509
external/linker/src/ILLink.Tasks/ILLink.Tasks.targets
vendored
Normal file
File diff suppressed because it is too large
Load Diff
176
external/linker/src/ILLink.Tasks/LinkTask.cs
vendored
Normal file
176
external/linker/src/ILLink.Tasks/LinkTask.cs
vendored
Normal file
@ -0,0 +1,176 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace ILLink.Tasks
|
||||
{
|
||||
public class ILLink : ToolTask
|
||||
{
|
||||
/// <summary>
|
||||
/// Paths to the assembly files that should be considered as
|
||||
/// input to the linker. Currently the linker will
|
||||
/// additionally be able to resolve any assemblies in the
|
||||
/// same directory as an assembly in AssemblyPaths, but this
|
||||
/// behavior should not be relied upon. Instead, work under
|
||||
/// the assumption that only the AssemblyPaths given will be
|
||||
/// resolved.
|
||||
/// Each path can also have an "action" metadata,
|
||||
/// which will set the illink action to take for
|
||||
/// that assembly.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem [] AssemblyPaths { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The names of the assemblies to root. This should contain
|
||||
/// assembly names without an extension, not file names or
|
||||
/// paths. Exactly which parts of the assemblies get rooted
|
||||
/// is subject to change. Currently these get passed to
|
||||
/// illink with "-a", which roots the entry point for
|
||||
/// executables, and everything for libraries. To control
|
||||
/// the linker more explicitly, either pass descriptor
|
||||
/// files, or pass extra arguments for illink.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem [] RootAssemblyNames { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The directory in which to place linked assemblies.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem OutputDirectory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of XML root descriptor files specifying linker
|
||||
/// roots at a granular level. See the mono/linker
|
||||
/// documentation for details about the format.
|
||||
/// </summary>
|
||||
public ITaskItem [] RootDescriptorFiles { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Boolean specifying whether to clear initlocals flag on methods.
|
||||
/// </summary>
|
||||
public bool ClearInitLocals { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A comma-separated list of assemblies whose methods
|
||||
/// should have initlocals flag cleared if ClearInitLocals is true.
|
||||
/// </summary>
|
||||
public string ClearInitLocalsAssemblies { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Extra arguments to pass to illink, delimited by spaces.
|
||||
/// </summary>
|
||||
public string ExtraArgs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Make illink dump dependencies file for linker analyzer tool.
|
||||
/// </summary>
|
||||
public bool DumpDependencies { get; set; }
|
||||
|
||||
|
||||
private static string DotNetHostPathEnvironmentName = "DOTNET_HOST_PATH";
|
||||
|
||||
private string _dotnetPath;
|
||||
|
||||
private string DotNetPath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!String.IsNullOrEmpty (_dotnetPath))
|
||||
{
|
||||
return _dotnetPath;
|
||||
}
|
||||
_dotnetPath = Environment.GetEnvironmentVariable (DotNetHostPathEnvironmentName);
|
||||
if (String.IsNullOrEmpty (_dotnetPath))
|
||||
{
|
||||
throw new InvalidOperationException ($"{DotNetHostPathEnvironmentName} is not set");
|
||||
}
|
||||
return _dotnetPath;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// ToolTask implementation
|
||||
|
||||
protected override string ToolName => Path.GetFileName (DotNetPath);
|
||||
|
||||
protected override string GenerateFullPathToTool () => DotNetPath;
|
||||
|
||||
private string _illinkPath = "";
|
||||
|
||||
public string ILLinkPath {
|
||||
get {
|
||||
if (!String.IsNullOrEmpty (_illinkPath))
|
||||
{
|
||||
return _illinkPath;
|
||||
}
|
||||
var taskDirectory = Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location);
|
||||
_illinkPath = Path.Combine (taskDirectory, "illink.dll");
|
||||
return _illinkPath;
|
||||
}
|
||||
set => _illinkPath = value;
|
||||
}
|
||||
|
||||
protected override string GenerateCommandLineCommands ()
|
||||
{
|
||||
var args = new StringBuilder ();
|
||||
args.Append (ILLinkPath);
|
||||
|
||||
if (RootDescriptorFiles != null) {
|
||||
foreach (var rootFile in RootDescriptorFiles) {
|
||||
args.Append (" -x ").Append (rootFile.ItemSpec);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var assemblyItem in RootAssemblyNames) {
|
||||
args.Append (" -a ").Append (assemblyItem.ItemSpec);
|
||||
}
|
||||
|
||||
HashSet<string> directories = new HashSet<string> ();
|
||||
foreach (var assembly in AssemblyPaths) {
|
||||
var assemblyPath = assembly.ItemSpec;
|
||||
var dir = Path.GetDirectoryName (assemblyPath);
|
||||
if (!directories.Contains (dir)) {
|
||||
directories.Add (dir);
|
||||
args.Append (" -d ").Append (dir);
|
||||
}
|
||||
|
||||
string action = assembly.GetMetadata ("action");
|
||||
if ((action != null) && (action.Length > 0)) {
|
||||
args.Append (" -p ");
|
||||
args.Append (action);
|
||||
args.Append (" ").Append (Path.GetFileNameWithoutExtension (assemblyPath));
|
||||
}
|
||||
}
|
||||
|
||||
if (OutputDirectory != null) {
|
||||
args.Append (" -out ").Append (OutputDirectory.ItemSpec);
|
||||
}
|
||||
|
||||
if (ClearInitLocals) {
|
||||
args.Append (" -s ");
|
||||
// Version of ILLink.CustomSteps is passed as a workaround for msbuild issue #3016
|
||||
args.Append ("LLink.CustomSteps.ClearInitLocalsStep,ILLink.CustomSteps,Version=0.0.0.0:OutputStep");
|
||||
if ((ClearInitLocalsAssemblies != null) && (ClearInitLocalsAssemblies.Length > 0)) {
|
||||
args.Append (" -m ClearInitLocalsAssemblies ");
|
||||
args.Append (ClearInitLocalsAssemblies);
|
||||
}
|
||||
}
|
||||
|
||||
if (ExtraArgs != null) {
|
||||
args.Append (" ").Append (ExtraArgs);
|
||||
}
|
||||
|
||||
if (DumpDependencies)
|
||||
args.Append (" --dump-dependencies");
|
||||
|
||||
return args.ToString ();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
174
external/linker/src/ILLink.Tasks/README.md
vendored
Normal file
174
external/linker/src/ILLink.Tasks/README.md
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
# ILLink.Tasks
|
||||
|
||||
ILLink.Tasks is a package containing MSBuild tasks and targets that
|
||||
will run the linker to run during publish of a .NET Core app.
|
||||
|
||||
ILLink.Tasks provides an MSBuild task called ILLink that makes it easy
|
||||
to run the linker from an MSBuild project file:
|
||||
|
||||
```xml
|
||||
<ILLink AssemblyPaths="@(AssemblyFilesToLink)"
|
||||
RootAssemblyNames="@(LinkerRootAssemblies)"
|
||||
RootDescriptorFiles="@(LinkerRootDescriptors)"
|
||||
OutputDirectory="output"
|
||||
ExtraArgs="-t -c link -l none" />
|
||||
```
|
||||
|
||||
For a description of the options that this task supports, see the
|
||||
comments in [LinkTask.cs](LinkTask.cs).
|
||||
|
||||
|
||||
In addition, ILLink.Tasks contains MSBuild logic that makes the linker
|
||||
run automatically during `dotnet publish` for .NET Core apps. This
|
||||
will:
|
||||
|
||||
- Determine the assemblies and options to pass to illink.
|
||||
- Remove unused native files from the publish output.
|
||||
|
||||
The full set of options is described below.
|
||||
|
||||
## Building
|
||||
|
||||
```
|
||||
linker> ./corebuild/dotnet.{sh/ps1} restore illink.sln
|
||||
linker> ./corebuild/dotnet.{sh/ps1} pack src/ILLink.Tasks/ILLink.Tasks.csproj
|
||||
```
|
||||
|
||||
The output package will be placed in
|
||||
`corebuild/integration/bin/nupkgs`. If you are building on unix, you
|
||||
will need to adjust
|
||||
[ILLink.Tasks.nuspec](ILLink.Tasks.nuspec). Replace
|
||||
the dll file includes with the following:
|
||||
|
||||
`<file src="netcoreapp2.0/**/*.dll" target="tools/netcoreapp2.0" />`
|
||||
|
||||
## Using ILLink.Tasks
|
||||
|
||||
Add a package reference to the linker. Ensure that either the
|
||||
[dotnet-core](https://dotnet.myget.org/gallery/dotnet-core) myget feed
|
||||
or the path to the locally-built linker package path exists in the
|
||||
project's nuget.config. If using myget, you probably want to ensure
|
||||
that you're using the latest version available at
|
||||
https://dotnet.myget.org/feed/dotnet-core/package/nuget/ILLink.Tasks.
|
||||
|
||||
After adding the package, linking will be turned on during `dotnet
|
||||
publish`. The publish output will contain the linked assemblies.
|
||||
|
||||
## Default behavior
|
||||
|
||||
By default, the linker will operate in a conservative mode that keeps
|
||||
all managed assemblies that aren't part of the framework (they are
|
||||
kept intact, and the linker simply copies them). It also analyzes all
|
||||
non-framework assemblies to find and keep code used by them (they are
|
||||
roots for the analysis). This means that unanalyzed reflection calls
|
||||
within the app should continue to work after linking. Reflection calls
|
||||
to code in the framework can potentially break when using the linker,
|
||||
if the target of the call is removed.
|
||||
|
||||
For portable publish, framework assemblies usually do not get
|
||||
published with the app. In this case they will not be analyzed or
|
||||
linked.
|
||||
|
||||
For self-contained publish, framework assemblies are part of the
|
||||
publish output, and are analyzed by the linker. Any framework
|
||||
assemblies that aren't predicted to be used at runtime based on the
|
||||
linker analysis will be removed from the publish output. Used
|
||||
framework assemblies will be kept, and any used code within these
|
||||
assemblies will be compiled to native code. Unused parts of used
|
||||
framework assemblies are kept as IL, so that reflection calls will
|
||||
continue to work, with runtime JIT compilation.
|
||||
|
||||
Native dependencies that aren't referenced by any of the kept managed
|
||||
assemblies will be removed from the publish output as well.
|
||||
|
||||
## Caveats
|
||||
|
||||
You should make sure to test the publish output before deploying your
|
||||
code, because the linker can potentially break apps that use
|
||||
reflection.
|
||||
|
||||
The linker does not analyze reflection calls, so any reflection
|
||||
targets outside of the kept assemblies will need to be rooted
|
||||
explicitly using either `LinkerRootAssemblies` or
|
||||
`LinkerRootDescriptors` (see below).
|
||||
|
||||
Sometimes an application may include multiple versions of the same
|
||||
assembly. This may happen when portable apps include platform-specific
|
||||
managed code, which gets placed in the `runtimes` directory of the
|
||||
publish output. In such cases, the linker will pick one of the
|
||||
duplicate assemblies to analyze. This means that dependencies of the
|
||||
un-analyzed duplicates may not be included in the application, so you
|
||||
may need to root such dependencies manually.
|
||||
|
||||
## Options
|
||||
|
||||
The following MSBuild properties can be used to control the behavior
|
||||
of the linker, from the command-line (via `dotnet publish
|
||||
/p:PropertyName=PropertyValue`), or from the .csproj file (via
|
||||
`<PropertyName>PropertyValue</PropertyName>`). They are defined and
|
||||
used in
|
||||
[ILLink.Tasks.targets](ILLink.Tasks.targets).
|
||||
|
||||
- `LinkDuringPublish` (default `true`) - Set to `false` to disable
|
||||
linking.
|
||||
|
||||
- `ShowLinkerSizeComparison` (default `false`) - Set to `true` to
|
||||
print out a table showing the size impact of the linker.
|
||||
|
||||
- `RootAllApplicationAssemblies` (default `true`) - If `true`, all
|
||||
application assemblies are rooted by the linker. This means they are
|
||||
kept in their entirety, and analyzed for dependencies. If `false`,
|
||||
only the app dll's entry point is rooted.
|
||||
|
||||
- `LinkerRootAssemblies` - The set of assemblies to root. The default
|
||||
depends on the value of `RootAllApplicationAssemblies`. Additional
|
||||
assemblies can be rooted by adding them to this ItemGroup.
|
||||
|
||||
- `LinkerRootDescriptors` - The set of [xml descriptors](../linker#syntax-of-xml-descriptor)
|
||||
specifying additional roots within assemblies. The default is to
|
||||
include a generated descriptor that roots everything in the
|
||||
application assembly if `RootAllApplicationAssemblies` is
|
||||
`true`. Additional roots from descriptors can be included by adding
|
||||
the descriptor files to this ItemGroup.
|
||||
|
||||
- `ExtraLinkerArgs` - Extra arguments to pass to the linker. The
|
||||
default sets some flags that output symbols, tolerate resolution
|
||||
errors, log warnings, skip mono-specific localization assemblies,
|
||||
and keep type-forwarder assemblies. See
|
||||
[ILLink.Tasks.targets](ILLink.Tasks.targets).
|
||||
Setting this will override the defaults.
|
||||
|
||||
- Assembly actions: illink has the ability to specify an [action](../linker#actions-on-the-assemblies) to
|
||||
take per-assembly. ILLink.Tasks provides high-level switches that
|
||||
control the action to take for a set of assemblies. The set of
|
||||
managed files that make up the application are split into
|
||||
"application" and "platform" assemblies. The "platform" represents
|
||||
the .NET framework, while the "application" represents the rest of
|
||||
the application and its other dependencies. The assembly action can
|
||||
be set for each of these groups independently, for assemblies that
|
||||
are analyzed as used and as unused, with the following switches:
|
||||
|
||||
- `UsedApplicationAssemblyAction` - The default is to `Copy` any used
|
||||
application assemblies to the output, leaving them as-is.
|
||||
- `UnusedApplicationAssemblyAction` - The default is to `Delete` (not
|
||||
publish) unused application assemblies.
|
||||
- `UsedPlatformAssemblyAction` - For self-contained publish, the
|
||||
default is `AddBypassNGen`, which will add the BypassNGenAttribute
|
||||
to unused code in used platform assemblies. This causes the native
|
||||
compilation step to compile only parts of these assemblies that
|
||||
are used. For portable publish, the default is to `Skip` these,
|
||||
because the platform assemblies are generally not published with
|
||||
the app.
|
||||
- `UnusedPlatformAssemblyAction` - For self-contained publish, the
|
||||
default is to `Delete` (not publish) unused platform
|
||||
assemblies. For portable publish, the default is to `Skip`.
|
||||
|
||||
The full list of assembly actions is described in
|
||||
[AssemblyAction.cs](../linker/Linker/AssemblyAction.cs) Some
|
||||
combinations of actions may be disallowed if they do not make
|
||||
sense. For more details, see
|
||||
[SetAssemblyActions.cs](SetAssemblyActions.cs).
|
||||
|
||||
- `LinkerTrimNativeDeps` (default `true`) - If `true`, enable
|
||||
detection and removal of unused native dependencies. If `false`, all
|
||||
native dependencies are kept.
|
16
external/linker/src/ILLink.Tasks/Sdk/Sdk.props
vendored
Normal file
16
external/linker/src/ILLink.Tasks/Sdk/Sdk.props
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
<!--
|
||||
***********************************************************************************************
|
||||
Sdk.props
|
||||
|
||||
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
|
||||
created a backup copy. Incorrect changes to this file will make it
|
||||
impossible to load or build your projects from the command-line or the IDE.
|
||||
|
||||
Copyright (c) .NET Foundation. All rights reserved.
|
||||
***********************************************************************************************
|
||||
-->
|
||||
<Project ToolsVersion="14.0">
|
||||
|
||||
<UsingTask TaskName="ILLink.Tasks.ILLink" AssemblyFile="$(MSBuildThisFileDirectory)..\tools\netcoreapp2.0\ILLink.Tasks.dll" />
|
||||
|
||||
</Project>
|
138
external/linker/src/ILLink.Tasks/SetAssemblyActions.cs
vendored
Normal file
138
external/linker/src/ILLink.Tasks/SetAssemblyActions.cs
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
using System.IO;
|
||||
|
||||
namespace ILLink.Tasks
|
||||
{
|
||||
public class SetAssemblyActions : Task
|
||||
{
|
||||
/// <summary>
|
||||
/// Paths to the assembly files that should be considered as
|
||||
/// input to the linker.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem [] AssemblyPaths { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Application assembly names.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem [] ApplicationAssemblyNames { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Platform assembly names.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem [] PlatformAssemblyNames { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Action to perform on used application assemblies.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem UsedApplicationAssemblyAction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Action to perform on unused application assemblies.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem UnusedApplicationAssemblyAction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Action to perform on used platform assemblies.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem UsedPlatformAssemblyAction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Action to perform on unused platform assemblies.
|
||||
/// </summary>
|
||||
[Required]
|
||||
public ITaskItem UnusedPlatformAssemblyAction { get; set; }
|
||||
|
||||
[Output]
|
||||
public ITaskItem [] AssemblyPathsWithActions { get; set; }
|
||||
|
||||
public override bool Execute ()
|
||||
{
|
||||
string applicationAssemblyAction;
|
||||
string usedApplicationAssemblyAction = UsedApplicationAssemblyAction.ItemSpec;
|
||||
string unusedApplicationAssemblyAction = UnusedApplicationAssemblyAction.ItemSpec;
|
||||
if (!GetAssemblyAction (usedApplicationAssemblyAction.ToLower (), unusedApplicationAssemblyAction.ToLower (), out applicationAssemblyAction)) {
|
||||
Log.LogError ("Unsupported combination of application assembly actions: {0}, {1}.",
|
||||
usedApplicationAssemblyAction, unusedApplicationAssemblyAction);
|
||||
return false;
|
||||
}
|
||||
|
||||
string platformAssemblyAction;
|
||||
string usedPlatformAssemblyAction = UsedPlatformAssemblyAction.ItemSpec;
|
||||
string unusedPlatformAssemblyAction = UnusedPlatformAssemblyAction.ItemSpec;
|
||||
if (!GetAssemblyAction (usedPlatformAssemblyAction.ToLower (), unusedPlatformAssemblyAction.ToLower (), out platformAssemblyAction)) {
|
||||
Log.LogError ("Unsupported combination of platform assembly actions: {0}, {1}.",
|
||||
usedPlatformAssemblyAction, unusedPlatformAssemblyAction);
|
||||
return false;
|
||||
}
|
||||
|
||||
List<ITaskItem> resultAssemblies = new List<ITaskItem> ();
|
||||
|
||||
AddAssemblyActionMetadata (ApplicationAssemblyNames, applicationAssemblyAction, resultAssemblies);
|
||||
AddAssemblyActionMetadata (PlatformAssemblyNames, platformAssemblyAction, resultAssemblies);
|
||||
|
||||
AssemblyPathsWithActions = resultAssemblies.ToArray ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetAssemblyAction (string usedAssemblyAction, string unusedAssemblyAction, out string assemblyAction)
|
||||
{
|
||||
assemblyAction = "illegal";
|
||||
if ((unusedAssemblyAction != usedAssemblyAction) && (unusedAssemblyAction != "delete")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (usedAssemblyAction) {
|
||||
case "link":
|
||||
assemblyAction = "link";
|
||||
break;
|
||||
|
||||
case "copy":
|
||||
assemblyAction = (unusedAssemblyAction == "delete") ? "copyused" : "copy";
|
||||
break;
|
||||
|
||||
case "addbypassngen":
|
||||
assemblyAction = (unusedAssemblyAction == "delete") ? "addbypassngenused" : "addbypassngen";
|
||||
break;
|
||||
|
||||
case "skip":
|
||||
if (unusedAssemblyAction != usedAssemblyAction) {
|
||||
return false;
|
||||
}
|
||||
assemblyAction = "skip";
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddAssemblyActionMetadata (ITaskItem [] assemblies, string action, List<ITaskItem> resultList)
|
||||
{
|
||||
HashSet<string> assemblyHashSet = new HashSet<string> ();
|
||||
foreach (var assembly in assemblies) {
|
||||
assemblyHashSet.Add (assembly.ItemSpec);
|
||||
}
|
||||
|
||||
foreach (var assembly in AssemblyPaths) {
|
||||
if (assemblyHashSet.Contains (Path.GetFileNameWithoutExtension (assembly.ItemSpec))) {
|
||||
assembly.SetMetadata ("action", action);
|
||||
resultList.Add (assembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
26
external/linker/src/ILLink.Tasks/Utils.cs
vendored
Normal file
26
external/linker/src/ILLink.Tasks/Utils.cs
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using Mono.Cecil;
|
||||
using Mono.Linker;
|
||||
|
||||
public static class Utils
|
||||
{
|
||||
public static bool IsManagedAssembly (string fileName)
|
||||
{
|
||||
try {
|
||||
ModuleDefinition module = ModuleDefinition.ReadModule (fileName);
|
||||
return true;
|
||||
} catch (BadImageFormatException) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsCrossgenedAssembly (string fileName)
|
||||
{
|
||||
try {
|
||||
ModuleDefinition module = ModuleDefinition.ReadModule (fileName);
|
||||
return module.IsCrossgened ();
|
||||
} catch (BadImageFormatException) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user