2 // driver.cs: Guides the compilation process through the different phases.
5 // Cesar Lopez Nataren (cesar@ciencias.unam.mx)
7 // (C) 2003, Cesar Lopez Nataren
8 // (C) Copyright 2005, 2006, Novell Inc. (http://www.novell.com)
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
33 using System
.Globalization
;
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
;
45 namespace Mono
.JScript
{
49 // Assemblies references to be linked. Initialized with
52 private static ArrayList references
;
55 private static ArrayList link_paths
;
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" +
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 ()
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");
102 /// Loads all assemblies referenced on the command line
104 private static void LoadReferences ()
106 foreach (string r
in references
)
107 LoadAssembly (r
, false);
110 private static void LoadAssembly (string assembly
, bool soft
)
113 string total_log
= "";
116 char [] path_chars
= { '/', '\\' }
;
118 if (assembly
.IndexOfAny (path_chars
) != -1) {
119 a
= Assembly
.LoadFrom (assembly
);
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
);
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"))
135 a
= Assembly
.LoadFrom (full_path
);
138 } catch (FileNotFoundException ff
) {
139 total_log
+= ff
.FusionLog
;
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)");
155 /// Registers an assembly to load types from.
157 private static void AddAssembly (Assembly a
)
159 foreach (Assembly assembly
in assemblies
) {
164 int top
= assemblies
.Length
;
165 Assembly
[] n
= new Assembly
[top
+ 1];
167 assemblies
.CopyTo (n
, 0);
173 static string [] LoadArgs (string file
)
176 ArrayList args
= new ArrayList ();
179 f
= new StreamReader (file
);
184 StringBuilder sb
= new StringBuilder ();
186 while ((line
= f
.ReadLine ()) != null){
189 for (int i
= 0; i
< t
; i
++){
192 if (c
== '"' || c
== '\''){
195 for (i
++; i
< t
; i
++){
202 } else if (c
== ' '){
204 args
.Add (sb
.ToString ());
211 args
.Add (sb
.ToString ());
216 string [] ret_value
= new string [args
.Count
];
217 args
.CopyTo (ret_value
, 0);
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
)
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
)
250 case "/?": case "/h": case "/help":
253 Environment
.Exit (0);
257 if ((i
+ 1) >= args
.Length
){
259 Environment
.Exit (1);
261 SetOutputFile (args
[++i
]);
264 if ((i
+ 1) >= args
.Length
){
266 Environment
.Exit (1);
269 references
.Add (args
[++i
]);
273 if ((i
+ 1) >= args
.Length
){
275 Environment
.Exit (1);
277 link_paths
.Add (args
[++i
]);
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 (':');
299 arg
= option
.Substring (0, idx
);
301 value = option
.Substring (idx
+ 1);
311 Environment
.Exit (1);
313 SetOutputFile (value);
319 if (value == String
.Empty
) {
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
;
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");
342 string pkgout
= p
.StandardOutput
.ReadToEnd ();
344 if (p
.ExitCode
!= 0) {
345 Console
.Error
.WriteLine ("Error running pkg-config. Check the above output.");
346 Environment
.Exit (1);
350 string [] xargs
= pkgout
.Trim (new Char
[] {' ', '\n', '\r', '\t'}
).
351 Split (new Char
[] { ' ', '\t'}
);
352 args
= AddArgs (args
, xargs
);
360 Console
.WriteLine ("/reference requires an argument");
361 Environment
.Exit (1);
364 string [] refs
= value.Split (new char [] { ';', ',' }
);
365 foreach (string r
in refs
)
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
);
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);
409 Console
.WriteLine ("fatal error JS2013: Target '{0}' is invalid."
410 + " Specify 'exe' or 'library'", value);
411 Environment
.Exit (1);
415 if (value.Length
== 0) {
416 Console
.WriteLine ("fatal error JS2028: No warning level specified"
417 + " with option '{0}'", option
);
418 Environment
.Exit (1);
422 warning_level
= int.Parse (value, CultureInfo
.InvariantCulture
);
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);
436 static string [] AddArgs (string [] args
, string [] extra_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
);
450 args
.CopyTo (new_args
, 0);
451 extra_args
.CopyTo (new_args
, args
.Length
);
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 ('/');
464 // Windows does not like /file.cs, switch that to:
469 pattern
= spec
.Substring (1);
471 path
= spec
.Substring (0, p
);
472 pattern
= spec
.Substring (p
+ 1);
477 p
= spec
.LastIndexOf ('\\');
479 path
= spec
.Substring (0, p
);
480 pattern
= spec
.Substring (p
+ 1);
488 static void ProcessFile (string f
)
490 if (first_source
== null)
496 static void CompileFiles (string spec
, bool recurse
)
498 string path
, pattern
;
500 SplitPathAndPattern (spec
, out path
, out pattern
);
501 if (pattern
.IndexOf ('*') == -1){
506 string [] files
= null;
508 files
= Directory
.GetFiles (path
, pattern
);
509 } catch (System
.IO
.DirectoryNotFoundException
) {
510 Console
.WriteLine ("Source file `" + spec
+ "' could not be found");
512 } catch (System
.IO
.IOException
){
513 Console
.WriteLine ("Source file `" + spec
+ "' could not be found");
516 foreach (string f
in files
)
522 string [] dirs
= null;
525 dirs
= Directory
.GetDirectories (path
);
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
)
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
];
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
);
573 args
= AddArgs (args
, extra_args
);
577 if (parsing_options
){
579 parsing_options
= false;
583 if (arg
.StartsWith ("-")){
584 if (UnixParseOption (arg
, ref args
, ref i
))
588 string csc_opt
= "/" + arg
.Substring (1);
589 if (CSCParseOption (csc_opt
, ref args
, ref i
))
592 if (arg
.StartsWith ("/")){
593 if (CSCParseOption (arg
, ref args
, ref i
))
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");
610 // Load Core Library for default compilation
613 references
.Insert (0, "mscorlib");
617 // Load assemblies required
619 link_paths
.Add (GetSystemDir ());
620 link_paths
.Add (Directory
.GetCurrentDirectory ());
628 private static void Main (string [] args
) {
629 if (args
.Length
< 1) {
631 Environment
.Exit (0);
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
);
664 static string GetCodeFromFile (string fn
)
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 ();