3 using System.Collections.Generic;
5 using System.Globalization;
9 Library, Exe, Module, WinExe
12 public enum LanguageVersion
22 class MsbuildGenerator {
25 Console.WriteLine ("Invalid argument");
28 static string template;
29 static MsbuildGenerator ()
31 using (var input = new StreamReader ("csproj.tmpl")){
32 template = input.ReadToEnd ();
36 // The directory as specified in order.xml
40 // Our base directory, this is relative to our exectution point mono/msvc/scripts
45 // Class directory, relative to
48 public MsbuildGenerator (string dir)
54 class_dir = "..\\class\\";
55 base_dir = "..\\..\\..\\mcs\\mcs";
59 foreach (char c in dir){
61 mcs_topdir = "..\\" + mcs_topdir;
63 class_dir = mcs_topdir.Substring (3);
65 base_dir = "..\\..\\..\\mcs\\" + dir;
71 StringBuilder defines = new StringBuilder ();
75 Target Target = Target.Exe;
76 string TargetExt = ".exe";
79 bool VerifyClsCompliance = true;
82 bool want_debugging_support = false;
84 bool WarningsAreErrors;
85 Dictionary<string,string> embedded_resources = new Dictionary<string,string> ();
86 List<string> references = new List<string> ();
87 List<string> reference_aliases = new List<string> ();
88 List<string> warning_as_error = new List<string> ();
90 List<int> ignore_warning = new List<int> ();
91 bool load_default_config = true;
92 string StrongNameKeyFile;
93 string StrongNameKeyContainer;
94 bool StrongNameDelaySign = false;
95 LanguageVersion Version = LanguageVersion.Default;
98 readonly char[] argument_value_separator = new char [] { ';', ',' };
101 // This parses the -arg and /arg options to the compiler, even if the strings
102 // in the following text use "/arg" on the strings.
104 bool CSCParseOption (string option, ref string [] args)
106 int idx = option.IndexOf (':');
113 arg = option.Substring (0, idx);
115 value = option.Substring (idx + 1);
118 switch (arg.ToLower (CultureInfo.InvariantCulture)){
130 Target = Target.WinExe;
134 Target = Target.Library;
139 Target = Target.Module;
140 TargetExt = ".netmodule";
149 if (value.Length == 0){
151 Environment.Exit (1);
169 case "/incremental+":
170 case "/incremental-":
176 if (value.Length == 0){
178 Environment.Exit (1);
181 foreach (string d in value.Split (argument_value_separator)){
182 if (defines.Length != 0)
183 defines.Append (";");
192 // We should collect data, runtime, etc and store in the file specified
196 case "/linkresource":
199 bool embeded = arg [1] == 'r' || arg [1] == 'R';
200 string[] s = value.Split (argument_value_separator);
203 if (s[0].Length == 0)
205 embedded_resources [s[0]] = Path.GetFileName (s[0]);
208 embedded_resources [s [0]] = s [1];
211 Console.WriteLine ("Does not support this method yet: {0}", arg);
212 Environment.Exit (1);
215 Console.WriteLine ("Wrong number of arguments for option `{0}'", option);
216 Environment.Exit (1);
224 Console.WriteLine ("/recurse not supported");
225 Environment.Exit (1);
230 if (value.Length == 0){
231 Console.WriteLine ("-reference requires an argument");
232 Environment.Exit (1);
235 string[] refs = value.Split (argument_value_separator);
236 foreach (string r in refs){
238 int index = val.IndexOf ('=');
240 reference_aliases.Add (r);
245 references.Add (val);
256 Console.WriteLine ("{0} = not supported", arg);
257 throw new Exception ();
260 win32IconFile = value;
264 want_debugging_support = false;
269 want_debugging_support = true;
286 VerifyClsCompliance = false;
299 case "/warnaserror+":
300 if (value.Length == 0) {
301 WarningsAreErrors = true;
303 foreach (string wid in value.Split (argument_value_separator))
304 warning_as_error.Add (wid);
308 case "/warnaserror-":
309 if (value.Length == 0) {
310 WarningsAreErrors = false;
312 foreach (string wid in value.Split (argument_value_separator))
313 warning_as_error.Remove (wid);
318 WarningLevel = Int32.Parse (value);
324 if (value.Length == 0){
325 Console.WriteLine ("/nowarn requires an argument");
326 Environment.Exit (1);
329 warns = value.Split (argument_value_separator);
330 foreach (string wc in warns){
332 if (wc.Trim ().Length == 0)
335 int warn = Int32.Parse (wc);
337 throw new ArgumentOutOfRangeException("warn");
339 ignore_warning.Add (warn);
341 Console.WriteLine (String.Format("`{0}' is not a valid warning number", wc));
342 Environment.Exit (1);
349 load_default_config = false;
365 if (value == String.Empty) {
366 Console.WriteLine ("{0} requires an argument", arg);
367 Environment.Exit (1);
369 StrongNameKeyFile = value;
371 case "/keycontainer":
372 if (value == String.Empty) {
373 Console.WriteLine ("{0} requires an argument", arg);
374 Environment.Exit (1);
376 StrongNameKeyContainer = value;
379 StrongNameDelaySign = true;
382 StrongNameDelaySign = false;
386 switch (value.ToLower (CultureInfo.InvariantCulture)) {
388 Version = LanguageVersion.ISO_1;
392 Version = LanguageVersion.Default;
395 Version = LanguageVersion.ISO_2;
398 Version = LanguageVersion.Future;
401 Console.WriteLine ("Invalid option `{0}' for /langversion. It must be either `ISO-1', `ISO-2' or `Default'", value);
402 Environment.Exit (1);
413 static string [] LoadArgs (string file)
416 var args = new List<string> ();
419 f = new StreamReader (file);
424 StringBuilder sb = new StringBuilder ();
426 while ((line = f.ReadLine ()) != null){
429 for (int i = 0; i < t; i++){
432 if (c == '"' || c == '\''){
435 for (i++; i < t; i++){
442 } else if (c == ' '){
444 args.Add (sb.ToString ());
451 args.Add (sb.ToString ());
456 string [] ret_value = new string [args.Count];
457 args.CopyTo (ret_value, 0);
462 static string Load (string f)
464 if (File.Exists (f)){
465 using (var sr = new StreamReader (f)){
466 return sr.ReadToEnd ();
472 public void Generate (XElement xproject)
474 string library = xproject.Attribute ("library").Value;
475 string boot, mcs, flags, output_name, built_sources, library_output, response;
477 boot = xproject.Element ("boot").Value;
478 mcs = xproject.Element ("mcs").Value;
479 flags = xproject.Element ("flags").Value;
480 output_name =xproject.Element ("output").Value;
481 built_sources = xproject.Element ("built_sources").Value;
482 library_output = xproject.Element ("library_output").Value;
483 response = xproject.Element ("response").Value;
486 // Prebuild code, might be in inputs, check:
487 // inputs/LIBRARY-PROFILE.pre
488 // inputs/LIBRARY.pre
490 string prebuild = Load (library + ".pre");
492 int q = library.IndexOf ("-");
494 prebuild = prebuild + Load (library.Substring (0, q) + ".pre");
496 var all_args = new Queue<string []> ();
497 all_args.Enqueue (flags.Split ());
498 while (all_args.Count > 0){
499 string [] f = all_args.Dequeue ();
501 for (int i = 0; i < f.Length; i++){
503 f [i] = "/" + f [i].Substring (1);
505 if (f [i][0] == '@') {
506 string [] extra_args;
507 string response_file = f [i].Substring (1);
509 extra_args = LoadArgs (base_dir + "\\" + response_file);
510 if (extra_args == null) {
511 Console.WriteLine ("Unable to open response file: " + response_file);
512 Environment.Exit (1);
515 all_args.Enqueue (extra_args);
519 if (CSCParseOption (f [i], ref f))
521 Console.WriteLine ("Failure with {0}", f [i]);
522 Environment.Exit (1);
526 string [] source_files;
527 using (var reader = new StreamReader (base_dir + "\\" + response)){
528 source_files = reader.ReadToEnd ().Split ();
530 StringBuilder sources = new StringBuilder ();
531 foreach (string s in source_files){
534 sources.Append (String.Format (" <Compile Include=\"{0}\" />\n", s.Replace ("/", "\\")));
536 foreach (string s in built_sources.Split ()){
540 sources.Append (String.Format (" <Compile Include=\"{0}\" />\n", s.Replace ("/", "\\")));
544 // Compute the csc command that we need to use
546 // The mcs string is formatted like this:
547 // MONO_PATH=./../../class/lib/basic: /cvs/mono/runtime/mono-wrapper ./../../class/lib/basic/mcs.exe
549 // The first block is a set of MONO_PATHs, the last part is the compiler
551 if (mcs.StartsWith ("MONO_PATH="))
552 mcs = mcs.Substring (10);
554 var compiler = mcs.Substring (mcs.LastIndexOf (' ') + 1);
555 if (compiler.EndsWith ("class/lib/basic/mcs.exe"))
557 else if (compiler.EndsWith ("class/lib/net_1_1_bootstrap/mcs.exe"))
558 compiler = "net_1_1_bootstrap";
559 else if (compiler.EndsWith ("class/lib/net_1_1/mcs.exe"))
560 compiler = "net_1_1";
561 else if (compiler.EndsWith ("class/lib/net_2_0_bootstrap/gmcs.exe"))
562 compiler = "net_2_0_bootstrap";
563 else if (compiler.EndsWith ("mcs/gmcs.exe"))
565 else if (compiler.EndsWith ("class/lib/net_2_1_bootstrap/smcs.exe"))
566 compiler = "net_2_1_bootstrap";
567 else if (compiler.EndsWith ("class/lib/net_2_1_raw/smcs.exe"))
568 compiler = "net_2_1_raw";
570 Console.WriteLine ("Can not determine compiler from {0}", compiler);
571 Environment.Exit (1);
574 var mono_paths = mcs.Substring (0, mcs.IndexOf (' ')).Split (new char [] {':'});
575 for (int i = 0; i < mono_paths.Length; i++){
576 int p = mono_paths [i].LastIndexOf ('/');
578 mono_paths [i] = mono_paths [i].Substring (p + 1);
581 var encoded_mono_paths = string.Join ("-", mono_paths).Replace ("--", "-");
582 var encoded_mp_compiler = (encoded_mono_paths + "-" + compiler).Replace ("--", "-");
584 string csc_tool_path = mcs_topdir + "..\\mono\\msvc\\scripts\\" + encoded_mp_compiler;
585 if (!Directory.Exists (encoded_mp_compiler)){
586 Console.WriteLine ("Created {0}", encoded_mp_compiler);
587 Directory.CreateDirectory (encoded_mp_compiler);
589 if (!File.Exists (Path.Combine (encoded_mp_compiler, "csc.exe"))){
590 File.Copy ("monowrap.exe", Path.Combine (encoded_mp_compiler, "csc.exe"));
591 File.Copy ("monowrap.pdb", Path.Combine (encoded_mp_compiler, "csc.pdb"));
594 var refs = new StringBuilder ();
596 // mcs is different that csc in this regard, somehow with -noconfig we still import System and System.XML
598 if (dir == "mcs" && !load_default_config){
599 references.Add ("System.dll");
600 references.Add ("System.Xml.dll");
603 if (references.Count > 0 || reference_aliases.Count > 0){
604 refs.Append ("<ItemGroup>\n");
605 string last = mono_paths [0].Substring (mono_paths [0].LastIndexOf ('/') + 1);
607 string hint_path = class_dir + "\\lib\\" + last;
609 foreach (string r in references){
610 refs.Append (" <Reference Include=\"" + r + "\">\n");
611 refs.Append (" <SpecificVersion>False</SpecificVersion>\n");
612 refs.Append (" <HintPath>" + hint_path + "\\" + r + "</HintPath>\n");
613 refs.Append (" </Reference>\n");
616 foreach (string r in reference_aliases){
617 int index = r.IndexOf ('=');
618 string alias = r.Substring (0, index);
619 string assembly = r.Substring (index + 1);
621 refs.Append (" <Reference Include=\"" + assembly + "\">\n");
622 refs.Append (" <SpecificVersion>False</SpecificVersion>\n");
623 refs.Append (" <HintPath>" + hint_path + "\\" + r + "</HintPath>\n");
624 refs.Append (" <Aliases>" + alias + "</Aliases>\n");
625 refs.Append (" </Reference>\n");
628 refs.Append (" </ItemGroup>\n");
632 Path.GetDirectoryName (library_output);
634 Console.WriteLine ("Error in path: {0} while processing {1}", library_output, library);
638 // Replace the template values
640 string output = template.
641 Replace ("@DEFINES@", defines.ToString ()).
642 Replace ("@NOSTDLIB@", StdLib ? "" : "<NoStdLib>true</NoStdLib>").
643 Replace ("@ALLOWUNSAFE@", Unsafe ? "<AllowUnsafeBlocks>true</AllowUnsafeBlocks>" : "").
644 Replace ("@ASSEMBLYNAME@", Path.GetFileNameWithoutExtension (output_name)).
645 Replace ("@OUTPUTDIR@", Path.GetDirectoryName (library_output)).
646 Replace ("@DEFINECONSTANTS@", defines.ToString ()).
647 Replace ("@CSCTOOLPATH@", csc_tool_path).
648 Replace ("@DEBUG@", want_debugging_support ? "true" : "false").
649 Replace ("@DEBUGTYPE@", want_debugging_support ? "full" : "pdbonly").
650 Replace ("@REFERENCES@", refs.ToString ()).
651 Replace ("@PREBUILD@", prebuild).
652 Replace ("@SOURCES@", sources.ToString ());
655 string ofile = "..\\..\\..\\mcs\\" + dir + "\\" + library + ".csproj";
656 //Console.WriteLine ("Generated {0}", ofile.Replace ("\\", "/"));
657 using (var o = new StreamWriter (ofile)){
658 o.WriteLine (output);
664 public class Driver {
666 static void Main (string [] args)
668 if (!File.Exists ("genproj.cs") || !File.Exists ("monowrap.cs")){
669 Console.WriteLine ("This command should be ran from mono/msvc/scripts");
670 Environment.Exit (1);
673 XDocument doc = XDocument.Load ("order.xml");
674 foreach (XElement project in doc.Root.Elements ()){
675 string dir = project.Attribute ("dir").Value;
676 string library = project.Attribute ("library").Value;
679 // Do only class libraries for now
681 if (!(dir.StartsWith ("class") || dir.StartsWith ("mcs")))
685 // Do not do 2.1, it is not working yet
686 // Do not do basic, as there is no point (requires a system mcs to be installed).
688 if (library.Contains ("net_2_1") || library.Contains ("-basic"))
691 var gen = new MsbuildGenerator (dir);
693 gen.Generate (project);
694 } catch (Exception e) {
695 Console.WriteLine ("Error in {0}\n{1}", dir, e);