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 ();
37 string mcs_topdir, class_dir;
39 public MsbuildGenerator (string dir)
43 foreach (char c in dir){
45 mcs_topdir = "..\\" + mcs_topdir;
47 class_dir = mcs_topdir.Substring (3);
50 base_dir = "..\\..\\..\\mcs\\" + dir;
55 StringBuilder defines = new StringBuilder ();
59 Target Target = Target.Exe;
60 string TargetExt = ".exe";
63 bool VerifyClsCompliance = true;
66 bool want_debugging_support = false;
68 bool WarningsAreErrors;
69 Dictionary<string,string> embedded_resources = new Dictionary<string,string> ();
70 List<string> references = new List<string> ();
71 List<string> reference_aliases = new List<string> ();
72 List<string> warning_as_error = new List<string> ();
74 List<int> ignore_warning = new List<int> ();
75 bool load_default_config = true;
76 string StrongNameKeyFile;
77 string StrongNameKeyContainer;
78 bool StrongNameDelaySign = false;
79 LanguageVersion Version = LanguageVersion.Default;
82 readonly char[] argument_value_separator = new char [] { ';', ',' };
85 // This parses the -arg and /arg options to the compiler, even if the strings
86 // in the following text use "/arg" on the strings.
88 bool CSCParseOption (string option, ref string [] args)
90 int idx = option.IndexOf (':');
97 arg = option.Substring (0, idx);
99 value = option.Substring (idx + 1);
102 switch (arg.ToLower (CultureInfo.InvariantCulture)){
114 Target = Target.WinExe;
118 Target = Target.Library;
123 Target = Target.Module;
124 TargetExt = ".netmodule";
133 if (value.Length == 0){
135 Environment.Exit (1);
153 case "/incremental+":
154 case "/incremental-":
160 if (value.Length == 0){
162 Environment.Exit (1);
165 foreach (string d in value.Split (argument_value_separator)){
166 if (defines.Length != 0)
167 defines.Append (";");
176 // We should collect data, runtime, etc and store in the file specified
180 case "/linkresource":
183 bool embeded = arg [1] == 'r' || arg [1] == 'R';
184 string[] s = value.Split (argument_value_separator);
187 if (s[0].Length == 0)
189 embedded_resources [s[0]] = Path.GetFileName (s[0]);
192 embedded_resources [s [0]] = s [1];
195 Console.WriteLine ("Does not support this method yet: {0}", arg);
196 Environment.Exit (1);
199 Console.WriteLine ("Wrong number of arguments for option `{0}'", option);
200 Environment.Exit (1);
208 Console.WriteLine ("/recurse not supported");
209 Environment.Exit (1);
214 if (value.Length == 0){
215 Console.WriteLine ("-reference requires an argument");
216 Environment.Exit (1);
219 string[] refs = value.Split (argument_value_separator);
220 foreach (string r in refs){
222 int index = val.IndexOf ('=');
224 reference_aliases.Add (r);
229 references.Add (val);
240 Console.WriteLine ("{0} = not supported", arg);
241 throw new Exception ();
244 win32IconFile = value;
248 want_debugging_support = false;
253 want_debugging_support = true;
270 VerifyClsCompliance = false;
283 case "/warnaserror+":
284 if (value.Length == 0) {
285 WarningsAreErrors = true;
287 foreach (string wid in value.Split (argument_value_separator))
288 warning_as_error.Add (wid);
292 case "/warnaserror-":
293 if (value.Length == 0) {
294 WarningsAreErrors = false;
296 foreach (string wid in value.Split (argument_value_separator))
297 warning_as_error.Remove (wid);
302 WarningLevel = Int32.Parse (value);
308 if (value.Length == 0){
309 Console.WriteLine ("/nowarn requires an argument");
310 Environment.Exit (1);
313 warns = value.Split (argument_value_separator);
314 foreach (string wc in warns){
316 if (wc.Trim ().Length == 0)
319 int warn = Int32.Parse (wc);
321 throw new ArgumentOutOfRangeException("warn");
323 ignore_warning.Add (warn);
325 Console.WriteLine (String.Format("`{0}' is not a valid warning number", wc));
326 Environment.Exit (1);
333 load_default_config = false;
349 if (value == String.Empty) {
350 Console.WriteLine ("{0} requires an argument", arg);
351 Environment.Exit (1);
353 StrongNameKeyFile = value;
355 case "/keycontainer":
356 if (value == String.Empty) {
357 Console.WriteLine ("{0} requires an argument", arg);
358 Environment.Exit (1);
360 StrongNameKeyContainer = value;
363 StrongNameDelaySign = true;
366 StrongNameDelaySign = false;
370 switch (value.ToLower (CultureInfo.InvariantCulture)) {
372 Version = LanguageVersion.ISO_1;
376 Version = LanguageVersion.Default;
379 Version = LanguageVersion.ISO_2;
382 Version = LanguageVersion.Future;
385 Console.WriteLine ("Invalid option `{0}' for /langversion. It must be either `ISO-1', `ISO-2' or `Default'", value);
386 Environment.Exit (1);
397 static string [] LoadArgs (string file)
400 var args = new List<string> ();
403 f = new StreamReader (file);
408 StringBuilder sb = new StringBuilder ();
410 while ((line = f.ReadLine ()) != null){
413 for (int i = 0; i < t; i++){
416 if (c == '"' || c == '\''){
419 for (i++; i < t; i++){
426 } else if (c == ' '){
428 args.Add (sb.ToString ());
435 args.Add (sb.ToString ());
440 string [] ret_value = new string [args.Count];
441 args.CopyTo (ret_value, 0);
446 static string Load (string f)
448 if (File.Exists (f)){
449 using (var sr = new StreamReader (f)){
450 return sr.ReadToEnd ();
456 public void Generate (XElement xproject)
458 string library = xproject.Attribute ("library").Value;
459 string boot, mcs, flags, output_name, built_sources, library_output, response;
461 boot = xproject.Element ("boot").Value;
462 mcs = xproject.Element ("mcs").Value;
463 flags = xproject.Element ("flags").Value;
464 output_name =xproject.Element ("output").Value;
465 built_sources = xproject.Element ("built_sources").Value;
466 library_output = xproject.Element ("library_output").Value;
467 response = xproject.Element ("response").Value;
470 // Prebuild code, might be in inputs, check:
471 // inputs/LIBRARY-PROFILE.pre
472 // inputs/LIBRARY.pre
474 string prebuild = Load (library + ".pre");
476 int q = library.IndexOf ("-");
478 prebuild = prebuild + Load (library.Substring (0, q) + ".pre");
480 var all_args = new Queue<string []> ();
481 all_args.Enqueue (flags.Split ());
482 while (all_args.Count > 0){
483 string [] f = all_args.Dequeue ();
485 for (int i = 0; i < f.Length; i++){
487 f [i] = "/" + f [i].Substring (1);
489 if (f [i][0] == '@') {
490 string [] extra_args;
491 string response_file = f [i].Substring (1);
493 extra_args = LoadArgs (base_dir + "\\" + response_file);
494 if (extra_args == null) {
495 Console.WriteLine ("Unable to open response file: " + response_file);
496 Environment.Exit (1);
499 all_args.Enqueue (extra_args);
503 if (CSCParseOption (f [i], ref f))
505 Console.WriteLine ("Failure with {0}", f [i]);
506 Environment.Exit (1);
510 string [] source_files;
511 using (var reader = new StreamReader (base_dir + "\\" + response)){
512 source_files = reader.ReadToEnd ().Split ();
514 StringBuilder sources = new StringBuilder ();
515 foreach (string s in source_files){
518 sources.Append (String.Format (" <Compile Include=\"{0}\" />\n", s));
522 // Compute the csc command that we need to use
524 // The mcs string is formatted like this:
525 // MONO_PATH=./../../class/lib/basic: /cvs/mono/runtime/mono-wrapper ./../../class/lib/basic/mcs.exe
527 // The first block is a set of MONO_PATHs, the last part is the compiler
529 if (mcs.StartsWith ("MONO_PATH="))
530 mcs = mcs.Substring (10);
532 var compiler = mcs.Substring (mcs.LastIndexOf (' ') + 1);
533 if (compiler.EndsWith ("class/lib/basic/mcs.exe"))
535 else if (compiler.EndsWith ("class/lib/net_1_1_bootstrap/mcs.exe"))
536 compiler = "net_1_1_bootstrap";
537 else if (compiler.EndsWith ("class/lib/net_1_1/mcs.exe"))
538 compiler = "net_1_1";
539 else if (compiler.EndsWith ("class/lib/net_2_0_bootstrap/gmcs.exe"))
540 compiler = "net_2_0_bootstrap";
541 else if (compiler.EndsWith ("mcs/gmcs.exe"))
543 else if (compiler.EndsWith ("class/lib/net_2_1_bootstrap/smcs.exe"))
544 compiler = "net_2_1_bootstrap";
545 else if (compiler.EndsWith ("class/lib/net_2_1_raw/smcs.exe"))
546 compiler = "net_2_1_raw";
548 Console.WriteLine ("Can not determine compiler from {0}", compiler);
549 Environment.Exit (1);
552 var mono_paths = mcs.Substring (0, mcs.IndexOf (' ')).Split (new char [] {':'});
553 for (int i = 0; i < mono_paths.Length; i++){
554 int p = mono_paths [i].LastIndexOf ('/');
556 mono_paths [i] = mono_paths [i].Substring (p + 1);
559 var encoded_mono_paths = string.Join ("-", mono_paths).Replace ("--", "-");
560 var encoded_mp_compiler = (encoded_mono_paths + "-" + compiler).Replace ("--", "-");
562 string csc_tool_path = mcs_topdir + "..\\mono\\msvc\\scripts\\" + encoded_mp_compiler;
563 if (!Directory.Exists (encoded_mp_compiler)){
564 Console.WriteLine ("Created {0}", encoded_mp_compiler);
565 Directory.CreateDirectory (encoded_mp_compiler);
567 if (!File.Exists (Path.Combine (encoded_mp_compiler, "csc.exe"))){
568 File.Copy ("monowrap.exe", Path.Combine (encoded_mp_compiler, "csc.exe"));
569 File.Copy ("monowrap.pdb", Path.Combine (encoded_mp_compiler, "csc.pdb"));
572 var refs = new StringBuilder ();
574 if (references.Count > 0 || reference_aliases.Count > 0){
575 refs.Append ("<ItemGroup>\n");
576 string last = mono_paths [0].Substring (mono_paths [0].LastIndexOf ('/') + 1);
578 string hint_path = class_dir + "\\lib\\" + last;
580 foreach (string r in references){
581 refs.Append (" <Reference Include=\"" + r + "\">\n");
582 refs.Append (" <SpecificVersion>False</SpecificVersion>\n");
583 refs.Append (" <HintPath>" + hint_path + "\\" + r + "</HintPath>\n");
584 refs.Append (" </Reference>\n");
587 foreach (string r in reference_aliases){
588 int index = r.IndexOf ('=');
589 string alias = r.Substring (0, index);
590 string assembly = r.Substring (index + 1);
592 refs.Append (" <Reference Include=\"" + assembly + "\">\n");
593 refs.Append (" <SpecificVersion>False</SpecificVersion>\n");
594 refs.Append (" <HintPath>" + hint_path + "\\" + r + "</HintPath>\n");
595 refs.Append (" <Aliases>" + alias + "</Aliases>\n");
596 refs.Append (" </Reference>\n");
599 refs.Append (" </ItemGroup>\n");
603 // Replace the template values
605 string output = template.
606 Replace ("@DEFINES@", defines.ToString ()).
607 Replace ("@NOSTDLIB@", StdLib ? "" : "<NoStdLib>true</NoStdLib>").
608 Replace ("@ALLOWUNSAFE@", Unsafe ? "<AllowUnsafeBlocks>true</AllowUnsafeBlocks>" : "").
609 Replace ("@ASSEMBLYNAME@", Path.GetFileNameWithoutExtension (output_name)).
610 Replace ("@OUTPUTDIR@", Path.GetDirectoryName (library_output)).
611 Replace ("@DEFINECONSTANTS@", defines.ToString ()).
612 Replace ("@CSCTOOLPATH@", csc_tool_path).
613 Replace ("@DEBUG@", want_debugging_support ? "true" : "false").
614 Replace ("@DEBUGTYPE@", want_debugging_support ? "full" : "pdbonly").
615 Replace ("@REFERENCES@", refs.ToString ()).
616 Replace ("@PREBUILD@", prebuild).
617 Replace ("@SOURCES@", sources.ToString ());
620 string ofile = "..\\..\\..\\mcs\\" + dir + "\\" + library + ".csproj";
621 //Console.WriteLine ("Generated {0}", ofile.Replace ("\\", "/"));
622 using (var o = new StreamWriter (ofile)){
623 o.WriteLine (output);
629 public class Driver {
631 static void Main (string [] args)
633 if (!File.Exists ("genproj.cs") || !File.Exists ("monowrap.cs")){
634 Console.WriteLine ("This command should be ran from mono/msvc/scripts");
635 Environment.Exit (1);
638 XDocument doc = XDocument.Load ("order.xml");
639 foreach (XElement project in doc.Root.Elements ()){
640 string dir = project.Attribute ("dir").Value;
641 string library = project.Attribute ("library").Value;
644 // Do only class libraries for now
646 if (!dir.StartsWith ("class"))
650 // Do not do 2.1 for now, it is not working yet
652 if (library.Contains ("net_2_1"))
655 var gen = new MsbuildGenerator (dir);
657 gen.Generate (project);
658 } catch (Exception e) {
659 Console.WriteLine ("Error in {0}\n{1}", dir, e);