|
1 | 1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | 2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | 3 |
|
| 4 | +using System; |
4 | 5 | using System.Collections.Generic; |
5 | 6 | using System.Diagnostics.CodeAnalysis; |
| 7 | +using System.IO; |
6 | 8 | using System.Linq; |
| 9 | +using System.Reflection.PortableExecutable; |
7 | 10 | using System.Text; |
8 | 11 | using Microsoft.Build.Framework; |
9 | 12 | using Microsoft.Build.Utilities; |
10 | 13 |
|
11 | 14 | public class ManagedToNativeGenerator : Task |
12 | 15 | { |
13 | 16 | [Required] |
14 | | - public string[]? Assemblies { get; set; } |
| 17 | + public string[] Assemblies { get; set; } = Array.Empty<string>(); |
15 | 18 |
|
16 | 19 | public string? RuntimeIcallTableFile { get; set; } |
17 | 20 |
|
@@ -62,12 +65,14 @@ public override bool Execute() |
62 | 65 |
|
63 | 66 | private void ExecuteInternal() |
64 | 67 | { |
| 68 | + List<string> managedAssemblies = FilterOutUnmanagedBinaries(Assemblies); |
| 69 | + |
65 | 70 | var pinvoke = new PInvokeTableGenerator(FixupSymbolName, Log); |
66 | 71 | var icall = new IcallTableGenerator(FixupSymbolName, Log); |
67 | 72 |
|
68 | 73 | IEnumerable<string> cookies = Enumerable.Concat( |
69 | | - pinvoke.Generate(PInvokeModules, Assemblies!, PInvokeOutputPath!), |
70 | | - icall.Generate(RuntimeIcallTableFile, Assemblies!, IcallOutputPath) |
| 74 | + pinvoke.Generate(PInvokeModules, managedAssemblies, PInvokeOutputPath!), |
| 75 | + icall.Generate(RuntimeIcallTableFile, managedAssemblies, IcallOutputPath) |
71 | 76 | ); |
72 | 77 |
|
73 | 78 | var m2n = new InterpToNativeGenerator(Log); |
@@ -110,4 +115,43 @@ public string FixupSymbolName(string name) |
110 | 115 | _symbolNameFixups[name] = fixedName; |
111 | 116 | return fixedName; |
112 | 117 | } |
| 118 | + |
| 119 | + private List<string> FilterOutUnmanagedBinaries(string[] assemblies) |
| 120 | + { |
| 121 | + List<string> managedAssemblies = new(assemblies.Length); |
| 122 | + foreach (string asmPath in Assemblies) |
| 123 | + { |
| 124 | + if (!File.Exists(asmPath)) |
| 125 | + throw new LogAsErrorException($"Cannot find assembly {asmPath}"); |
| 126 | + |
| 127 | + try |
| 128 | + { |
| 129 | + if (!IsManagedAssembly(asmPath)) |
| 130 | + { |
| 131 | + Log.LogMessage(MessageImportance.Low, $"Skipping unmanaged {asmPath}."); |
| 132 | + continue; |
| 133 | + } |
| 134 | + } |
| 135 | + catch (Exception ex) |
| 136 | + { |
| 137 | + Log.LogMessage(MessageImportance.Low, $"Failed to read assembly {asmPath}: {ex}"); |
| 138 | + throw new LogAsErrorException($"Failed to read assembly {asmPath}: {ex.Message}"); |
| 139 | + } |
| 140 | + |
| 141 | + managedAssemblies.Add(asmPath); |
| 142 | + } |
| 143 | + |
| 144 | + return managedAssemblies; |
| 145 | + } |
| 146 | + |
| 147 | + private static bool IsManagedAssembly(string filePath) |
| 148 | + { |
| 149 | + if (!File.Exists(filePath)) |
| 150 | + return false; |
| 151 | + |
| 152 | + using FileStream fileStream = File.OpenRead(filePath); |
| 153 | + using PEReader reader = new(fileStream, PEStreamOptions.Default); |
| 154 | + return reader.HasMetadata; |
| 155 | + } |
| 156 | + |
113 | 157 | } |
0 commit comments