X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fassembly.cs;h=cb12a9aad7f7945fd354ee8045b5b7926c0dad46;hb=f574f7b447e29c6f083fcad4e6dc5f89d3cb4b4d;hp=a9236a73ac009b851b6cec7f42e642bb4bfcae10;hpb=1a525eb46edfa7b047baecd19016973e8e15d59a;p=mono.git diff --git a/mcs/mcs/assembly.cs b/mcs/mcs/assembly.cs index a9236a73ac0..cb12a9aad7f 100644 --- a/mcs/mcs/assembly.cs +++ b/mcs/mcs/assembly.cs @@ -6,7 +6,8 @@ // Marek Safar (marek.safar@gmail.com) // // Copyright 2001, 2002, 2003 Ximian, Inc. -// Copyright 2004 Novell, Inc. +// Copyright 2004-2011 Novell, Inc. +// Copyright 2011 Xamarin Inc // @@ -14,13 +15,21 @@ using System; using System.IO; using System.Collections.Generic; using System.Globalization; -using System.Reflection; -using System.Reflection.Emit; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; - using Mono.Security.Cryptography; +using Mono.CompilerServices.SymbolWriter; + +#if STATIC +using IKVM.Reflection; +using IKVM.Reflection.Emit; +using SecurityType = System.Collections.Generic.List; +#else +using SecurityType = System.Collections.Generic.Dictionary; +using System.Reflection; +using System.Reflection.Emit; +#endif namespace Mono.CSharp { @@ -29,24 +38,27 @@ namespace Mono.CSharp string FullName { get; } bool HasExtensionMethod { get; } bool IsCLSCompliant { get; } + bool IsMissing { get; } string Name { get; } byte[] GetPublicKeyToken (); + bool IsFriendAssemblyTo (IAssemblyDefinition assembly); } - public class AssemblyDefinition : IAssemblyDefinition + public abstract class AssemblyDefinition : IAssemblyDefinition { // TODO: make it private and move all builder based methods here public AssemblyBuilder Builder; - AssemblyBuilderExtension builder_extra; + protected AssemblyBuilderExtension builder_extra; + MonoSymbolWriter symbol_writer; bool is_cls_compliant; bool wrap_non_exception_throws; bool wrap_non_exception_throws_custom; - ModuleContainer module; - string name; - string file_name; + protected ModuleContainer module; + readonly string name; + protected readonly string file_name; byte[] public_key, public_key_token; bool delay_sign; @@ -58,37 +70,31 @@ namespace Mono.CSharp Attribute cls_attribute; Method entry_point; - List added_modules; - Dictionary declarative_security; + protected List added_modules; + SecurityType declarative_security; Dictionary emitted_forwarders; AssemblyAttributesPlaceholder module_target_attrs; - // - // In-memory only assembly container - // - public AssemblyDefinition (ModuleContainer module, string name) + protected AssemblyDefinition (ModuleContainer module, string name) { this.module = module; this.name = Path.GetFileNameWithoutExtension (name); wrap_non_exception_throws = true; - delay_sign = RootContext.StrongNameDelaySign; + delay_sign = Compiler.Settings.StrongNameDelaySign; // // Load strong name key early enough for assembly importer to be able to // use the keys for InternalsVisibleTo // This should go somewhere close to ReferencesLoading but don't have the place yet // - if (RootContext.StrongNameKeyFile != null || RootContext.StrongNameKeyContainer != null) { - LoadPublicKey (RootContext.StrongNameKeyFile, RootContext.StrongNameKeyContainer); + if (Compiler.Settings.HasKeyFileOrContainer) { + LoadPublicKey (Compiler.Settings.StrongNameKeyFile, Compiler.Settings.StrongNameKeyContainer); } } - // - // Assembly container with file output - // - public AssemblyDefinition (ModuleContainer module, string name, string fileName) + protected AssemblyDefinition (ModuleContainer module, string name, string fileName) : this (module, name) { this.file_name = fileName; @@ -138,12 +144,23 @@ namespace Mono.CSharp } } + // TODO: This should not exist here but will require more changes + public MetadataImporter Importer { + get; set; + } + public bool IsCLSCompliant { get { return is_cls_compliant; } } + bool IAssemblyDefinition.IsMissing { + get { + return false; + } + } + public string Name { get { return name; @@ -156,7 +173,7 @@ namespace Mono.CSharp } } - Report Report { + protected Report Report { get { return Compiler.Report; } @@ -164,24 +181,18 @@ namespace Mono.CSharp #endregion - public void AddModule (string moduleFile) + public void AddModule (ImportedModuleDefinition module) { - var mod = builder_extra.AddModule (moduleFile); - var imported = Compiler.MetaImporter.ImportModule (mod, module.GlobalRootNamespace); - if (added_modules == null) { added_modules = new List (); - added_modules.Add (imported); + added_modules.Add (module); } - } + } public void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa) { if (a.IsValidSecurityAttribute ()) { - if (declarative_security == null) - declarative_security = new Dictionary (); - - a.ExtractSecurityPermissionSet (declarative_security); + a.ExtractSecurityPermissionSet (ctor, ref declarative_security); return; } @@ -190,7 +201,7 @@ namespace Mono.CSharp if (value == null || value.Length == 0) return; - if (RootContext.Target == Target.Exe) { + if (Compiler.Settings.Target == Target.Exe) { a.Error_AttributeEmitError ("The executables cannot be satelite assemblies, remove the attribute or keep it empty"); return; } @@ -198,7 +209,7 @@ namespace Mono.CSharp if (value == "neutral") value = ""; - if (RootContext.Target == Target.Module) { + if (Compiler.Settings.Target == Target.Module) { SetCustomAttribute (ctor, cdata); } else { builder_extra.SetCulture (value, a.Location); @@ -212,13 +223,13 @@ namespace Mono.CSharp if (value == null || value.Length == 0) return; - var vinfo = IsValidAssemblyVersion (value.Replace ('*', '0')); + var vinfo = IsValidAssemblyVersion (value, true); if (vinfo == null) { a.Error_AttributeEmitError (string.Format ("Specified version `{0}' is not valid", value)); return; } - if (RootContext.Target == Target.Module) { + if (Compiler.Settings.Target == Target.Module) { SetCustomAttribute (ctor, cdata); } else { builder_extra.SetVersion (vinfo, a.Location); @@ -234,7 +245,7 @@ namespace Mono.CSharp alg |= ((uint) cdata [pos + 2]) << 16; alg |= ((uint) cdata [pos + 3]) << 24; - if (RootContext.Target == Target.Module) { + if (Compiler.Settings.Target == Target.Module) { SetCustomAttribute (ctor, cdata); } else { builder_extra.SetAlgorithmId (alg, a.Location); @@ -254,7 +265,7 @@ namespace Mono.CSharp if ((flags & (uint) AssemblyNameFlags.PublicKey) != 0 && public_key == null) flags &= ~(uint) AssemblyNameFlags.PublicKey; - if (RootContext.Target == Target.Module) { + if (Compiler.Settings.Target == Target.Module) { SetCustomAttribute (ctor, cdata); } else { builder_extra.SetFlags (flags, a.Location); @@ -294,7 +305,7 @@ namespace Mono.CSharp return; } - builder_extra.AddTypeForwarder (t, a.Location); + builder_extra.AddTypeForwarder (t.GetDefinition (), a.Location); return; } @@ -307,17 +318,16 @@ namespace Mono.CSharp string assembly_name = a.GetString (); if (assembly_name.Length == 0) return; - - AssemblyName aname = null; - try { - aname = new AssemblyName (assembly_name); - } catch (Exception) { +#if STATIC + ParsedAssemblyName aname; + ParseAssemblyResult r = Fusion.ParseAssemblyName (assembly_name, out aname); + if (r != ParseAssemblyResult.OK) { Report.Warning (1700, 3, a.Location, "Assembly reference `{0}' is invalid and cannot be resolved", assembly_name); return; } - if (aname.Version != null || aname.CultureInfo != null || aname.ProcessorArchitecture != ProcessorArchitecture.None) { + if (aname.Version != null || aname.Culture != null || aname.ProcessorArchitecture != ProcessorArchitecture.None) { Report.Error (1725, a.Location, "Friend assembly reference `{0}' is invalid. InternalsVisibleTo declarations cannot have a version, culture or processor architecture specified", assembly_name); @@ -325,17 +335,25 @@ namespace Mono.CSharp return; } - // TODO: GetPublicKey () does not work on .NET when AssemblyName is constructed from a string - if (public_key != null && aname.GetPublicKey () == null) { + if (public_key != null && !aname.HasPublicKey) { Report.Error (1726, a.Location, "Friend assembly reference `{0}' is invalid. Strong named assemblies must specify a public key in their InternalsVisibleTo declarations", assembly_name); return; } +#endif } else if (a.Type == pa.RuntimeCompatibility) { wrap_non_exception_throws_custom = true; + } else if (a.Type == pa.AssemblyFileVersion) { + string value = a.GetString (); + if (string.IsNullOrEmpty (value) || IsValidAssemblyVersion (value, false) == null) { + Report.Warning (1607, 1, a.Location, "The version number `{0}' specified for `{1}' is invalid", + value, a.Name); + return; + } } + SetCustomAttribute (ctor, cdata); } @@ -348,12 +366,22 @@ namespace Mono.CSharp { // TODO: It should check only references assemblies but there is // no working SRE API - foreach (var a in Compiler.MetaImporter.Assemblies) { + foreach (var entry in Importer.Assemblies) { + var a = entry as ImportedAssemblyDefinition; + if (a == null) + continue; + if (public_key != null && !a.HasStrongName) { Report.Error (1577, "Referenced assembly `{0}' does not have a strong name", a.FullName); } + var ci = a.Assembly.GetName ().CultureInfo; + if (!ci.Equals (System.Globalization.CultureInfo.InvariantCulture)) { + Report.Warning (1607, 1, "Referenced assembly `{0}' has different culture setting of `{1}'", + a.Name, ci.Name); + } + if (!a.IsFriendAssemblyTo (this)) continue; @@ -363,22 +391,18 @@ namespace Mono.CSharp if (ArrayComparer.IsEqual (GetPublicKeyToken (), atoken)) continue; + Report.SymbolRelatedToPreviousError (a.Location); Report.Error (281, "Friend access was granted to `{0}', but the output assembly is named `{1}'. Try adding a reference to `{0}' or change the output assembly name to match it", attr.FullName, FullName); } } - // - // Initializes the code generator - // - public bool Create (AppDomain domain, AssemblyBuilderAccess access) + protected AssemblyName CreateAssemblyName () { - ResolveAssemblySecurityAttributes (); - var an = new AssemblyName (name); - if (public_key != null && RootContext.Target != Target.Module) { + if (public_key != null && Compiler.Settings.Target != Target.Module) { if (delay_sign) { an.SetPublicKey (public_key); } else { @@ -392,68 +416,26 @@ namespace Mono.CSharp } } - try { - Builder = file_name == null ? - domain.DefineDynamicAssembly (an, access) : - domain.DefineDynamicAssembly (an, access, Dirname (file_name)); - } catch (ArgumentException) { - // specified key may not be exportable outside it's container - if (RootContext.StrongNameKeyContainer != null) { - Report.Error (1548, "Could not access the key inside the container `" + - RootContext.StrongNameKeyContainer + "'."); - } - throw; - } - - builder_extra = new AssemblyBuilderExtension (Builder, Compiler); - - return true; + return an; } - public ModuleBuilder CreateModuleBuilder () + public virtual ModuleBuilder CreateModuleBuilder () { - // Creates transient module if (file_name == null) - return Builder.DefineDynamicModule (name, false); - - ModuleBuilder mbuilder = null; - - try { - var module_name = Path.GetFileName (file_name); - mbuilder = Builder.DefineDynamicModule (module_name, module_name, RootContext.GenerateDebugInfo); - -#if !MS_COMPATIBLE - // TODO: We should use SymbolWriter from DefineDynamicModule - if (RootContext.GenerateDebugInfo && !SymbolWriter.Initialize (mbuilder, file_name)) { - Report.Error (40, "Unexpected debug information initialization error `{0}'", - "Could not find the symbol writer assembly (Mono.CompilerServices.SymbolWriter.dll)"); - } -#endif - } catch (ExecutionEngineException e) { - Report.Error (40, "Unexpected debug information initialization error `{0}'", - e.Message); - } - - return mbuilder; - } - - static string Dirname (string name) - { - int pos = name.LastIndexOf ('/'); - - if (pos != -1) - return name.Substring (0, pos); + throw new NotSupportedException ("transient module in static assembly"); - pos = name.LastIndexOf ('\\'); - if (pos != -1) - return name.Substring (0, pos); + var module_name = Path.GetFileName (file_name); - return "."; + // Always initialize module without symbolInfo. We could be framework dependent + // but returned ISymbolWriter does not have all what we need therefore some + // adaptor will be needed for now we alwayas emit MDB format when generating + // debug info + return Builder.DefineDynamicModule (module_name, module_name, false); } - public void Emit () + public virtual void Emit () { - if (RootContext.Target == Target.Module) { + if (Compiler.Settings.Target == Target.Module) { module_target_attrs = new AssemblyAttributesPlaceholder (module, name); module_target_attrs.CreateType (); module_target_attrs.DefineType (); @@ -463,50 +445,51 @@ namespace Mono.CSharp ReadModulesAssemblyAttributes (); } + if (Compiler.Settings.GenerateDebugInfo) { + symbol_writer = new MonoSymbolWriter (file_name); + + // Register all source files with symbol writer + foreach (var source in Compiler.SourceFiles) { + source.DefineSymbolInfo (symbol_writer); + } + + // TODO: global variables + SymbolWriter.symwriter = symbol_writer; + } + module.Emit (); if (module.HasExtensionMethod) { - var pa = Compiler.PredefinedAttributes.Extension; + var pa = module.PredefinedAttributes.Extension; if (pa.IsDefined) { SetCustomAttribute (pa.Constructor, AttributeEncoder.Empty); } } if (!wrap_non_exception_throws_custom) { - PredefinedAttribute pa = Compiler.PredefinedAttributes.RuntimeCompatibility; + PredefinedAttribute pa = module.PredefinedAttributes.RuntimeCompatibility; if (pa.IsDefined && pa.ResolveBuilder ()) { - var prop = pa.GetProperty ("WrapNonExceptionThrows", TypeManager.bool_type, Location.Null); + var prop = module.PredefinedMembers.RuntimeCompatibilityWrapNonExceptionThrows.Get (); if (prop != null) { - AttributeEncoder encoder = new AttributeEncoder (false); - encoder.EncodeNamedPropertyArgument (prop, new BoolLiteral (true, Location.Null)); + AttributeEncoder encoder = new AttributeEncoder (); + encoder.EncodeNamedPropertyArgument (prop, new BoolLiteral (Compiler.BuiltinTypes, true, Location.Null)); SetCustomAttribute (pa.Constructor, encoder.ToArray ()); } } } if (declarative_security != null) { - - MethodInfo add_permission = typeof (AssemblyBuilder).GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic); - object builder_instance = Builder; - - try { - // Microsoft runtime hacking - if (add_permission == null) { - var assembly_builder = typeof (AssemblyBuilder).Assembly.GetType ("System.Reflection.Emit.AssemblyBuilderData"); - add_permission = assembly_builder.GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic); - - FieldInfo fi = typeof (AssemblyBuilder).GetField ("m_assemblyData", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField); - builder_instance = fi.GetValue (Builder); - } - - var args = new PermissionSet [3]; - declarative_security.TryGetValue (SecurityAction.RequestMinimum, out args [0]); - declarative_security.TryGetValue (SecurityAction.RequestOptional, out args [1]); - declarative_security.TryGetValue (SecurityAction.RequestRefuse, out args [2]); - add_permission.Invoke (builder_instance, args); - } catch { - Report.RuntimeMissingSupport (Location.Null, "assembly permission setting"); +#if STATIC + foreach (var entry in declarative_security) { + Builder.__AddDeclarativeSecurity (entry); } +#else + var args = new PermissionSet[3]; + declarative_security.TryGetValue (SecurityAction.RequestMinimum, out args[0]); + declarative_security.TryGetValue (SecurityAction.RequestOptional, out args[1]); + declarative_security.TryGetValue (SecurityAction.RequestRefuse, out args[2]); + builder_extra.AddPermissionRequests (args); +#endif } CheckReferencesPublicToken (); @@ -523,7 +506,7 @@ namespace Mono.CSharp byte[] hash = ha.ComputeHash (public_key); // we need the last 8 bytes in reverse order public_key_token = new byte[8]; - Array.Copy (hash, (hash.Length - 8), public_key_token, 0, 8); + Buffer.BlockCopy (hash, hash.Length - 8, public_key_token, 0, 8); Array.Reverse (public_key_token, 0, 8); return public_key_token; } @@ -550,7 +533,7 @@ namespace Mono.CSharp // For attribute based KeyFile do additional lookup // in output assembly path // - if (!key_file_exists && RootContext.StrongNameKeyFile == null) { + if (!key_file_exists && Compiler.Settings.StrongNameKeyFile == null) { // // The key file can be relative to output assembly // @@ -582,11 +565,19 @@ namespace Mono.CSharp byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa); // AssemblyName.SetPublicKey requires an additional header - byte[] publicKeyHeader = new byte[12] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00 }; + byte[] publicKeyHeader = new byte[8] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00 }; // Encode public key public_key = new byte[12 + publickey.Length]; - Buffer.BlockCopy (publicKeyHeader, 0, public_key, 0, 12); + Buffer.BlockCopy (publicKeyHeader, 0, public_key, 0, publicKeyHeader.Length); + + // Length of Public Key (in bytes) + int lastPart = public_key.Length - 12; + public_key[8] = (byte) (lastPart & 0xFF); + public_key[9] = (byte) ((lastPart >> 8) & 0xFF); + public_key[10] = (byte) ((lastPart >> 16) & 0xFF); + public_key[11] = (byte) ((lastPart >> 24) & 0xFF); + Buffer.BlockCopy (publickey, 0, public_key, 12, publickey.Length); } catch { Error_AssemblySigning ("The specified key file `" + keyFile + "' has incorrect format"); @@ -617,31 +608,31 @@ namespace Mono.CSharp public void Resolve () { - if (RootContext.Unsafe) { + if (Compiler.Settings.Unsafe && module.PredefinedTypes.SecurityAction.Define ()) { // // Emits [assembly: SecurityPermissionAttribute (SecurityAction.RequestMinimum, SkipVerification = true)] // when -unsafe option was specified // - Location loc = Location.Null; MemberAccess system_security_permissions = new MemberAccess (new MemberAccess ( new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Security", loc), "Permissions", loc); + var req_min = module.PredefinedMembers.SecurityActionRequestMinimum.Resolve (loc); + Arguments pos = new Arguments (1); - pos.Add (new Argument (new MemberAccess (new MemberAccess (system_security_permissions, "SecurityAction", loc), "RequestMinimum"))); + pos.Add (new Argument (req_min.GetConstant (null))); Arguments named = new Arguments (1); - named.Add (new NamedArgument ("SkipVerification", loc, new BoolLiteral (true, loc))); + named.Add (new NamedArgument ("SkipVerification", loc, new BoolLiteral (Compiler.BuiltinTypes, true, loc))); - GlobalAttribute g = new GlobalAttribute (new NamespaceEntry (module, null, null, null), "assembly", + Attribute g = new Attribute ("assembly", new MemberAccess (system_security_permissions, "SecurityPermissionAttribute"), new Arguments[] { pos, named }, loc, false); g.AttachTo (module, module); - - if (g.Resolve () != null) { - declarative_security = new Dictionary (); - g.ExtractSecurityPermissionSet (declarative_security); + var ctor = g.Resolve (); + if (ctor != null) { + g.ExtractSecurityPermissionSet (ctor, ref declarative_security); } } @@ -652,13 +643,13 @@ namespace Mono.CSharp if (!module.OptAttributes.CheckTargets()) return; - cls_attribute = module.ResolveAssemblyAttribute (Compiler.PredefinedAttributes.CLSCompliant); + cls_attribute = module.ResolveAssemblyAttribute (module.PredefinedAttributes.CLSCompliant); if (cls_attribute != null) { is_cls_compliant = cls_attribute.GetClsCompliantAttributeValue (); } - if (added_modules != null && RootContext.VerifyClsCompliance && is_cls_compliant) { + if (added_modules != null && Compiler.Settings.VerifyClsCompliance && is_cls_compliant) { foreach (var m in added_modules) { if (!m.IsCLSCompliant) { Report.Error (3013, @@ -668,7 +659,7 @@ namespace Mono.CSharp } } - Attribute a = module.ResolveAssemblyAttribute (Compiler.PredefinedAttributes.RuntimeCompatibility); + Attribute a = module.ResolveAssemblyAttribute (module.PredefinedAttributes.RuntimeCompatibility); if (a != null) { var val = a.GetNamedValue ("WrapNonExceptionThrows") as BoolConstant; if (val != null) @@ -676,7 +667,7 @@ namespace Mono.CSharp } } - void ResolveAssemblySecurityAttributes () + protected void ResolveAssemblySecurityAttributes () { string key_file = null; string key_container = null; @@ -695,7 +686,7 @@ namespace Mono.CSharp case "AssemblyKeyFile": case "AssemblyKeyFileAttribute": case "System.Reflection.AssemblyKeyFileAttribute": - if (RootContext.StrongNameKeyFile != null) { + if (Compiler.Settings.StrongNameKeyFile != null) { Report.SymbolRelatedToPreviousError (a.Location, a.GetSignatureForError ()); Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module", "keyfile", "System.Reflection.AssemblyKeyFileAttribute"); @@ -710,7 +701,7 @@ namespace Mono.CSharp case "AssemblyKeyName": case "AssemblyKeyNameAttribute": case "System.Reflection.AssemblyKeyNameAttribute": - if (RootContext.StrongNameKeyContainer != null) { + if (Compiler.Settings.StrongNameKeyContainer != null) { Report.SymbolRelatedToPreviousError (a.Location, a.GetSignatureForError ()); Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module", "keycontainer", "System.Reflection.AssemblyKeyNameAttribute"); @@ -756,28 +747,38 @@ namespace Mono.CSharp // // Add Win32 resources // - if (RootContext.Win32ResourceFile != null) { - Builder.DefineUnmanagedResource (RootContext.Win32ResourceFile); + if (Compiler.Settings.Win32ResourceFile != null) { + Builder.DefineUnmanagedResource (Compiler.Settings.Win32ResourceFile); } else { Builder.DefineVersionInfoResource (); } - if (RootContext.Win32IconFile != null) { - builder_extra.DefineWin32IconResource (RootContext.Win32IconFile); + if (Compiler.Settings.Win32IconFile != null) { + builder_extra.DefineWin32IconResource (Compiler.Settings.Win32IconFile); } - if (RootContext.Resources != null) { - if (RootContext.Target == Target.Module) { + if (Compiler.Settings.Resources != null) { + if (Compiler.Settings.Target == Target.Module) { Report.Error (1507, "Cannot link resource file when building a module"); } else { - foreach (var res in RootContext.Resources) { + int counter = 0; + foreach (var res in Compiler.Settings.Resources) { if (!File.Exists (res.FileName)) { Report.Error (1566, "Error reading resource file `{0}'", res.FileName); continue; } if (res.IsEmbeded) { - var stream = File.OpenRead (res.FileName); + Stream stream; + if (counter++ < 10) { + stream = File.OpenRead (res.FileName); + } else { + // TODO: SRE API requires resource stream to be available during AssemblyBuilder::Save + // we workaround it by reading everything into memory to compile projects with + // many embedded resource (over 3500) references + stream = new MemoryStream (File.ReadAllBytes (res.FileName)); + } + module.Builder.DefineManifestResource (res.Name, stream, res.Attributes); } else { Builder.AddResourceFile (res.Name, Path.GetFileName (res.FileName), res.Attributes); @@ -792,7 +793,7 @@ namespace Mono.CSharp PortableExecutableKinds pekind; ImageFileMachine machine; - switch (RootContext.Platform) { + switch (Compiler.Settings.Platform) { case Platform.X86: pekind = PortableExecutableKinds.Required32Bit | PortableExecutableKinds.ILOnly; machine = ImageFileMachine.I386; @@ -812,15 +813,30 @@ namespace Mono.CSharp break; } - if (RootContext.Target == Target.Module) { - builder_extra.SetModuleTarget (); - } - + Compiler.TimeReporter.Start (TimeReporter.TimerType.OutputSave); try { - Builder.Save (module.Builder.ScopeName, pekind, machine); + if (Compiler.Settings.Target == Target.Module) { + SaveModule (pekind, machine); + } else { + Builder.Save (module.Builder.ScopeName, pekind, machine); + } } catch (Exception e) { Report.Error (16, "Could not write to file `" + name + "', cause: " + e.Message); } + Compiler.TimeReporter.Stop (TimeReporter.TimerType.OutputSave); + + // Save debug symbols file + if (symbol_writer != null && Compiler.Report.Errors == 0) { + // TODO: it should run in parallel + Compiler.TimeReporter.Start (TimeReporter.TimerType.DebugSave); + symbol_writer.WriteSymbolFile (SymbolWriter.GetGuid (module.Builder)); + Compiler.TimeReporter.Stop (TimeReporter.TimerType.DebugSave); + } + } + + protected virtual void SaveModule (PortableExecutableKinds pekind, ImageFileMachine machine) + { + Report.RuntimeMissingSupport (Location.Null, "-target:module"); } void SetCustomAttribute (MethodSpec ctor, byte[] data) @@ -833,8 +849,8 @@ namespace Mono.CSharp void SetEntryPoint () { - if (!RootContext.NeedsEntryPoint) { - if (RootContext.MainClass != null) + if (!Compiler.Settings.NeedsEntryPoint) { + if (Compiler.Settings.MainClass != null) Report.Error (2017, "Cannot specify -main if building a module or library"); return; @@ -842,7 +858,7 @@ namespace Mono.CSharp PEFileKinds file_kind; - switch (RootContext.Target) { + switch (Compiler.Settings.Target) { case Target.Library: case Target.Module: file_kind = PEFileKinds.Dll; @@ -856,26 +872,24 @@ namespace Mono.CSharp } if (entry_point == null) { - if (RootContext.MainClass != null) { - // TODO: Should use MemberCache - DeclSpace main_cont = module.GetDefinition (RootContext.MainClass) as DeclSpace; - if (main_cont == null) { - Report.Error (1555, "Could not find `{0}' specified for Main method", RootContext.MainClass); + string main_class = Compiler.Settings.MainClass; + if (main_class != null) { + // TODO: Handle dotted names + var texpr = module.GlobalRootNamespace.LookupType (module, main_class, 0, LookupMode.Probing, Location.Null); + if (texpr == null) { + Report.Error (1555, "Could not find `{0}' specified for Main method", main_class); return; } - if (!(main_cont is ClassOrStruct)) { - Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", RootContext.MainClass); + var mtype = texpr.Type.MemberDefinition as ClassOrStruct; + if (mtype == null) { + Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", main_class); return; } - Report.Error (1558, main_cont.Location, "`{0}' does not have a suitable static Main method", main_cont.GetSignatureForError ()); - return; - } - - if (Report.Errors == 0) { + Report.Error (1558, mtype.Location, "`{0}' does not have a suitable static Main method", mtype.GetSignatureForError ()); + } else { string pname = file_name == null ? name : Path.GetFileName (file_name); - Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point", pname); } @@ -898,29 +912,80 @@ namespace Mono.CSharp Report.Error (1548, "Error during assembly signing. " + text); } - static string IsValidAssemblyVersion (string version) + public bool IsFriendAssemblyTo (IAssemblyDefinition assembly) { - Version v; - try { - v = new Version (version); - } catch { - try { - int major = int.Parse (version, CultureInfo.InvariantCulture); - v = new Version (major, 0); - } catch { + return false; + } + + static Version IsValidAssemblyVersion (string version, bool allowGenerated) + { + string[] parts = version.Split ('.'); + if (parts.Length < 1 || parts.Length > 4) + return null; + + var values = new int[4]; + for (int i = 0; i < parts.Length; ++i) { + if (!int.TryParse (parts[i], out values[i])) { + if (parts[i].Length == 1 && parts[i][0] == '*' && allowGenerated) { + if (i == 2) { + // Nothing can follow * + if (parts.Length > 3) + return null; + + // Generate Build value based on days since 1/1/2000 + TimeSpan days = DateTime.Today - new DateTime (2000, 1, 1); + values[i] = System.Math.Max (days.Days, 0); + i = 3; + } + + if (i == 3) { + // Generate Revision value based on every other second today + var seconds = DateTime.Now - DateTime.Today; + values[i] = (int) seconds.TotalSeconds / 2; + continue; + } + } + return null; } - } - foreach (int candidate in new int [] { v.Major, v.Minor, v.Build, v.Revision }) { - if (candidate > ushort.MaxValue) + if (values[i] > ushort.MaxValue) return null; } - return new Version (v.Major, System.Math.Max (0, v.Minor), System.Math.Max (0, v.Build), System.Math.Max (0, v.Revision)).ToString (4); + return new Version (values[0], values[1], values[2], values[3]); } } + public class AssemblyResource : IEquatable + { + public AssemblyResource (string fileName, string name) + : this (fileName, name, false) + { + } + + public AssemblyResource (string fileName, string name, bool isPrivate) + { + FileName = fileName; + Name = name; + Attributes = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public; + } + + public ResourceAttributes Attributes { get; private set; } + public string Name { get; private set; } + public string FileName { get; private set; } + public bool IsEmbeded { get; set; } + + #region IEquatable Members + + public bool Equals (AssemblyResource other) + { + return Name == other.Name; + } + + #endregion + } + // // A placeholder class for assembly attributes when emitting module // @@ -934,7 +999,7 @@ namespace Mono.CSharp public AssemblyAttributesPlaceholder (ModuleContainer parent, string outputName) : base (parent, new MemberName (GetGeneratedName (outputName)), Modifiers.STATIC) { - assembly = new Field (this, new TypeExpression (TypeManager.object_type, Location), Modifiers.PUBLIC | Modifiers.STATIC, + assembly = new Field (this, new TypeExpression (parent.Compiler.BuiltinTypes.Object, Location), Modifiers.PUBLIC | Modifiers.STATIC, new MemberName (AssemblyFieldName), null); AddField (assembly); @@ -953,128 +1018,165 @@ namespace Mono.CSharp // // Extension to System.Reflection.Emit.AssemblyBuilder to have fully compatible - // compiler + // compiler. This is a default implementation for framework System.Reflection.Emit + // which does not implement any of the methods // - class AssemblyBuilderExtension + public class AssemblyBuilderExtension { - static MethodInfo adder_method; - static MethodInfo set_module_only; - static MethodInfo add_type_forwarder; - static MethodInfo win32_icon_define; - static FieldInfo assembly_version; - static FieldInfo assembly_algorithm; - static FieldInfo assembly_culture; - static FieldInfo assembly_flags; - - AssemblyBuilder builder; - CompilerContext ctx; - - public AssemblyBuilderExtension (AssemblyBuilder ab, CompilerContext ctx) + readonly CompilerContext ctx; + + public AssemblyBuilderExtension (CompilerContext ctx) { - this.builder = ab; this.ctx = ctx; } - public Module AddModule (string module) + public virtual System.Reflection.Module AddModule (string module) { - try { - if (adder_method == null) - adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance | BindingFlags.NonPublic); + ctx.Report.RuntimeMissingSupport (Location.Null, "-addmodule"); + return null; + } - return (Module) adder_method.Invoke (builder, new object[] { module }); - } catch { - ctx.Report.RuntimeMissingSupport (Location.Null, "-addmodule"); - return null; - } + public virtual void AddPermissionRequests (PermissionSet[] permissions) + { + ctx.Report.RuntimeMissingSupport (Location.Null, "assembly declarative security"); } - public void AddTypeForwarder (TypeSpec type, Location loc) + public virtual void AddTypeForwarder (TypeSpec type, Location loc) { - try { - if (add_type_forwarder == null) { - add_type_forwarder = typeof (AssemblyBuilder).GetMethod ("AddTypeForwarder", BindingFlags.NonPublic | BindingFlags.Instance); - } + ctx.Report.RuntimeMissingSupport (loc, "TypeForwardedToAttribute"); + } - add_type_forwarder.Invoke (builder, new object[] { type.GetMetaInfo () }); - } catch { - ctx.Report.RuntimeMissingSupport (loc, "TypeForwardedToAttribute"); - } + public virtual void DefineWin32IconResource (string fileName) + { + ctx.Report.RuntimeMissingSupport (Location.Null, "-win32icon"); } - public void DefineWin32IconResource (string fileName) + public virtual void SetAlgorithmId (uint value, Location loc) { - try { - if (win32_icon_define == null) - win32_icon_define = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance | BindingFlags.NonPublic); + ctx.Report.RuntimeMissingSupport (loc, "AssemblyAlgorithmIdAttribute"); + } - win32_icon_define.Invoke (builder, new object[] { fileName }); - } catch { - ctx.Report.RuntimeMissingSupport (Location.Null, "-win32icon"); - } + public virtual void SetCulture (string culture, Location loc) + { + ctx.Report.RuntimeMissingSupport (loc, "AssemblyCultureAttribute"); } - public void SetAlgorithmId (uint value, Location loc) + public virtual void SetFlags (uint flags, Location loc) { - try { - if (assembly_algorithm == null) - assembly_algorithm = typeof (AssemblyBuilder).GetField ("algid", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField); + ctx.Report.RuntimeMissingSupport (loc, "AssemblyFlagsAttribute"); + } - assembly_algorithm.SetValue (builder, value); - } catch { - ctx.Report.RuntimeMissingSupport (loc, "AssemblyAlgorithmIdAttribute"); - } + public virtual void SetVersion (Version version, Location loc) + { + ctx.Report.RuntimeMissingSupport (loc, "AssemblyVersionAttribute"); } + } + + abstract class AssemblyReferencesLoader + { + protected readonly CompilerContext compiler; - public void SetCulture (string culture, Location loc) + protected readonly List paths; + + public AssemblyReferencesLoader (CompilerContext compiler) { - try { - if (assembly_culture == null) - assembly_culture = typeof (AssemblyBuilder).GetField ("culture", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField); + this.compiler = compiler; - assembly_culture.SetValue (builder, culture); - } catch { - ctx.Report.RuntimeMissingSupport (loc, "AssemblyCultureAttribute"); - } + paths = new List (); + paths.AddRange (compiler.Settings.ReferencesLookupPaths); + paths.Add (Directory.GetCurrentDirectory ()); } + public abstract bool HasObjectType (T assembly); + protected abstract string[] GetDefaultReferences (); + public abstract T LoadAssemblyFile (string fileName, bool isImplicitReference); + public abstract void LoadReferences (ModuleContainer module); - public void SetFlags (uint flags, Location loc) + protected void Error_FileNotFound (string fileName) { - try { - if (assembly_flags == null) - assembly_flags = typeof (AssemblyBuilder).GetField ("flags", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField); - - assembly_flags.SetValue (builder, flags); - } catch { - ctx.Report.RuntimeMissingSupport (loc, "AssemblyFlagsAttribute"); - } + compiler.Report.Error (6, "Metadata file `{0}' could not be found", fileName); + } + protected void Error_FileCorrupted (string fileName) + { + compiler.Report.Error (9, "Metadata file `{0}' does not contain valid metadata", fileName); } - public void SetVersion (string version, Location loc) + protected void Error_AssemblyIsModule (string fileName) { - try { - if (assembly_version == null) - assembly_version = typeof (AssemblyBuilder).GetField ("version", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField); + compiler.Report.Error (1509, + "Referenced assembly file `{0}' is a module. Consider using `-addmodule' option to add the module", + fileName); + } - assembly_version.SetValue (builder, version); - } catch { - ctx.Report.RuntimeMissingSupport (loc, "AssemblyVersionAttribute"); - } + protected void Error_ModuleIsAssembly (string fileName) + { + compiler.Report.Error (1542, + "Added module file `{0}' is an assembly. Consider using `-r' option to reference the file", + fileName); } - public void SetModuleTarget () + protected void LoadReferencesCore (ModuleContainer module, out T corlib_assembly, out List> loaded) { - try { - if (set_module_only == null) { - var module_only = typeof (AssemblyBuilder).GetProperty ("IsModuleOnly", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - set_module_only = module_only.GetSetMethod (true); + compiler.TimeReporter.Start (TimeReporter.TimerType.ReferencesLoading); + + loaded = new List> (); + + // + // Load mscorlib.dll as the first + // + if (module.Compiler.Settings.StdLib) { + corlib_assembly = LoadAssemblyFile ("mscorlib.dll", true); + } else { + corlib_assembly = default (T); + } + + T a; + foreach (string r in module.Compiler.Settings.AssemblyReferences) { + a = LoadAssemblyFile (r, false); + if (a == null || EqualityComparer.Default.Equals (a, corlib_assembly)) + continue; + + var key = Tuple.Create (module.GlobalRootNamespace, a); + if (loaded.Contains (key)) + continue; + + // A corlib assembly is the first assembly which contains System.Object + if (corlib_assembly == null && HasObjectType (a)) { + corlib_assembly = a; + continue; } - set_module_only.Invoke (builder, new object[] { true }); - } catch { - ctx.Report.RuntimeMissingSupport (Location.Null, "-target:module"); + loaded.Add (key); } + + foreach (var entry in module.Compiler.Settings.AssemblyReferencesAliases) { + a = LoadAssemblyFile (entry.Item2, false); + if (a == null) + continue; + + var key = Tuple.Create (module.CreateRootNamespace (entry.Item1), a); + if (loaded.Contains (key)) + continue; + + loaded.Add (key); + } + + if (compiler.Settings.LoadDefaultReferences) { + foreach (string r in GetDefaultReferences ()) { + a = LoadAssemblyFile (r, true); + if (a == null) + continue; + + var key = Tuple.Create (module.GlobalRootNamespace, a); + if (loaded.Contains (key)) + continue; + + loaded.Add (key); + } + } + + compiler.TimeReporter.Stop (TimeReporter.TimerType.ReferencesLoading); } } }