2 // Mono.AssemblyLinker.AssemblyLinker
5 // Zoltan Varga (vargaz@freemail.hu)
7 // (C) Ximian, Inc. http://www.ximian.com
13 using System.Collections;
14 using System.Reflection;
15 using System.Reflection.Emit;
17 namespace Mono.AssemblyLinker
20 public string fileName;
26 public string fileName;
28 public bool isEmbedded;
29 public bool isPrivate;
38 public class AssemblyLinker {
40 ArrayList inputFiles = new ArrayList ();
41 ArrayList resources = new ArrayList ();
42 ArrayList cattrs = new ArrayList ();
51 public static int Main (String[] args) {
52 return new AssemblyLinker ().DynMain (args);
55 private int DynMain (String[] args) {
63 private void ParseArgs (string[] args) {
68 foreach (string str in args) {
69 if ((str [0] != '-') && (str [0] != '/')) {
70 string[] parts = str.Split (',');
71 ModuleInfo mod = new ModuleInfo ();
72 mod.fileName = parts [0];
74 mod.target = parts [1];
80 string opt = GetCommand (str, out arg);
91 ReportMissingFileSpec (opt);
92 res = new ResourceInfo ();
93 res.isEmbedded = true;
94 String[] parts = arg.Split (',');
95 res.fileName = parts [0];
98 if (parts.Length > 2) {
103 res.isPrivate = true;
106 ReportInvalidArgument (opt, parts [2]);
116 ReportMissingFileSpec (opt);
117 res = new ResourceInfo ();
118 String[] parts = arg.Split (',');
119 res.fileName = parts [0];
120 if (parts.Length > 1)
121 res.name = parts [1];
122 if (parts.Length > 2)
123 res.target = parts [2];
124 if (parts.Length > 3) {
129 res.isPrivate = true;
132 ReportInvalidArgument (opt, parts [3]);
142 ReportMissingArgument (opt);
144 int val = Int32.Parse (arg);
145 AddCattr (typeof (AssemblyAlgorithmIdAttribute), typeof (uint), val);
148 ReportInvalidArgument (opt, arg);
153 ReportNotImplemented (opt);
157 ReportNotImplemented (opt);
161 ReportNotImplemented (opt);
167 ReportMissingText (opt);
168 AddCattr (typeof (AssemblyCompanyAttribute), arg);
172 case "configuration":
174 ReportMissingText (opt);
175 AddCattr (typeof (AssemblyConfigurationAttribute), arg);
181 ReportMissingText (opt);
182 AddCattr (typeof (AssemblyCopyrightAttribute), arg);
188 ReportMissingText (opt);
189 AddCattr (typeof (AssemblyCultureAttribute), arg);
194 ReportNotImplemented (opt);
200 ReportMissingText (opt);
201 AddCattr (typeof (AssemblyDescriptionAttribute), arg);
207 ReportMissingFileSpec (opt);
208 res = new ResourceInfo ();
209 res.name = "Security.Evidence";
211 res.isEmbedded = true;
212 res.isPrivate = true;
218 ReportMissingText (opt);
220 AddCattr (typeof (AssemblyFileVersionAttribute), arg);
225 ReportMissingArgument (opt);
227 int val = Int32.Parse (arg);
228 AddCattr (typeof (AssemblyFlagsAttribute), typeof (uint), val);
231 ReportInvalidArgument (opt, arg);
242 ReportMissingText (opt);
243 AddCattr (typeof (AssemblyKeyFileAttribute), arg);
249 ReportMissingText (opt);
250 AddCattr (typeof (AssemblyKeyNameAttribute), arg);
255 ReportMissingText (opt);
264 ReportMissingFileSpec (opt);
271 ReportMissingText (opt);
272 AddCattr (typeof (AssemblyProductAttribute), arg);
276 case "productversion":
278 ReportMissingText (opt);
279 AddCattr (typeof (AssemblyInformationalVersionAttribute), arg);
285 ReportMissingText (opt);
296 Report (0, "target:win is not implemented");
299 ReportInvalidArgument (opt, arg);
306 ReportMissingFileSpec (opt);
307 ReportNotImplemented (opt);
312 ReportMissingText (opt);
313 AddCattr (typeof (AssemblyTitleAttribute), arg);
319 ReportMissingText (opt);
320 AddCattr (typeof (AssemblyTrademarkAttribute), arg);
325 // This option conflicts with the standard UNIX meaning
330 AddCattr (typeof (AssemblyVersionAttribute), arg);
335 ReportMissingFileSpec (opt);
341 ReportMissingFileSpec (opt);
346 Report (1013, String.Format ("Unrecognized command line option: '{0}'", opt));
351 if ((inputFiles.Count == 0) && (resources.Count == 0))
352 Report (1016, "No valid input files were specified");
355 Report (1017, "No target filename was specified");
357 if (target == Target.Dll && (entryPoint != null))
358 Report (1035, "Libraries cannot have an entry point");
360 if (target == Target.Exe && (entryPoint == null))
361 Report (1036, "Entry point required for executable applications");
364 private string GetCommand (string str, out string command_arg) {
365 if ((str [0] == '-') && (str.Length > 1) && (str [1] == '-'))
366 str = str.Substring (1);
368 int end_index = str.IndexOfAny (new char[] {':', '='}, 1);
369 string command = str.Substring (1,
370 end_index == -1 ? str.Length - 1 : end_index - 1);
372 if (end_index != -1) {
373 command_arg = str.Substring (end_index+1);
374 if (command_arg == String.Empty)
380 return command.ToLower ();
383 private void AddCattr (Type attrType, Type arg, object value) {
384 cattrs.Add (new CustomAttributeBuilder (attrType.GetConstructor (new Type [] { arg }), new object [] { value }));
387 private void AddCattr (Type attrType, object value) {
388 AddCattr (attrType, typeof (string), value);
391 private void AddResource (ResourceInfo res) {
392 foreach (ResourceInfo res2 in resources) {
393 if (res.name == res2.name) {
400 private void PrintVersion () {
401 Console.WriteLine ("Mono Assembly Linker (al.exe) version " + Assembly.GetExecutingAssembly ().GetName ().Version.ToString ());
404 private void Version () {
406 Environment.Exit (0);
409 private void Usage () {
412 foreach (string s in usage)
413 Console.WriteLine (s);
414 Environment.Exit (0);
417 private void Report (int errorNum, string msg) {
418 Console.WriteLine (String.Format ("ALINK: error A{0:0000}: {1}", errorNum, msg));
419 Environment.Exit (1);
422 private void ReportWarning (int errorNum, string msg) {
423 Console.WriteLine (String.Format ("ALINK: warning A{0:0000}: {1}", errorNum, msg));
426 private void ReportInvalidArgument (string option, string value) {
427 Report (1012, String.Format ("'{0}' is not a valid setting for option '{1}'", value, option));
430 private void ReportMissingArgument (string option) {
431 Report (1003, String.Format ("Compiler option '{0}' must be followed by an argument", option));
434 private void ReportNotImplemented (string option) {
435 Report (0, String.Format ("Compiler option '{0}' is not implemented", option));
438 private void ReportMissingFileSpec (string option) {
439 Report (1008, String.Format ("Missing file specification for '{0}' command-line option", option));
442 private void ReportMissingText (string option) {
443 Report (1010, String.Format ("Missing ':<text>' for '{0}' option", option));
446 private void DoIt () {
447 AssemblyName aname = new AssemblyName ();
448 aname.Name = Path.GetFileNameWithoutExtension (outFile);
450 string fileName = Path.GetFileName (outFile);
454 if (fileName != outFile)
455 ab = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Save, Path.GetDirectoryName (outFile));
457 ab = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Save);
459 foreach (CustomAttributeBuilder cb in cattrs)
460 ab.SetCustomAttribute (cb);
466 foreach (ModuleInfo mod in inputFiles) {
467 MethodInfo mi = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
469 Report (0, "Cannot add modules on this runtime: try the Mono runtime instead.");
471 if (mod.target != null) {
472 File.Copy (mod.fileName, mod.target, true);
473 mod.fileName = mod.target;
476 bool isAssembly = false;
478 AssemblyName.GetAssemblyName (mod.fileName);
485 ReportWarning (1020, "Ignoring included assembly '" + mod.fileName + "'");
487 mi.Invoke (ab, new object [] { mod.fileName });
494 if (entryPoint != null) {
495 string mainClass = entryPoint.Substring (0, entryPoint.LastIndexOf ('.'));
496 string mainMethod = entryPoint.Substring (entryPoint.LastIndexOf ('.') + 1);
498 MethodInfo mainMethodInfo = null;
501 Type mainType = ab.GetType (mainClass);
502 if (mainType != null)
503 mainMethodInfo = mainType.GetMethod (mainMethod);
505 catch (Exception ex) {
506 Console.WriteLine (ex);
508 if (mainMethodInfo != null)
509 ab.SetEntryPoint (mainMethodInfo);
511 Report (1037, "Unable to find the entry point method '" + entryPoint + "'");
518 ab.DefineVersionInfoResource ();
520 if (win32IconFile != null) {
522 MethodInfo mi = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
524 Report (0, "Cannot embed win32 icons on this runtime: try the Mono runtime instead.");
525 mi.Invoke (ab, new object [] { win32IconFile });
527 catch (Exception ex) {
528 Report (1031, "Error reading icon '" + win32IconFile + "' --" + ex);
532 if (win32ResFile != null) {
534 ab.DefineUnmanagedResource (win32ResFile);
536 catch (Exception ex) {
537 Report (1019, "Metadata failure creating assembly -- " + ex);
541 foreach (ResourceInfo res in resources) {
542 if (res.name == null)
543 res.name = Path.GetFileName (res.fileName);
545 foreach (ResourceInfo res2 in resources)
546 if ((res != res2) && (res.name == res2.name))
547 Report (1046, String.Format ("Resource identifier '{0}' has already been used in this assembly", res.name));
549 if (res.isEmbedded) {
550 MethodInfo mi = typeof (AssemblyBuilder).GetMethod ("EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
551 null, CallingConventions.Any, new Type [] { typeof (string), typeof (string) }, null);
553 Report (0, "Cannot embed resources on this runtime: try the Mono runtime instead.");
554 mi.Invoke (ab, new object [] { res.name, res.fileName });
557 if (res.target != null) {
558 File.Copy (res.fileName, res.target, true);
559 res.fileName = res.target;
562 ab.DefineResource (res.name, "", res.fileName,
563 res.isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public);
570 catch (Exception ex) {
571 Report (1019, "Metadata failure creating assembly -- " + ex);
576 "Usage: al [options] [sources]",
577 "Options: ('/out' must be specified)",
579 " /? or /help Display this usage message",
580 " @<filename> Read response file for more options",
581 " /algid:<id> Algorithm used to hash files (in hexadecimal)",
582 " /base[address]:<addr> Base address for the library",
583 " /bugreport:<filename> Create a 'Bug Report' file",
584 " /comp[any]:<text> Company name",
585 " /config[uration]:<text> Configuration string",
586 " /copy[right]:<text> Copyright message",
587 " /c[ulture]:<text> Supported culture",
588 " /delay[sign][+|-] Delay sign this assembly",
589 " /descr[iption]:<text> Description",
590 " /e[vidence]:<filename> Security evidence file to embed",
591 " /fileversion:<version> Optional Win32 version (overrides assembly version)",
592 " /flags:<flags> Assembly flags (in hexadecimal)",
593 " /fullpaths Display files using fully-qualified filenames",
594 " /keyf[ile]:<filename> File containing key to sign the assembly",
595 " /keyn[ame]:<text> Key container name of key to sign assembly",
596 " /main:<method> Specifies the method name of the entry point",
597 " /nologo Suppress the startup banner and copyright message",
598 " /out:<filename> Output file name for the assembly manifest",
599 " /prod[uct]:<text> Product name",
600 " /productv[ersion]:<text> Product version",
601 " /t[arget]:lib[rary] Create a library",
602 " /t[arget]:exe Create a console executable",
603 " /t[arget]:win[exe] Create a Windows executable",
604 " /template:<filename> Specifies an assembly to get default options from",
605 " /title:<text> Title",
606 " /trade[mark]:<text> Trademark message",
607 " /v[ersion]:<version> Version (use * to auto-generate remaining numbers)",
608 " /win32icon:<filename> Use this icon for the output",
609 " /win32res:<filename> Specifies the Win32 resource file",
611 "Sources: (at least one source input is required)",
612 " <filename>[,<targetfile>] add file to assembly",
613 " /embed[resource]:<filename>[,<name>[,Private]]",
614 " embed the file as a resource in the assembly",
615 " /link[resource]:<filename>[,<name>[,<targetfile>[,Private]]]",
616 " link the file as a resource to the assembly",