28 readonly Dictionary<string, string> done =
new Dictionary<string, string>();
29 readonly Dictionary<string, RuntimeJavaType> todo =
new Dictionary<string, RuntimeJavaType>();
39 this.options = options ??
throw new ArgumentNullException(nameof(options));
40 this.diagnostics = diagnostics ??
throw new ArgumentNullException(nameof(diagnostics));
48 var references =
new List<string>();
49 if (options.References !=
null)
50 foreach (var reference
in options.References)
51 references.Add(reference);
53 var libpaths =
new List<string>();
54 if (options.Libraries !=
null)
55 foreach (var library
in options.Libraries)
56 libpaths.Add(library);
58 var namespaces =
new List<string>();
59 if (options.Namespaces !=
null)
60 foreach (var ns
in options.Namespaces)
63 if (File.Exists(options.Assembly) && options.NoStdLib)
67 references.Add(options.Assembly);
71 var coreLibName = FindCoreLibName(references, libpaths);
72 if (coreLibName ==
null)
74 diagnostics.CoreClassesMissing();
79 var universe =
new Universe(coreLibName);
81 assemblyResolver.Warning +=
new AssemblyResolver.WarningEvent(Resolver_Warning);
82 assemblyResolver.Init(universe, options.NoStdLib, references, libpaths);
84 var cache =
new Dictionary<string, Assembly>();
85 foreach (var reference
in references)
87 Assembly[] dummy =
null;
88 if (assemblyResolver.ResolveReference(cache,
ref dummy, reference) ==
false)
90 diagnostics.ReferenceNotFound(reference);
95 Assembly assembly =
null;
98 file =
new FileInfo(options.Assembly);
100 catch (FileNotFoundException)
102 diagnostics.InputFileNotFound(options.Assembly);
107 diagnostics.ErrorReadingFile(options.Assembly, x.ToString());
111 if (file !=
null && file.Exists)
113 assembly = assemblyResolver.LoadFile(options.Assembly);
117 assembly = assemblyResolver.LoadWithPartialName(options.Assembly);
124 if (assembly ==
null)
127 diagnostics.ReferenceNotFound(options.Assembly);
131 Assembly runtimeAssembly =
null;
132 Assembly baseAssembly =
null;
134 if (options.Bootstrap)
136 var runtimeAssemblyPath = references.FirstOrDefault(i => Path.GetFileNameWithoutExtension(i) ==
"IKVM.Runtime");
137 if (runtimeAssemblyPath !=
null)
138 runtimeAssembly = assemblyResolver.LoadFile(runtimeAssemblyPath);
140 if (runtimeAssembly ==
null || runtimeAssembly.__IsMissing)
142 diagnostics.RuntimeNotFound();
146 compiler =
new StaticCompiler(universe, assemblyResolver, runtimeAssembly);
153 var runtimeAssemblyPath = references.FirstOrDefault(i => Path.GetFileNameWithoutExtension(i) ==
"IKVM.Runtime");
154 if (runtimeAssemblyPath !=
null)
155 runtimeAssembly = assemblyResolver.LoadFile(runtimeAssemblyPath);
157 var baseAssemblyPath = references.FirstOrDefault(i => Path.GetFileNameWithoutExtension(i) ==
"IKVM.Java");
158 if (baseAssemblyPath !=
null)
159 baseAssembly = assemblyResolver.LoadFile(baseAssemblyPath);
161 if (runtimeAssembly ==
null || runtimeAssembly.__IsMissing)
163 diagnostics.RuntimeNotFound();
167 if (baseAssembly ==
null || runtimeAssembly.__IsMissing)
169 diagnostics.CoreClassesMissing();
173 compiler =
new StaticCompiler(universe, assemblyResolver, runtimeAssembly);
179 diagnostics.ExportingImportsNotSupported();
183 if (options.Output ==
null)
184 options.Output = assembly.GetName().Name +
".jar";
188 using (zipFile =
new ZipArchive(
new FileStream(options.Output, FileMode.Create), ZipArchiveMode.Create))
192 var assemblies =
new List<Assembly>();
193 assemblies.Add(assembly);
196 LoadSharedClassLoaderAssemblies(compiler, assembly, assemblies);
198 foreach (var
asm in assemblies)
200 if (ProcessTypes(context,
asm.GetTypes()) != 0)
203 if (options.ContinueOnError ==
false)
207 if (options.Forwarders && ProcessTypes(context,
asm.ManifestModule.__GetExportedTypes()) != 0)
210 if (options.ContinueOnError ==
false)
217 if (options.ContinueOnError ==
false)
218 diagnostics.UnknownWarning($
"Assembly reflection encountered an error. Resultant JAR may be incomplete. ({x.Message})");
224 catch (InvalidDataException e)
227 diagnostics.InvalidZip(options.Output);
240 static string FindCoreLibName(List<string> references, List<string> libpaths)
242 foreach (var reference
in references)
243 if (GetAssemblyNameIfCoreLib(reference) is
string coreLibName)
254 static string GetAssemblyNameIfCoreLib(
string path)
256 if (File.Exists(path) ==
false)
261 using var st = File.OpenRead(path);
262 using var pe =
new PEReader(st);
263 var mr = pe.GetMetadataReader();
265 foreach (var handle
in mr.TypeDefinitions)
266 if (IsSystemObject(mr, handle))
267 return mr.GetString(mr.GetAssemblyDefinition().Name);
271 catch (
System.BadImageFormatException)
275 catch (InvalidOperationException)
291 static bool IsSystemObject(MetadataReader reader, TypeDefinitionHandle th)
293 var td = reader.GetTypeDefinition(th);
294 var ns = reader.GetString(td.Namespace);
295 var nm = reader.GetString(td.Name);
297 return ns ==
"System" && nm ==
"Object";
300 static void Resolver_Warning(
AssemblyResolver.WarningId warning,
string message,
string[] parameters)
303 Console.Error.WriteLine(
"Warning: " + message, parameters);
306 static void LoadSharedClassLoaderAssemblies(
StaticCompiler compiler, Assembly assembly, List<Assembly> assemblies)
308 if (assembly.GetManifestResourceInfo(
"ikvm.exports") !=
null)
310 using (var stream = assembly.GetManifestResourceStream(
"ikvm.exports"))
312 var rdr =
new BinaryReader(stream);
313 var assemblyCount = rdr.ReadInt32();
314 for (
int i = 0; i < assemblyCount; i++)
316 var name = rdr.ReadString();
317 var typeCount = rdr.ReadInt32();
320 for (
int j = 0; j < typeCount; j++)
326 assemblies.Add(compiler.Load(name));
330 Console.WriteLine(
"Warning: Unable to load shared class loader assembly: {0}", name);
338 void WriteClass(RuntimeJavaType javaType)
340 var entry = zipFile.CreateEntry(javaType.Name.Replace(
'.',
'/') +
".class");
341 entry.LastWriteTime =
new DateTime(1980, 01, 01, 0, 0, 0, DateTimeKind.Utc);
342 using Stream stream = entry.Open();
344 javaType.Context.
StubGenerator.Write(stream, javaType, options.IncludeNonPublicTypes, options.IncludeNonPublicInterfaces, options.IncludeNonPublicMembers, options.IncludeParameterNames, options.SerialVersionUID);
347 bool ExportNamespace(IList<string> namespaces, Type type)
349 if (namespaces.Count == 0)
352 var name = type.FullName;
353 foreach (
string ns
in namespaces)
354 if (name.StartsWith(ns, StringComparison.Ordinal))
363 foreach (var t
in types)
365 if ((t.IsPublic || options.IncludeNonPublicTypes) && ExportNamespace(options.Namespaces, t) && !t.IsGenericTypeDefinition && !context.
AttributeHelper.IsHideFromJava(t) && (!t.IsGenericType || !context.
AttributeHelper.IsJavaModule(t.Module)))
382 foreach (var c
in new List<RuntimeJavaType>(todo.Values).OrderBy(i => i.Name))
384 if (!done.ContainsKey(c.Name))
387 done.Add(c.Name,
null);
391 rc = ProcessClass(c);
399 if (options.ContinueOnError)
402 Console.WriteLine(x);
417 void AddToExportList(RuntimeJavaType c)
422 bool IsNonVectorArray(RuntimeJavaType tw)
424 return !tw.IsArray && tw.TypeAsBaseType.IsArray;
427 int AddToExportListIfNeeded(RuntimeJavaType javaType)
429 while (javaType.IsArray)
430 javaType = javaType.ElementTypeWrapper;
434 javaType.Diagnostics.
MissingType(unloadableJavaType.MissingType.Name, unloadableJavaType.MissingType.Assembly.FullName);
442 else if ((javaType.TypeAsTBD !=
null && javaType.TypeAsTBD.IsGenericType) || IsNonVectorArray(javaType) || !javaType.IsPublic)
444 AddToExportList(javaType);
450 int AddToExportListIfNeeded(RuntimeJavaType[] types)
452 foreach (var tw
in types)
454 var rc = AddToExportListIfNeeded(tw);
462 int ProcessClass(RuntimeJavaType tw)
466 var superclass = tw.BaseTypeWrapper;
467 if (superclass !=
null)
469 rc = AddToExportListIfNeeded(superclass);
474 rc = AddToExportListIfNeeded(tw.Interfaces);
478 var outerClass = tw.DeclaringTypeWrapper;
479 if (outerClass !=
null)
480 AddToExportList(outerClass);
482 foreach (var innerClass
in tw.InnerClasses)
483 if (innerClass.IsPublic)
484 AddToExportList(innerClass);
486 foreach (var mw
in tw.GetMethods())
488 if (mw.IsPublic || mw.IsProtected)
492 rc = AddToExportListIfNeeded(mw.ReturnType);
496 rc = AddToExportListIfNeeded(mw.GetParameters());
502 foreach (var fw
in tw.GetFields())
504 if (fw.IsPublic || fw.IsProtected)
507 rc = AddToExportListIfNeeded(fw.FieldTypeWrapper);
Maintains services relevant to an instane of the IKVM runtime.
AttributeHelper AttributeHelper
Gets the AttributeHelper associated with this instance of the runtime.
StubGenerator StubGenerator
Gets the StubGenerator associated with this instance of the runtime.
Types Types
Gets the Types associated with this instance of the runtime.
RuntimeManagedJavaTypeFactory ManagedJavaTypeFactory
Gets the RuntimeManagedJavaTypeFactory associated with this instance of the runtime.
RuntimeClassLoaderFactory ClassLoaderFactory
Gets the RuntimeClassLoaderFactory associated with this instance of the runtime.