1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using Microsoft.Build.Framework; 5 using Microsoft.Build.Utilities; 6 7 namespace ILLink.Tasks 8 { 9 public class ILLink : Task 10 { 11 /// <summary> 12 /// Paths to the assembly files that should be considered as 13 /// input to the linker. Currently the linker will 14 /// additionally be able to resolve any assemblies in the 15 /// same directory as an assembly in AssemblyPaths, but this 16 /// behavior should not be relied upon. Instead, work under 17 /// the assumption that only the AssemblyPaths given will be 18 /// resolved. 19 /// </summary> 20 [Required] 21 public ITaskItem [] AssemblyPaths { get; set; } 22 23 /// <summary> 24 /// The names of the assemblies to root. This should contain 25 /// assembly names without an extension, not file names or 26 /// paths. Exactly which parts of the assemblies get rooted 27 /// is subject to change. Currently these get passed to 28 /// illink with "-a", which roots the entry point for 29 /// executables, and everything for libraries. To control 30 /// the linker more explicitly, either pass descriptor 31 /// files, or pass extra arguments for illink. 32 /// </summary> 33 [Required] 34 public ITaskItem [] RootAssemblyNames { get; set; } 35 36 /// <summary> 37 /// The directory in which to place linked assemblies. 38 /// </summary> 39 [Required] 40 public ITaskItem OutputDirectory { get; set; } 41 42 /// <summary> 43 /// A list of XML root descriptor files specifying linker 44 /// roots at a granular level. See the mono/linker 45 /// documentation for details about the format. 46 /// </summary> 47 public ITaskItem [] RootDescriptorFiles { get; set; } 48 49 /// <summary> 50 /// Extra arguments to pass to illink, delimited by spaces. 51 /// </summary> 52 public string ExtraArgs { get; set; } 53 54 /// <summary> 55 /// Make illink dump dependencies file for linker analyzer tool. 56 /// </summary> 57 public bool DumpDependencies { get; set; } 58 Execute()59 public override bool Execute () 60 { 61 string [] args = GenerateCommandLineCommands (); 62 var argsString = String.Join (" ", args); 63 Log.LogMessageFromText ($"illink {argsString}", MessageImportance.Normal); 64 int ret = Mono.Linker.Driver.Main (args); 65 return ret == 0; 66 } 67 GenerateCommandLineCommands()68 string [] GenerateCommandLineCommands () 69 { 70 var args = new List<string> (); 71 72 if (RootDescriptorFiles != null) { 73 foreach (var rootFile in RootDescriptorFiles) { 74 args.Add ("-x"); 75 args.Add (rootFile.ItemSpec); 76 } 77 } 78 79 foreach (var assemblyItem in RootAssemblyNames) { 80 args.Add ("-a"); 81 args.Add (assemblyItem.ItemSpec); 82 } 83 84 HashSet<string> directories = new HashSet<string> (); 85 foreach (var assembly in AssemblyPaths) { 86 var assemblyPath = assembly.ItemSpec; 87 var dir = Path.GetDirectoryName (assemblyPath); 88 if (!directories.Contains (dir)) { 89 directories.Add (dir); 90 args.Add ("-d"); 91 args.Add (dir); 92 } 93 94 string action = assembly.GetMetadata ("action"); 95 if ((action != null) && (action.Length > 0)) { 96 args.Add ("-p"); 97 args.Add (action); 98 args.Add (Path.GetFileNameWithoutExtension (assemblyPath)); 99 } 100 } 101 102 if (OutputDirectory != null) { 103 args.Add ("-out"); 104 args.Add (OutputDirectory.ItemSpec); 105 } 106 107 if (ExtraArgs != null) { 108 args.AddRange (ExtraArgs.Split (' ')); 109 } 110 111 if (DumpDependencies) 112 args.Add ("--dump-dependencies"); 113 114 return args.ToArray (); 115 } 116 117 } 118 } 119