2004-01-15 Zoltan Varga <vargaz@freemail.hu>
authorZoltan Varga <vargaz@gmail.com>
Thu, 15 Jan 2004 12:54:46 +0000 (12:54 -0000)
committerZoltan Varga <vargaz@gmail.com>
Thu, 15 Jan 2004 12:54:46 +0000 (12:54 -0000)
* Al.cs Makefile ChangeLog al.exe.sources: New files.

svn path=/trunk/mcs/; revision=22112

mcs/tools/al/Al.cs [new file with mode: 0644]
mcs/tools/al/ChangeLog [new file with mode: 0644]
mcs/tools/al/Makefile [new file with mode: 0644]
mcs/tools/al/al.exe.sources [new file with mode: 0644]

diff --git a/mcs/tools/al/Al.cs b/mcs/tools/al/Al.cs
new file mode 100644 (file)
index 0000000..1693af6
--- /dev/null
@@ -0,0 +1,617 @@
+//
+// Mono.AssemblyLinker.AssemblyLinker
+//
+// Author(s):
+//   Zoltan Varga (vargaz@freemail.hu)
+//
+// (C) Ximian, Inc.  http://www.ximian.com
+//
+
+
+using System;
+using System.IO;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace Mono.AssemblyLinker
+{
+       class ModuleInfo {
+               public string fileName;
+               public string target;
+       }
+
+       class ResourceInfo {
+               public string name;
+               public string fileName;
+               public string target;
+               public bool isEmbedded;
+               public bool isPrivate;
+       }
+
+       enum Target {
+               Dll,
+               Exe,
+               Win
+       }
+
+       public class AssemblyLinker {
+
+               ArrayList inputFiles = new ArrayList ();
+               ArrayList resources = new ArrayList ();
+               ArrayList cattrs = new ArrayList ();
+               string outputFile;
+               bool fullPaths;
+               string outFile;
+               string entryPoint;
+               string win32IconFile;
+               string win32ResFile;
+               Target target;
+
+               public static int Main (String[] args) {
+                       return new AssemblyLinker ().DynMain (args);
+               }
+
+               private int DynMain (String[] args) {
+                       ParseArgs (args);
+
+                       DoIt ();
+
+                       return 0;
+               }
+
+               private void ParseArgs (string[] args) {
+
+                       if (args.Length == 0)
+                               Usage ();
+
+                       foreach (string str in args) {
+                               if ((str [0] != '-') && (str [0] != '/')) {
+                                       string[] parts = str.Split (',');
+                                       ModuleInfo mod = new ModuleInfo ();
+                                       mod.fileName = parts [0];
+                                       if (parts.Length > 1)
+                                               mod.target = parts [1];
+                                       inputFiles.Add (mod);
+                                       continue;
+                               }
+
+                               string arg;
+                               string opt = GetCommand (str, out arg);
+
+                               switch (opt) {
+                               case "help":
+                               case "?":
+                                       Usage ();
+                                       break;
+
+                               case "embed": {
+                                       if (arg == null)
+                                               ReportMissingFileSpec (opt);
+                                       ResourceInfo res = new ResourceInfo ();
+                                       res.isEmbedded = true;
+                                       String[] parts = arg.Split (',');
+                                       res.fileName = parts [0];
+                                       if (parts.Length > 1)
+                                               res.name = parts [1];
+                                       if (parts.Length > 2) {
+                                               switch (parts [2]) {
+                                               case "public":
+                                                       break;
+                                               case "private":
+                                                       res.isPrivate = true;
+                                                       break;
+                                               default:
+                                                       ReportInvalidArgument (opt, parts [2]);
+                                                       break;
+                                               }
+                                       }
+                                       resources.Add (res);
+                                       break;
+                               }
+
+                               case "link": {
+                                       if (arg == null)
+                                               ReportMissingFileSpec (opt);
+                                       ResourceInfo res = new ResourceInfo ();
+                                       String[] parts = arg.Split (',');
+                                       res.fileName = parts [0];
+                                       if (parts.Length > 1)
+                                               res.name = parts [1];
+                                       if (parts.Length > 2)
+                                               res.target = parts [2];
+                                       if (parts.Length > 3) {
+                                               switch (parts [3]) {
+                                               case "public":
+                                                       break;
+                                               case "private":
+                                                       res.isPrivate = true;
+                                                       break;
+                                               default:
+                                                       ReportInvalidArgument (opt, parts [3]);
+                                                       break;
+                                               }
+                                       }
+                                       resources.Add (res);
+                                       break;
+                               }
+
+                               case "algid":
+                                       if (arg == null)
+                                               ReportMissingArgument (opt);
+                                       try {
+                                               int val = Int32.Parse (arg);
+                                               AddCattr (typeof (AssemblyAlgorithmIdAttribute), typeof (uint), val);
+                                       }
+                                       catch (Exception) {
+                                               ReportInvalidArgument (opt, arg);
+                                       }
+                                       break;
+
+                               case "base":
+                                       ReportNotImplemented (opt);
+                                       break;
+
+                               case "baseaddress":
+                                       ReportNotImplemented (opt);
+                                       break;
+
+                               case "bugreport":
+                                       ReportNotImplemented (opt);
+                                       break;
+
+                               case "comp":
+                               case "company":
+                                       if (arg == null)
+                                               ReportMissingText (opt);
+                                       AddCattr (typeof (AssemblyCompanyAttribute), arg);
+                                       break;
+
+                               case "config":
+                               case "configuration":
+                                       if (arg == null)
+                                               ReportMissingText (opt);
+                                       AddCattr (typeof (AssemblyConfigurationAttribute), arg);
+                                       break;
+
+                               case "copy":
+                               case "copyright":
+                                       if (arg == null)
+                                               ReportMissingText (opt);
+                                       AddCattr (typeof (AssemblyCopyrightAttribute), arg);
+                                       break;
+
+                               case "c":
+                               case "culture":
+                                       if (arg == null)
+                                               ReportMissingText (opt);
+                                       AddCattr (typeof (AssemblyCultureAttribute), arg);
+                                       break;
+
+                               case "delay":
+                               case "delaysign":
+                                       ReportNotImplemented (opt);
+                                       break;
+
+                               case "descr":
+                               case "description":
+                                       if (arg == null)
+                                               ReportMissingText (opt);
+                                       AddCattr (typeof (AssemblyDescriptionAttribute), arg);
+                                       break;
+
+                               case "e":
+                               case "evidence":
+                                       if (arg == null)
+                                               ReportMissingFileSpec (opt);
+                                       ResourceInfo res = new ResourceInfo ();
+                                       res.name = "Security.Evidence";
+                                       res.fileName = arg;
+                                       res.isEmbedded = true;
+                                       res.isPrivate = true;
+                                       resources.Add (res);
+                                       break;
+
+                               case "fileversion":
+                                       if (arg == null)
+                                               ReportMissingText (opt);
+
+                                       AddCattr (typeof (AssemblyFileVersionAttribute), arg);
+                                       break;
+
+                               case "flags":
+                                       if (arg == null)
+                                               ReportMissingArgument (opt);
+                                       try {
+                                               int val = Int32.Parse (arg);
+                                               AddCattr (typeof (AssemblyFlagsAttribute), typeof (uint), val);
+                                       }
+                                       catch (Exception) {
+                                               ReportInvalidArgument (opt, arg);
+                                       }
+                                       break;
+
+                               case "fullpaths":
+                                       fullPaths = true;
+                                       break;
+
+                               case "keyf":
+                               case "keyfile":
+                                       if (arg == null)
+                                               ReportMissingText (opt);
+                                       AddCattr (typeof (AssemblyKeyFileAttribute), arg);
+                                       break;
+                                       
+                               case "keyn":
+                               case "keyname":
+                                       if (arg == null)
+                                               ReportMissingText (opt);
+                                       AddCattr (typeof (AssemblyKeyNameAttribute), arg);
+                                       break;
+
+                               case "main":
+                                       if (arg == null)
+                                               ReportMissingText (opt);
+                                       entryPoint = arg;
+                                       break;
+
+                               case "nologo":
+                                       break;
+
+                               case "out":
+                                       if (arg == null)
+                                               ReportMissingFileSpec (opt);
+                                       outFile = arg;
+                                       break;
+
+                               case "prod":
+                               case "product":
+                                       if (arg == null)
+                                               ReportMissingText (opt);
+                                       AddCattr (typeof (AssemblyProductAttribute), arg);
+                                       break;
+
+                               case "productv":
+                               case "productversion":
+                                       if (arg == null)
+                                               ReportMissingText (opt);
+                                       AddCattr (typeof (AssemblyInformationalVersionAttribute), arg);
+                                       break;
+
+                               case "t":
+                               case "target":
+                                       if (arg == null)
+                                               ReportMissingText (opt);
+                                       switch (arg) {
+                                       case "lib":
+                                       case "library":
+                                               target = Target.Dll;
+                                               break;
+                                       case "exe":
+                                               target = Target.Exe;
+                                               break;
+                                       case "win":
+                                       case "winexe":
+                                               Report (0, "target:win is not implemented");
+                                               break;
+                                       default:
+                                               ReportInvalidArgument (opt, arg);
+                                               break;
+                                       }
+                                       break;
+
+                               case "template":
+                                       if (arg == null)
+                                               ReportMissingFileSpec (opt);
+                                       ReportNotImplemented (opt);
+                                       break;
+
+                               case "title":
+                                       if (arg == null)
+                                               ReportMissingText (opt);
+                                       AddCattr (typeof (AssemblyTitleAttribute), arg);
+                                       break;
+
+                               case "trade":
+                               case "trademark":
+                                       if (arg == null)
+                                               ReportMissingText (opt);
+                                       AddCattr (typeof (AssemblyTrademarkAttribute), arg);
+                                       break;
+
+                               case "v":
+                               case "version":
+                                       // This option conflicts with the standard UNIX meaning
+                                       if (arg == null) {
+                                               Version ();
+                                               break;
+                                       }
+                                       AddCattr (typeof (AssemblyVersionAttribute), arg);
+                                       break;
+
+                               case "win32icon":
+                                       if (arg == null)
+                                               ReportMissingFileSpec (opt);
+                                       win32IconFile = arg;
+                                       break;
+
+                               case "win32res":
+                                       if (arg == null)
+                                               ReportMissingFileSpec (opt);
+                                       win32ResFile = arg;
+                                       break;
+
+                               default:
+                                       Report (1013, String.Format ("Unrecognized command line option: '{0}'", opt));
+                                       break;
+                               }
+                       }
+
+                       if ((inputFiles.Count == 0) && (resources.Count == 0))
+                               Report (1016, "No valid input files were specified");
+
+                       if (outFile == null)
+                               Report (1017, "No target filename was specified");
+
+                       if (target == Target.Dll && (entryPoint != null))
+                               Report (1035, "Libraries cannot have an entry point");
+
+                       if (target == Target.Exe && (entryPoint == null))
+                               Report (1036, "Entry point required for executable applications");
+               }
+
+               private string GetCommand (string str, out string command_arg) {
+                       if ((str [0] == '-') && (str.Length > 1) && (str [1] == '-'))
+                               str = str.Substring (1);
+
+                       int end_index = str.IndexOfAny (new char[] {':', '='}, 1);
+                       string command = str.Substring (1,
+                                                                                       end_index == -1 ? str.Length - 1 : end_index - 1);
+                       
+                       if (end_index != -1) {
+                               command_arg = str.Substring (end_index+1);
+                               if (command_arg == String.Empty)
+                                       command_arg = null;
+                       } else {
+                               command_arg = null;
+                       }
+                               
+                       return command.ToLower ();
+               }
+
+               private void AddCattr (Type attrType, Type arg, object value) {
+                       cattrs.Add (new CustomAttributeBuilder (attrType.GetConstructor (new Type [] { arg }), new object [] { value }));
+               }
+
+               private void AddCattr (Type attrType, object value) {
+                       AddCattr (attrType, typeof (string), value);
+               }
+
+               private void AddResource (ResourceInfo res) {
+                       foreach (ResourceInfo res2 in resources) {
+                               if (res.name == res2.name) {
+
+                               }
+                       }
+                       resources.Add (res);
+               }
+
+               private void PrintVersion () {
+                       Console.WriteLine ("Mono Assembly Linker (al.exe) version " + Assembly.GetExecutingAssembly ().GetName ().Version.ToString ());
+               }
+
+               private void Version () {
+                       PrintVersion ();
+                       Environment.Exit (0);
+               }
+
+               private void Usage () {
+                       PrintVersion ();
+                       
+                       foreach (string s in usage)
+                               Console.WriteLine (s);
+                       Environment.Exit (0);
+               }
+
+               private void Report (int errorNum, string msg) {
+                       Console.WriteLine (String.Format ("ALINK: error A{0:0000}: {1}", errorNum, msg));
+                       Environment.Exit (1);
+               }
+
+               private void ReportWarning (int errorNum, string msg) {
+                       Console.WriteLine (String.Format ("ALINK: warning A{0:0000}: {1}", errorNum, msg));
+               }
+
+               private void ReportInvalidArgument (string option, string value) {
+                       Report (1012, String.Format ("'{0}' is not a valid setting for option '{1}'", value, option));
+               }
+
+               private void ReportMissingArgument (string option) {
+                       Report (1003, String.Format ("Compiler option '{0}' must be followed by an argument", option));
+               }
+
+               private void ReportNotImplemented (string option) {
+                       Report (0, String.Format ("Compiler option '{0}' is not implemented", option));
+               }
+
+               private void ReportMissingFileSpec (string option) {
+                       Report (1008, String.Format ("Missing file specification for '{0}' command-line option", option));
+               }
+
+               private void ReportMissingText (string option) {
+                       Report (1010, String.Format ("Missing ':<text>' for '{0}' option", option));
+               }
+
+               private void DoIt () {
+                       AssemblyName aname = new AssemblyName ();
+                       aname.Name = Path.GetFileNameWithoutExtension (outFile);
+
+                       string fileName = Path.GetFileName (outFile);
+
+                       AssemblyBuilder ab;
+
+                       if (fileName != outFile)
+                               ab = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Save, Path.GetDirectoryName (outFile));
+                       else
+                               ab = AppDomain.CurrentDomain.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Save);
+
+                       foreach (CustomAttributeBuilder cb in cattrs)
+                               ab.SetCustomAttribute (cb);
+
+                       /*
+                        * Emit modules
+                        */
+
+                       foreach (ModuleInfo mod in inputFiles) {
+                               MethodInfo mi = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
+                               if (mi == null)
+                                       Report (0, "Cannot add modules on this runtime: try the Mono runtime instead.");
+
+                               if (mod.target != null) {
+                                       File.Copy (mod.fileName, mod.target, true);
+                                       mod.fileName = mod.target;
+                               }
+
+                               bool isAssembly = false;
+                               try {
+                                       AssemblyName.GetAssemblyName (mod.fileName);
+                                       isAssembly = true;
+                               }
+                               catch (Exception) {
+                               }
+
+                               if (isAssembly)
+                                       ReportWarning (1020, "Ignoring included assembly '" + mod.fileName + "'");
+                               else
+                                       mi.Invoke (ab, new object [] { mod.fileName });
+                       }
+
+                       /*
+                        * Set entry point
+                        */
+
+                       string mainClass = entryPoint.Substring (0, entryPoint.LastIndexOf ('.'));
+                       string mainMethod = entryPoint.Substring (entryPoint.LastIndexOf ('.') + 1);
+
+                       MethodInfo mainMethodInfo = null;
+
+                       try {
+                               Type mainType = ab.GetType (mainClass);
+                               if (mainType != null)
+                                       mainMethodInfo = mainType.GetMethod (mainMethod);
+                       }
+                       catch (Exception ex) {
+                               Console.WriteLine (ex);
+                       }
+                       if (mainMethodInfo != null)
+                               ab.SetEntryPoint (mainMethodInfo);
+                       else
+                               Report (1037, "Unable to find the entry point method '" + entryPoint + "'");
+
+                       /*
+                        * Emit resources
+                        */
+
+                       ab.DefineVersionInfoResource ();
+
+                       if (win32IconFile != null) {
+                               try {
+                                       MethodInfo mi = typeof (AssemblyBuilder).GetMethod ("DefineIconResource", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
+                                       if (mi == null)
+                                               Report (0, "Cannot embed win32 icons on this runtime: try the Mono runtime instead.");
+                                       mi.Invoke (ab, new object [] {  win32IconFile });
+                               }
+                               catch (Exception ex) {
+                                       Report (1031, "Error reading icon '" + win32IconFile + "' --" + ex);
+                               }
+                       }
+
+                       if (win32ResFile != null) {
+                               try {
+                                       ab.DefineUnmanagedResource (win32ResFile);
+                               }
+                               catch (Exception ex) {
+                                       Report (1019, "Metadata failure creating assembly -- " + ex);
+                               }
+                       }
+
+                       foreach (ResourceInfo res in resources) {
+                               if (res.name == null)
+                                       res.name = Path.GetFileName (res.fileName);
+
+                               foreach (ResourceInfo res2 in resources)
+                                       if ((res != res2) && (res.name == res2.name))
+                                               Report (1046, String.Format ("Resource identifier '{0}' has already been used in this assembly", res.name));
+
+                               if (res.isEmbedded) {
+                                       MethodInfo mi = typeof (AssemblyBuilder).GetMethod ("EmbedResourceFile", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic,
+                                               null, CallingConventions.Any, new Type [] { typeof (string), typeof (string) }, null);
+                                       if (mi == null)
+                                               Report (0, "Cannot embed resources on this runtime: try the Mono runtime instead.");
+                                       mi.Invoke (ab, new object [] { res.name, res.fileName });
+                               }
+                               else {
+                                       if (res.target != null) {
+                                               File.Copy (res.fileName, res.target, true);
+                                               res.fileName = res.target;
+                                       }
+
+                                       ab.DefineResource (res.name, "", res.fileName, 
+                                                                          res.isPrivate ? ResourceAttributes.Private : ResourceAttributes.Public);
+                               }
+                       }
+
+                       try {
+                               ab.Save (fileName);
+                       }
+                       catch (Exception ex) {
+                               Report (1019, "Metadata failure creating assembly -- " + ex);
+                       }
+               }
+
+               string[] usage = {
+                       "Usage: al [options] [sources]",
+                       "Options: ('/out' must be specified)",
+                       "",
+                       "  /? or /help               Display this usage message",
+                       "  @<filename>               Read response file for more options",
+                       "  /algid:<id>               Algorithm used to hash files (in hexadecimal)",
+                       "  /base[address]:<addr>     Base address for the library",
+                       "  /bugreport:<filename>     Create a 'Bug Report' file",
+                       "  /comp[any]:<text>         Company name",
+                       "  /config[uration]:<text>   Configuration string",
+                       "  /copy[right]:<text>       Copyright message",
+                       "  /c[ulture]:<text>         Supported culture",
+                       "  /delay[sign][+|-]         Delay sign this assembly",
+                       "  /descr[iption]:<text>     Description",
+                       "  /e[vidence]:<filename>    Security evidence file to embed",
+                       "  /fileversion:<version>    Optional Win32 version (overrides assembly version)",
+                       "  /flags:<flags>            Assembly flags  (in hexadecimal)",
+                       "  /fullpaths                Display files using fully-qualified filenames",
+                       "  /keyf[ile]:<filename>     File containing key to sign the assembly",
+                       "  /keyn[ame]:<text>         Key container name of key to sign assembly",
+                       "  /main:<method>            Specifies the method name of the entry point",
+                       "  /nologo                   Suppress the startup banner and copyright message",
+                       "  /out:<filename>           Output file name for the assembly manifest",
+                       "  /prod[uct]:<text>         Product name",
+                       "  /productv[ersion]:<text>  Product version",
+                       "  /t[arget]:lib[rary]       Create a library",
+                       "  /t[arget]:exe             Create a console executable",
+                       "  /t[arget]:win[exe]        Create a Windows executable",
+                       "  /template:<filename>      Specifies an assembly to get default options from",
+                       "  /title:<text>             Title",
+                       "  /trade[mark]:<text>       Trademark message",
+                       "  /v[ersion]:<version>      Version (use * to auto-generate remaining numbers)",
+                       "  /win32icon:<filename>     Use this icon for the output",
+                       "  /win32res:<filename>      Specifies the Win32 resource file",
+                       "",
+                       "Sources: (at least one source input is required)",
+                       "  <filename>[,<targetfile>] add file to assembly",
+                       "  /embed[resource]:<filename>[,<name>[,Private]]",
+                       "                            embed the file as a resource in the assembly",
+                       "  /link[resource]:<filename>[,<name>[,<targetfile>[,Private]]]",
+                       "                            link the file as a resource to the assembly",
+               };
+
+       }
+}
diff --git a/mcs/tools/al/ChangeLog b/mcs/tools/al/ChangeLog
new file mode 100644 (file)
index 0000000..bf5be6f
--- /dev/null
@@ -0,0 +1,4 @@
+2004-01-15  Zoltan Varga  <vargaz@freemail.hu>
+
+       * Al.cs Makefile ChangeLog al.exe.sources: New files.
+
diff --git a/mcs/tools/al/Makefile b/mcs/tools/al/Makefile
new file mode 100644 (file)
index 0000000..cc0f1bf
--- /dev/null
@@ -0,0 +1,7 @@
+thisdir = tools/al
+SUBDIRS = 
+include ../../build/rules.make
+
+PROGRAM = al.exe
+
+include ../../build/executable.make
diff --git a/mcs/tools/al/al.exe.sources b/mcs/tools/al/al.exe.sources
new file mode 100644 (file)
index 0000000..8116c71
--- /dev/null
@@ -0,0 +1 @@
+Al.cs