2009-11-05 Marek Safar <marek.safar@gmail.com>
[mcs.git] / tools / linker / Mono.Linker / Driver.cs
blob7d1963cc3db22e5225e5404117e7a9f0dc4cb03d
1 //
2 // Driver.cs
3 //
4 // Author:
5 // Jb Evain (jbevain@gmail.com)
6 //
7 // (C) 2006 Jb Evain
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System;
30 using System.Collections;
31 using System.IO;
32 using SR = System.Reflection;
33 using System.Xml.XPath;
35 using Mono.Linker.Steps;
37 namespace Mono.Linker {
39 public class Driver {
41 static readonly string _linker = "Mono CIL Linker";
43 public static int Main (string [] args)
45 if (args.Length == 0)
46 Usage ("No parameters specified");
48 try {
50 Driver driver = new Driver (args);
51 driver.Run ();
53 } catch (Exception e) {
54 Console.WriteLine ("Fatal error in {0}", _linker);
55 Console.WriteLine (e);
56 return 1;
59 return 0;
62 Queue _queue;
64 public Driver (string [] args)
66 _queue = new Queue (args);
69 bool HaveMoreTokens ()
71 return _queue.Count > 0;
74 void Run ()
76 Pipeline p = GetStandardPipeline ();
77 LinkContext context = GetDefaultContext (p);
78 I18nAssemblies assemblies = I18nAssemblies.All;
79 ArrayList custom_steps = new ArrayList ();
81 bool resolver = false;
82 while (HaveMoreTokens ()) {
83 string token = GetParam ();
84 if (token.Length < 2)
85 Usage ("Option is too short");
87 if (! (token [0] == '-' || token [1] == '/'))
88 Usage ("Expecting an option, got instead: " + token);
90 if (token [0] == '-' && token [1] == '-') {
92 if (token.Length < 3)
93 Usage ("Option is too short");
95 switch (token [2]) {
96 case 'v':
97 Version ();
98 break;
99 case 'a':
100 About ();
101 break;
102 default:
103 Usage (null);
104 break;
108 switch (token [1]) {
109 case 'd': {
110 DirectoryInfo info = new DirectoryInfo (GetParam ());
111 context.Resolver.AddSearchDirectory (info.FullName);
112 break;
114 case 'o':
115 context.OutputDirectory = GetParam ();
116 break;
117 case 'c':
118 context.CoreAction = ParseAssemblyAction (GetParam ());
119 break;
120 case 'p':
121 AssemblyAction action = ParseAssemblyAction (GetParam ());
122 context.Actions [GetParam ()] = action;
123 break;
124 case 's':
125 custom_steps.Add (GetParam ());
126 break;
127 case 'x':
128 foreach (string file in GetFiles (GetParam ()))
129 p.PrependStep (new ResolveFromXmlStep (new XPathDocument (file)));
130 resolver = true;
131 break;
132 case 'a':
133 foreach (string file in GetFiles (GetParam ()))
134 p.PrependStep (new ResolveFromAssemblyStep (file));
135 resolver = true;
136 break;
137 case 'i':
138 foreach (string file in GetFiles (GetParam ()))
139 p.PrependStep (new ResolveFromXApiStep (new XPathDocument (file)));
140 resolver = true;
141 break;
142 case 'l':
143 assemblies = ParseI18n (GetParam ());
144 break;
145 case 'm':
146 context.SetParameter (GetParam (), GetParam ());
147 break;
148 case 'b':
149 context.LinkSymbols = bool.Parse (GetParam ());
150 break;
151 case 'g':
152 if (!bool.Parse (GetParam ()))
153 p.RemoveStep (typeof (RegenerateGuidStep));
154 break;
155 default:
156 Usage ("Unknown option: `" + token [1] + "'");
157 break;
161 if (!resolver)
162 Usage ("No resolver was created (use -x, -a or -i)");
164 foreach (string custom_step in custom_steps)
165 AddCustomStep (p, custom_step);
167 p.AddStepAfter (typeof (LoadReferencesStep), new LoadI18nAssemblies (assemblies));
169 p.Process (context);
172 static void AddCustomStep (Pipeline pipeline, string arg)
174 int pos = arg.IndexOf (":");
175 if (pos == -1) {
176 pipeline.AppendStep (ResolveStep (arg));
177 return;
180 string [] parts = arg.Split (':');
181 if (parts.Length != 2)
182 Usage ("Step is specified as TYPE:STEP");
184 if (parts [0].IndexOf (",") > -1)
185 pipeline.AddStepBefore (FindStep (pipeline, parts [1]), ResolveStep (parts [0]));
186 else if (parts [1].IndexOf (",") > -1)
187 pipeline.AddStepAfter (FindStep (pipeline, parts [0]), ResolveStep (parts [1]));
188 else
189 Usage ("No comma separator in TYPE or STEP");
192 static Type FindStep (Pipeline pipeline, string name)
194 foreach (IStep step in pipeline.GetSteps ()) {
195 Type t = step.GetType ();
196 if (t.Name == name)
197 return t;
200 return null;
203 static IStep ResolveStep (string type)
205 Type step = Type.GetType (type, false);
206 if (step == null)
207 Usage (String.Format ("Step type '{0}' not found.", type));
208 if (!typeof (IStep).IsAssignableFrom (step))
209 Usage (String.Format ("Step type '{0}' does not implement IStep interface.", type));
210 return (IStep) Activator.CreateInstance (step);
213 static string [] GetFiles (string param)
215 if (param.Length < 1 || param [0] != '@')
216 return new string [] {param};
218 string file = param.Substring (1);
219 return ReadLines (file);
222 static string [] ReadLines (string file)
224 ArrayList lines = new ArrayList ();
225 using (StreamReader reader = new StreamReader (file)) {
226 string line;
227 while ((line = reader.ReadLine ()) != null)
228 lines.Add (line);
230 return (string []) lines.ToArray (typeof (string));
233 static I18nAssemblies ParseI18n (string str)
235 I18nAssemblies assemblies = I18nAssemblies.None;
236 string [] parts = str.Split (',');
237 foreach (string part in parts)
238 assemblies |= (I18nAssemblies) Enum.Parse (typeof (I18nAssemblies), part.Trim (), true);
240 return assemblies;
243 static AssemblyAction ParseAssemblyAction (string s)
245 return (AssemblyAction) Enum.Parse (typeof (AssemblyAction), s, true);
248 string GetParam ()
250 if (_queue.Count == 0)
251 Usage ("Expecting a parameter");
253 return (string) _queue.Dequeue ();
256 static LinkContext GetDefaultContext (Pipeline pipeline)
258 LinkContext context = new LinkContext (pipeline);
259 context.CoreAction = AssemblyAction.Skip;
260 context.OutputDirectory = "output";
261 return context;
264 static void Usage (string msg)
266 Console.WriteLine (_linker);
267 if (msg != null)
268 Console.WriteLine ("Error: " + msg);
269 Console.WriteLine ("monolinker [options] -x|-a|-i file");
271 Console.WriteLine (" --about About the {0}", _linker);
272 Console.WriteLine (" --version Print the version number of the {0}", _linker);
273 Console.WriteLine (" -out Specify the output directory, default to `output'");
274 Console.WriteLine (" -c Action on the core assemblies, skip, copy or link, default to skip");
275 Console.WriteLine (" -p Action per assembly");
276 Console.WriteLine (" -s Add a new step to the pipeline.");
277 Console.WriteLine (" -d Add a directory where the linker will look for assemblies");
278 Console.WriteLine (" -b Generate debug symbols for each linked module (true or false)");
279 Console.WriteLine (" -g Generate a new unique guid for each linked module (true or false)");
280 Console.WriteLine (" -l List of i18n assemblies to copy to the output directory");
281 Console.WriteLine (" separated with a comma: none,all,cjk,mideast,other,rare,west");
282 Console.WriteLine (" default is all");
283 Console.WriteLine (" -x Link from an XML descriptor");
284 Console.WriteLine (" -a Link from a list of assemblies");
285 Console.WriteLine (" -i Link from an mono-api-info descriptor");
286 Console.WriteLine ("");
288 Environment.Exit (1);
291 static void Version ()
293 Console.WriteLine ("{0} Version {1}",
294 _linker,
295 System.Reflection.Assembly.GetExecutingAssembly ().GetName ().Version);
297 Environment.Exit(1);
300 static void About ()
302 Console.WriteLine ("For more information, visit the project Web site");
303 Console.WriteLine (" http://www.mono-project.com/");
305 Environment.Exit(1);
308 static Pipeline GetStandardPipeline ()
310 Pipeline p = new Pipeline ();
311 p.AppendStep (new LoadReferencesStep ());
312 p.AppendStep (new BlacklistStep ());
313 p.AppendStep (new TypeMapStep ());
314 p.AppendStep (new MarkStep ());
315 p.AppendStep (new SweepStep ());
316 p.AppendStep (new CleanStep ());
317 p.AppendStep (new RegenerateGuidStep ());
318 p.AppendStep (new OutputStep ());
319 return p;