You've already forked linux-packaging-mono
Imported Upstream version 5.12.0.220
Former-commit-id: c477e03582759447177c6d4bf412cd2355aad476
This commit is contained in:
parent
8bd104cef2
commit
8fc30896db
229
external/linker/linker/Linker.Steps/MarkStep.cs
vendored
229
external/linker/linker/Linker.Steps/MarkStep.cs
vendored
@@ -46,6 +46,7 @@ namespace Mono.Linker.Steps {
|
||||
protected Dictionary<TypeDefinition, CustomAttribute> _assemblyDebuggerDisplayAttributes;
|
||||
protected Dictionary<TypeDefinition, CustomAttribute> _assemblyDebuggerTypeProxyAttributes;
|
||||
protected Queue<CustomAttribute> _topLevelAttributes;
|
||||
protected Queue<CustomAttribute> _lateMarkedAttributes;
|
||||
|
||||
public AnnotationStore Annotations {
|
||||
get { return _context.Annotations; }
|
||||
@@ -62,6 +63,7 @@ namespace Mono.Linker.Steps {
|
||||
_methods = new Queue<MethodDefinition> ();
|
||||
_virtual_methods = new List<MethodDefinition> ();
|
||||
_topLevelAttributes = new Queue<CustomAttribute> ();
|
||||
_lateMarkedAttributes = new Queue<CustomAttribute> ();
|
||||
|
||||
_assemblyDebuggerDisplayAttributes = new Dictionary<TypeDefinition, CustomAttribute> ();
|
||||
_assemblyDebuggerTypeProxyAttributes = new Dictionary<TypeDefinition, CustomAttribute> ();
|
||||
@@ -131,7 +133,7 @@ namespace Mono.Linker.Steps {
|
||||
if (QueueIsEmpty ())
|
||||
throw new InvalidOperationException ("No entry methods");
|
||||
|
||||
while (ProcessPrimaryQueue () || ProcessLazyAttributes ())
|
||||
while (ProcessPrimaryQueue () || ProcessLazyAttributes () || ProcessLateMarkedAttributes ())
|
||||
|
||||
// deal with [TypeForwardedTo] pseudo-attributes
|
||||
foreach (AssemblyDefinition assembly in _context.GetAssemblies ()) {
|
||||
@@ -148,13 +150,9 @@ namespace Mono.Linker.Steps {
|
||||
|
||||
if (!isForwarder)
|
||||
continue;
|
||||
TypeDefinition type = null;
|
||||
try {
|
||||
type = exported.Resolve ();
|
||||
}
|
||||
catch (AssemblyResolutionException) {
|
||||
TypeDefinition type = exported.Resolve ();
|
||||
if (type == null)
|
||||
continue;
|
||||
}
|
||||
if (!Annotations.IsMarked (type))
|
||||
continue;
|
||||
Tracer.Push (type);
|
||||
@@ -260,10 +258,15 @@ namespace Mono.Linker.Steps {
|
||||
Tracer.Push (provider);
|
||||
try {
|
||||
foreach (CustomAttribute ca in provider.CustomAttributes) {
|
||||
if (!ShouldMarkCustomAttribute (ca))
|
||||
continue;
|
||||
|
||||
MarkCustomAttribute (ca);
|
||||
if (_context.KeepUsedAttributeTypesOnly) {
|
||||
_lateMarkedAttributes.Enqueue (ca);
|
||||
} else {
|
||||
if (!ShouldMarkCustomAttribute (ca))
|
||||
continue;
|
||||
|
||||
MarkCustomAttribute (ca);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Tracer.Pop ();
|
||||
@@ -305,11 +308,16 @@ namespace Mono.Linker.Steps {
|
||||
|
||||
protected virtual bool ShouldMarkCustomAttribute (CustomAttribute ca)
|
||||
{
|
||||
if (_context.KeepUsedAttributeTypesOnly && !Annotations.IsMarked (ca.AttributeType.Resolve ()))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual bool ShouldMarkTopLevelCustomAttribute (CustomAttribute ca, MethodDefinition resolvedConstructor)
|
||||
{
|
||||
if (!ShouldMarkCustomAttribute (ca))
|
||||
return false;
|
||||
|
||||
// If an attribute's module has not been marked after processing all types in all assemblies and the attribute itself has not been marked,
|
||||
// then surely nothing is using this attribute and there is no need to mark it
|
||||
if (!Annotations.IsMarked (resolvedConstructor.Module) && !Annotations.IsMarked (ca.AttributeType))
|
||||
@@ -574,6 +582,40 @@ namespace Mono.Linker.Steps {
|
||||
return markOccurred;
|
||||
}
|
||||
|
||||
bool ProcessLateMarkedAttributes ()
|
||||
{
|
||||
var startingQueueCount = _lateMarkedAttributes.Count;
|
||||
if (startingQueueCount == 0)
|
||||
return false;
|
||||
|
||||
var skippedItems = new List<CustomAttribute> ();
|
||||
var markOccurred = false;
|
||||
|
||||
while (_lateMarkedAttributes.Count != 0) {
|
||||
var customAttribute = _lateMarkedAttributes.Dequeue ();
|
||||
|
||||
var resolved = customAttribute.Constructor.Resolve ();
|
||||
if (resolved == null) {
|
||||
HandleUnresolvedMethod (customAttribute.Constructor);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ShouldMarkCustomAttribute (customAttribute)) {
|
||||
skippedItems.Add (customAttribute);
|
||||
continue;
|
||||
}
|
||||
|
||||
markOccurred = true;
|
||||
MarkCustomAttribute (customAttribute);
|
||||
}
|
||||
|
||||
// requeue the items we skipped in case we need to make another pass
|
||||
foreach (var item in skippedItems)
|
||||
_lateMarkedAttributes.Enqueue (item);
|
||||
|
||||
return markOccurred;
|
||||
}
|
||||
|
||||
protected void MarkField (FieldReference reference)
|
||||
{
|
||||
// if (IgnoreScope (reference.DeclaringType.Scope))
|
||||
@@ -663,7 +705,7 @@ namespace Mono.Linker.Steps {
|
||||
MarkSecurityDeclarations (type);
|
||||
|
||||
if (IsMulticastDelegate (type)) {
|
||||
MarkMethodCollection (type.Methods);
|
||||
MarkMulticastDelegate (type);
|
||||
}
|
||||
|
||||
if (IsSerializable (type))
|
||||
@@ -1104,6 +1146,11 @@ namespace Mono.Linker.Steps {
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void MarkMulticastDelegate (TypeDefinition type)
|
||||
{
|
||||
MarkMethodCollection (type.Methods);
|
||||
}
|
||||
|
||||
protected TypeDefinition ResolveTypeDefinition (TypeReference type)
|
||||
{
|
||||
TypeDefinition td = type as TypeDefinition;
|
||||
@@ -1541,7 +1588,7 @@ namespace Mono.Linker.Steps {
|
||||
MarkCustomAttributes (prop);
|
||||
}
|
||||
|
||||
protected void MarkEvent (EventDefinition evt)
|
||||
protected virtual void MarkEvent (EventDefinition evt)
|
||||
{
|
||||
MarkCustomAttributes (evt);
|
||||
MarkMethodIfNotNull (evt.AddMethod);
|
||||
@@ -1568,6 +1615,17 @@ namespace Mono.Linker.Steps {
|
||||
|
||||
foreach (Instruction instruction in body.Instructions)
|
||||
MarkInstruction (instruction);
|
||||
|
||||
MarkThingsUsedViaReflection (body);
|
||||
}
|
||||
|
||||
protected virtual void MarkThingsUsedViaReflection (MethodBody body)
|
||||
{
|
||||
MarkSomethingUsedViaReflection ("GetConstructor", MarkConstructorsUsedViaReflection, body.Instructions);
|
||||
MarkSomethingUsedViaReflection ("GetMethod", MarkMethodsUsedViaReflection, body.Instructions);
|
||||
MarkSomethingUsedViaReflection ("GetProperty", MarkPropertyUsedViaReflection, body.Instructions);
|
||||
MarkSomethingUsedViaReflection ("GetField", MarkFieldUsedViaReflection, body.Instructions);
|
||||
MarkSomethingUsedViaReflection ("GetEvent", MarkEventUsedViaReflection, body.Instructions);
|
||||
}
|
||||
|
||||
protected virtual void MarkInstruction (Instruction instruction)
|
||||
@@ -1615,5 +1673,152 @@ namespace Mono.Linker.Steps {
|
||||
MarkCustomAttributes (iface);
|
||||
MarkType (iface.InterfaceType);
|
||||
}
|
||||
|
||||
|
||||
void MarkSomethingUsedViaReflection (string reflectionMethod, Action<Collection<Instruction>, string, TypeDefinition, BindingFlags> markMethod, Collection<Instruction> instructions)
|
||||
{
|
||||
for (var i = 0; i < instructions.Count; i++) {
|
||||
var instruction = instructions [i];
|
||||
if (instruction.OpCode != OpCodes.Call && instruction.OpCode != OpCodes.Callvirt)
|
||||
continue;
|
||||
|
||||
var methodBeingCalled = instruction.Operand as MethodReference;
|
||||
if (methodBeingCalled == null || methodBeingCalled.DeclaringType.Name != "Type" || methodBeingCalled.DeclaringType.Namespace != "System")
|
||||
continue;
|
||||
|
||||
if (methodBeingCalled.Name != reflectionMethod)
|
||||
continue;
|
||||
|
||||
_context.Tracer.Push ($"Reflection-{methodBeingCalled}");
|
||||
var nameOfThingUsedViaReflection = OperandOfNearestInstructionBefore<string> (i, OpCodes.Ldstr, instructions);
|
||||
var bindingFlags = (BindingFlags) OperandOfNearestInstructionBefore<sbyte> (i, OpCodes.Ldc_I4_S, instructions);
|
||||
|
||||
// There might be more than one ldtoken opcode above the call in the IL stream. Be conservative and check all of
|
||||
// the types which were loaded for the method being used.
|
||||
var declaringTypesOfThingInvokedViaReflection = OperandsOfInstructionsBefore (i, OpCodes.Ldtoken, instructions);
|
||||
foreach (var declaringTypeOfThingInvokedViaReflection in declaringTypesOfThingInvokedViaReflection) {
|
||||
var typeDefinition = declaringTypeOfThingInvokedViaReflection?.Resolve ();
|
||||
if (typeDefinition != null)
|
||||
markMethod (instructions, nameOfThingUsedViaReflection, typeDefinition, bindingFlags);
|
||||
}
|
||||
_context.Tracer.Pop ();
|
||||
}
|
||||
}
|
||||
|
||||
void MarkConstructorsUsedViaReflection (Collection<Instruction> instructions, string unused, TypeDefinition declaringType, BindingFlags bindingFlags)
|
||||
{
|
||||
foreach (var method in declaringType.Methods) {
|
||||
if ((bindingFlags == BindingFlags.Default || bindingFlags.IsSet(BindingFlags.Public) == method.IsPublic) && method.Name == ".ctor")
|
||||
MarkMethod (method);
|
||||
}
|
||||
}
|
||||
|
||||
void MarkMethodsUsedViaReflection (Collection<Instruction> instructions, string name, TypeDefinition declaringType, BindingFlags bindingFlags)
|
||||
{
|
||||
if (name == null)
|
||||
return;
|
||||
|
||||
foreach (var method in declaringType.Methods) {
|
||||
if ((bindingFlags == BindingFlags.Default || bindingFlags.IsSet(BindingFlags.Public) == method.IsPublic && bindingFlags.IsSet(BindingFlags.Static) == method.IsStatic)
|
||||
&& method.Name == name)
|
||||
MarkMethod (method);
|
||||
}
|
||||
}
|
||||
|
||||
void MarkPropertyUsedViaReflection (Collection<Instruction> instructions, string name, TypeDefinition declaringType, BindingFlags unused)
|
||||
{
|
||||
if (name == null)
|
||||
return;
|
||||
|
||||
foreach (var property in declaringType.Properties) {
|
||||
if (property.Name == name) {
|
||||
// It is not easy to reliably detect in the IL code whether the getter or setter (or both) are used.
|
||||
// Be conservative and mark everything for the property.
|
||||
MarkProperty (property);
|
||||
MarkMethodIfNotNull (property.GetMethod);
|
||||
MarkMethodIfNotNull (property.SetMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MarkFieldUsedViaReflection (Collection<Instruction> instructions, string name, TypeDefinition declaringType, BindingFlags unused)
|
||||
{
|
||||
if (name == null)
|
||||
return;
|
||||
|
||||
foreach (var field in declaringType.Fields) {
|
||||
if (field.Name == name)
|
||||
MarkField (field);
|
||||
}
|
||||
}
|
||||
|
||||
void MarkEventUsedViaReflection (Collection<Instruction> instructions, string name, TypeDefinition declaringType, BindingFlags unused)
|
||||
{
|
||||
if (name == null)
|
||||
return;
|
||||
|
||||
foreach (var eventInfo in declaringType.Events) {
|
||||
if (eventInfo.Name == name)
|
||||
MarkEvent (eventInfo);
|
||||
}
|
||||
}
|
||||
|
||||
static TOperand OperandOfNearestInstructionBefore<TOperand> (int startingInstructionIndex, OpCode opCode, IList<Instruction> instructions)
|
||||
{
|
||||
for (var i = startingInstructionIndex; i >= 0; i--) {
|
||||
if (instructions [i].OpCode == opCode)
|
||||
return (TOperand) instructions [i].Operand;
|
||||
}
|
||||
|
||||
return default (TOperand);
|
||||
}
|
||||
|
||||
static List<TypeReference> OperandsOfInstructionsBefore (int startingInstructionIndex, OpCode opCode, IList<Instruction> instructions)
|
||||
{
|
||||
var operands = new List<TypeReference> ();
|
||||
for (var i = startingInstructionIndex; i >= 0; i--) {
|
||||
if (instructions [i].OpCode == opCode) {
|
||||
var type = instructions [i].Operand as TypeReference;
|
||||
if (type != null)
|
||||
operands.Add (type);
|
||||
}
|
||||
}
|
||||
|
||||
return operands;
|
||||
}
|
||||
}
|
||||
|
||||
// Make our own copy of the BindingFlags enum, so that we don't depend on System.Reflection.
|
||||
[Flags]
|
||||
enum BindingFlags
|
||||
{
|
||||
Default = 0,
|
||||
IgnoreCase = 1,
|
||||
DeclaredOnly = 2,
|
||||
Instance = 4,
|
||||
Static = 8,
|
||||
Public = 16,
|
||||
NonPublic = 32,
|
||||
FlattenHierarchy = 64,
|
||||
InvokeMethod = 256,
|
||||
CreateInstance = 512,
|
||||
GetField = 1024,
|
||||
SetField = 2048,
|
||||
GetProperty = 4096,
|
||||
SetProperty = 8192,
|
||||
PutDispProperty = 16384,
|
||||
PutRefDispProperty = 32768,
|
||||
ExactBinding = 65536,
|
||||
SuppressChangeType = 131072,
|
||||
OptionalParamBinding = 262144,
|
||||
IgnoreReturn = 16777216
|
||||
}
|
||||
|
||||
static class BindingFlagsExtensions
|
||||
{
|
||||
public static bool IsSet(this BindingFlags flags, BindingFlags check)
|
||||
{
|
||||
return (flags & check) == check;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,12 @@ namespace Mono.Linker.Steps {
|
||||
(module.Attributes & (ModuleAttributes) 0x04) != 0;
|
||||
}
|
||||
|
||||
void WriteAssembly (AssemblyDefinition assembly, string directory)
|
||||
protected void WriteAssembly (AssemblyDefinition assembly, string directory)
|
||||
{
|
||||
WriteAssembly (assembly, directory, SaveSymbols (assembly));
|
||||
}
|
||||
|
||||
protected virtual void WriteAssembly (AssemblyDefinition assembly, string directory, WriterParameters writerParameters)
|
||||
{
|
||||
foreach (var module in assembly.Modules) {
|
||||
// Write back pure IL even for R2R assemblies
|
||||
@@ -104,7 +109,7 @@ namespace Mono.Linker.Steps {
|
||||
}
|
||||
}
|
||||
|
||||
assembly.Write (GetAssemblyFileName (assembly, directory), SaveSymbols (assembly));
|
||||
assembly.Write (GetAssemblyFileName (assembly, directory), writerParameters);
|
||||
}
|
||||
|
||||
void OutputAssembly (AssemblyDefinition assembly)
|
||||
@@ -126,17 +131,11 @@ namespace Mono.Linker.Steps {
|
||||
case AssemblyAction.Copy:
|
||||
Context.Tracer.AddDependency (assembly);
|
||||
CloseSymbols (assembly);
|
||||
CopyAssembly (GetOriginalAssemblyFileInfo (assembly), directory, Context.LinkSymbols);
|
||||
CopyAssembly (assembly, directory);
|
||||
break;
|
||||
case AssemblyAction.Delete:
|
||||
CloseSymbols (assembly);
|
||||
var target = GetAssemblyFileName (assembly, directory);
|
||||
if (File.Exists (target)) {
|
||||
File.Delete (target);
|
||||
File.Delete (target + ".mdb");
|
||||
File.Delete (Path.ChangeExtension (target, "pdb"));
|
||||
File.Delete (GetConfigFile (target));
|
||||
}
|
||||
DeleteAssembly (assembly, directory);
|
||||
break;
|
||||
default:
|
||||
CloseSymbols (assembly);
|
||||
@@ -144,6 +143,17 @@ namespace Mono.Linker.Steps {
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void DeleteAssembly(AssemblyDefinition assembly, string directory)
|
||||
{
|
||||
var target = GetAssemblyFileName (assembly, directory);
|
||||
if (File.Exists (target)) {
|
||||
File.Delete (target);
|
||||
File.Delete (target + ".mdb");
|
||||
File.Delete (Path.ChangeExtension (target, "pdb"));
|
||||
File.Delete (GetConfigFile (target));
|
||||
}
|
||||
}
|
||||
|
||||
void CloseSymbols (AssemblyDefinition assembly)
|
||||
{
|
||||
Annotations.CloseSymbolReader (assembly);
|
||||
@@ -158,6 +168,12 @@ namespace Mono.Linker.Steps {
|
||||
if (!assembly.MainModule.HasSymbols)
|
||||
return parameters;
|
||||
|
||||
#if NATIVE_READER_SUPPORT
|
||||
// NativePdb's can't be written on non-windows platforms
|
||||
if (Environment.OSVersion.Platform != PlatformID.Win32NT && assembly.MainModule.SymbolReader is Mono.Cecil.Pdb.NativePdbReader)
|
||||
return parameters;
|
||||
#endif
|
||||
|
||||
if (Context.SymbolWriterProvider != null)
|
||||
parameters.SymbolWriterProvider = Context.SymbolWriterProvider;
|
||||
else
|
||||
@@ -165,7 +181,7 @@ namespace Mono.Linker.Steps {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
static void CopyConfigFileIfNeeded (AssemblyDefinition assembly, string directory)
|
||||
void CopyConfigFileIfNeeded (AssemblyDefinition assembly, string directory)
|
||||
{
|
||||
string config = GetConfigFile (GetOriginalAssemblyFileInfo (assembly).FullName);
|
||||
if (!File.Exists (config))
|
||||
@@ -189,8 +205,17 @@ namespace Mono.Linker.Steps {
|
||||
return new FileInfo (assembly.MainModule.FileName);
|
||||
}
|
||||
|
||||
static void CopyAssembly (FileInfo fi, string directory, bool symbols)
|
||||
protected virtual void CopyAssembly (AssemblyDefinition assembly, string directory)
|
||||
{
|
||||
// Special case. When an assembly has embedded pdbs, link symbols is not enabled, and the assembly's action is copy,
|
||||
// we want to match the behavior of assemblies with the other symbol types and end up with an assembly that does not have symbols.
|
||||
// In order to do that, we can't simply copy files. We need to write the assembly without symbols
|
||||
if (assembly.MainModule.HasSymbols && !Context.LinkSymbols && assembly.MainModule.SymbolReader is EmbeddedPortablePdbReader) {
|
||||
WriteAssembly (assembly, directory, new WriterParameters ());
|
||||
return;
|
||||
}
|
||||
|
||||
FileInfo fi = GetOriginalAssemblyFileInfo (assembly);
|
||||
string target = Path.GetFullPath (Path.Combine (directory, fi.Name));
|
||||
string source = fi.FullName;
|
||||
if (source == target)
|
||||
@@ -198,7 +223,7 @@ namespace Mono.Linker.Steps {
|
||||
|
||||
File.Copy (source, target, true);
|
||||
|
||||
if (!symbols)
|
||||
if (!Context.LinkSymbols)
|
||||
return;
|
||||
|
||||
var mdb = source + ".mdb";
|
||||
@@ -210,7 +235,7 @@ namespace Mono.Linker.Steps {
|
||||
File.Copy (pdb, Path.ChangeExtension (target, "pdb"), true);
|
||||
}
|
||||
|
||||
static string GetAssemblyFileName (AssemblyDefinition assembly, string directory)
|
||||
protected virtual string GetAssemblyFileName (AssemblyDefinition assembly, string directory)
|
||||
{
|
||||
string file = GetOriginalAssemblyFileInfo (assembly).Name;
|
||||
return Path.Combine (directory, file);
|
||||
|
||||
68
external/linker/linker/Linker.Steps/RemoveSecurityStep.cs
vendored
Normal file
68
external/linker/linker/Linker.Steps/RemoveSecurityStep.cs
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Mono.Cecil;
|
||||
|
||||
namespace Mono.Linker.Steps {
|
||||
public class RemoveSecurityStep : BaseStep {
|
||||
protected override void ProcessAssembly (AssemblyDefinition assembly)
|
||||
{
|
||||
if (Annotations.GetAction (assembly) == AssemblyAction.Link) {
|
||||
ClearSecurityDeclarations (assembly);
|
||||
RemoveCustomAttributesThatAreForSecurity (assembly);
|
||||
|
||||
foreach (var type in assembly.MainModule.Types)
|
||||
ProcessType (type);
|
||||
}
|
||||
}
|
||||
|
||||
static void ProcessType (TypeDefinition type)
|
||||
{
|
||||
RemoveCustomAttributesThatAreForSecurity (type);
|
||||
ClearSecurityDeclarations (type);
|
||||
type.HasSecurity = false;
|
||||
|
||||
foreach (var field in type.Fields)
|
||||
RemoveCustomAttributesThatAreForSecurity (field);
|
||||
|
||||
foreach (var method in type.Methods) {
|
||||
ClearSecurityDeclarations (method);
|
||||
RemoveCustomAttributesThatAreForSecurity (method);
|
||||
method.HasSecurity = false;
|
||||
}
|
||||
|
||||
foreach (var nested in type.NestedTypes)
|
||||
ProcessType (nested);
|
||||
}
|
||||
|
||||
static void ClearSecurityDeclarations (ISecurityDeclarationProvider provider)
|
||||
{
|
||||
provider.SecurityDeclarations.Clear ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We have to remove some security attributes, otherwise pe verify will complain that a type has HasSecurity = false
|
||||
/// </summary>
|
||||
/// <param name="provider"></param>
|
||||
static void RemoveCustomAttributesThatAreForSecurity (ICustomAttributeProvider provider)
|
||||
{
|
||||
if (!provider.HasCustomAttributes)
|
||||
return;
|
||||
|
||||
var attrsToRemove = provider.CustomAttributes.Where (IsCustomAttributeForSecurity).ToArray ();
|
||||
foreach (var remove in attrsToRemove)
|
||||
provider.CustomAttributes.Remove (remove);
|
||||
}
|
||||
|
||||
static bool IsCustomAttributeForSecurity (CustomAttribute attr)
|
||||
{
|
||||
switch (attr.AttributeType.FullName) {
|
||||
case "System.Security.SecurityCriticalAttribute":
|
||||
case "System.Security.SecuritySafeCriticalAttribute":
|
||||
case "System.Security.SuppressUnmanagedCodeSecurityAttribute":
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,12 +117,7 @@ namespace Mono.Linker.Steps
|
||||
|
||||
if (!isForwarder)
|
||||
continue;
|
||||
TypeDefinition resolvedExportedType = null;
|
||||
try {
|
||||
resolvedExportedType = exported.Resolve ();
|
||||
} catch (AssemblyResolutionException) {
|
||||
continue;
|
||||
}
|
||||
TypeDefinition resolvedExportedType = exported.Resolve ();
|
||||
|
||||
if (resolvedExportedType == null) {
|
||||
//
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace Mono.Linker.Steps {
|
||||
}
|
||||
}
|
||||
|
||||
protected void ProcessAssembly (AssemblyDefinition assembly, XPathNodeIterator iterator)
|
||||
protected virtual void ProcessAssembly (AssemblyDefinition assembly, XPathNodeIterator iterator)
|
||||
{
|
||||
Tracer.Push (assembly);
|
||||
if (GetTypePreserve (iterator.Current) == TypePreserve.All) {
|
||||
@@ -213,12 +213,7 @@ namespace Mono.Linker.Steps {
|
||||
{
|
||||
if (regex.Match (exportedType.FullName).Success) {
|
||||
MarkingHelpers.MarkExportedType (exportedType, module);
|
||||
TypeDefinition type = null;
|
||||
try {
|
||||
type = exportedType.Resolve ();
|
||||
}
|
||||
catch (AssemblyResolutionException) {
|
||||
}
|
||||
TypeDefinition type = exportedType.Resolve ();
|
||||
if (type != null) {
|
||||
ProcessType (type, nav);
|
||||
}
|
||||
@@ -241,7 +236,7 @@ namespace Mono.Linker.Steps {
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessType (TypeDefinition type, XPathNavigator nav)
|
||||
protected virtual void ProcessType (TypeDefinition type, XPathNavigator nav)
|
||||
{
|
||||
TypePreserve preserve = GetTypePreserve (nav);
|
||||
|
||||
@@ -323,15 +318,19 @@ namespace Mono.Linker.Steps {
|
||||
|
||||
void ProcessFields (TypeDefinition type, XPathNodeIterator iterator)
|
||||
{
|
||||
while (iterator.MoveNext ()) {
|
||||
string value = GetSignature (iterator.Current);
|
||||
if (!String.IsNullOrEmpty (value))
|
||||
ProcessFieldSignature (type, value);
|
||||
while (iterator.MoveNext ())
|
||||
ProcessField (type, iterator);
|
||||
}
|
||||
|
||||
value = GetAttribute (iterator.Current, "name");
|
||||
if (!String.IsNullOrEmpty (value))
|
||||
ProcessFieldName (type, value);
|
||||
}
|
||||
protected virtual void ProcessField (TypeDefinition type, XPathNodeIterator iterator)
|
||||
{
|
||||
string value = GetSignature (iterator.Current);
|
||||
if (!String.IsNullOrEmpty (value))
|
||||
ProcessFieldSignature (type, value);
|
||||
|
||||
value = GetAttribute (iterator.Current, "name");
|
||||
if (!String.IsNullOrEmpty (value))
|
||||
ProcessFieldName (type, value);
|
||||
}
|
||||
|
||||
void ProcessFieldSignature (TypeDefinition type, string signature)
|
||||
@@ -375,13 +374,13 @@ namespace Mono.Linker.Steps {
|
||||
return field.FieldType.FullName + " " + field.Name;
|
||||
}
|
||||
|
||||
protected virtual void ProcessMethods (TypeDefinition type, XPathNodeIterator iterator)
|
||||
void ProcessMethods (TypeDefinition type, XPathNodeIterator iterator)
|
||||
{
|
||||
while (iterator.MoveNext ())
|
||||
ProcessMethod (type, iterator);
|
||||
}
|
||||
|
||||
protected void ProcessMethod(TypeDefinition type, XPathNodeIterator iterator)
|
||||
protected virtual void ProcessMethod (TypeDefinition type, XPathNodeIterator iterator)
|
||||
{
|
||||
string value = GetSignature (iterator.Current);
|
||||
if (!String.IsNullOrEmpty (value))
|
||||
@@ -462,15 +461,19 @@ namespace Mono.Linker.Steps {
|
||||
|
||||
void ProcessEvents (TypeDefinition type, XPathNodeIterator iterator)
|
||||
{
|
||||
while (iterator.MoveNext ()) {
|
||||
string value = GetSignature (iterator.Current);
|
||||
if (!String.IsNullOrEmpty (value))
|
||||
ProcessEventSignature (type, value);
|
||||
while (iterator.MoveNext ())
|
||||
ProcessEvent (type, iterator);
|
||||
}
|
||||
|
||||
value = GetAttribute (iterator.Current, "name");
|
||||
if (!String.IsNullOrEmpty (value))
|
||||
ProcessEventName (type, value);
|
||||
}
|
||||
protected virtual void ProcessEvent (TypeDefinition type, XPathNodeIterator iterator)
|
||||
{
|
||||
string value = GetSignature (iterator.Current);
|
||||
if (!String.IsNullOrEmpty (value))
|
||||
ProcessEventSignature (type, value);
|
||||
|
||||
value = GetAttribute (iterator.Current, "name");
|
||||
if (!String.IsNullOrEmpty (value))
|
||||
ProcessEventName (type, value);
|
||||
}
|
||||
|
||||
void ProcessEventSignature (TypeDefinition type, string signature)
|
||||
@@ -520,15 +523,19 @@ namespace Mono.Linker.Steps {
|
||||
|
||||
void ProcessProperties (TypeDefinition type, XPathNodeIterator iterator)
|
||||
{
|
||||
while (iterator.MoveNext ()) {
|
||||
string value = GetSignature (iterator.Current);
|
||||
if (!String.IsNullOrEmpty (value))
|
||||
ProcessPropertySignature (type, value, GetAccessors (iterator.Current));
|
||||
while (iterator.MoveNext ())
|
||||
ProcessProperty (type, iterator);
|
||||
}
|
||||
|
||||
value = GetAttribute (iterator.Current, "name");
|
||||
if (!String.IsNullOrEmpty (value))
|
||||
ProcessPropertyName (type, value, _accessorsAll);
|
||||
}
|
||||
protected virtual void ProcessProperty (TypeDefinition type, XPathNodeIterator iterator)
|
||||
{
|
||||
string value = GetSignature (iterator.Current);
|
||||
if (!String.IsNullOrEmpty (value))
|
||||
ProcessPropertySignature (type, value, GetAccessors (iterator.Current));
|
||||
|
||||
value = GetAttribute (iterator.Current, "name");
|
||||
if (!String.IsNullOrEmpty (value))
|
||||
ProcessPropertyName (type, value, _accessorsAll);
|
||||
}
|
||||
|
||||
void ProcessPropertySignature (TypeDefinition type, string signature, string[] accessors)
|
||||
|
||||
90
external/linker/linker/Linker.Steps/SweepStep.cs
vendored
90
external/linker/linker/Linker.Steps/SweepStep.cs
vendored
@@ -124,6 +124,9 @@ namespace Mono.Linker.Steps {
|
||||
|
||||
SweepResources (assembly);
|
||||
SweepCustomAttributes (assembly);
|
||||
|
||||
foreach (var module in assembly.Modules)
|
||||
SweepCustomAttributes (module);
|
||||
}
|
||||
|
||||
bool IsMarkedAssembly (AssemblyDefinition assembly)
|
||||
@@ -169,13 +172,9 @@ namespace Mono.Linker.Steps {
|
||||
var references = assembly.MainModule.AssemblyReferences;
|
||||
for (int i = 0; i < references.Count; i++) {
|
||||
var reference = references [i];
|
||||
AssemblyDefinition r = null;
|
||||
try {
|
||||
r = Context.Resolver.Resolve (reference);
|
||||
}
|
||||
catch (AssemblyResolutionException) {
|
||||
AssemblyDefinition r = Context.Resolver.Resolve (reference);
|
||||
if (r == null)
|
||||
continue;
|
||||
}
|
||||
if (!AreSameReference (r.Name, target.Name))
|
||||
continue;
|
||||
|
||||
@@ -282,6 +281,9 @@ namespace Mono.Linker.Steps {
|
||||
|
||||
if (type.HasProperties)
|
||||
SweepCustomAttributeCollection (type.Properties);
|
||||
|
||||
if (type.HasEvents)
|
||||
SweepCustomAttributeCollection (type.Events);
|
||||
}
|
||||
|
||||
protected void SweepNestedTypes (TypeDefinition type)
|
||||
@@ -308,15 +310,70 @@ namespace Mono.Linker.Steps {
|
||||
}
|
||||
}
|
||||
|
||||
protected void SweepCustomAttributes (ICustomAttributeProvider provider)
|
||||
protected void SweepCustomAttributes (TypeDefinition type)
|
||||
{
|
||||
var removed = SweepCustomAttributes (type as ICustomAttributeProvider);
|
||||
|
||||
if (ShouldSetHasSecurityToFalse (type, type, type.HasSecurity, removed))
|
||||
type.HasSecurity = false;
|
||||
}
|
||||
|
||||
protected void SweepCustomAttributes (MethodDefinition method)
|
||||
{
|
||||
var removed = SweepCustomAttributes (method as ICustomAttributeProvider);
|
||||
|
||||
if (ShouldSetHasSecurityToFalse (method, method, method.HasSecurity, removed))
|
||||
method.HasSecurity = false;
|
||||
}
|
||||
|
||||
bool ShouldSetHasSecurityToFalse (ISecurityDeclarationProvider providerAsSecurity, ICustomAttributeProvider provider, bool existingHasSecurity, IList<CustomAttribute> removedAttributes)
|
||||
{
|
||||
if (existingHasSecurity && removedAttributes.Count > 0 && !providerAsSecurity.HasSecurityDeclarations) {
|
||||
// If the method or type had security before and all attributes were removed, or no remaining attributes are security attributes,
|
||||
// then we need to set HasSecurity to false
|
||||
if (provider.CustomAttributes.Count == 0 || provider.CustomAttributes.All (attr => !IsSecurityAttributeType (attr.AttributeType.Resolve ())))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsSecurityAttributeType (TypeDefinition definition)
|
||||
{
|
||||
if (definition == null)
|
||||
return false;
|
||||
|
||||
if (definition.Namespace == "System.Security") {
|
||||
switch (definition.FullName) {
|
||||
// This seems to be one attribute in the System.Security namespace that doesn't count
|
||||
// as an attribute that requires HasSecurity to be true
|
||||
case "System.Security.SecurityCriticalAttribute":
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (definition.BaseType == null)
|
||||
return false;
|
||||
|
||||
return IsSecurityAttributeType (definition.BaseType.Resolve ());
|
||||
}
|
||||
|
||||
protected IList<CustomAttribute> SweepCustomAttributes (ICustomAttributeProvider provider)
|
||||
{
|
||||
var removed = new List<CustomAttribute>();
|
||||
|
||||
for (int i = provider.CustomAttributes.Count - 1; i >= 0; i--) {
|
||||
var attribute = provider.CustomAttributes [i];
|
||||
if (!Annotations.IsMarked (attribute)) {
|
||||
CustomAttributeUsageRemoved (provider, attribute);
|
||||
removed.Add (provider.CustomAttributes [i]);
|
||||
provider.CustomAttributes.RemoveAt (i);
|
||||
}
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
protected void SweepCustomAttributeCollection<T> (Collection<T> providers) where T : ICustomAttributeProvider
|
||||
@@ -330,6 +387,14 @@ namespace Mono.Linker.Steps {
|
||||
SweepCollection (methods);
|
||||
if (sweepSymbols)
|
||||
SweepDebugInfo (methods);
|
||||
|
||||
foreach (var method in methods) {
|
||||
if (!method.HasParameters)
|
||||
continue;
|
||||
|
||||
foreach (var parameter in method.Parameters)
|
||||
SweepCustomAttributes (parameter);
|
||||
}
|
||||
}
|
||||
|
||||
void SweepDebugInfo (Collection<MethodDefinition> methods)
|
||||
@@ -377,6 +442,17 @@ namespace Mono.Linker.Steps {
|
||||
}
|
||||
}
|
||||
|
||||
protected void SweepCollection (IList<MethodDefinition> list)
|
||||
{
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
if (ShouldRemove (list [i])) {
|
||||
ElementRemoved (list [i]);
|
||||
list.RemoveAt (i--);
|
||||
} else {
|
||||
SweepCustomAttributes (list [i]);
|
||||
}
|
||||
}
|
||||
|
||||
protected void SweepCollection<T> (IList<T> list) where T : ICustomAttributeProvider
|
||||
{
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
|
||||
@@ -40,6 +40,9 @@ namespace Mono.Linker {
|
||||
#endif
|
||||
|
||||
readonly Dictionary<string, AssemblyDefinition> _assemblies;
|
||||
HashSet<string> _unresolvedAssemblies;
|
||||
bool _ignoreUnresolved;
|
||||
LinkContext _context;
|
||||
|
||||
public IDictionary<string, AssemblyDefinition> AssemblyCache {
|
||||
get { return _assemblies; }
|
||||
@@ -55,12 +58,32 @@ namespace Mono.Linker {
|
||||
_assemblies = assembly_cache;
|
||||
}
|
||||
|
||||
public bool IgnoreUnresolved {
|
||||
get { return _ignoreUnresolved; }
|
||||
set { _ignoreUnresolved = value; }
|
||||
}
|
||||
|
||||
public LinkContext Context {
|
||||
get { return _context; }
|
||||
set { _context = value; }
|
||||
}
|
||||
|
||||
public override AssemblyDefinition Resolve (AssemblyNameReference name, ReaderParameters parameters)
|
||||
{
|
||||
AssemblyDefinition asm;
|
||||
if (!_assemblies.TryGetValue (name.Name, out asm)) {
|
||||
asm = base.Resolve (name, parameters);
|
||||
_assemblies [asm.Name.Name] = asm;
|
||||
AssemblyDefinition asm = null;
|
||||
if (!_assemblies.TryGetValue (name.Name, out asm) && (_unresolvedAssemblies == null || !_unresolvedAssemblies.Contains (name.Name))) {
|
||||
try {
|
||||
asm = base.Resolve (name, parameters);
|
||||
_assemblies [name.Name] = asm;
|
||||
} catch (AssemblyResolutionException) {
|
||||
if (!_ignoreUnresolved)
|
||||
throw;
|
||||
|
||||
_context.LogMessage ($"warning: unresolved assembly {name.Name}");
|
||||
if (_unresolvedAssemblies == null)
|
||||
_unresolvedAssemblies = new HashSet<string> ();
|
||||
_unresolvedAssemblies.Add (name.Name);
|
||||
}
|
||||
}
|
||||
|
||||
return asm;
|
||||
@@ -80,6 +103,8 @@ namespace Mono.Linker {
|
||||
}
|
||||
|
||||
_assemblies.Clear ();
|
||||
if (_unresolvedAssemblies != null)
|
||||
_unresolvedAssemblies.Clear ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
40
external/linker/linker/Linker/Driver.cs
vendored
40
external/linker/linker/Linker/Driver.cs
vendored
@@ -44,6 +44,11 @@ namespace Mono.Linker {
|
||||
#endif
|
||||
|
||||
public static int Main (string [] args)
|
||||
{
|
||||
return Execute (args);
|
||||
}
|
||||
|
||||
public static int Execute (string[] args, ILogger customLogger = null)
|
||||
{
|
||||
if (args.Length == 0)
|
||||
Usage ("No parameters specified");
|
||||
@@ -51,7 +56,7 @@ namespace Mono.Linker {
|
||||
try {
|
||||
|
||||
Driver driver = new Driver (args);
|
||||
driver.Run ();
|
||||
driver.Run (customLogger);
|
||||
|
||||
} catch (Exception e) {
|
||||
Console.WriteLine ("Fatal error in {0}", _linker);
|
||||
@@ -75,10 +80,13 @@ namespace Mono.Linker {
|
||||
return _queue.Count > 0;
|
||||
}
|
||||
|
||||
void Run ()
|
||||
public void Run (ILogger customLogger = null)
|
||||
{
|
||||
Pipeline p = GetStandardPipeline ();
|
||||
using (LinkContext context = GetDefaultContext (p)) {
|
||||
if (customLogger != null)
|
||||
context.Logger = customLogger;
|
||||
|
||||
I18nAssemblies assemblies = I18nAssemblies.All;
|
||||
var custom_steps = new List<string> ();
|
||||
bool dumpDependencies = false;
|
||||
@@ -98,12 +106,18 @@ namespace Mono.Linker {
|
||||
Usage ("Option is too short");
|
||||
|
||||
if (token == "--skip-unresolved") {
|
||||
context.IgnoreUnresolved = bool.Parse (GetParam ());
|
||||
bool ignoreUnresolved = bool.Parse (GetParam ());
|
||||
context.IgnoreUnresolved = ignoreUnresolved;
|
||||
context.Resolver.IgnoreUnresolved = ignoreUnresolved;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token == "--dependencies-file")
|
||||
{
|
||||
if (token == "--verbose") {
|
||||
context.LogMessages = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token == "--dependencies-file") {
|
||||
context.Tracer.DependenciesFileName = GetParam ();
|
||||
continue;
|
||||
}
|
||||
@@ -118,6 +132,17 @@ namespace Mono.Linker {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token == "--used-attrs-only") {
|
||||
context.KeepUsedAttributeTypesOnly = bool.Parse (GetParam ());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token == "--strip-security") {
|
||||
if (bool.Parse (GetParam ()))
|
||||
p.AddStepBefore (typeof (MarkStep), new RemoveSecurityStep ());
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (token [2]) {
|
||||
case 'v':
|
||||
Version ();
|
||||
@@ -330,10 +355,13 @@ namespace Mono.Linker {
|
||||
|
||||
Console.WriteLine (" --about About the {0}", _linker);
|
||||
Console.WriteLine (" --version Print the version number of the {0}", _linker);
|
||||
Console.WriteLine (" --skip-unresolved Ignore unresolved types and methods (true or false)");
|
||||
Console.WriteLine (" --skip-unresolved Ignore unresolved types, methods, and assemblies (true or false)");
|
||||
Console.WriteLine (" --verbose Log messages indicating progress and warnings");
|
||||
Console.WriteLine (" --dependencies-file Specify the dependencies file path, if unset the default path is used: <output directory>/linker-dependencies.xml.gz");
|
||||
Console.WriteLine (" --dump-dependencies Dump dependencies for the linker analyzer tool");
|
||||
Console.WriteLine (" --reduced-tracing Reduces dependency output related to assemblies that will not be modified");
|
||||
Console.WriteLine (" --used-attrs-only Attributes on types, methods, etc will be removed if the attribute type is not used");
|
||||
Console.WriteLine (" --strip-security In linked assemblies, attributes on assemblies, types, and methods related to security will be removed");
|
||||
Console.WriteLine (" -out Specify the output directory, default to `output'");
|
||||
Console.WriteLine (" -c Action on the core assemblies, skip, copy, copyused, addbypassngen, addbypassngenused or link, default to skip");
|
||||
Console.WriteLine (" -u Action on the user assemblies, skip, copy, copyused, addbypassngen, addbypassngenused or link, default to link");
|
||||
|
||||
45
external/linker/linker/Linker/LinkContext.cs
vendored
45
external/linker/linker/Linker/LinkContext.cs
vendored
@@ -109,6 +109,8 @@ namespace Mono.Linker {
|
||||
|
||||
public bool EnableReducedTracing { get; set; }
|
||||
|
||||
public bool KeepUsedAttributeTypesOnly { get; set; }
|
||||
|
||||
public System.Collections.IDictionary Actions {
|
||||
get { return _actions; }
|
||||
}
|
||||
@@ -131,7 +133,7 @@ namespace Mono.Linker {
|
||||
set { _symbolWriterProvider = value; }
|
||||
}
|
||||
|
||||
public bool LogInternalExceptions { get; set; } = false;
|
||||
public bool LogMessages { get; set; } = false;
|
||||
|
||||
public ILogger Logger { get; set; } = new ConsoleLogger ();
|
||||
|
||||
@@ -156,9 +158,12 @@ namespace Mono.Linker {
|
||||
{
|
||||
_pipeline = pipeline;
|
||||
_resolver = resolver;
|
||||
_resolver.Context = this;
|
||||
_actions = new Dictionary<string, AssemblyAction> ();
|
||||
_parameters = new Dictionary<string, string> ();
|
||||
_readerParameters = readerParameters;
|
||||
|
||||
SymbolReaderProvider = new DefaultSymbolReaderProvider (false);
|
||||
|
||||
if (factory == null)
|
||||
throw new ArgumentNullException (nameof (factory));
|
||||
@@ -204,7 +209,7 @@ namespace Mono.Linker {
|
||||
try {
|
||||
AssemblyDefinition assembly = _resolver.Resolve (reference, _readerParameters);
|
||||
|
||||
if (SeenFirstTime (assembly)) {
|
||||
if (assembly != null && SeenFirstTime (assembly)) {
|
||||
SafeReadSymbols (assembly);
|
||||
SetAction (assembly);
|
||||
}
|
||||
@@ -223,34 +228,32 @@ namespace Mono.Linker {
|
||||
|
||||
public virtual void SafeReadSymbols (AssemblyDefinition assembly)
|
||||
{
|
||||
if (!_linkSymbols)
|
||||
return;
|
||||
|
||||
if (assembly.MainModule.HasSymbols)
|
||||
return;
|
||||
|
||||
try {
|
||||
if (_symbolReaderProvider != null) {
|
||||
var symbolReader = _symbolReaderProvider.GetSymbolReader (
|
||||
assembly.MainModule,
|
||||
assembly.MainModule.FileName);
|
||||
if (_symbolReaderProvider == null)
|
||||
throw new ArgumentNullException (nameof (_symbolReaderProvider));
|
||||
|
||||
_annotations.AddSymbolReader (assembly, symbolReader);
|
||||
assembly.MainModule.ReadSymbols (symbolReader);
|
||||
} else
|
||||
assembly.MainModule.ReadSymbols ();
|
||||
} catch {}
|
||||
try {
|
||||
var symbolReader = _symbolReaderProvider.GetSymbolReader (
|
||||
assembly.MainModule,
|
||||
assembly.MainModule.FileName);
|
||||
|
||||
if (symbolReader == null)
|
||||
return;
|
||||
|
||||
_annotations.AddSymbolReader (assembly, symbolReader);
|
||||
assembly.MainModule.ReadSymbols (symbolReader);
|
||||
} catch { }
|
||||
}
|
||||
|
||||
public virtual ICollection<AssemblyDefinition> ResolveReferences (AssemblyDefinition assembly)
|
||||
{
|
||||
List<AssemblyDefinition> references = new List<AssemblyDefinition> ();
|
||||
foreach (AssemblyNameReference reference in assembly.MainModule.AssemblyReferences) {
|
||||
try {
|
||||
references.Add (Resolve (reference));
|
||||
}
|
||||
catch (AssemblyResolutionException) {
|
||||
}
|
||||
AssemblyDefinition definition = Resolve (reference);
|
||||
if (definition != null)
|
||||
references.Add (definition);
|
||||
}
|
||||
return references;
|
||||
}
|
||||
@@ -341,7 +344,7 @@ namespace Mono.Linker {
|
||||
|
||||
public void LogMessage (MessageImportance importance, string message, params object [] values)
|
||||
{
|
||||
if (LogInternalExceptions && Logger != null)
|
||||
if (LogMessages && Logger != null)
|
||||
Logger.LogMessage (importance, message, values);
|
||||
}
|
||||
}
|
||||
|
||||
11
external/linker/linker/Mono.Linker.csproj
vendored
11
external/linker/linker/Mono.Linker.csproj
vendored
@@ -33,7 +33,7 @@
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>False</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DefineConstants>DEBUG;TRACE;NATIVE_READER_SUPPORT</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
@@ -41,7 +41,7 @@
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>True</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<DefineConstants>TRACE;NATIVE_READER_SUPPORT</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
@@ -64,6 +64,7 @@
|
||||
<Compile Include="Linker.Steps\CleanStep.cs" />
|
||||
<Compile Include="Linker.Steps\RegenerateGuidStep.cs" />
|
||||
<Compile Include="Linker.Steps\LoadI18nAssemblies.cs" />
|
||||
<Compile Include="Linker.Steps\RemoveSecurityStep.cs" />
|
||||
<Compile Include="Linker\IXApiVisitor.cs" />
|
||||
<Compile Include="Linker\I18nAssemblies.cs" />
|
||||
<Compile Include="Linker.Steps\IStep.cs" />
|
||||
@@ -110,6 +111,12 @@
|
||||
<Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
|
||||
<Name>Mono.Cecil</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\cecil\symbols\mdb\Mono.Cecil.Mdb.csproj">
|
||||
<SetConfiguration Condition=" '$(Configuration)' == 'illink_Debug' ">Configuration=netstandard_Debug</SetConfiguration>
|
||||
<SetConfiguration Condition=" '$(Configuration)' == 'illink_Release' ">Configuration=netstandard_Release</SetConfiguration>
|
||||
<Project>{8559dd7f-a16f-46d0-a05a-9139faeba8fd}</Project>
|
||||
<Name>Mono.Cecil.Mdb</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\cecil\symbols\pdb\Mono.Cecil.Pdb.csproj">
|
||||
<SetConfiguration Condition=" '$(Configuration)' == 'illink_Debug' ">Configuration=netstandard_Debug</SetConfiguration>
|
||||
<SetConfiguration Condition=" '$(Configuration)' == 'illink_Release' ">Configuration=netstandard_Release</SetConfiguration>
|
||||
|
||||
@@ -1,164 +1,102 @@
|
||||
monolinker
|
||||
====
|
||||
|
||||
monolinker is the Mono CIL Linker.
|
||||
# IL Linker
|
||||
|
||||
The linker is a tool one can use to only ship the minimal possible set of
|
||||
functions that a set of programs might require to run as opposed to the full
|
||||
libraries.
|
||||
|
||||
* How does the linker work?
|
||||
## How does the linker work?
|
||||
|
||||
The linker analyses the intermediate code (CIL) produced by every compiler
|
||||
targeting the Mono platform like mcs, gmcs, vbnc, booc or others. It will walk
|
||||
targeting the .NET platform like mcs, csc, vbnc, booc or others. It will walk
|
||||
through all the code that it is given to it, and basically, perform a mark and
|
||||
sweep operations on all the code that it is referenced, to only keep what is
|
||||
necessary for the source program to run.
|
||||
|
||||
* Usage
|
||||
## Usage
|
||||
|
||||
1) Linking from a source assembly
|
||||
### Linking from a source assembly
|
||||
|
||||
The command:
|
||||
|
||||
monolinker -a Program.exe
|
||||
`illinker -a Program.exe`
|
||||
|
||||
will use the assembly Program.exe as a source. That means that the linker will
|
||||
walk through all the methods of Program.exe to generate only what is necessary
|
||||
for this assembly to run.
|
||||
|
||||
2) Linking from an xml descriptor
|
||||
### Linking from an [XML descriptor](#syntax-of-xml-descriptor)
|
||||
|
||||
The command:
|
||||
|
||||
monolinker -x desc.xml
|
||||
`illinker -x desc.xml`
|
||||
|
||||
will use the XML descriptor as a source. That means that the linker will
|
||||
use this file to decide what to link in a set of assemblies. The format of the
|
||||
descriptors is described further on in this document.
|
||||
|
||||
3) Linking from an api info file
|
||||
### Linking from an API info file
|
||||
|
||||
The command:
|
||||
|
||||
monolinker -i assembly.info
|
||||
`illinker -i assembly.info`
|
||||
|
||||
will use a file produced by mono-api-info as a source. The linker will use
|
||||
will use a file produced by `mono-api-info` as a source. The linker will use
|
||||
this file to link only what is necessary to match the public API defined in
|
||||
the info file.
|
||||
|
||||
4) Actions on the assemblies
|
||||
### Actions on the assemblies
|
||||
|
||||
You can specify what the linker should do exactly per assembly.
|
||||
|
||||
The linker can do 3 things:
|
||||
|
||||
- skip them, and do nothing with them,
|
||||
- copy them to the output directory,
|
||||
- link them, to reduce their size.
|
||||
- skip them, and do nothing with them,
|
||||
- copy them to the output directory,
|
||||
- link them, to reduce their size.
|
||||
|
||||
You can specify an action per assembly like this:
|
||||
|
||||
monolinker -p link Foo
|
||||
`illinker -p link Foo`
|
||||
|
||||
or
|
||||
|
||||
monolinker -p skip System.Windows.Forms
|
||||
`illinker -p skip System.Windows.Forms`
|
||||
|
||||
Or you can specify what to do for the core assemblies.
|
||||
|
||||
Core assemblies are the assemblies that belongs to the base class library,
|
||||
Core assemblies are the assemblies that belong to the base class library,
|
||||
like mscorlib.dll, System.dll or System.Windows.Forms.dll.
|
||||
|
||||
You can specify what action to do on the core assemblies with the option:
|
||||
|
||||
-c skip|copy|link
|
||||
`-c skip|copy|link`
|
||||
|
||||
5) The output directory
|
||||
### The output directory
|
||||
|
||||
By default, the linker will create an `output' directory in the current
|
||||
By default, the linker will create an `output` directory in the current
|
||||
directory where it will emit the linked files, to avoid erasing source
|
||||
assemblies. You can specify the output directory with the option:
|
||||
|
||||
-o output_directory
|
||||
`-o output_directory`
|
||||
|
||||
If you specify the directory `.', please ensure that you won't write over
|
||||
important assemblies of yours.
|
||||
|
||||
* Syntax of a xml descriptor
|
||||
### Specifying directories where the linker should look for assemblies
|
||||
|
||||
Here is an example that shows all the possibilities of this format:
|
||||
|
||||
---
|
||||
<linker>
|
||||
<assembly fullname="Library">
|
||||
<type fullname="Foo" />
|
||||
<type fullname="Bar" preserve="nothing" required="false" />
|
||||
<type fullname="Baz" preserve="fields" required="false" />
|
||||
<type fullname="Gazonk">
|
||||
<method signature="System.Void .ctor(System.String)" />
|
||||
<field signature="System.String _blah" />
|
||||
</type>
|
||||
</assembly>
|
||||
</linker>
|
||||
---
|
||||
|
||||
In this example, the linker will link the types Foo, Bar, Baz and Gazonk.
|
||||
|
||||
The fullname attribute specifies the fullname of the type in the format
|
||||
specified by ECMA-335. This is in Mono and certain cases not the same
|
||||
as the one reported by Type.FullName (nested classes e.g.).
|
||||
|
||||
The preserve attribute ensures that all the fields of the type Baz will be
|
||||
always be linked, not matter if they are used or not, but that neither the
|
||||
fields or the methods of Bar will be linked if they are not used. Not
|
||||
specifying a preserve attribute implies that we are preserving everything in
|
||||
the specified type.
|
||||
|
||||
The required attribute specifies that if the type is not marked, during the
|
||||
mark operation, it will not be linked.
|
||||
|
||||
The type Gazonk will be linked, as well as its constructor taking a string as a
|
||||
parameter, and it's _blah field.
|
||||
|
||||
You can have multiple assembly nodes.
|
||||
|
||||
6) The i18n Assemblies
|
||||
|
||||
Mono have a few assemblies which contains everything region specific:
|
||||
|
||||
I18N.CJK.dll
|
||||
I18N.MidEast.dll
|
||||
I18N.Other.dll
|
||||
I18N.Rare.dll
|
||||
I18N.West.dll
|
||||
|
||||
By default, they will all be copied to the output directory. But you can
|
||||
specify which one you want using the command:
|
||||
|
||||
monolinker -l choice
|
||||
|
||||
Where choice can either be: none, all, cjk, mideast, other, rare or west. You can
|
||||
combine the values with a comma.
|
||||
By default, the linker will first look for assemblies in the directories `.`
|
||||
and `bin`. You can specify
|
||||
|
||||
Example:
|
||||
|
||||
monolinker -a assembly -l mideast,cjk
|
||||
`illinker -d ../../libs -a program.exe`
|
||||
|
||||
7) Specifying directories where the linker should look for assemblies
|
||||
|
||||
By default, the linker will first look for assemblies in the directories `.'
|
||||
and `bin'. You can specify
|
||||
|
||||
Example:
|
||||
|
||||
monolinker -d ../../libs -a program.exe
|
||||
|
||||
8) Adding custom steps to the linker.
|
||||
### Adding custom steps to the linker.
|
||||
|
||||
You can write custom steps for the linker and tell the linker to use them.
|
||||
Let's take a simple example:
|
||||
|
||||
```csharp
|
||||
using System;
|
||||
|
||||
using Mono.Linker;
|
||||
@@ -176,58 +114,120 @@ namespace Foo {
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
That is compiled against the linker to a Foo.dll assembly.
|
||||
That is compiled against the linker to `Foo.dll` assembly.
|
||||
|
||||
You can ask the linker to add it at the end of the pipeline:
|
||||
|
||||
monolinker -s Foo.FooStep,Foo -a program.exe
|
||||
`illinker -s Foo.FooStep,Foo -a program.exe`
|
||||
|
||||
Or you can ask the linker to add it after a specific step:
|
||||
|
||||
monolinker -s MarkStep:Foo.FooStep,Foo -a program.exe
|
||||
`illinker -s MarkStep:Foo.FooStep,Foo -a program.exe`
|
||||
|
||||
Or before a specific step:
|
||||
|
||||
monolinker -s Foo.FooStep,Foo:MarkStep
|
||||
`illinker -s Foo.FooStep,Foo:MarkStep`
|
||||
|
||||
* Inside the linker
|
||||
## Mono specific options
|
||||
|
||||
### The i18n Assemblies
|
||||
|
||||
Mono has a few assemblies which contains everything region specific:
|
||||
|
||||
I18N.CJK.dll
|
||||
I18N.MidEast.dll
|
||||
I18N.Other.dll
|
||||
I18N.Rare.dll
|
||||
I18N.West.dll
|
||||
|
||||
By default, they will all be copied to the output directory. But you can
|
||||
specify which one you want using the command:
|
||||
|
||||
`illinker -l choice`
|
||||
|
||||
Where choice can either be: none, all, cjk, mideast, other, rare or west. You can
|
||||
combine the values with a comma.
|
||||
|
||||
Example:
|
||||
|
||||
`illinker -a assembly -l mideast,cjk`
|
||||
|
||||
## Syntax of xml descriptor
|
||||
|
||||
Here is an example that shows all the possibilities of this format:
|
||||
|
||||
```xml
|
||||
<linker>
|
||||
<assembly fullname="Library">
|
||||
<type fullname="Foo" />
|
||||
<type fullname="Bar" preserve="nothing" required="false" />
|
||||
<type fullname="Baz" preserve="fields" required="false" />
|
||||
<type fullname="Gazonk">
|
||||
<method signature="System.Void .ctor(System.String)" />
|
||||
<field signature="System.String _blah" />
|
||||
</type>
|
||||
</assembly>
|
||||
</linker>
|
||||
```
|
||||
|
||||
In this example, the linker will link the types Foo, Bar, Baz and Gazonk.
|
||||
|
||||
The fullname attribute specifies the fullname of the type in the format
|
||||
specified by ECMA-335. This is in certain cases not the same
|
||||
as the one reported by Type.FullName (nested classes e.g.).
|
||||
|
||||
The preserve attribute ensures that all the fields of the type Baz will be
|
||||
always be linked, not matter if they are used or not, but that neither the
|
||||
fields or the methods of Bar will be linked if they are not used. Not
|
||||
specifying a preserve attribute implies that we are preserving everything in
|
||||
the specified type.
|
||||
|
||||
The required attribute specifies that if the type is not marked, during the
|
||||
mark operation, it will not be linked.
|
||||
|
||||
The type Gazonk will be linked, as well as its constructor taking a string as a
|
||||
parameter, and it's _blah field.
|
||||
|
||||
You can have multiple assembly nodes.
|
||||
|
||||
# Inside the linker
|
||||
|
||||
The linker is a quite small piece of code, and it pretty simple to address.
|
||||
Its only dependency is Mono.Cecil, that is used to read, modify and write back
|
||||
Its only dependency is `Mono.Cecil`, that is used to read, modify and write back
|
||||
the assemblies.
|
||||
|
||||
Everything is located in the namespace Mono.Linker, or in sub namespaces.
|
||||
Everything is located in the namespace Linker, or in sub namespaces.
|
||||
Being a command line utility, its entry point function is in the class Driver.
|
||||
|
||||
This class is in charge of analyzing the command line, and to instantiate two
|
||||
important objects, a LinkContext, and a Pipeline.
|
||||
|
||||
The LinkContext contains all the informations that will be used during the
|
||||
The LinkContext contains all the information that will be used during the
|
||||
linking process, such as the assemblies involved, the output directory and
|
||||
probably other useful stuff.
|
||||
|
||||
The Pipeline is simply a queue of actions (steps), to be applied to the current
|
||||
context. The whole process of linking is split into those differents steps
|
||||
that are all located in the Mono.Linker.Steps namespace.
|
||||
context. The whole process of linking is split into those different steps
|
||||
that are all located in the Linker.Steps namespace.
|
||||
|
||||
Here are the current steps that are implemented, in the order they are used:
|
||||
|
||||
1) ResolveFromAssembly or ResolveFromXml
|
||||
## ResolveFromAssembly or ResolveFromXml
|
||||
|
||||
Those steps are used to initialize the context, and pre-mark the root code
|
||||
Those steps are used to initialize the context and pre-mark the root code
|
||||
that will be used as a source for the linker.
|
||||
|
||||
Resolving from an assembly or resolving from a xml descriptor is a decision
|
||||
Resolving from an assembly or resolving from an xml descriptor is a decision
|
||||
taken in the command line parsing.
|
||||
|
||||
2) LoadReferences
|
||||
## LoadReferences
|
||||
|
||||
This step will load all the references of all the assemblies involved in the
|
||||
current context.
|
||||
|
||||
3) Blacklist
|
||||
## Blacklist
|
||||
|
||||
This step is used if and only if you have specified that the core should be
|
||||
linked. It will load a bunch of resources from the assemblies, that are
|
||||
@@ -237,7 +237,7 @@ that are used from inside the runtime are properly linked and not removed.
|
||||
It is doing so by inserting a ResolveFromXml step per blacklist in the
|
||||
pipeline.
|
||||
|
||||
4) Mark
|
||||
## Mark
|
||||
|
||||
This is the most complex step. The linker will get from the context the list
|
||||
of types, fields and methods that have been pre-marked in the resolve steps,
|
||||
@@ -252,53 +252,47 @@ mscorlib assembly, and add it to the queue. When this WriteLine method will be
|
||||
dequeued, and processed, the linker will go through everything that is used in
|
||||
it, and add it to the queue, if they have not been processed already.
|
||||
|
||||
To know if something have been marked to be linked, or processed, the linker
|
||||
To know if something has been marked to be linked, or processed, the linker
|
||||
is using a functionality of Cecil called annotations. Almost everything in
|
||||
Cecil can be annotated. Concretely, it means that almost everything own an
|
||||
Cecil can be annotated. Concretely, it means that almost everything owns an
|
||||
Hashtable in which you can add what you want, using the keys and the values you
|
||||
want.
|
||||
|
||||
So the linker will annotate assemblies, types, methods and fields to know
|
||||
what should be linked or not, and what have been processed, and how it should
|
||||
what should be linked or not, and what has been processed, and how it should
|
||||
process them.
|
||||
|
||||
This is really useful as we don't have to recreate a full hierarchy of classes
|
||||
to encapsulate the different Cecil types to add the few informations we want.
|
||||
to encapsulate the different Cecil types to add the few pieces of information we want.
|
||||
|
||||
5) Sweep
|
||||
## Sweep
|
||||
|
||||
This simple step will walk through all the elements of an assembly, and based
|
||||
on their annotations, remove them or keep them.
|
||||
|
||||
6) Clean
|
||||
## Clean
|
||||
|
||||
This step will clean parts of the assemblies, like properties. If a proprety
|
||||
This step will clean parts of the assemblies, like properties. If a property
|
||||
used to have a getter and a setter, and that after the mark & sweep steps,
|
||||
only the getter is linked, it will update the property to reflect that.
|
||||
|
||||
There is a few things to keep clean like properties has we've seen, events,
|
||||
There are a few things to keep clean like properties we've seen, events,
|
||||
nested classes, and probably a few others.
|
||||
|
||||
7) Output
|
||||
## Output
|
||||
|
||||
For each assembly in the context, this step will act on the action associated
|
||||
to the assembly. If the assembly is marked as skip, it won't do anything,
|
||||
with the assembly. If the assembly is marked as skip, it won't do anything,
|
||||
if it's marked as copy, it will copy the assembly to the output directory,
|
||||
and if it's link, it will save the modified assembly to the output directory.
|
||||
|
||||
* Reporting a bug
|
||||
# Reporting a bug
|
||||
|
||||
If you face a bug in the linker, please report it to:
|
||||
If you face a bug in the linker, please report it using GitHub issues
|
||||
|
||||
http://bugzilla.ximian.com
|
||||
|
||||
Product: Mono tools, Component: linker.
|
||||
|
||||
* Mailing lists
|
||||
# Mailing lists
|
||||
|
||||
You can ask questions about the linker of the cecil Google Group:
|
||||
|
||||
http://groups.google.com/group/mono-cecil
|
||||
|
||||
--
|
||||
Jb Evain <jbevain@novell.com>
|
||||
@@ -1,122 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Mono.Cecil;
|
||||
|
||||
namespace Mono.Linker.Tests.Extensions {
|
||||
public static class CecilExtensions {
|
||||
public static IEnumerable<TypeDefinition> AllDefinedTypes (this AssemblyDefinition assemblyDefinition)
|
||||
{
|
||||
return assemblyDefinition.Modules.SelectMany (m => m.AllDefinedTypes ());
|
||||
}
|
||||
|
||||
public static IEnumerable<TypeDefinition> AllDefinedTypes (this ModuleDefinition moduleDefinition)
|
||||
{
|
||||
foreach (var typeDefinition in moduleDefinition.Types) {
|
||||
yield return typeDefinition;
|
||||
|
||||
foreach (var definition in typeDefinition.AllDefinedTypes ())
|
||||
yield return definition;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<TypeDefinition> AllDefinedTypes (this TypeDefinition typeDefinition)
|
||||
{
|
||||
foreach (var nestedType in typeDefinition.NestedTypes) {
|
||||
yield return nestedType;
|
||||
|
||||
foreach (var definition in nestedType.AllDefinedTypes ())
|
||||
yield return definition;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<IMemberDefinition> AllMembers (this ModuleDefinition module)
|
||||
{
|
||||
foreach (var type in module.AllDefinedTypes ()) {
|
||||
yield return type;
|
||||
|
||||
foreach (var member in type.AllMembers ())
|
||||
yield return member;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<IMemberDefinition> AllMembers (this TypeDefinition type)
|
||||
{
|
||||
foreach (var field in type.Fields)
|
||||
yield return field;
|
||||
|
||||
foreach (var prop in type.Properties)
|
||||
yield return prop;
|
||||
|
||||
foreach (var method in type.Methods)
|
||||
yield return method;
|
||||
|
||||
foreach (var @event in type.Events)
|
||||
yield return @event;
|
||||
}
|
||||
|
||||
public static bool HasAttribute (this ICustomAttributeProvider provider, string name)
|
||||
{
|
||||
return provider.CustomAttributes.Any (ca => ca.AttributeType.Name == name);
|
||||
}
|
||||
|
||||
public static bool HasAttributeDerivedFrom (this ICustomAttributeProvider provider, string name)
|
||||
{
|
||||
return provider.CustomAttributes.Any (ca => ca.AttributeType.Resolve ().DerivesFrom (name));
|
||||
}
|
||||
|
||||
public static bool DerivesFrom (this TypeDefinition type, string baseTypeName)
|
||||
{
|
||||
if (type.Name == baseTypeName)
|
||||
return true;
|
||||
|
||||
if (type.BaseType == null)
|
||||
return false;
|
||||
|
||||
if (type.BaseType.Name == baseTypeName)
|
||||
return true;
|
||||
|
||||
return type.BaseType.Resolve ().DerivesFrom (baseTypeName);
|
||||
}
|
||||
|
||||
public static PropertyDefinition GetPropertyDefinition (this MethodDefinition method)
|
||||
{
|
||||
if (!method.IsSetter && !method.IsGetter)
|
||||
throw new ArgumentException ();
|
||||
|
||||
var propertyName = method.Name.Substring (4);
|
||||
return method.DeclaringType.Properties.First (p => p.Name == propertyName);
|
||||
}
|
||||
|
||||
public static string GetSignature (this MethodDefinition method)
|
||||
{
|
||||
var builder = new StringBuilder ();
|
||||
builder.Append (method.Name);
|
||||
if (method.HasGenericParameters) {
|
||||
builder.Append ('<');
|
||||
|
||||
for (int i = 0; i < method.GenericParameters.Count - 1; i++)
|
||||
builder.Append ($"{method.GenericParameters [i]},");
|
||||
|
||||
builder.Append ($"{method.GenericParameters [method.GenericParameters.Count - 1]}>");
|
||||
}
|
||||
|
||||
builder.Append ("(");
|
||||
|
||||
if (method.HasParameters) {
|
||||
for (int i = 0; i < method.Parameters.Count - 1; i++) {
|
||||
// TODO: modifiers
|
||||
// TODO: default values
|
||||
builder.Append ($"{method.Parameters [i].ParameterType},");
|
||||
}
|
||||
|
||||
builder.Append (method.Parameters [method.Parameters.Count - 1].ParameterType);
|
||||
}
|
||||
|
||||
builder.Append (")");
|
||||
|
||||
return builder.ToString ();
|
||||
}
|
||||
}
|
||||
}
|
||||
922
external/linker/linker/Tests/Extensions/NiceIO.cs
vendored
922
external/linker/linker/Tests/Extensions/NiceIO.cs
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,11 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Mono.Linker.Tests.Cases.Expectations.Assertions {
|
||||
/// <summary>
|
||||
/// Base attribute for attributes that mark up the expected behavior of the linker on a member
|
||||
/// </summary>
|
||||
[Conditional("INCLUDE_EXPECTATIONS")]
|
||||
public abstract class BaseExpectedLinkedBehaviorAttribute : Attribute {
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
namespace Mono.Linker.Tests.Cases.Expectations.Assertions
|
||||
{
|
||||
public abstract class BaseInAssemblyAttribute : BaseExpectedLinkedBehaviorAttribute {
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Mono.Linker.Tests.Cases.Expectations.Assertions {
|
||||
[AttributeUsage (AttributeTargets.Class)]
|
||||
public class IgnoreTestCaseAttribute : Attribute {
|
||||
|
||||
public IgnoreTestCaseAttribute (string reason)
|
||||
{
|
||||
if (reason == null)
|
||||
throw new ArgumentNullException (nameof (reason));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Mono.Linker.Tests.Cases.Expectations.Assertions {
|
||||
/// <summary>
|
||||
/// Verifies that an assembly does exist in the output directory
|
||||
/// </summary>
|
||||
[AttributeUsage (AttributeTargets.Class | AttributeTargets.Delegate, AllowMultiple = true, Inherited = false)]
|
||||
public class KeptAssemblyAttribute : KeptAttribute {
|
||||
|
||||
public KeptAssemblyAttribute (string fileName)
|
||||
{
|
||||
if (string.IsNullOrEmpty (fileName))
|
||||
throw new ArgumentException ("Value cannot be null or empty.", nameof (fileName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Mono.Linker.Tests.Cases.Expectations.Assertions {
|
||||
[AttributeUsage (AttributeTargets.All, Inherited = false)]
|
||||
public class KeptAttribute : BaseExpectedLinkedBehaviorAttribute {
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Mono.Linker.Tests.Cases.Expectations.Assertions
|
||||
{
|
||||
[AttributeUsage (AttributeTargets.All, AllowMultiple = true, Inherited = false)]
|
||||
public class KeptAttributeAttribute : KeptAttribute
|
||||
{
|
||||
|
||||
public KeptAttributeAttribute (string attributeName)
|
||||
{
|
||||
if (string.IsNullOrEmpty (attributeName))
|
||||
throw new ArgumentException ("Value cannot be null or empty.", nameof (attributeName));
|
||||
}
|
||||
|
||||
public KeptAttributeAttribute (Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException (nameof (type));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Mono.Linker.Tests.Cases.Expectations.Assertions {
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Event, AllowMultiple = false, Inherited = false)]
|
||||
public sealed class KeptBackingFieldAttribute : KeptAttribute {
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user