internal CompilerClassLoader(AssemblyClassLoader[] referencedAssemblies, CompilerOptions options, string path, bool targetIsModule, string assemblyName, Dictionary<string, ClassItem> classes) : base(options.codegenoptions, null) { this.referencedAssemblies = referencedAssemblies; this.options = options; this.classes = classes; this.assemblyName = assemblyName; FileInfo assemblyPath = new FileInfo(path); this.assemblyFile = assemblyPath.Name; this.assemblyDir = assemblyPath.DirectoryName; this.targetIsModule = targetIsModule; Tracer.Info(Tracer.Compiler, "Instantiate CompilerClassLoader for {0}", assemblyName); }
internal static void IssueMessage(CompilerOptions options, Message msgId, params string[] values) { StringBuilder sb = new StringBuilder(); sb.Append((int)msgId); if(values.Length > 0) { sb.Append(':').Append(values[0]); } string key = sb.ToString(); if(options.suppressWarnings.ContainsKey(key) || options.suppressWarnings.ContainsKey(((int)msgId).ToString())) { return; } options.suppressWarnings.Add(key, key); if(options.writeSuppressWarningsFile != null) { File.AppendAllText(options.writeSuppressWarningsFile, "-nowarn:" + key + Environment.NewLine); } string msg; switch(msgId) { case Message.MainMethodFound: msg = "Found main method in class \"{0}\""; break; case Message.OutputFileIs: msg = "Output file is \"{0}\""; break; case Message.AutoAddRef: msg = "Automatically adding reference to \"{0}\""; break; case Message.MainMethodFromManifest: msg = "Using main class \"{0}\" based on jar manifest"; break; case Message.ClassNotFound: msg = "Class \"{0}\" not found"; break; case Message.ClassFormatError: msg = "Unable to compile class \"{0}\"" + Environment.NewLine + " (class format error \"{1}\")"; break; case Message.DuplicateClassName: msg = "Duplicate class name: \"{0}\""; break; case Message.IllegalAccessError: msg = "Unable to compile class \"{0}\"" + Environment.NewLine + " (illegal access error \"{1}\")"; break; case Message.VerificationError: msg = "Unable to compile class \"{0}\"" + Environment.NewLine + " (verification error \"{1}\")"; break; case Message.NoClassDefFoundError: msg = "Unable to compile class \"{0}\"" + Environment.NewLine + " (missing class \"{1}\")"; break; case Message.GenericUnableToCompileError: msg = "Unable to compile class \"{0}\"" + Environment.NewLine + " (\"{1}\": \"{2}\")"; break; case Message.DuplicateResourceName: msg = "Skipping resource (name clash): \"{0}\""; break; case Message.NotAClassFile: msg = "Not a class file \"{0}\", including it as resource" + Environment.NewLine + " (class format error \"{1}\")"; break; case Message.SkippingReferencedClass: msg = "Skipping class: \"{0}\"" + Environment.NewLine + " (class is already available in referenced assembly \"{1}\")"; break; case Message.NoJniRuntime: msg = "Unable to load runtime JNI assembly"; break; case Message.EmittedNoClassDefFoundError: msg = "Emitted java.lang.NoClassDefFoundError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedIllegalAccessError: msg = "Emitted java.lang.IllegalAccessError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedInstantiationError: msg = "Emitted java.lang.InstantiationError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedIncompatibleClassChangeError: msg = "Emitted java.lang.IncompatibleClassChangeError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedNoSuchFieldError: msg = "Emitted java.lang.NoSuchFieldError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedAbstractMethodError: msg = "Emitted java.lang.AbstractMethodError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedNoSuchMethodError: msg = "Emitted java.lang.NoSuchMethodError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedLinkageError: msg = "Emitted java.lang.LinkageError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedVerificationError: msg = "Emitted java.lang.VerificationError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedClassFormatError: msg = "Emitted java.lang.ClassFormatError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.InvalidCustomAttribute: msg = "Error emitting \"{0}\" custom attribute" + Environment.NewLine + " (\"{1}\")"; break; case Message.IgnoredCustomAttribute: msg = "Custom attribute \"{0}\" was ignored" + Environment.NewLine + " (\"{1}\")"; break; case Message.AssumeAssemblyVersionMatch: msg = "Assuming assembly reference \"{0}\" matches \"{1}\", you may need to supply runtime policy"; break; case Message.InvalidDirectoryInLibOptionPath: msg = "Directory \"{0}\" specified in -lib option is not valid"; break; case Message.InvalidDirectoryInLibEnvironmentPath: msg = "Directory \"{0}\" specified in LIB environment is not valid"; break; case Message.LegacySearchRule: msg = "Found assembly \"{0}\" using legacy search rule, please append '.dll' to the reference"; break; case Message.AssemblyLocationIgnored: msg = "Assembly \"{0}\" is ignored as previously loaded assembly \"{1}\" has the same identity \"{2}\""; break; case Message.InterfaceMethodCantBeInternal: msg = "Ignoring @ikvm.lang.Internal annotation on interface method" + Environment.NewLine + " (\"{0}.{1}{2}\")"; break; case Message.DllExportMustBeStaticMethod: msg = "Ignoring @ikvm.lang.DllExport annotation on non-static method" + Environment.NewLine + " (\"{0}.{1}{2}\")"; break; case Message.DllExportRequiresSupportedPlatform: msg = "Ignoring @ikvm.lang.DllExport annotation due to unsupported target platform"; break; case Message.NonPrimaryAssemblyReference: msg = "Referenced assembly \"{0}\" is not the primary assembly of a shared class loader group, referencing primary assembly \"{1}\" instead"; break; case Message.DuplicateAssemblyReference: msg = "Duplicate assembly reference \"{0}\""; break; case Message.UnableToCreateProxy: msg = "Unable to create proxy \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.DuplicateProxy: msg = "Duplicate proxy \"{0}\""; break; case Message.MapXmlUnableToResolveOpCode: msg = "Unable to resolve opcode in remap file: {0}"; break; case Message.MapXmlError: msg = "Error in remap file: {0}"; break; case Message.InputFileNotFound: msg = "Source file '{0}' not found"; break; case Message.UnknownFileType: msg = "Unknown file type: {0}"; break; case Message.UnknownElementInMapFile: msg = "Unknown element {0} in remap file, line {1}, column {2}"; break; case Message.UnknownAttributeInMapFile: msg = "Unknown attribute {0} in remap file, line {1}, column {2}"; break; case Message.InvalidMemberNameInMapFile: msg = "Invalid {0} name '{1}' in remap file in class {2}"; break; case Message.InvalidMemberSignatureInMapFile: msg = "Invalid {0} signature '{3}' in remap file for {0} {1}.{2}"; break; case Message.InvalidPropertyNameInMapFile: msg = "Invalid property {0} name '{3}' in remap file for property {1}.{2}"; break; case Message.InvalidPropertySignatureInMapFile: msg = "Invalid property {0} signature '{3}' in remap file for property {1}.{2}"; break; case Message.UnknownWarning: msg = "{0}"; break; default: throw new InvalidProgramException(); } bool error = msgId >= Message.StartErrors || (options.warnaserror && msgId >= Message.StartWarnings) || options.errorWarnings.ContainsKey(key) || options.errorWarnings.ContainsKey(((int)msgId).ToString()); Console.Error.Write("{0} IKVMC{1:D4}: ", error ? "error" : msgId < Message.StartWarnings ? "note" : "warning", (int)msgId); if (error && Message.StartWarnings <= msgId && msgId < Message.StartErrors) { Console.Error.Write("Warning as Error: "); } Console.Error.WriteLine(msg, values); if(options != toplevel && options.path != null) { Console.Error.WriteLine(" (in {0})", options.path); } if(error) { if (++errorCount == 100) { throw new FatalCompilerErrorException(Message.MaximumErrorCountReached); } } }
private static int CreateCompiler(CompilerOptions options, ref CompilerClassLoader loader, ref bool compilingCoreAssembly) { Tracer.Info(Tracer.Compiler, "JVM.Compile path: {0}, assembly: {1}", options.path, options.assembly); AssemblyName runtimeAssemblyName = StaticCompiler.runtimeAssembly.GetName(); bool allReferencesAreStrongNamed = IsSigned(StaticCompiler.runtimeAssembly); List<Assembly> references = new List<Assembly>(); foreach(Assembly reference in options.references ?? new Assembly[0]) { references.Add(reference); allReferencesAreStrongNamed &= IsSigned(reference); Tracer.Info(Tracer.Compiler, "Loaded reference assembly: {0}", reference.FullName); // if it's an IKVM compiled assembly, make sure that it was compiled // against same version of the runtime foreach(AssemblyName asmref in reference.GetReferencedAssemblies()) { if(asmref.Name == runtimeAssemblyName.Name) { if(IsSigned(StaticCompiler.runtimeAssembly)) { // TODO we really should support binding redirects here to allow different revisions to be mixed if(asmref.FullName != runtimeAssemblyName.FullName) { throw new FatalCompilerErrorException(Message.RuntimeMismatch, reference.Location, runtimeAssemblyName.FullName, asmref.FullName); } } else { if(asmref.GetPublicKeyToken() != null && asmref.GetPublicKeyToken().Length != 0) { throw new FatalCompilerErrorException(Message.RuntimeMismatch, reference.Location, runtimeAssemblyName.FullName, asmref.FullName); } } } } } List<object> assemblyAnnotations = new List<object>(); Dictionary<string, string> baseClasses = new Dictionary<string, string>(); Tracer.Info(Tracer.Compiler, "Parsing class files"); foreach(KeyValuePair<string, ClassItem> kv in options.classes) { ClassFile f; try { byte[] buf = kv.Value.data; f = new ClassFile(buf, 0, buf.Length, null, ClassFileParseOptions.None); if(!f.IsInterface && f.SuperClass != null) { baseClasses[f.SuperClass] = f.SuperClass; } // NOTE the "assembly" type in the unnamed package is a magic type // that acts as the placeholder for assembly attributes if(f.Name == "assembly" && f.Annotations != null) { assemblyAnnotations.AddRange(f.Annotations); } } catch(ClassFormatError) { continue; } if(options.mainClass == null && (options.guessFileKind || options.target != PEFileKinds.Dll)) { foreach(ClassFile.Method m in f.Methods) { if(m.IsPublic && m.IsStatic && m.Name == "main" && m.Signature == "([Ljava.lang.String;)V") { StaticCompiler.IssueMessage(Message.MainMethodFound, f.Name); options.mainClass = f.Name; break; } } } } Dictionary<string, ClassItem> h = new Dictionary<string, ClassItem>(); // HACK remove "assembly" type that exists only as a placeholder for assembly attributes options.classes.Remove("assembly"); foreach(KeyValuePair<string, ClassItem> kv in options.classes) { string name = kv.Key; bool excluded = false; for(int j = 0; j < options.classesToExclude.Length; j++) { if(Regex.IsMatch(name, options.classesToExclude[j])) { excluded = true; break; } } if(h.ContainsKey(name)) { StaticCompiler.IssueMessage(Message.DuplicateClassName, name); excluded = true; } if(!excluded) { h[name] = kv.Value; } } options.classes = null; if(options.guessFileKind && options.mainClass == null) { options.target = PEFileKinds.Dll; } if(options.target == PEFileKinds.Dll && options.mainClass != null) { throw new FatalCompilerErrorException(Message.MainClassRequiresExe); } if(options.target != PEFileKinds.Dll && options.mainClass == null) { throw new FatalCompilerErrorException(Message.ExeRequiresMainClass); } if(options.target == PEFileKinds.Dll && options.props.Count != 0) { throw new FatalCompilerErrorException(Message.PropertiesRequireExe); } if(options.path == null) { if(options.target == PEFileKinds.Dll) { if(options.targetIsModule) { options.path = options.assembly + ".netmodule"; } else { options.path = options.assembly + ".dll"; } } else { options.path = options.assembly + ".exe"; } StaticCompiler.IssueMessage(Message.OutputFileIs, options.path); } if(options.targetIsModule) { if(options.classLoader != null) { throw new FatalCompilerErrorException(Message.ModuleCannotHaveClassLoader); } // TODO if we're overwriting a user specified assembly name, we need to emit a warning options.assembly = new FileInfo(options.path).Name; } Tracer.Info(Tracer.Compiler, "Constructing compiler"); AssemblyClassLoader[] referencedAssemblies = new AssemblyClassLoader[references.Count]; for(int i = 0; i < references.Count; i++) { AssemblyClassLoader acl = AssemblyClassLoader.FromAssembly(references[i]); if (acl.MainAssembly != references[i]) { StaticCompiler.IssueMessage(options, Message.NonPrimaryAssemblyReference, references[i].GetName().Name, acl.MainAssembly.GetName().Name); } if (Array.IndexOf(referencedAssemblies, acl) != -1) { StaticCompiler.IssueMessage(options, Message.DuplicateAssemblyReference, acl.MainAssembly.FullName); } referencedAssemblies[i] = acl; } loader = new CompilerClassLoader(referencedAssemblies, options, options.path, options.targetIsModule, options.assembly, h); loader.baseClasses = baseClasses; loader.assemblyAnnotations = assemblyAnnotations; loader.classesToCompile = new List<string>(h.Keys); if(options.remapfile != null) { Tracer.Info(Tracer.Compiler, "Loading remapped types (1) from {0}", options.remapfile); System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(IKVM.Internal.MapXml.Root)); ser.UnknownElement += new System.Xml.Serialization.XmlElementEventHandler(ser_UnknownElement); ser.UnknownAttribute += new System.Xml.Serialization.XmlAttributeEventHandler(ser_UnknownAttribute); FileStream fs; try { fs = File.OpenRead(options.remapfile); } catch(Exception x) { throw new FatalCompilerErrorException(Message.ErrorReadingFile, options.remapfile, x.Message); } try { XmlTextReader rdr = new XmlTextReader(fs); IKVM.Internal.MapXml.Root.xmlReader = rdr; IKVM.Internal.MapXml.Root map; try { map = (IKVM.Internal.MapXml.Root)ser.Deserialize(rdr); } catch(InvalidOperationException x) { throw new FatalCompilerErrorException(Message.ErrorParsingMapFile, options.remapfile, x.Message); } if(!loader.ValidateAndSetMap(map)) { return 1; } } finally { fs.Close(); } if(loader.CheckCompilingCoreAssembly()) { compilingCoreAssembly = true; ClassLoaderWrapper.SetBootstrapClassLoader(loader); } } // If we do not yet have a reference to the core assembly and we are not compiling the core assembly, // try to find the core assembly by looking at the assemblies that the runtime references if(JVM.CoreAssembly == null && !compilingCoreAssembly) { foreach(AssemblyName name in StaticCompiler.runtimeAssembly.GetReferencedAssemblies()) { Assembly asm = null; try { asm = LoadReferencedAssembly(StaticCompiler.runtimeAssembly.Location + "/../" + name.Name + ".dll"); } catch(FileNotFoundException) { } if(asm != null && IsCoreAssembly(asm)) { JVM.CoreAssembly = asm; break; } } if(JVM.CoreAssembly == null) { throw new FatalCompilerErrorException(Message.BootstrapClassesMissing); } // we need to scan again for remapped types, now that we've loaded the core library ClassLoaderWrapper.LoadRemappedTypes(); } if(!compilingCoreAssembly) { allReferencesAreStrongNamed &= IsSigned(JVM.CoreAssembly); loader.AddReference(AssemblyClassLoader.FromAssembly(JVM.CoreAssembly)); } if((options.keyPair != null || options.publicKey != null) && !allReferencesAreStrongNamed) { throw new FatalCompilerErrorException(Message.StrongNameRequiresStrongNamedRefs); } if(loader.map != null) { loader.LoadMapXml(); } if(!compilingCoreAssembly) { FakeTypes.Load(JVM.CoreAssembly); } return 0; }
internal static void SuppressWarning(CompilerOptions options, Message message, string name) { options.suppressWarnings[(int)message + ":" + name] = null; }
private static int CreateCompiler(CompilerOptions options, ref CompilerClassLoader loader, ref bool compilingCoreAssembly) { Tracer.Info(Tracer.Compiler, "JVM.Compile path: {0}, assembly: {1}", options.path, options.assembly); AssemblyName runtimeAssemblyName = StaticCompiler.runtimeAssembly.GetName(); bool allReferencesAreStrongNamed = IsSigned(StaticCompiler.runtimeAssembly); List<Assembly> references = new List<Assembly>(); foreach(Assembly reference in options.references ?? new Assembly[0]) { references.Add(reference); allReferencesAreStrongNamed &= IsSigned(reference); Tracer.Info(Tracer.Compiler, "Loaded reference assembly: {0}", reference.FullName); // if it's an IKVM compiled assembly, make sure that it was compiled // against same version of the runtime foreach(AssemblyName asmref in reference.GetReferencedAssemblies()) { if(asmref.Name == runtimeAssemblyName.Name) { if(IsSigned(StaticCompiler.runtimeAssembly)) { // TODO we really should support binding redirects here to allow different revisions to be mixed if(asmref.FullName != runtimeAssemblyName.FullName) { throw new FatalCompilerErrorException(Message.RuntimeMismatch, reference.Location, runtimeAssemblyName.FullName, asmref.FullName); } } else { if(asmref.GetPublicKeyToken() != null && asmref.GetPublicKeyToken().Length != 0) { throw new FatalCompilerErrorException(Message.RuntimeMismatch, reference.Location, runtimeAssemblyName.FullName, asmref.FullName); } } } } } Tracer.Info(Tracer.Compiler, "Parsing class files"); // map the class names to jar entries Dictionary<string, Jar.Item> h = new Dictionary<string, Jar.Item>(); List<string> classNames = new List<string>(); foreach (Jar jar in options.jars) { if (options.IsResourcesJar(jar)) { continue; } foreach (Jar.Item item in jar) { string name = item.Name; if (name.EndsWith(".class", StringComparison.Ordinal) && name.Length > 6 && name.IndexOf('.') == name.Length - 6) { string className = name.Substring(0, name.Length - 6).Replace('/', '.'); if (h.ContainsKey(className)) { StaticCompiler.IssueMessage(Message.DuplicateClassName, className); Jar.Item itemRef = h[className]; if ((options.classesJar != -1 && itemRef.Jar == options.jars[options.classesJar]) || jar != itemRef.Jar) { // the previous class stays, because it was either in an earlier jar or we're processing the classes.jar // which contains the classes loaded from the file system (where the first encountered class wins) continue; } else { // we have a jar that contains multiple entries with the same name, the last one wins h.Remove(className); classNames.Remove(className); } } h.Add(className, item); classNames.Add(className); } } } if (options.assemblyAttributeAnnotations == null) { // look for "assembly" type that acts as a placeholder for assembly attributes Jar.Item assemblyType; if (h.TryGetValue("assembly", out assemblyType)) { try { byte[] buf = assemblyType.GetData(); ClassFile f = new ClassFile(buf, 0, buf.Length, null, ClassFileParseOptions.None, null); // NOTE the "assembly" type in the unnamed package is a magic type // that acts as the placeholder for assembly attributes if (f.Name == "assembly" && f.Annotations != null) { options.assemblyAttributeAnnotations = f.Annotations; // HACK remove "assembly" type that exists only as a placeholder for assembly attributes h.Remove(f.Name); assemblyType.Remove(); StaticCompiler.IssueMessage(Message.LegacyAssemblyAttributesFound); } } catch (ClassFormatError) { } } } // now look for a main method if (options.mainClass == null && (options.guessFileKind || options.target != PEFileKinds.Dll)) { foreach (string className in classNames) { try { byte[] buf = h[className].GetData(); ClassFile f = new ClassFile(buf, 0, buf.Length, null, ClassFileParseOptions.None, null); if (f.Name == className) { foreach (ClassFile.Method m in f.Methods) { if (m.IsPublic && m.IsStatic && m.Name == "main" && m.Signature == "([Ljava.lang.String;)V") { StaticCompiler.IssueMessage(Message.MainMethodFound, f.Name); options.mainClass = f.Name; goto break_outer; } } } } catch (ClassFormatError) { } } break_outer: ; } if(options.guessFileKind && options.mainClass == null) { options.target = PEFileKinds.Dll; } if(options.target == PEFileKinds.Dll && options.mainClass != null) { throw new FatalCompilerErrorException(Message.MainClassRequiresExe); } if(options.target != PEFileKinds.Dll && options.mainClass == null) { throw new FatalCompilerErrorException(Message.ExeRequiresMainClass); } if(options.target == PEFileKinds.Dll && options.props.Count != 0) { throw new FatalCompilerErrorException(Message.PropertiesRequireExe); } if(options.path == null) { if(options.target == PEFileKinds.Dll) { if(options.targetIsModule) { options.path = IkvmcCompiler.GetFileInfo(options.assembly + ".netmodule"); } else { options.path = IkvmcCompiler.GetFileInfo(options.assembly + ".dll"); } } else { options.path = IkvmcCompiler.GetFileInfo(options.assembly + ".exe"); } StaticCompiler.IssueMessage(Message.OutputFileIs, options.path.ToString()); } if(options.targetIsModule) { if(options.classLoader != null) { throw new FatalCompilerErrorException(Message.ModuleCannotHaveClassLoader); } // TODO if we're overwriting a user specified assembly name, we need to emit a warning options.assembly = options.path.Name; } Tracer.Info(Tracer.Compiler, "Constructing compiler"); AssemblyClassLoader[] referencedAssemblies = new AssemblyClassLoader[references.Count]; for(int i = 0; i < references.Count; i++) { AssemblyClassLoader acl = AssemblyClassLoader.FromAssembly(references[i]); if (Array.IndexOf(referencedAssemblies, acl) != -1) { StaticCompiler.IssueMessage(options, Message.DuplicateAssemblyReference, acl.MainAssembly.FullName); } referencedAssemblies[i] = acl; } loader = new CompilerClassLoader(referencedAssemblies, options, options.path, options.targetIsModule, options.assembly, h, compilingCoreAssembly); loader.classesToCompile = new List<string>(h.Keys); if(options.remapfile != null) { Tracer.Info(Tracer.Compiler, "Loading remapped types (1) from {0}", options.remapfile); System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(IKVM.Internal.MapXml.Root)); ser.UnknownElement += new System.Xml.Serialization.XmlElementEventHandler(ser_UnknownElement); ser.UnknownAttribute += new System.Xml.Serialization.XmlAttributeEventHandler(ser_UnknownAttribute); FileStream fs; try { fs = options.remapfile.OpenRead(); } catch(Exception x) { throw new FatalCompilerErrorException(Message.ErrorReadingFile, options.remapfile, x.Message); } try { XmlTextReader rdr = new XmlTextReader(fs); IKVM.Internal.MapXml.Root.xmlReader = rdr; IKVM.Internal.MapXml.Root map; try { map = (IKVM.Internal.MapXml.Root)ser.Deserialize(rdr); } catch(InvalidOperationException x) { throw new FatalCompilerErrorException(Message.ErrorParsingMapFile, options.remapfile, x.Message); } if(!loader.ValidateAndSetMap(map)) { return 1; } } finally { fs.Close(); } if(loader.CheckCompilingCoreAssembly()) { compilingCoreAssembly = true; ClassLoaderWrapper.SetBootstrapClassLoader(loader); } } // If we do not yet have a reference to the core assembly and we are not compiling the core assembly, // try to find the core assembly by looking at the assemblies that the runtime references if(JVM.CoreAssembly == null && !compilingCoreAssembly) { foreach(AssemblyName name in StaticCompiler.runtimeAssembly.GetReferencedAssemblies()) { Assembly asm = null; try { asm = LoadReferencedAssembly(StaticCompiler.runtimeAssembly.Location + "/../" + name.Name + ".dll"); } catch(FileNotFoundException) { } if(asm != null && IsCoreAssembly(asm)) { AssemblyClassLoader.PreloadExportedAssemblies(asm); JVM.CoreAssembly = asm; break; } } if(JVM.CoreAssembly == null) { throw new FatalCompilerErrorException(Message.BootstrapClassesMissing); } // we need to scan again for remapped types, now that we've loaded the core library ClassLoaderWrapper.LoadRemappedTypes(); } if(!compilingCoreAssembly) { allReferencesAreStrongNamed &= IsSigned(JVM.CoreAssembly); loader.AddReference(AssemblyClassLoader.FromAssembly(JVM.CoreAssembly)); } if((options.keyPair != null || options.publicKey != null) && !allReferencesAreStrongNamed) { throw new FatalCompilerErrorException(Message.StrongNameRequiresStrongNamedRefs); } if(loader.map != null) { loader.LoadMapXml(); } if(!compilingCoreAssembly) { FakeTypes.Load(JVM.CoreAssembly); } return 0; }
internal static void IssueMessage(CompilerOptions options, Message msgId, params string[] values) { StringBuilder sb = new StringBuilder(); sb.Append((int)msgId); if(values.Length > 0) { sb.Append(':').Append(values[0]); } string key = sb.ToString(); if(options.suppressWarnings.ContainsKey(key) || options.suppressWarnings.ContainsKey(((int)msgId).ToString())) { return; } options.suppressWarnings.Add(key, key); if(options.writeSuppressWarningsFile != null) { File.AppendAllText(options.writeSuppressWarningsFile, "-nowarn:" + key + Environment.NewLine); } string msg; switch(msgId) { case Message.MainMethodFound: msg = "found main method in class \"{0}\""; break; case Message.OutputFileIs: msg = "output file is \"{0}\""; break; case Message.AutoAddRef: msg = "automatically adding reference to \"{0}\""; break; case Message.MainMethodFromManifest: msg = "using main class \"{0}\" based on jar manifest"; break; case Message.ClassNotFound: msg = "class \"{0}\" not found"; break; case Message.ClassFormatError: msg = "unable to compile class \"{0}\"" + Environment.NewLine + " (class format error \"{1}\")"; break; case Message.DuplicateClassName: msg = "duplicate class name: \"{0}\""; break; case Message.IllegalAccessError: msg = "unable to compile class \"{0}\"" + Environment.NewLine + " (illegal access error \"{1}\")"; break; case Message.VerificationError: msg = "unable to compile class \"{0}\"" + Environment.NewLine + " (verification error \"{1}\")"; break; case Message.NoClassDefFoundError: msg = "unable to compile class \"{0}\"" + Environment.NewLine + " (missing class \"{1}\")"; break; case Message.GenericUnableToCompileError: msg = "unable to compile class \"{0}\"" + Environment.NewLine + " (\"{1}\": \"{2}\")"; break; case Message.DuplicateResourceName: msg = "skipping resource (name clash): \"{0}\""; break; case Message.NotAClassFile: msg = "not a class file \"{0}\", including it as resource" + Environment.NewLine + " (class format error \"{1}\")"; break; case Message.SkippingReferencedClass: msg = "skipping class: \"{0}\"" + Environment.NewLine + " (class is already available in referenced assembly \"{1}\")"; break; case Message.NoJniRuntime: msg = "unable to load runtime JNI assembly"; break; case Message.EmittedNoClassDefFoundError: msg = "emitted java.lang.NoClassDefFoundError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedIllegalAccessError: msg = "emitted java.lang.IllegalAccessError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedInstantiationError: msg = "emitted java.lang.InstantiationError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedIncompatibleClassChangeError: msg = "emitted java.lang.IncompatibleClassChangeError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedNoSuchFieldError: msg = "emitted java.lang.NoSuchFieldError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedAbstractMethodError: msg = "emitted java.lang.AbstractMethodError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedNoSuchMethodError: msg = "emitted java.lang.NoSuchMethodError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedLinkageError: msg = "emitted java.lang.LinkageError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedVerificationError: msg = "emitted java.lang.VerificationError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.EmittedClassFormatError: msg = "emitted java.lang.ClassFormatError in \"{0}\"" + Environment.NewLine + " (\"{1}\")"; break; case Message.InvalidCustomAttribute: msg = "error emitting \"{0}\" custom attribute" + Environment.NewLine + " (\"{1}\")"; break; case Message.IgnoredCustomAttribute: msg = "custom attribute \"{0}\" was ignored" + Environment.NewLine + " (\"{1}\")"; break; case Message.AssumeAssemblyVersionMatch: msg = "assuming assembly reference \"{0}\" matches \"{1}\", you may need to supply runtime policy"; break; case Message.InvalidDirectoryInLibOptionPath: msg = "directory \"{0}\" specified in -lib option is not valid"; break; case Message.InvalidDirectoryInLibEnvironmentPath: msg = "directory \"{0}\" specified in LIB environment is not valid"; break; case Message.LegacySearchRule: msg = "found assembly \"{0}\" using legacy search rule, please append '.dll' to the reference"; break; case Message.AssemblyLocationIgnored: msg = "assembly \"{0}\" is ignored as previously loaded assembly \"{1}\" has the same identity \"{2}\""; break; case Message.InterfaceMethodCantBeInternal: msg = "ignoring @ikvm.lang.Internal annotation on interface method" + Environment.NewLine + " (\"{0}.{1}{2}\")"; break; case Message.UnknownWarning: msg = "{0}"; break; default: throw new InvalidProgramException(); } if(options.errorWarnings.ContainsKey(key) || options.errorWarnings.ContainsKey(((int)msgId).ToString())) { Console.Error.Write("{0} IKVMC{1:D4}: ", "Error", (int)msgId); Console.Error.WriteLine(msg, values); Environment.Exit(1); } Console.Error.Write("{0} IKVMC{1:D4}: ", msgId < Message.StartWarnings ? "Note" : "Warning", (int)msgId); Console.Error.WriteLine(msg, values); if(options != toplevel && options.path != null) { Console.Error.WriteLine(" (in {0})", options.path); } }
private static int CreateCompiler(CompilerOptions options, ref CompilerClassLoader loader, ref bool compilingCoreAssembly) { Tracer.Info(Tracer.Compiler, "JVM.Compile path: {0}, assembly: {1}", options.path, options.assembly); AssemblyName runtimeAssemblyName = StaticCompiler.runtimeAssembly.GetName(); bool allReferencesAreStrongNamed = IsSigned(StaticCompiler.runtimeAssembly); List<Assembly> references = new List<Assembly>(); foreach(Assembly reference in options.references ?? new Assembly[0]) { try { if(IsCoreAssembly(reference)) { JVM.CoreAssembly = reference; } references.Add(reference); allReferencesAreStrongNamed &= IsSigned(reference); Tracer.Info(Tracer.Compiler, "Loaded reference assembly: {0}", reference.FullName); // if it's an IKVM compiled assembly, make sure that it was compiled // against same version of the runtime foreach(AssemblyName asmref in reference.GetReferencedAssemblies()) { if(asmref.Name == runtimeAssemblyName.Name) { if(IsSigned(StaticCompiler.runtimeAssembly)) { if(asmref.FullName != runtimeAssemblyName.FullName) { Console.Error.WriteLine("Error: referenced assembly {0} was compiled with an incompatible IKVM.Runtime version ({1})", reference.Location, asmref.Version); Console.Error.WriteLine(" Current runtime: {0}", runtimeAssemblyName.FullName); Console.Error.WriteLine(" Referenced assembly runtime: {0}", asmref.FullName); return 1; } } else { if(asmref.GetPublicKeyToken() != null && asmref.GetPublicKeyToken().Length != 0) { Console.Error.WriteLine("Error: referenced assembly {0} was compiled with an incompatible (signed) IKVM.Runtime version", reference.Location); Console.Error.WriteLine(" Current runtime: {0}", runtimeAssemblyName.FullName); Console.Error.WriteLine(" Referenced assembly runtime: {0}", asmref.FullName); return 1; } } } } } catch(Exception x) { Console.Error.WriteLine("Error: invalid reference: {0} ({1})", reference.Location, x.Message); return 1; } } List<object> assemblyAnnotations = new List<object>(); Dictionary<string, string> baseClasses = new Dictionary<string, string>(); Tracer.Info(Tracer.Compiler, "Parsing class files"); foreach(KeyValuePair<string, byte[]> kv in options.classes) { ClassFile f; try { byte[] buf = kv.Value; f = new ClassFile(buf, 0, buf.Length, null, ClassFileParseOptions.None); if(!f.IsInterface && f.SuperClass != null) { baseClasses[f.SuperClass] = f.SuperClass; } // NOTE the "assembly" type in the unnamed package is a magic type // that acts as the placeholder for assembly attributes if(f.Name == "assembly" && f.Annotations != null) { assemblyAnnotations.AddRange(f.Annotations); } } catch(ClassFormatError) { continue; } if(options.mainClass == null && (options.guessFileKind || options.target != PEFileKinds.Dll)) { foreach(ClassFile.Method m in f.Methods) { if(m.IsPublic && m.IsStatic && m.Name == "main" && m.Signature == "([Ljava.lang.String;)V") { StaticCompiler.IssueMessage(Message.MainMethodFound, f.Name); options.mainClass = f.Name; break; } } } } Dictionary<string, byte[]> h = new Dictionary<string, byte[]>(); // HACK remove "assembly" type that exists only as a placeholder for assembly attributes options.classes.Remove("assembly"); foreach(KeyValuePair<string, byte[]> kv in options.classes) { string name = kv.Key; bool excluded = false; for(int j = 0; j < options.classesToExclude.Length; j++) { if(Regex.IsMatch(name, options.classesToExclude[j])) { excluded = true; break; } } if(h.ContainsKey(name)) { StaticCompiler.IssueMessage(Message.DuplicateClassName, name); excluded = true; } if(!excluded) { h[name] = kv.Value; } } options.classes = null; if(options.guessFileKind && options.mainClass == null) { options.target = PEFileKinds.Dll; } if(options.target == PEFileKinds.Dll && options.mainClass != null) { Console.Error.WriteLine("Error: main class cannot be specified for library or module"); return 1; } if(options.target != PEFileKinds.Dll && options.mainClass == null) { Console.Error.WriteLine("Error: no main method found"); return 1; } if(options.target == PEFileKinds.Dll && options.props.Count != 0) { Console.Error.WriteLine("Error: properties cannot be specified for library or module"); return 1; } if(options.path == null) { if(options.target == PEFileKinds.Dll) { if(options.targetIsModule) { options.path = options.assembly + ".netmodule"; } else { options.path = options.assembly + ".dll"; } } else { options.path = options.assembly + ".exe"; } StaticCompiler.IssueMessage(Message.OutputFileIs, options.path); } if(options.targetIsModule) { if(options.classLoader != null) { Console.Error.WriteLine("Error: cannot specify assembly class loader for modules"); return 1; } // TODO if we're overwriting a user specified assembly name, we need to emit a warning options.assembly = new FileInfo(options.path).Name; } if(options.target == PEFileKinds.Dll && !options.path.ToLower().EndsWith(".dll") && !options.targetIsModule) { Console.Error.WriteLine("Error: library output file must end with .dll"); return 1; } if(options.target != PEFileKinds.Dll && !options.path.ToLower().EndsWith(".exe")) { Console.Error.WriteLine("Error: executable output file must end with .exe"); return 1; } Tracer.Info(Tracer.Compiler, "Constructing compiler"); AssemblyClassLoader[] referencedAssemblies = new AssemblyClassLoader[references.Count]; for(int i = 0; i < references.Count; i++) { referencedAssemblies[i] = AssemblyClassLoader.FromAssembly(references[i]); } loader = new CompilerClassLoader(referencedAssemblies, options, options.path, options.targetIsModule, options.assembly, h); loader.baseClasses = baseClasses; loader.assemblyAnnotations = assemblyAnnotations; loader.classesToCompile = new List<string>(h.Keys); if(options.remapfile != null) { Tracer.Info(Tracer.Compiler, "Loading remapped types (1) from {0}", options.remapfile); System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(IKVM.Internal.MapXml.Root)); ser.UnknownElement += new System.Xml.Serialization.XmlElementEventHandler(ser_UnknownElement); ser.UnknownAttribute += new System.Xml.Serialization.XmlAttributeEventHandler(ser_UnknownAttribute); using(FileStream fs = File.Open(options.remapfile, FileMode.Open)) { XmlTextReader rdr = new XmlTextReader(fs); IKVM.Internal.MapXml.Root.xmlReader = rdr; IKVM.Internal.MapXml.Root.filename = new FileInfo(fs.Name).Name; if (!loader.ValidateAndSetMap((IKVM.Internal.MapXml.Root)ser.Deserialize(rdr))) { return 1; } } if(loader.CheckCompilingCoreAssembly()) { compilingCoreAssembly = true; ClassLoaderWrapper.SetBootstrapClassLoader(loader); loader.EmitRemappedTypes(); } } // If we do not yet have a reference to the core assembly and we are not compiling the core assembly, // try to find the core assembly by looking at the assemblies that the runtime references if(JVM.CoreAssembly == null && !compilingCoreAssembly) { foreach(AssemblyName name in StaticCompiler.runtimeAssembly.GetReferencedAssemblies()) { Assembly asm = null; try { asm = LoadReferencedAssembly(StaticCompiler.runtimeAssembly.Location + "/../" + name.Name + ".dll"); } catch(FileNotFoundException) { } if(asm != null && IsCoreAssembly(asm)) { JVM.CoreAssembly = asm; break; } } if(JVM.CoreAssembly == null) { Console.Error.WriteLine("Error: bootstrap classes missing and core assembly not found"); return 1; } // we need to scan again for remapped types, now that we've loaded the core library ClassLoaderWrapper.LoadRemappedTypes(); } if(!compilingCoreAssembly) { allReferencesAreStrongNamed &= IsSigned(JVM.CoreAssembly); loader.AddReference(AssemblyClassLoader.FromAssembly(JVM.CoreAssembly)); } if((options.keyPair != null || options.publicKey != null) && !allReferencesAreStrongNamed) { Console.Error.WriteLine("Error: all referenced assemblies must be strong named, to be able to sign the output assembly"); return 1; } if(loader.map != null) { loader.LoadMapXml(); } if(!compilingCoreAssembly) { FakeTypes.Load(JVM.CoreAssembly); } return 0; }