2
// assembly.cs: Assembly declaration and specifications
5
// Miguel de Icaza (miguel@ximian.com)
6
// Marek Safar (marek.safar@gmail.com)
8
// Copyright 2001, 2002, 2003 Ximian, Inc.
9
// Copyright 2004-2011 Novell, Inc.
10
// Copyright 2011 Xamarin Inc
16
using System.Collections.Generic;
17
using System.Globalization;
18
using System.Security;
19
using System.Security.Cryptography;
20
using System.Security.Permissions;
21
using Mono.Security.Cryptography;
22
using Mono.CompilerServices.SymbolWriter;
25
using IKVM.Reflection;
26
using IKVM.Reflection.Emit;
27
using SecurityType = System.Collections.Generic.List<IKVM.Reflection.Emit.CustomAttributeBuilder>;
29
using SecurityType = System.Collections.Generic.Dictionary<System.Security.Permissions.SecurityAction, System.Security.PermissionSet>;
30
using System.Reflection;
31
using System.Reflection.Emit;
36
public interface IAssemblyDefinition
38
string FullName { get; }
39
bool HasExtensionMethod { get; }
40
bool IsCLSCompliant { get; }
41
bool IsMissing { get; }
44
byte[] GetPublicKeyToken ();
45
bool IsFriendAssemblyTo (IAssemblyDefinition assembly);
48
public abstract class AssemblyDefinition : IAssemblyDefinition
50
// TODO: make it private and move all builder based methods here
51
public AssemblyBuilder Builder;
52
protected AssemblyBuilderExtension builder_extra;
53
MonoSymbolFile symbol_writer;
55
bool is_cls_compliant;
56
bool wrap_non_exception_throws;
57
bool wrap_non_exception_throws_custom;
59
protected ModuleContainer module;
61
protected readonly string file_name;
63
byte[] public_key, public_key_token;
66
// Holds private/public key pair when private key
68
StrongNameKeyPair private_key;
70
Attribute cls_attribute;
73
protected List<ImportedModuleDefinition> added_modules;
74
SecurityType declarative_security;
75
Dictionary<ITypeDefinition, Attribute> emitted_forwarders;
76
AssemblyAttributesPlaceholder module_target_attrs;
78
protected AssemblyDefinition (ModuleContainer module, string name)
81
this.name = Path.GetFileNameWithoutExtension (name);
83
wrap_non_exception_throws = true;
85
delay_sign = Compiler.Settings.StrongNameDelaySign;
88
// Load strong name key early enough for assembly importer to be able to
89
// use the keys for InternalsVisibleTo
90
// This should go somewhere close to ReferencesLoading but don't have the place yet
92
if (Compiler.Settings.HasKeyFileOrContainer) {
93
LoadPublicKey (Compiler.Settings.StrongNameKeyFile, Compiler.Settings.StrongNameKeyContainer);
97
protected AssemblyDefinition (ModuleContainer module, string name, string fileName)
100
this.file_name = fileName;
105
public Attribute CLSCompliantAttribute {
107
return cls_attribute;
111
public CompilerContext Compiler {
113
return module.Compiler;
118
// Assembly entry point, aka Main method
120
public Method EntryPoint {
129
public string FullName {
131
return Builder.FullName;
135
public bool HasExtensionMethod {
137
return module.HasExtensionMethod;
141
public bool HasCLSCompliantAttribute {
143
return cls_attribute != null;
147
// TODO: This should not exist here but will require more changes
148
public MetadataImporter Importer {
152
public bool IsCLSCompliant {
154
return is_cls_compliant;
158
bool IAssemblyDefinition.IsMissing {
170
public bool WrapNonExceptionThrows {
172
return wrap_non_exception_throws;
176
protected Report Report {
178
return Compiler.Report;
182
public MonoSymbolFile SymbolWriter {
184
return symbol_writer;
190
public void AddModule (ImportedModuleDefinition module)
192
if (added_modules == null) {
193
added_modules = new List<ImportedModuleDefinition> ();
194
added_modules.Add (module);
198
public void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
200
if (a.IsValidSecurityAttribute ()) {
201
a.ExtractSecurityPermissionSet (ctor, ref declarative_security);
205
if (a.Type == pa.AssemblyCulture) {
206
string value = a.GetString ();
207
if (value == null || value.Length == 0)
210
if (Compiler.Settings.Target == Target.Exe) {
211
a.Error_AttributeEmitError ("The executables cannot be satelite assemblies, remove the attribute or keep it empty");
215
if (value == "neutral")
218
if (Compiler.Settings.Target == Target.Module) {
219
SetCustomAttribute (ctor, cdata);
221
builder_extra.SetCulture (value, a.Location);
227
if (a.Type == pa.AssemblyVersion) {
228
string value = a.GetString ();
229
if (value == null || value.Length == 0)
232
var vinfo = IsValidAssemblyVersion (value, true);
234
a.Error_AttributeEmitError (string.Format ("Specified version `{0}' is not valid", value));
238
if (Compiler.Settings.Target == Target.Module) {
239
SetCustomAttribute (ctor, cdata);
241
builder_extra.SetVersion (vinfo, a.Location);
247
if (a.Type == pa.AssemblyAlgorithmId) {
248
const int pos = 2; // skip CA header
249
uint alg = (uint) cdata [pos];
250
alg |= ((uint) cdata [pos + 1]) << 8;
251
alg |= ((uint) cdata [pos + 2]) << 16;
252
alg |= ((uint) cdata [pos + 3]) << 24;
254
if (Compiler.Settings.Target == Target.Module) {
255
SetCustomAttribute (ctor, cdata);
257
builder_extra.SetAlgorithmId (alg, a.Location);
263
if (a.Type == pa.AssemblyFlags) {
264
const int pos = 2; // skip CA header
265
uint flags = (uint) cdata[pos];
266
flags |= ((uint) cdata [pos + 1]) << 8;
267
flags |= ((uint) cdata [pos + 2]) << 16;
268
flags |= ((uint) cdata [pos + 3]) << 24;
270
// Ignore set PublicKey flag if assembly is not strongnamed
271
if ((flags & (uint) AssemblyNameFlags.PublicKey) != 0 && public_key == null)
272
flags &= ~(uint) AssemblyNameFlags.PublicKey;
274
if (Compiler.Settings.Target == Target.Module) {
275
SetCustomAttribute (ctor, cdata);
277
builder_extra.SetFlags (flags, a.Location);
283
if (a.Type == pa.TypeForwarder) {
284
TypeSpec t = a.GetArgumentType ();
285
if (t == null || TypeManager.HasElementType (t)) {
286
Report.Error (735, a.Location, "Invalid type specified as an argument for TypeForwardedTo attribute");
290
if (emitted_forwarders == null) {
291
emitted_forwarders = new Dictionary<ITypeDefinition, Attribute> ();
292
} else if (emitted_forwarders.ContainsKey (t.MemberDefinition)) {
293
Report.SymbolRelatedToPreviousError (emitted_forwarders[t.MemberDefinition].Location, null);
294
Report.Error (739, a.Location, "A duplicate type forward of type `{0}'",
295
TypeManager.CSharpName (t));
299
emitted_forwarders.Add (t.MemberDefinition, a);
301
if (t.MemberDefinition.DeclaringAssembly == this) {
302
Report.SymbolRelatedToPreviousError (t);
303
Report.Error (729, a.Location, "Cannot forward type `{0}' because it is defined in this assembly",
304
TypeManager.CSharpName (t));
309
Report.Error (730, a.Location, "Cannot forward type `{0}' because it is a nested type",
310
TypeManager.CSharpName (t));
314
builder_extra.AddTypeForwarder (t.GetDefinition (), a.Location);
318
if (a.Type == pa.Extension) {
319
a.Error_MisusedExtensionAttribute ();
323
if (a.Type == pa.InternalsVisibleTo) {
324
string assembly_name = a.GetString ();
325
if (assembly_name.Length == 0)
328
ParsedAssemblyName aname;
329
ParseAssemblyResult r = Fusion.ParseAssemblyName (assembly_name, out aname);
330
if (r != ParseAssemblyResult.OK) {
331
Report.Warning (1700, 3, a.Location, "Assembly reference `{0}' is invalid and cannot be resolved",
336
if (aname.Version != null || aname.Culture != null || aname.ProcessorArchitecture != ProcessorArchitecture.None) {
337
Report.Error (1725, a.Location,
338
"Friend assembly reference `{0}' is invalid. InternalsVisibleTo declarations cannot have a version, culture or processor architecture specified",
344
if (public_key != null && !aname.HasPublicKey) {
345
Report.Error (1726, a.Location,
346
"Friend assembly reference `{0}' is invalid. Strong named assemblies must specify a public key in their InternalsVisibleTo declarations",
351
} else if (a.Type == pa.RuntimeCompatibility) {
352
wrap_non_exception_throws_custom = true;
353
} else if (a.Type == pa.AssemblyFileVersion) {
354
string value = a.GetString ();
355
if (string.IsNullOrEmpty (value) || IsValidAssemblyVersion (value, false) == null) {
356
Report.Warning (1607, 1, a.Location, "The version number `{0}' specified for `{1}' is invalid",
363
SetCustomAttribute (ctor, cdata);
367
// When using assembly public key attributes InternalsVisibleTo key
368
// was not checked, we have to do it later when we actually know what
369
// our public key token is
371
void CheckReferencesPublicToken ()
373
// TODO: It should check only references assemblies but there is
374
// no working SRE API
375
foreach (var entry in Importer.Assemblies) {
376
var a = entry as ImportedAssemblyDefinition;
380
if (public_key != null && !a.HasStrongName) {
381
Report.Error (1577, "Referenced assembly `{0}' does not have a strong name",
385
var ci = a.Assembly.GetName ().CultureInfo;
386
if (!ci.Equals (System.Globalization.CultureInfo.InvariantCulture)) {
387
Report.Warning (1607, 1, "Referenced assembly `{0}' has different culture setting of `{1}'",
391
if (!a.IsFriendAssemblyTo (this))
394
var attr = a.GetAssemblyVisibleToName (this);
395
var atoken = attr.GetPublicKeyToken ();
397
if (ArrayComparer.IsEqual (GetPublicKeyToken (), atoken))
400
Report.SymbolRelatedToPreviousError (a.Location);
402
"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",
403
attr.FullName, FullName);
407
protected AssemblyName CreateAssemblyName ()
409
var an = new AssemblyName (name);
411
if (public_key != null && Compiler.Settings.Target != Target.Module) {
413
an.SetPublicKey (public_key);
415
if (public_key.Length == 16) {
416
Report.Error (1606, "Could not sign the assembly. ECMA key can only be used to delay-sign assemblies");
417
} else if (private_key == null) {
418
Error_AssemblySigning ("The specified key file does not have a private key");
420
an.KeyPair = private_key;
428
public virtual ModuleBuilder CreateModuleBuilder ()
430
if (file_name == null)
431
throw new NotSupportedException ("transient module in static assembly");
433
var module_name = Path.GetFileName (file_name);
435
// Always initialize module without symbolInfo. We could be framework dependent
436
// but returned ISymbolWriter does not have all what we need therefore some
437
// adaptor will be needed for now we alwayas emit MDB format when generating
439
return Builder.DefineDynamicModule (module_name, module_name, false);
442
public virtual void Emit ()
444
if (Compiler.Settings.Target == Target.Module) {
445
module_target_attrs = new AssemblyAttributesPlaceholder (module, name);
446
module_target_attrs.CreateContainer ();
447
module_target_attrs.DefineContainer ();
448
module_target_attrs.Define ();
449
module.AddCompilerGeneratedClass (module_target_attrs);
450
} else if (added_modules != null) {
451
ReadModulesAssemblyAttributes ();
454
if (Compiler.Settings.GenerateDebugInfo) {
455
symbol_writer = new MonoSymbolFile ();
458
module.EmitContainer ();
460
if (module.HasExtensionMethod) {
461
var pa = module.PredefinedAttributes.Extension;
463
SetCustomAttribute (pa.Constructor, AttributeEncoder.Empty);
467
if (!wrap_non_exception_throws_custom) {
468
PredefinedAttribute pa = module.PredefinedAttributes.RuntimeCompatibility;
469
if (pa.IsDefined && pa.ResolveBuilder ()) {
470
var prop = module.PredefinedMembers.RuntimeCompatibilityWrapNonExceptionThrows.Get ();
472
AttributeEncoder encoder = new AttributeEncoder ();
473
encoder.EncodeNamedPropertyArgument (prop, new BoolLiteral (Compiler.BuiltinTypes, true, Location.Null));
474
SetCustomAttribute (pa.Constructor, encoder.ToArray ());
479
if (declarative_security != null) {
481
foreach (var entry in declarative_security) {
482
Builder.__AddDeclarativeSecurity (entry);
485
throw new NotSupportedException ("Assembly-level security");
489
CheckReferencesPublicToken ();
494
public byte[] GetPublicKeyToken ()
496
if (public_key == null || public_key_token != null)
497
return public_key_token;
499
HashAlgorithm ha = SHA1.Create ();
500
byte[] hash = ha.ComputeHash (public_key);
501
// we need the last 8 bytes in reverse order
502
public_key_token = new byte[8];
503
Buffer.BlockCopy (hash, hash.Length - 8, public_key_token, 0, 8);
504
Array.Reverse (public_key_token, 0, 8);
505
return public_key_token;
509
// Either keyFile or keyContainer has to be non-null
511
void LoadPublicKey (string keyFile, string keyContainer)
513
if (keyContainer != null) {
515
private_key = new StrongNameKeyPair (keyContainer);
516
public_key = private_key.PublicKey;
518
Error_AssemblySigning ("The specified key container `" + keyContainer + "' does not exist");
524
bool key_file_exists = File.Exists (keyFile);
527
// For attribute based KeyFile do additional lookup
528
// in output assembly path
530
if (!key_file_exists && Compiler.Settings.StrongNameKeyFile == null) {
532
// The key file can be relative to output assembly
534
string test_path = Path.Combine (Path.GetDirectoryName (file_name), keyFile);
535
key_file_exists = File.Exists (test_path);
540
if (!key_file_exists) {
541
Error_AssemblySigning ("The specified key file `" + keyFile + "' does not exist");
545
using (FileStream fs = new FileStream (keyFile, FileMode.Open, FileAccess.Read)) {
546
byte[] snkeypair = new byte[fs.Length];
547
fs.Read (snkeypair, 0, snkeypair.Length);
549
// check for ECMA key
550
if (snkeypair.Length == 16) {
551
public_key = snkeypair;
556
// take it, with or without, a private key
557
RSA rsa = CryptoConvert.FromCapiKeyBlob (snkeypair);
558
// and make sure we only feed the public part to Sys.Ref
559
byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
561
// AssemblyName.SetPublicKey requires an additional header
562
byte[] publicKeyHeader = new byte[8] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00 };
565
public_key = new byte[12 + publickey.Length];
566
Buffer.BlockCopy (publicKeyHeader, 0, public_key, 0, publicKeyHeader.Length);
568
// Length of Public Key (in bytes)
569
int lastPart = public_key.Length - 12;
570
public_key[8] = (byte) (lastPart & 0xFF);
571
public_key[9] = (byte) ((lastPart >> 8) & 0xFF);
572
public_key[10] = (byte) ((lastPart >> 16) & 0xFF);
573
public_key[11] = (byte) ((lastPart >> 24) & 0xFF);
575
Buffer.BlockCopy (publickey, 0, public_key, 12, publickey.Length);
577
Error_AssemblySigning ("The specified key file `" + keyFile + "' has incorrect format");
585
// TODO: Is there better way to test for a private key presence ?
586
CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
587
private_key = new StrongNameKeyPair (snkeypair);
592
void ReadModulesAssemblyAttributes ()
594
foreach (var m in added_modules) {
595
var cattrs = m.ReadAssemblyAttributes ();
599
module.OptAttributes.AddAttributes (cattrs);
603
public void Resolve ()
605
if (Compiler.Settings.Unsafe && module.PredefinedTypes.SecurityAction.Define ()) {
607
// Emits [assembly: SecurityPermissionAttribute (SecurityAction.RequestMinimum, SkipVerification = true)]
608
// when -unsafe option was specified
610
Location loc = Location.Null;
612
MemberAccess system_security_permissions = new MemberAccess (new MemberAccess (
613
new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Security", loc), "Permissions", loc);
615
var req_min = module.PredefinedMembers.SecurityActionRequestMinimum.Resolve (loc);
617
Arguments pos = new Arguments (1);
618
pos.Add (new Argument (req_min.GetConstant (null)));
620
Arguments named = new Arguments (1);
621
named.Add (new NamedArgument ("SkipVerification", loc, new BoolLiteral (Compiler.BuiltinTypes, true, loc)));
623
Attribute g = new Attribute ("assembly",
624
new MemberAccess (system_security_permissions, "SecurityPermissionAttribute"),
625
new Arguments[] { pos, named }, loc, false);
626
g.AttachTo (module, module);
627
var ctor = g.Resolve ();
629
g.ExtractSecurityPermissionSet (ctor, ref declarative_security);
633
if (module.OptAttributes == null)
636
// Ensure that we only have GlobalAttributes, since the Search isn't safe with other types.
637
if (!module.OptAttributes.CheckTargets())
640
cls_attribute = module.ResolveAssemblyAttribute (module.PredefinedAttributes.CLSCompliant);
642
if (cls_attribute != null) {
643
is_cls_compliant = cls_attribute.GetClsCompliantAttributeValue ();
646
if (added_modules != null && Compiler.Settings.VerifyClsCompliance && is_cls_compliant) {
647
foreach (var m in added_modules) {
648
if (!m.IsCLSCompliant) {
650
"Added modules must be marked with the CLSCompliant attribute to match the assembly",
656
Attribute a = module.ResolveAssemblyAttribute (module.PredefinedAttributes.RuntimeCompatibility);
658
var val = a.GetNamedValue ("WrapNonExceptionThrows") as BoolConstant;
660
wrap_non_exception_throws = val.Value;
664
protected void ResolveAssemblySecurityAttributes ()
666
string key_file = null;
667
string key_container = null;
669
if (module.OptAttributes != null) {
670
foreach (Attribute a in module.OptAttributes.Attrs) {
671
// cannot rely on any resolve-based members before you call Resolve
672
if (a.ExplicitTarget != "assembly")
675
// TODO: This code is buggy: comparing Attribute name without resolving is wrong.
676
// However, this is invoked by CodeGen.Init, when none of the namespaces
678
// TODO: Does not handle quoted attributes properly
680
case "AssemblyKeyFile":
681
case "AssemblyKeyFileAttribute":
682
case "System.Reflection.AssemblyKeyFileAttribute":
683
if (Compiler.Settings.StrongNameKeyFile != null) {
684
Report.SymbolRelatedToPreviousError (a.Location, a.GetSignatureForError ());
685
Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
686
"keyfile", "System.Reflection.AssemblyKeyFileAttribute");
688
string value = a.GetString ();
689
if (!string.IsNullOrEmpty (value)) {
690
Error_ObsoleteSecurityAttribute (a, "keyfile");
695
case "AssemblyKeyName":
696
case "AssemblyKeyNameAttribute":
697
case "System.Reflection.AssemblyKeyNameAttribute":
698
if (Compiler.Settings.StrongNameKeyContainer != null) {
699
Report.SymbolRelatedToPreviousError (a.Location, a.GetSignatureForError ());
700
Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
701
"keycontainer", "System.Reflection.AssemblyKeyNameAttribute");
703
string value = a.GetString ();
704
if (!string.IsNullOrEmpty (value)) {
705
Error_ObsoleteSecurityAttribute (a, "keycontainer");
706
key_container = value;
710
case "AssemblyDelaySign":
711
case "AssemblyDelaySignAttribute":
712
case "System.Reflection.AssemblyDelaySignAttribute":
713
bool b = a.GetBoolean ();
715
Error_ObsoleteSecurityAttribute (a, "delaysign");
724
// We came here only to report assembly attributes warnings
725
if (public_key != null)
729
// Load the strong key file found in attributes when no
730
// command line key was given
732
if (key_file != null || key_container != null) {
733
LoadPublicKey (key_file, key_container);
734
} else if (delay_sign) {
735
Report.Warning (1607, 1, "Delay signing was requested but no key file was given");
739
public void EmbedResources ()
742
// Add Win32 resources
744
if (Compiler.Settings.Win32ResourceFile != null) {
745
Builder.DefineUnmanagedResource (Compiler.Settings.Win32ResourceFile);
747
Builder.DefineVersionInfoResource ();
750
if (Compiler.Settings.Win32IconFile != null) {
751
builder_extra.DefineWin32IconResource (Compiler.Settings.Win32IconFile);
754
if (Compiler.Settings.Resources != null) {
755
if (Compiler.Settings.Target == Target.Module) {
756
Report.Error (1507, "Cannot link resource file when building a module");
759
foreach (var res in Compiler.Settings.Resources) {
760
if (!File.Exists (res.FileName)) {
761
Report.Error (1566, "Error reading resource file `{0}'", res.FileName);
767
if (counter++ < 10) {
768
stream = File.OpenRead (res.FileName);
770
// TODO: SRE API requires resource stream to be available during AssemblyBuilder::Save
771
// we workaround it by reading everything into memory to compile projects with
772
// many embedded resource (over 3500) references
773
stream = new MemoryStream (File.ReadAllBytes (res.FileName));
776
module.Builder.DefineManifestResource (res.Name, stream, res.Attributes);
778
Builder.AddResourceFile (res.Name, Path.GetFileName (res.FileName), res.Attributes);
787
PortableExecutableKinds pekind = PortableExecutableKinds.ILOnly;
788
ImageFileMachine machine;
790
switch (Compiler.Settings.Platform) {
792
pekind |= PortableExecutableKinds.Required32Bit;
793
machine = ImageFileMachine.I386;
796
pekind |= PortableExecutableKinds.PE32Plus;
797
machine = ImageFileMachine.AMD64;
800
machine = ImageFileMachine.IA64;
802
case Platform.AnyCPU32Preferred:
804
pekind |= PortableExecutableKinds.Preferred32Bit;
805
machine = ImageFileMachine.I386;
808
throw new NotSupportedException ();
812
machine = ImageFileMachine.ARM;
815
throw new NotSupportedException ();
817
case Platform.AnyCPU:
819
machine = ImageFileMachine.I386;
823
Compiler.TimeReporter.Start (TimeReporter.TimerType.OutputSave);
825
if (Compiler.Settings.Target == Target.Module) {
826
SaveModule (pekind, machine);
828
Builder.Save (module.Builder.ScopeName, pekind, machine);
830
} catch (Exception e) {
831
Report.Error (16, "Could not write to file `" + name + "', cause: " + e.Message);
833
Compiler.TimeReporter.Stop (TimeReporter.TimerType.OutputSave);
835
// Save debug symbols file
836
if (symbol_writer != null && Compiler.Report.Errors == 0) {
837
// TODO: it should run in parallel
838
Compiler.TimeReporter.Start (TimeReporter.TimerType.DebugSave);
840
var filename = file_name + ".mdb";
842
// We mmap the file, so unlink the previous version since it may be in use
843
File.Delete (filename);
845
// We can safely ignore
848
module.WriteDebugSymbol (symbol_writer);
850
using (FileStream fs = new FileStream (filename, FileMode.Create, FileAccess.Write)) {
851
symbol_writer.CreateSymbolFile (module.Builder.ModuleVersionId, fs);
854
Compiler.TimeReporter.Stop (TimeReporter.TimerType.DebugSave);
858
protected virtual void SaveModule (PortableExecutableKinds pekind, ImageFileMachine machine)
860
Report.RuntimeMissingSupport (Location.Null, "-target:module");
863
void SetCustomAttribute (MethodSpec ctor, byte[] data)
865
if (module_target_attrs != null)
866
module_target_attrs.AddAssemblyAttribute (ctor, data);
868
Builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), data);
871
void SetEntryPoint ()
873
if (!Compiler.Settings.NeedsEntryPoint) {
874
if (Compiler.Settings.MainClass != null)
875
Report.Error (2017, "Cannot specify -main if building a module or library");
880
PEFileKinds file_kind;
882
switch (Compiler.Settings.Target) {
885
file_kind = PEFileKinds.Dll;
888
file_kind = PEFileKinds.WindowApplication;
891
file_kind = PEFileKinds.ConsoleApplication;
895
if (entry_point == null) {
896
string main_class = Compiler.Settings.MainClass;
897
if (main_class != null) {
898
// TODO: Handle dotted names
899
var texpr = module.GlobalRootNamespace.LookupType (module, main_class, 0, LookupMode.Probing, Location.Null);
901
Report.Error (1555, "Could not find `{0}' specified for Main method", main_class);
905
var mtype = texpr.Type.MemberDefinition as ClassOrStruct;
907
Report.Error (1556, "`{0}' specified for Main method must be a valid class or struct", main_class);
911
Report.Error (1558, mtype.Location, "`{0}' does not have a suitable static Main method", mtype.GetSignatureForError ());
913
string pname = file_name == null ? name : Path.GetFileName (file_name);
914
Report.Error (5001, "Program `{0}' does not contain a static `Main' method suitable for an entry point",
921
Builder.SetEntryPoint (entry_point.MethodBuilder, file_kind);
924
void Error_ObsoleteSecurityAttribute (Attribute a, string option)
926
Report.Warning (1699, 1, a.Location,
927
"Use compiler option `{0}' or appropriate project settings instead of `{1}' attribute",
931
void Error_AssemblySigning (string text)
933
Report.Error (1548, "Error during assembly signing. " + text);
936
public bool IsFriendAssemblyTo (IAssemblyDefinition assembly)
941
static Version IsValidAssemblyVersion (string version, bool allowGenerated)
943
string[] parts = version.Split ('.');
944
if (parts.Length < 1 || parts.Length > 4)
947
var values = new int[4];
948
for (int i = 0; i < parts.Length; ++i) {
949
if (!int.TryParse (parts[i], out values[i])) {
950
if (parts[i].Length == 1 && parts[i][0] == '*' && allowGenerated) {
952
// Nothing can follow *
953
if (parts.Length > 3)
956
// Generate Build value based on days since 1/1/2000
957
TimeSpan days = DateTime.Today - new DateTime (2000, 1, 1);
958
values[i] = System.Math.Max (days.Days, 0);
963
// Generate Revision value based on every other second today
964
var seconds = DateTime.Now - DateTime.Today;
965
values[i] = (int) seconds.TotalSeconds / 2;
973
if (values[i] > ushort.MaxValue)
977
return new Version (values[0], values[1], values[2], values[3]);
981
public class AssemblyResource : IEquatable<AssemblyResource>
983
public AssemblyResource (string fileName, string name)
984
: this (fileName, name, false)
988
public AssemblyResource (string fileName, string name, bool isPrivate)
992
Attributes = isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public;
995
public ResourceAttributes Attributes { get; private set; }
996
public string Name { get; private set; }
997
public string FileName { get; private set; }
998
public bool IsEmbeded { get; set; }
1000
#region IEquatable<AssemblyResource> Members
1002
public bool Equals (AssemblyResource other)
1004
return Name == other.Name;
1011
// A placeholder class for assembly attributes when emitting module
1013
class AssemblyAttributesPlaceholder : CompilerGeneratedContainer
1015
static readonly string TypeNamePrefix = "<$AssemblyAttributes${0}>";
1016
public static readonly string AssemblyFieldName = "attributes";
1020
public AssemblyAttributesPlaceholder (ModuleContainer parent, string outputName)
1021
: base (parent, new MemberName (GetGeneratedName (outputName)), Modifiers.STATIC | Modifiers.INTERNAL)
1023
assembly = new Field (this, new TypeExpression (parent.Compiler.BuiltinTypes.Object, Location), Modifiers.PUBLIC | Modifiers.STATIC,
1024
new MemberName (AssemblyFieldName), null);
1026
AddField (assembly);
1029
public void AddAssemblyAttribute (MethodSpec ctor, byte[] data)
1031
assembly.SetCustomAttribute (ctor, data);
1034
public static string GetGeneratedName (string outputName)
1036
return string.Format (TypeNamePrefix, outputName);
1041
// Extension to System.Reflection.Emit.AssemblyBuilder to have fully compatible
1042
// compiler. This is a default implementation for framework System.Reflection.Emit
1043
// which does not implement any of the methods
1045
public class AssemblyBuilderExtension
1047
readonly CompilerContext ctx;
1049
public AssemblyBuilderExtension (CompilerContext ctx)
1054
public virtual System.Reflection.Module AddModule (string module)
1056
ctx.Report.RuntimeMissingSupport (Location.Null, "-addmodule");
1060
public virtual void AddPermissionRequests (PermissionSet[] permissions)
1062
ctx.Report.RuntimeMissingSupport (Location.Null, "assembly declarative security");
1065
public virtual void AddTypeForwarder (TypeSpec type, Location loc)
1067
ctx.Report.RuntimeMissingSupport (loc, "TypeForwardedToAttribute");
1070
public virtual void DefineWin32IconResource (string fileName)
1072
ctx.Report.RuntimeMissingSupport (Location.Null, "-win32icon");
1075
public virtual void SetAlgorithmId (uint value, Location loc)
1077
ctx.Report.RuntimeMissingSupport (loc, "AssemblyAlgorithmIdAttribute");
1080
public virtual void SetCulture (string culture, Location loc)
1082
ctx.Report.RuntimeMissingSupport (loc, "AssemblyCultureAttribute");
1085
public virtual void SetFlags (uint flags, Location loc)
1087
ctx.Report.RuntimeMissingSupport (loc, "AssemblyFlagsAttribute");
1090
public virtual void SetVersion (Version version, Location loc)
1092
ctx.Report.RuntimeMissingSupport (loc, "AssemblyVersionAttribute");
1096
abstract class AssemblyReferencesLoader<T>
1098
protected readonly CompilerContext compiler;
1100
protected readonly List<string> paths;
1102
public AssemblyReferencesLoader (CompilerContext compiler)
1104
this.compiler = compiler;
1106
paths = new List<string> ();
1107
paths.AddRange (compiler.Settings.ReferencesLookupPaths);
1108
paths.Add (Directory.GetCurrentDirectory ());
1111
public abstract bool HasObjectType (T assembly);
1112
protected abstract string[] GetDefaultReferences ();
1113
public abstract T LoadAssemblyFile (string fileName, bool isImplicitReference);
1114
public abstract void LoadReferences (ModuleContainer module);
1116
protected void Error_FileNotFound (string fileName)
1118
compiler.Report.Error (6, "Metadata file `{0}' could not be found", fileName);
1121
protected void Error_FileCorrupted (string fileName)
1123
compiler.Report.Error (9, "Metadata file `{0}' does not contain valid metadata", fileName);
1126
protected void Error_AssemblyIsModule (string fileName)
1128
compiler.Report.Error (1509,
1129
"Referenced assembly file `{0}' is a module. Consider using `-addmodule' option to add the module",
1133
protected void Error_ModuleIsAssembly (string fileName)
1135
compiler.Report.Error (1542,
1136
"Added module file `{0}' is an assembly. Consider using `-r' option to reference the file",
1140
protected void LoadReferencesCore (ModuleContainer module, out T corlib_assembly, out List<Tuple<RootNamespace, T>> loaded)
1142
compiler.TimeReporter.Start (TimeReporter.TimerType.ReferencesLoading);
1144
loaded = new List<Tuple<RootNamespace, T>> ();
1147
// Load mscorlib.dll as the first
1149
if (module.Compiler.Settings.StdLib) {
1150
corlib_assembly = LoadAssemblyFile ("mscorlib.dll", true);
1152
corlib_assembly = default (T);
1156
foreach (string r in module.Compiler.Settings.AssemblyReferences) {
1157
a = LoadAssemblyFile (r, false);
1158
if (a == null || EqualityComparer<T>.Default.Equals (a, corlib_assembly))
1161
var key = Tuple.Create (module.GlobalRootNamespace, a);
1162
if (loaded.Contains (key))
1165
// A corlib assembly is the first assembly which contains System.Object
1166
if (corlib_assembly == null && HasObjectType (a)) {
1167
corlib_assembly = a;
1174
foreach (var entry in module.Compiler.Settings.AssemblyReferencesAliases) {
1175
a = LoadAssemblyFile (entry.Item2, false);
1179
var key = Tuple.Create (module.CreateRootNamespace (entry.Item1), a);
1180
if (loaded.Contains (key))
1186
if (compiler.Settings.LoadDefaultReferences) {
1187
foreach (string r in GetDefaultReferences ()) {
1188
a = LoadAssemblyFile (r, true);
1192
var key = Tuple.Create (module.GlobalRootNamespace, a);
1193
if (loaded.Contains (key))
1200
compiler.TimeReporter.Stop (TimeReporter.TimerType.ReferencesLoading);