update readme (#21797)
[mono-project.git] / mcs / tools / al / Al.cs
blob3670d2f2eb94c6562db2a34b84eb5653165e4c07
1 //
2 // Mono.AssemblyLinker.AssemblyLinker
3 //
4 // Author(s):
5 // Zoltan Varga (vargaz@freemail.hu)
6 //
7 // (C) Ximian, Inc. http://www.ximian.com
8 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
9 //
11 using System;
12 using System.Globalization;
13 using System.IO;
14 using System.Collections;
15 using System.Collections.Generic;
16 using System.Security.Cryptography;
17 using System.Text;
18 using System.Configuration.Assemblies;
20 using IKVM.Reflection;
21 using IKVM.Reflection.Emit;
22 using Mono.Security.Cryptography;
24 namespace Mono.AssemblyLinker
26 class ModuleInfo {
27 public string fileName;
28 public string target;
31 class ResourceInfo {
32 public string name;
33 public string fileName;
34 public string target;
35 public bool isEmbedded;
36 public bool isPrivate;
39 enum Target {
40 Dll,
41 Exe,
42 Win
45 enum DelaySign {
46 NotSet,
47 Yes,
51 public enum Platform {
52 AnyCPU,
53 AnyCPU32Preferred,
54 Arm,
55 X86,
56 X64,
57 IA64
60 public class AssemblyLinker {
62 ArrayList inputFiles = new ArrayList ();
63 ArrayList resources = new ArrayList ();
64 ArrayList cattrs = new ArrayList ();
65 bool fullPaths;
66 string outFile;
67 string entryPoint;
68 string win32IconFile;
69 string win32ResFile;
70 string title;
71 string description;
72 string company;
73 string product;
74 string copyright;
75 string trademark;
76 string templateFile;
77 bool isTemplateFile = false;
78 Target target = Target.Dll;
79 Platform platform = Platform.AnyCPU;
80 DelaySign delaysign = DelaySign.NotSet;
81 string keyfile;
82 string keyname;
83 string culture;
84 Universe universe;
86 public static int Main (String[] args) {
87 return new AssemblyLinker ().DynMain (args);
90 private int DynMain (String[] args) {
91 using (universe = new Universe (UniverseOptions.MetadataOnly)) {
92 universe.LoadFile (typeof (object).Assembly.Location);
93 ParseArgs (args);
95 DoIt ();
97 return 0;
101 private void ParseArgs (string[] args)
103 ArrayList flat_args = new ArrayList ();
105 // Process response files
106 Hashtable response_files = new Hashtable ();
107 foreach (string str in args) {
108 if (str [0] != '@') {
109 flat_args.Add (str);
110 continue;
113 if (str.Length == 1)
114 ReportMissingFileSpec ("@");
116 string resfile_name = Path.GetFullPath (str.Substring (1));
117 if (response_files.ContainsKey (resfile_name))
118 Report (1006, "Response file '" + resfile_name + "' was already included");
119 response_files [resfile_name] = resfile_name;
120 LoadArgs (resfile_name, flat_args);
123 if (flat_args.Count == 0)
124 Usage ();
126 foreach (string str in flat_args) {
127 if ((str [0] != '-') && (str [0] != '/')) {
128 inputFiles.Add (GetModuleInfo (str));
129 continue;
132 if (!ParseOption(str)) {
133 if (RunningOnUnix) {
134 // cope with absolute filenames for modules on unix, as
135 // they also match the option pattern
137 // `/home/test.cs' is considered as a module, however
138 // '/test.cs' is considered as error
139 if (str.Length > 2 && str.IndexOf ('/', 2) != -1) {
140 inputFiles.Add (GetModuleInfo (str));
141 continue;
145 Report (1013, String.Format ("Unrecognized command line option: '{0}'", str));
146 break;
150 if ((inputFiles.Count == 0) && (resources.Count == 0))
151 Report (1016, "No valid input files were specified");
153 if (outFile == null)
154 Report (1017, "No target filename was specified");
156 if (target == Target.Dll && (entryPoint != null))
157 Report (1035, "Libraries cannot have an entry point");
159 if (target == Target.Exe && (entryPoint == null))
160 Report (1036, "Entry point required for executable applications");
163 private bool ParseOption (string str)
165 string arg;
166 string opt = GetCommand (str, out arg);
168 switch (opt) {
169 case "help":
170 case "?":
171 Usage ();
172 return true;
174 case "embed": {
175 if (arg == null)
176 ReportMissingFileSpec (opt);
177 ResourceInfo res = new ResourceInfo ();
178 res.isEmbedded = true;
179 String [] parts = arg.Split (',');
180 res.fileName = parts [0];
181 if (parts.Length > 1)
182 res.name = parts [1];
183 if (parts.Length > 2) {
184 switch (parts [2]) {
185 case "public":
186 break;
187 case "private":
188 res.isPrivate = true;
189 break;
190 default:
191 ReportInvalidArgument (opt, parts [2]);
192 break;
195 resources.Add (res);
196 return true;
199 case "link": {
200 if (arg == null)
201 ReportMissingFileSpec (opt);
202 ResourceInfo res = new ResourceInfo ();
203 String [] parts = arg.Split (',');
204 res.fileName = parts [0];
205 if (parts.Length > 1)
206 res.name = parts [1];
207 if (parts.Length > 2)
208 res.target = parts [2];
209 if (parts.Length > 3) {
210 switch (parts [3]) {
211 case "public":
212 break;
213 case "private":
214 res.isPrivate = true;
215 break;
216 default:
217 ReportInvalidArgument (opt, parts [3]);
218 break;
221 resources.Add (res);
222 return true;
225 case "algid":
226 if (arg == null)
227 ReportMissingArgument (opt);
228 try {
229 string realArg = arg;
230 if (realArg.StartsWith ("0x"))
231 realArg = realArg.Substring (2);
232 uint val = Convert.ToUInt32 (realArg, 16);
233 AddCattr (typeof (System.Reflection.AssemblyAlgorithmIdAttribute), typeof (uint), val);
234 } catch (Exception) {
235 ReportInvalidArgument (opt, arg);
237 return true;
239 case "base":
240 ReportNotImplemented (opt);
241 return true;
243 case "baseaddress":
244 ReportNotImplemented (opt);
245 return true;
247 case "bugreport":
248 ReportNotImplemented (opt);
249 return true;
251 case "comp":
252 case "company":
253 if (arg == null)
254 ReportMissingText (opt);
255 company = arg;
256 return true;
258 case "config":
259 case "configuration":
260 if (arg == null)
261 ReportMissingText (opt);
262 AddCattr (typeof (System.Reflection.AssemblyConfigurationAttribute), arg);
263 return true;
265 case "copy":
266 case "copyright":
267 if (arg == null)
268 ReportMissingText (opt);
269 copyright = arg;
270 return true;
272 case "c":
273 case "culture":
274 if (arg == null)
275 ReportMissingText (opt);
276 culture = arg;
277 return true;
279 case "delay":
280 case "delaysign":
281 case "delay+":
282 case "delaysign+":
283 delaysign = DelaySign.Yes;
284 return true;
286 case "delay-":
287 case "delaysign-":
288 delaysign = DelaySign.No;
289 return true;
291 case "descr":
292 case "description":
293 if (arg == null)
294 ReportMissingText (opt);
295 description = arg;
296 return true;
298 case "e":
299 case "evidence": {
300 if (arg == null)
301 ReportMissingFileSpec (opt);
302 ResourceInfo res = new ResourceInfo ();
303 res.name = "Security.Evidence";
304 res.fileName = arg;
305 res.isEmbedded = true;
306 res.isPrivate = true;
307 resources.Add (res);
308 return true;
310 case "fileversion":
311 if (arg == null)
312 ReportMissingText (opt);
314 AddCattr (typeof (System.Reflection.AssemblyFileVersionAttribute), arg);
315 return true;
317 case "flags":
318 if (arg == null)
319 ReportMissingArgument (opt);
320 try {
321 string realArg = arg;
322 if (realArg.StartsWith ("0x"))
323 realArg = realArg.Substring (2);
324 uint val = Convert.ToUInt32 (realArg, 16);
325 AddCattr (typeof (System.Reflection.AssemblyFlagsAttribute), typeof (uint), val);
326 } catch (Exception) {
327 ReportInvalidArgument (opt, arg);
329 return true;
331 case "fullpaths":
332 fullPaths = true;
333 return true;
335 case "keyf":
336 case "keyfile":
337 if (arg == null)
338 ReportMissingText (opt);
339 keyfile = arg;
340 return true;
342 case "keyn":
343 case "keyname":
344 if (arg == null)
345 ReportMissingText (opt);
346 keyname = arg;
347 return true;
349 case "main":
350 if (arg == null)
351 ReportMissingText (opt);
352 entryPoint = arg;
353 return true;
355 case "nologo":
356 return true;
358 case "out":
359 if (arg == null)
360 ReportMissingFileSpec (opt);
361 outFile = arg;
362 return true;
364 case "platform":
365 if (arg == null)
366 ReportMissingText (opt);
367 switch (arg.ToLowerInvariant ()) {
368 case "arm":
369 platform = Platform.Arm;
370 break;
371 case "anycpu":
372 platform = Platform.AnyCPU;
373 break;
374 case "x86":
375 platform = Platform.X86;
376 break;
377 case "x64":
378 platform = Platform.X64;
379 break;
380 case "itanium":
381 platform = Platform.IA64;
382 break;
383 case "anycpu32bitpreferred":
384 platform = Platform.AnyCPU32Preferred;
385 break;
386 default:
387 ReportInvalidArgument (opt, arg);
388 break;
390 return true;
392 case "prod":
393 case "product":
394 if (arg == null)
395 ReportMissingText (opt);
396 product = arg;
397 return true;
399 case "productv":
400 case "productversion":
401 if (arg == null)
402 ReportMissingText (opt);
403 AddCattr (typeof (System.Reflection.AssemblyInformationalVersionAttribute), arg);
404 return true;
406 case "t":
407 case "target":
408 if (arg == null)
409 ReportMissingText (opt);
410 switch (arg) {
411 case "lib":
412 case "library":
413 target = Target.Dll;
414 break;
415 case "exe":
416 target = Target.Exe;
417 break;
418 case "win":
419 case "winexe":
420 Report (0, "target:win is not implemented");
421 break;
422 default:
423 ReportInvalidArgument (opt, arg);
424 break;
426 return true;
428 case "template":
429 if (arg == null)
430 ReportMissingFileSpec (opt);
431 isTemplateFile = true;
432 templateFile = Path.Combine (Directory.GetCurrentDirectory (), arg);
433 return true;
435 case "title":
436 if (arg == null)
437 ReportMissingText (opt);
438 title = arg;
439 return true;
441 case "trade":
442 case "trademark":
443 if (arg == null)
444 ReportMissingText (opt);
445 trademark = arg;
446 return true;
448 case "v":
449 case "version":
450 // This option conflicts with the standard UNIX meaning
451 if (arg == null) {
452 Version ();
453 break;
455 AddCattr (typeof (System.Reflection.AssemblyVersionAttribute), arg);
456 return true;
458 case "win32icon":
459 if (arg == null)
460 ReportMissingFileSpec (opt);
461 win32IconFile = arg;
462 return true;
464 case "win32res":
465 if (arg == null)
466 ReportMissingFileSpec (opt);
467 win32ResFile = arg;
468 return true;
470 return false;
473 private bool RunningOnUnix {
474 get {
475 // check for Unix platforms - see FAQ for more details
476 // http://www.mono-project.com/FAQ:_Technical#How_to_detect_the_execution_platform_.3F
477 int platform = (int) Environment.OSVersion.Platform;
478 return ((platform == 4) || (platform == 128) || (platform == 6));
482 private ModuleInfo GetModuleInfo (string str)
484 string [] parts = str.Split (',');
485 ModuleInfo mod = new ModuleInfo ();
486 mod.fileName = parts [0];
487 if (parts.Length > 1)
488 mod.target = parts [1];
489 return mod;
492 private string GetCommand (string str, out string command_arg) {
493 if ((str [0] == '-') && (str.Length > 1) && (str [1] == '-'))
494 str = str.Substring (1);
496 int end_index = str.IndexOfAny (new char[] {':', '='}, 1);
497 string command = str.Substring (1,
498 end_index == -1 ? str.Length - 1 : end_index - 1);
500 if (end_index != -1) {
501 command_arg = str.Substring (end_index+1);
502 if (command_arg == String.Empty)
503 command_arg = null;
504 } else {
505 command_arg = null;
508 return command.ToLower ();
511 private void AddCattr (System.Type attrType, System.Type arg, object value) {
512 var importedAttrType = universe.Import(attrType);
513 var importedArg = universe.Import(arg);
515 cattrs.Add (new CustomAttributeBuilder (importedAttrType.GetConstructor (new [] { importedArg }), new [] { value }));
518 private void AddCattr (System.Type attrType, object value) {
519 AddCattr (attrType, typeof (string), value);
522 private void PrintVersion () {
523 Console.WriteLine ("Mono Assembly Linker (al.exe) version " + Consts.MonoVersion);
526 private void Version () {
527 PrintVersion ();
528 Environment.Exit (0);
531 private void Usage () {
532 PrintVersion ();
534 foreach (string s in usage)
535 Console.WriteLine (s);
536 Environment.Exit (0);
539 private void Report (int errorNum, string msg) {
540 Console.WriteLine (String.Format ("ALINK: error A{0:0000}: {1}", errorNum, msg));
541 Environment.Exit (1);
544 private void ReportWarning (int errorNum, string msg) {
545 Console.WriteLine (String.Format ("ALINK: warning A{0:0000}: {1}", errorNum, msg));
548 private void ReportInvalidArgument (string option, string value) {
549 Report (1012, String.Format ("'{0}' is not a valid setting for option '{1}'", value, option));
552 private void ReportMissingArgument (string option) {
553 Report (1003, String.Format ("Compiler option '{0}' must be followed by an argument", option));
556 private void ReportNotImplemented (string option) {
557 Report (0, String.Format ("Compiler option '{0}' is not implemented", option));
560 private void ReportMissingFileSpec (string option) {
561 Report (1008, String.Format ("Missing file specification for '{0}' command-line option", option));
564 private void ReportMissingText (string option) {
565 Report (1010, String.Format ("Missing ':<text>' for '{0}' option", option));
568 // copied from /mcs/mcs/codegen.cs
569 private void SetPublicKey (AssemblyName an, byte[] strongNameBlob)
571 // check for possible ECMA key
572 if (strongNameBlob.Length == 16) {
573 // will be rejected if not "the" ECMA key
574 an.SetPublicKey (strongNameBlob);
575 } else {
576 // take it, with or without, a private key
577 RSA rsa = CryptoConvert.FromCapiKeyBlob (strongNameBlob);
578 // and make sure we only feed the public part to Sys.Ref
579 byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
581 // AssemblyName.SetPublicKey requires an additional header
582 byte[] publicKeyHeader = new byte [12] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00 };
584 byte[] encodedPublicKey = new byte [12 + publickey.Length];
585 Buffer.BlockCopy (publicKeyHeader, 0, encodedPublicKey, 0, 12);
586 Buffer.BlockCopy (publickey, 0, encodedPublicKey, 12, publickey.Length);
587 an.SetPublicKey (encodedPublicKey);
591 private void SetKeyPair (AssemblyName aname)
593 if (keyfile != null) {
594 if (!File.Exists (keyfile)) {
595 Report (1044, String.Format ("Couldn't open '{0}' key file.", keyfile));
598 using (FileStream fs = File.OpenRead (keyfile)) {
599 byte[] data = new byte [fs.Length];
600 try {
601 fs.Read (data, 0, data.Length);
603 if (delaysign == DelaySign.Yes) {
604 SetPublicKey (aname, data);
605 } else {
606 CryptoConvert.FromCapiPrivateKeyBlob (data);
607 aname.KeyPair = new StrongNameKeyPair (data);
610 catch (CryptographicException) {
611 if (delaysign != DelaySign.Yes) {
612 if (data.Length == 16) {
613 // error # is different for ECMA key
614 Report (1019, "Could not strongname the assembly. " +
615 "ECMA key can only be used to delay-sign assemblies");
616 } else {
617 Report (1028, String.Format ("Key file {0}' is missing it's private key " +
618 "or couldn't be decoded.", keyfile));
620 } else {
621 Report (1044, String.Format ("Couldn't decode '{0}' key file.", keyfile));
624 fs.Close ();
626 } else if (keyname != null) {
627 // delay-sign doesn't apply to key containers
628 aname.KeyPair = new StrongNameKeyPair (keyname);
632 private void DoIt () {
633 AssemblyName aname = new AssemblyName ();
634 aname.Name = Path.GetFileNameWithoutExtension (outFile);
635 if (culture != null)
636 aname.CultureInfo = new CultureInfo (culture);
638 string fileName = Path.GetFileName (outFile);
640 AssemblyBuilder ab;
643 * Emit Manifest
644 * */
646 if (isTemplateFile)
647 aname = ReadCustomAttributesFromTemplateFile (templateFile, aname);
649 if (!String.IsNullOrEmpty (title))
650 AddCattr (typeof (System.Reflection.AssemblyTitleAttribute), title);
651 if (!String.IsNullOrEmpty (description))
652 AddCattr (typeof (System.Reflection.AssemblyDescriptionAttribute), description);
653 if (!String.IsNullOrEmpty (company))
654 AddCattr (typeof (System.Reflection.AssemblyCompanyAttribute), company);
655 if (!String.IsNullOrEmpty (product))
656 AddCattr (typeof (System.Reflection.AssemblyProductAttribute), product);
657 if (!String.IsNullOrEmpty (copyright))
658 AddCattr (typeof (System.Reflection.AssemblyCopyrightAttribute), copyright);
659 if (!String.IsNullOrEmpty (trademark))
660 AddCattr (typeof (System.Reflection.AssemblyTrademarkAttribute), trademark);
662 SetKeyPair (aname);
664 if (fileName != outFile)
665 ab = universe.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Save, Path.GetDirectoryName (outFile));
666 else
667 ab = universe.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Save);
669 foreach (CustomAttributeBuilder cb in cattrs)
670 ab.SetCustomAttribute (cb);
673 * Emit modules
676 foreach (ModuleInfo mod in inputFiles) {
677 if (mod.target != null) {
678 File.Copy (mod.fileName, mod.target, true);
679 mod.fileName = mod.target;
682 bool isAssembly = false;
683 try {
684 AssemblyName.GetAssemblyName (mod.fileName);
685 isAssembly = true;
687 catch (Exception) {
690 if (isAssembly)
691 ReportWarning (1020, "Ignoring included assembly '" + mod.fileName + "'");
692 else
693 ab.__AddModule (universe.OpenRawModule(mod.fileName));
697 * Set entry point
700 if (entryPoint != null) {
701 string mainClass = entryPoint.Substring (0, entryPoint.LastIndexOf ('.'));
702 string mainMethod = entryPoint.Substring (entryPoint.LastIndexOf ('.') + 1);
704 MethodInfo mainMethodInfo = null;
706 try {
707 IKVM.Reflection.Type mainType = ab.GetType (mainClass);
708 if (mainType != null)
709 mainMethodInfo = mainType.GetMethod (mainMethod);
711 catch (Exception ex) {
712 Console.WriteLine (ex);
714 if (mainMethodInfo != null)
715 ab.SetEntryPoint (mainMethodInfo);
716 else
717 Report (1037, "Unable to find the entry point method '" + entryPoint + "'");
721 * Emit resources
724 ab.DefineVersionInfoResource ();
726 if (win32IconFile != null) {
727 try {
728 ab.__DefineIconResource (File.ReadAllBytes (win32IconFile));
730 catch (Exception ex) {
731 Report (1031, "Error reading icon '" + win32IconFile + "' --" + ex);
735 if (win32ResFile != null) {
736 try {
737 ab.DefineUnmanagedResource (win32ResFile);
739 catch (Exception ex) {
740 Report (1019, "Metadata failure creating assembly -- " + ex);
744 ModuleBuilder mainModule = null;
746 foreach (ResourceInfo res in resources) {
747 if (res.name == null)
748 res.name = Path.GetFileName (res.fileName);
750 foreach (ResourceInfo res2 in resources)
751 if ((res != res2) && (res.name == res2.name))
752 Report (1046, String.Format ("Resource identifier '{0}' has already been used in this assembly", res.name));
754 if (res.isEmbedded) {
755 if (mainModule == null) {
756 mainModule = ab.DefineDynamicModule (fileName, fileName, false);
759 Stream stream = new MemoryStream (File.ReadAllBytes (res.fileName));
761 mainModule.DefineManifestResource (res.name, stream, res.isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public);
763 else {
764 if (res.target != null) {
765 File.Copy (res.fileName, res.target, true);
766 res.fileName = res.target;
769 // AddResourceFile must receive a file name and not a path.
770 // Drop directory and give warning if we have a path.
771 var resourceFileName = Path.GetFileName(res.fileName);
772 if (Path.GetDirectoryName (res.fileName) != null || Path.IsPathRooted(res.fileName)) {
773 ReportWarning (99999,
774 String.Format ("Path '{0}' in the resource name is not supported. Using just file name '{1}'",
775 res.fileName,
776 resourceFileName));
779 ab.AddResourceFile (res.name, resourceFileName,
780 res.isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public);
784 PortableExecutableKinds pekind = PortableExecutableKinds.ILOnly;
785 ImageFileMachine machine;
787 switch (platform) {
788 case Platform.X86:
789 pekind |= PortableExecutableKinds.Required32Bit;
790 machine = ImageFileMachine.I386;
791 break;
792 case Platform.X64:
793 pekind |= PortableExecutableKinds.PE32Plus;
794 machine = ImageFileMachine.AMD64;
795 break;
796 case Platform.IA64:
797 machine = ImageFileMachine.IA64;
798 break;
799 case Platform.AnyCPU32Preferred:
800 pekind |= PortableExecutableKinds.Preferred32Bit;
801 machine = ImageFileMachine.I386;
802 break;
803 case Platform.Arm:
804 machine = ImageFileMachine.ARM;
805 break;
806 case Platform.AnyCPU:
807 default:
808 machine = ImageFileMachine.I386;
809 break;
812 try {
813 ab.Save (fileName, pekind, machine);
815 catch (Exception ex) {
816 Report (1019, "Metadata failure creating assembly -- " + ex);
820 private AssemblyName ReadCustomAttributesFromTemplateFile (string templateFile, AssemblyName aname)
822 // LAMESPEC: according to MSDN, the template assembly must have a
823 // strong name but this is not enforced
824 var asm = universe.LoadFile (templateFile);
826 // Create missing assemblies, we don't want to load them!
827 // Code taken from ikdasm
828 var names = new HashSet<string> ();
829 AssemblyName[] assembly_refs = asm.ManifestModule.__GetReferencedAssemblies ();
831 var resolved_assemblies = new Assembly [assembly_refs.Length];
832 for (int i = 0; i < resolved_assemblies.Length; i++) {
833 string name = assembly_refs [i].Name;
835 while (names.Contains (name)) {
836 name = name + "_" + i;
838 names.Add (name);
839 resolved_assemblies [i] = universe.CreateMissingAssembly (assembly_refs [i].FullName);
841 asm.ManifestModule.__ResolveReferencedAssemblies (resolved_assemblies);
843 foreach (var attr_data in asm.__GetCustomAttributes (null, false)) {
844 string asm_name = attr_data.AttributeType.Assembly.GetName ().Name;
845 if (asm_name != "mscorlib")
846 continue;
848 switch (attr_data.AttributeType.FullName) {
849 case "System.Reflection.AssemblyKeyFileAttribute": {
850 if (keyfile != null)
851 // ignore if specified on command line
852 continue;
854 // / AssemblyKeyFileAttribute .ctor(string keyFile)
855 string key_file_value = (string) attr_data.ConstructorArguments [0].Value;
857 if (!String.IsNullOrEmpty (key_file_value))
858 keyfile = Path.Combine (Path.GetDirectoryName (templateFile), key_file_value);
860 break;
862 case "System.Reflection.AssemblyDelaySignAttribute": {
863 if (delaysign != DelaySign.NotSet)
864 // ignore if specified on command line
865 continue;
867 // AssemblyDelaySignAttribute .ctor(bool delaySign)
868 bool delay_sign_value = (bool) attr_data.ConstructorArguments [0].Value;
869 delaysign = delay_sign_value ? DelaySign.Yes : DelaySign.No;
871 break;
873 case "System.Reflection.AssemblyKeyNameAttribute": {
874 if (keyname != null)
875 // ignore if specified on command line
876 continue;
878 // AssemblyKeyNameAttribute .ctor(string keyName)
879 string key_name_value = (string) attr_data.ConstructorArguments [0].Value;
881 // ignore null or zero-length keyname
882 if (!String.IsNullOrEmpty (key_name_value))
883 keyname = key_name_value;
885 break;
887 case "System.Reflection.AssemblyTitleAttribute": {
888 if (title != null)
889 // ignore if specified on command line
890 continue;
892 // AssemblyTitleAttribute .ctor(string title)
893 string title_value = (string) attr_data.ConstructorArguments [0].Value;
895 if (!String.IsNullOrEmpty (title_value))
896 title = title_value;
898 break;
900 case "System.Reflection.AssemblyDescriptionAttribute": {
901 if (description != null)
902 // ignore if specified on command line
903 continue;
905 // AssemblyDescriptionAttribute .ctor(string description)
906 string description_value = (string) attr_data.ConstructorArguments [0].Value;
908 if (!String.IsNullOrEmpty (description_value))
909 description = description_value;
911 break;
913 case "System.Reflection.AssemblyProductAttribute": {
914 if (product != null)
915 // ignore if specified on command line
916 continue;
918 // AssemblyProductAttribute .ctor(string product)
919 string product_value = (string) attr_data.ConstructorArguments [0].Value;
921 if (!String.IsNullOrEmpty (product_value))
922 product = product_value;
924 break;
926 case "System.Reflection.AssemblyCompanyAttribute": {
927 if (company != null)
928 // ignore if specified on command line
929 continue;
931 // AssemblyCompanyAttribute .ctor(string company)
932 string company_value = (string) attr_data.ConstructorArguments [0].Value;
934 if (!String.IsNullOrEmpty (company_value))
935 company = company_value;
938 break;
940 case "System.Reflection.AssemblyCopyrightAttribute": {
941 if (copyright != null)
942 // ignore if specified on command line
943 continue;
945 // AssemblyCopyrightAttribute .ctor(string copyright)
946 string copyright_value = (string) attr_data.ConstructorArguments [0].Value;
948 if (!String.IsNullOrEmpty (copyright_value))
949 copyright = copyright_value;
951 break;
953 case "System.Reflection.AssemblyTrademarkAttribute": {
954 if (trademark != null)
955 // ignore if specified on command line
956 continue;
958 // AssemblyTrademarkAttribute .ctor(string trademark)
959 string trademark_value = (string) attr_data.ConstructorArguments [0].Value;
961 if (!String.IsNullOrEmpty (trademark_value))
962 trademark = trademark_value;
964 break;
968 var asm_name_for_template_file = asm.GetName ();
969 aname.Version = asm_name_for_template_file.Version;
970 aname.HashAlgorithm = asm_name_for_template_file.HashAlgorithm;
972 return aname;
975 private void LoadArgs (string file, ArrayList args) {
976 StreamReader f = null;
977 string line;
978 try {
979 f = new StreamReader (file);
981 StringBuilder sb = new StringBuilder ();
983 while ((line = f.ReadLine ()) != null){
984 int t = line.Length;
986 for (int i = 0; i < t; i++){
987 char c = line [i];
989 if (c == '"' || c == '\''){
990 char end = c;
992 for (i++; i < t; i++){
993 c = line [i];
995 if (c == end)
996 break;
997 sb.Append (c);
999 } else if (c == ' '){
1000 if (sb.Length > 0){
1001 args.Add (sb.ToString ());
1002 sb.Length = 0;
1004 } else
1005 sb.Append (c);
1007 if (sb.Length > 0){
1008 args.Add (sb.ToString ());
1009 sb.Length = 0;
1012 } catch (Exception ex) {
1013 Report (1007, "Error opening response file '" + file + "' -- '" + ex.Message + "'");
1014 } finally {
1015 if (f != null)
1016 f.Close ();
1020 string[] usage = {
1021 "Usage: al [options] [sources]",
1022 "Options: ('/out' must be specified)",
1024 " /? or /help Display this usage message",
1025 " @<filename> Read response file for more options",
1026 " /algid:<id> Algorithm used to hash files (in hexadecimal)",
1027 " /base[address]:<addr> Base address for the library",
1028 " /bugreport:<filename> Create a 'Bug Report' file",
1029 " /comp[any]:<text> Company name",
1030 " /config[uration]:<text> Configuration string",
1031 " /copy[right]:<text> Copyright message",
1032 " /c[ulture]:<text> Supported culture",
1033 " /delay[sign][+|-] Delay sign this assembly",
1034 " /descr[iption]:<text> Description",
1035 " /e[vidence]:<filename> Security evidence file to embed",
1036 " /fileversion:<version> Optional Win32 version (overrides assembly version)",
1037 " /flags:<flags> Assembly flags (in hexadecimal)",
1038 " /fullpaths Display files using fully-qualified filenames",
1039 " /keyf[ile]:<filename> File containing key to sign the assembly",
1040 " /keyn[ame]:<text> Key container name of key to sign assembly",
1041 " /main:<method> Specifies the method name of the entry point",
1042 " /nologo Suppress the startup banner and copyright message",
1043 " /out:<filename> Output file name for the assembly manifest",
1044 " /platform:<text> Limit which platforms this code can run on; must be",
1045 " one of x86, Itanium, x64, arm, anycpu32bitpreferred,",
1046 " or anycpu (the default)",
1047 " /prod[uct]:<text> Product name",
1048 " /productv[ersion]:<text> Product version",
1049 " /t[arget]:lib[rary] Create a library",
1050 " /t[arget]:exe Create a console executable",
1051 " /t[arget]:win[exe] Create a Windows executable",
1052 " /template:<filename> Specifies an assembly to get default options from",
1053 " /title:<text> Title",
1054 " /trade[mark]:<text> Trademark message",
1055 " /v[ersion]:<version> Version (use * to auto-generate remaining numbers)",
1056 " /win32icon:<filename> Use this icon for the output",
1057 " /win32res:<filename> Specifies the Win32 resource file",
1059 "Sources: (at least one source input is required)",
1060 " <filename>[,<targetfile>] add file to assembly",
1061 " /embed[resource]:<filename>[,<name>[,Private]]",
1062 " embed the file as a resource in the assembly",
1063 " /link[resource]:<filename>[,<name>[,<targetfile>[,Private]]]",
1064 " link the file as a resource to the assembly",