EmitRemappedTypes() private method

private EmitRemappedTypes ( ) : void
return void
Ejemplo n.º 1
0
        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
                {
                    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);
                FileStream fs;
                try
                {
                    fs = File.Open(options.remapfile, FileMode.Open);
                }
                catch(Exception x)
                {
                    Console.Error.WriteLine("Error opening remap file \"{0}\": {1}", options.remapfile, x.Message);
                    return 1;
                }
                try
                {
                    XmlTextReader rdr = new XmlTextReader(fs);
                    IKVM.Internal.MapXml.Root.xmlReader = rdr;
                    IKVM.Internal.MapXml.Root.filename = new FileInfo(fs.Name).Name;
                    IKVM.Internal.MapXml.Root map;
                    try
                    {
                        map = (IKVM.Internal.MapXml.Root)ser.Deserialize(rdr);
                    }
                    catch(InvalidOperationException x)
                    {
                        Console.Error.WriteLine("Error parsing remap file \"{0}\": {1}", options.remapfile, x.Message);
                        return 1;
                    }
                    if(!loader.ValidateAndSetMap(map))
                    {
                        return 1;
                    }
                }
                finally
                {
                    fs.Close();
                }
                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;
        }