use MOONLIGHT symbol
[mcs.git] / tools / mjs / mjs.cs
blob5075b131fc2d3e1d3b9505dea61fd1cb99a84d3b
1 //
2 // driver.cs: Guides the compilation process through the different phases.
3 //
4 // Author:
5 // Cesar Lopez Nataren (cesar@ciencias.unam.mx)
6 //
7 // (C) 2003, Cesar Lopez Nataren
8 // (C) Copyright 2005, 2006, Novell Inc. (http://www.novell.com)
9 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System;
33 using System.Globalization;
34 using System.IO;
35 using System.Text;
36 using Microsoft.Vsa;
37 using Microsoft.JScript;
38 using System.Reflection;
39 using System.Collections;
40 using System.Diagnostics;
41 using Microsoft.JScript.Vsa;
42 using System.Reflection.Emit;
43 using Mono.CSharp;
45 namespace Mono.JScript {
47 class Driver {
49 // Assemblies references to be linked. Initialized with
50 // mscorlib.dll
52 private static ArrayList references;
54 // Lookup paths
55 private static ArrayList link_paths;
57 // jscript files
58 private static ArrayList files;
60 private static string first_source;
62 private static bool want_debugging_support = false;
64 private static string output_file;
65 private static int warning_level = -1;
67 private static Assembly [] assemblies = new Assembly [0];
69 private static bool StdLib = true;
71 private static void Usage ()
73 Console.WriteLine ("Mono JScript compiler\n" +
74 "Copyright (C) 2003 - 2004 Cesar Lopez Nataren\n" +
75 "Copyright (C) 2004 - 2006 Novell Inc (http://novell.com)\n\n" +
76 "mjs [options] source-file\n" +
77 " /about About the Mono JScript compiler\n" +
78 " /lib:PATH1,PATH2 Adds the paths to the assembly link path\n" +
79 " /nostdlib[+|-] Does not load core libraries\n" +
80 " /out:<file> Specify name of binary output file\n" +
81 " /pkg:P1[,Pn] References packages P1..Pn\n" +
82 " /r[eference]:ASS Reference the specified assembly\n" +
84 "\n" +
85 "Resources:\n" +
86 " @file Read response file for more options\n\n" +
87 "Options can be of the form -option or /option");
90 private static void About ()
92 Console.WriteLine (
93 "The Mono JScript compiler is:\n" +
94 "Copyright (C) 2003 - 2004 Cesar Lopez Nataren\n" +
95 "Copyright (C) 2004 - 2006 Novell Inc.\n\n" +
96 "The compiler source code is released under the terms of both the MIT X11 and MPL\n" +
97 "The compiler was written by Cesar Lopez Nataren");
98 Environment.Exit (0);
101 /// <summary>
102 /// Loads all assemblies referenced on the command line
103 /// </summary>
104 private static void LoadReferences ()
106 foreach (string r in references)
107 LoadAssembly (r, false);
110 private static void LoadAssembly (string assembly, bool soft)
112 Assembly a;
113 string total_log = "";
115 try {
116 char [] path_chars = { '/', '\\' };
118 if (assembly.IndexOfAny (path_chars) != -1) {
119 a = Assembly.LoadFrom (assembly);
120 } else {
121 string ass = assembly;
122 if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
123 ass = assembly.Substring (0, assembly.Length - 4);
124 a = Assembly.Load (ass);
126 AddAssembly (a);
128 } catch (FileNotFoundException){
129 foreach (string dir in link_paths){
130 string full_path = Path.Combine (dir, assembly);
131 if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
132 full_path += ".dll";
134 try {
135 a = Assembly.LoadFrom (full_path);
136 AddAssembly (a);
137 return;
138 } catch (FileNotFoundException ff) {
139 total_log += ff.FusionLog;
140 continue;
143 if (!soft)
144 Console.WriteLine ("Cannot find assembly `" + assembly + "'" );
145 } catch (BadImageFormatException f) {
146 Console.WriteLine ("Cannot load assembly (bad file format)" + f.FusionLog);
147 } catch (FileLoadException f){
148 Console.WriteLine ("Cannot load assembly " + f.FusionLog);
149 } catch (ArgumentNullException){
150 Console.WriteLine ("Cannot load assembly (null argument)");
154 /// <summary>
155 /// Registers an assembly to load types from.
156 /// </summary>
157 private static void AddAssembly (Assembly a)
159 foreach (Assembly assembly in assemblies) {
160 if (a == assembly)
161 return;
164 int top = assemblies.Length;
165 Assembly [] n = new Assembly [top + 1];
167 assemblies.CopyTo (n, 0);
169 n [top] = a;
170 assemblies = n;
173 static string [] LoadArgs (string file)
175 StreamReader f;
176 ArrayList args = new ArrayList ();
177 string line;
178 try {
179 f = new StreamReader (file);
180 } catch {
181 return null;
184 StringBuilder sb = new StringBuilder ();
186 while ((line = f.ReadLine ()) != null){
187 int t = line.Length;
189 for (int i = 0; i < t; i++){
190 char c = line [i];
192 if (c == '"' || c == '\''){
193 char end = c;
195 for (i++; i < t; i++){
196 c = line [i];
198 if (c == end)
199 break;
200 sb.Append (c);
202 } else if (c == ' '){
203 if (sb.Length > 0){
204 args.Add (sb.ToString ());
205 sb.Length = 0;
207 } else
208 sb.Append (c);
210 if (sb.Length > 0){
211 args.Add (sb.ToString ());
212 sb.Length = 0;
216 string [] ret_value = new string [args.Count];
217 args.CopyTo (ret_value, 0);
219 return ret_value;
223 // Returns the directory where the system assemblies are installed
225 static string GetSystemDir ()
227 return Path.GetDirectoryName (typeof (object).Assembly.Location);
231 static void SetOutputFile (string name)
233 output_file = name;
236 static void Version ()
238 string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
239 Console.WriteLine ("Mono JScript compiler version {0}", version);
240 Environment.Exit (0);
243 static bool UnixParseOption (string arg, ref string [] args, ref int i)
245 switch (arg){
246 case "--version":
247 Version ();
248 return true;
250 case "/?": case "/h": case "/help":
251 case "--help":
252 Usage ();
253 Environment.Exit (0);
254 return true;
255 case "-o":
256 case "--output":
257 if ((i + 1) >= args.Length){
258 Usage ();
259 Environment.Exit (1);
261 SetOutputFile (args [++i]);
262 return true;
263 case "-r":
264 if ((i + 1) >= args.Length){
265 Usage ();
266 Environment.Exit (1);
269 references.Add (args [++i]);
270 return true;
272 case "-L":
273 if ((i + 1) >= args.Length){
274 Usage ();
275 Environment.Exit (1);
277 link_paths.Add (args [++i]);
278 return true;
280 case "--about":
281 About ();
282 return true;
284 return false;
288 // This parses the -arg and /arg options to the compiler, even if the strings
289 // in the following text use "/arg" on the strings.
291 static bool CSCParseOption (string option, ref string [] args, ref int i)
293 int idx = option.IndexOf (':');
294 string arg, value;
295 if (idx == -1){
296 arg = option;
297 value = "";
298 } else {
299 arg = option.Substring (0, idx);
301 value = option.Substring (idx + 1);
304 switch (arg){
305 case "/nologo":
306 return true;
308 case "/out":
309 if (value == ""){
310 Usage ();
311 Environment.Exit (1);
313 SetOutputFile (value);
314 return true;
316 case "/pkg":
317 string packages;
319 if (value == String.Empty) {
320 Usage ();
321 Environment.Exit (1);
323 packages = String.Join (" ", value.Split (new Char [] { ';', ',', '\n', '\r'}));
325 ProcessStartInfo pi = new ProcessStartInfo ();
326 pi.FileName = "pkg-config";
327 pi.RedirectStandardOutput = true;
328 pi.UseShellExecute = false;
329 pi.Arguments = "--libs " + packages;
330 Process p = null;
331 try {
332 p = Process.Start (pi);
333 } catch (Exception e) {
334 Console.Error.WriteLine ("Couldn't run pkg-config: " + e.Message);
335 Environment.Exit (1);
338 if (p.StandardOutput == null){
339 Console.Error.WriteLine ("Specified package did not return any information");
340 return true;
342 string pkgout = p.StandardOutput.ReadToEnd ();
343 p.WaitForExit ();
344 if (p.ExitCode != 0) {
345 Console.Error.WriteLine ("Error running pkg-config. Check the above output.");
346 Environment.Exit (1);
349 if (pkgout != null){
350 string [] xargs = pkgout.Trim (new Char [] {' ', '\n', '\r', '\t'}).
351 Split (new Char [] { ' ', '\t'});
352 args = AddArgs (args, xargs);
354 p.Close ();
355 return true;
357 case "/r":
358 case "/reference": {
359 if (value == ""){
360 Console.WriteLine ("/reference requires an argument");
361 Environment.Exit (1);
364 string [] refs = value.Split (new char [] { ';', ',' });
365 foreach (string r in refs)
366 references.Add (r);
367 return true;
370 case "/lib": {
371 string [] libdirs;
373 if (value == ""){
374 Console.WriteLine ("/lib requires an argument");
375 Environment.Exit (1);
378 libdirs = value.Split (new Char [] { ',' });
379 foreach (string dir in libdirs)
380 link_paths.Add (dir);
381 return true;
384 case "/about":
385 About ();
386 return true;
389 case "/nostdlib":
390 case "/nostdlib+":
391 StdLib = false;
392 return true;
394 case "/nostdlib-":
395 StdLib = true;
396 return true;
397 case "/target":
398 if (value.Length == 0) {
399 Console.WriteLine ("fatal error JS2013: Target type is invalid");
400 Environment.Exit (1);
403 if (string.Compare ("exe", value, true) == 0) {
404 // this is the default (and only) supported target
405 } else if (string.Compare ("library", value, true) != 0) {
406 Console.WriteLine ("mjs currently does not support creating libraries");
407 Environment.Exit (1);
408 } else {
409 Console.WriteLine ("fatal error JS2013: Target '{0}' is invalid."
410 + " Specify 'exe' or 'library'", value);
411 Environment.Exit (1);
413 return true;
414 case "/warn":
415 if (value.Length == 0) {
416 Console.WriteLine ("fatal error JS2028: No warning level specified"
417 + " with option '{0}'", option);
418 Environment.Exit (1);
421 try {
422 warning_level = int.Parse (value, CultureInfo.InvariantCulture);
423 } catch {
426 if (warning_level < 0 || warning_level > 4) {
427 Console.WriteLine ("fatal error JS2015: Invalid warning level specified"
428 + " with option '{0}'", option);
429 Environment.Exit (1);
431 return true;
433 return false;
436 static string [] AddArgs (string [] args, string [] extra_args)
438 string [] new_args;
439 new_args = new string [extra_args.Length + args.Length];
441 // if args contains '--' we have to take that into account
442 // split args into first half and second half based on '--'
443 // and add the extra_args before --
444 int split_position = Array.IndexOf (args, "--");
445 if (split_position != -1) {
446 Array.Copy (args, new_args, split_position);
447 extra_args.CopyTo (new_args, split_position);
448 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
449 } else {
450 args.CopyTo (new_args, 0);
451 extra_args.CopyTo (new_args, args.Length);
453 return new_args;
457 // Given a path specification, splits the path from the file/pattern
459 static void SplitPathAndPattern (string spec, out string path, out string pattern)
461 int p = spec.LastIndexOf ('/');
462 if (p != -1){
464 // Windows does not like /file.cs, switch that to:
465 // "\", "file.cs"
467 if (p == 0){
468 path = "\\";
469 pattern = spec.Substring (1);
470 } else {
471 path = spec.Substring (0, p);
472 pattern = spec.Substring (p + 1);
474 return;
477 p = spec.LastIndexOf ('\\');
478 if (p != -1){
479 path = spec.Substring (0, p);
480 pattern = spec.Substring (p + 1);
481 return;
484 path = ".";
485 pattern = spec;
488 static void ProcessFile (string f)
490 if (first_source == null)
491 first_source = f;
493 files.Add (f);
496 static void CompileFiles (string spec, bool recurse)
498 string path, pattern;
500 SplitPathAndPattern (spec, out path, out pattern);
501 if (pattern.IndexOf ('*') == -1){
502 ProcessFile (spec);
503 return;
506 string [] files = null;
507 try {
508 files = Directory.GetFiles (path, pattern);
509 } catch (System.IO.DirectoryNotFoundException) {
510 Console.WriteLine ("Source file `" + spec + "' could not be found");
511 return;
512 } catch (System.IO.IOException){
513 Console.WriteLine ("Source file `" + spec + "' could not be found");
514 return;
516 foreach (string f in files)
517 ProcessFile (f);
519 if (!recurse)
520 return;
522 string [] dirs = null;
524 try {
525 dirs = Directory.GetDirectories (path);
526 } catch {
529 foreach (string d in dirs) {
531 // Don't include path in this string, as each
532 // directory entry already does
533 CompileFiles (d + "/" + pattern, true);
537 internal static bool MainDriver (string [] args)
539 int i;
540 bool parsing_options = true;
542 references = new ArrayList ();
543 link_paths = new ArrayList ();
544 files = new ArrayList ();
546 Hashtable response_file_list = null;
548 for (i = 0; i < args.Length; i++){
549 string arg = args [i];
550 if (arg == "")
551 continue;
553 if (arg.StartsWith ("@")){
554 string [] extra_args;
555 string response_file = arg.Substring (1);
557 if (response_file_list == null)
558 response_file_list = new Hashtable ();
560 if (response_file_list.Contains (response_file)){
561 Console.WriteLine ("Response file `" + response_file + "' specified multiple times");
562 Environment.Exit (1);
565 response_file_list.Add (response_file, response_file);
567 extra_args = LoadArgs (response_file);
568 if (extra_args == null){
569 Console.WriteLine ("Unable to open response file: " + response_file);
570 return false;
573 args = AddArgs (args, extra_args);
574 continue;
577 if (parsing_options){
578 if (arg == "--"){
579 parsing_options = false;
580 continue;
583 if (arg.StartsWith ("-")){
584 if (UnixParseOption (arg, ref args, ref i))
585 continue;
587 // Try a -CSCOPTION
588 string csc_opt = "/" + arg.Substring (1);
589 if (CSCParseOption (csc_opt, ref args, ref i))
590 continue;
591 } else {
592 if (arg.StartsWith ("/")){
593 if (CSCParseOption (arg, ref args, ref i))
594 continue;
598 CompileFiles (arg, false);
602 // If there is nothing to put in the assembly, and we are not a library
604 if (first_source == null) /* && embedded_resources == null && resources == null) */ {
605 Console.WriteLine ("fatal error JS2026: No input sources specified");
606 return false;
610 // Load Core Library for default compilation
612 if (StdLib)
613 references.Insert (0, "mscorlib");
617 // Load assemblies required
619 link_paths.Add (GetSystemDir ());
620 link_paths.Add (Directory.GetCurrentDirectory ());
621 LoadReferences ();
622 return true;
626 // Entry point
628 private static void Main (string [] args) {
629 if (args.Length < 1) {
630 Usage ();
631 Environment.Exit (0);
633 MainDriver (args);
634 VsaEngine engine = new VsaEngine ();
635 engine.InitVsaEngine ("mjs:com.mono-project", new MonoEngineSite ());
637 foreach (string asm in references) {
638 IVsaReferenceItem item = (IVsaReferenceItem) engine.Items.CreateItem (asm, VsaItemType.Reference, VsaItemFlag.None);
639 item.AssemblyName = asm;
642 string asm_name = String.Empty;
644 foreach (Assembly assembly in assemblies) {
645 asm_name = assembly.GetName ().FullName;
646 IVsaReferenceItem item = (IVsaReferenceItem) engine.Items.CreateItem (asm_name, VsaItemType.Reference, VsaItemFlag.None);
647 item.AssemblyName = asm_name;
650 foreach (string file in files) {
651 IVsaCodeItem item = (IVsaCodeItem) engine.Items.CreateItem (file, VsaItemType.Code, VsaItemFlag.None);
652 item.SourceText = GetCodeFromFile (file);
654 engine.SetOption ("debug", want_debugging_support);
655 engine.SetOption ("link_path", link_paths);
656 engine.SetOption ("first_source", first_source);
657 engine.SetOption ("assemblies", assemblies);
658 engine.SetOption ("out", output_file);
659 if (warning_level != -1)
660 engine.SetOption ("WarningLevel", warning_level);
661 engine.Compile ();
664 static string GetCodeFromFile (string fn)
666 try {
667 StreamReader reader = new StreamReader (fn);
668 return reader.ReadToEnd ();
669 } catch (FileNotFoundException) {
670 throw new JScriptException (JSError.FileNotFound);
671 } catch (ArgumentNullException) {
672 throw new JScriptException (JSError.FileNotFound);
673 } catch (ArgumentException) {
674 throw new JScriptException (JSError.FileNotFound);
675 } catch (IOException) {
676 throw new JScriptException (JSError.NoError);
677 } catch (OutOfMemoryException) {
678 throw new JScriptException (JSError.OutOfMemory);
683 class MonoEngineSite : IVsaSite {
684 public void GetCompiledState (out byte [] pe, out byte [] debugInfo)
686 throw new NotImplementedException ();
689 public object GetEventSourceInstance (string itemName, string eventSourceName)
691 throw new NotImplementedException ();
694 public object GetGlobalInstance (string name)
696 throw new NotImplementedException ();
699 public void Notify (string notify, object info)
701 throw new NotImplementedException ();
704 public bool OnCompilerError (IVsaError error)
706 throw new NotImplementedException ();