3 using System.Collections.Generic;
5 using System.Globalization;
9 Library, Exe, Module, WinExe
12 public enum LanguageVersion
23 const string header = "Microsoft Visual Studio Solution File, Format Version 10.00\n" +
24 "# Visual Studio 2008";
26 const string project_start = "Project(\"{{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}}\") = \"{0}\", \"{1}\", \"{{{2}}}\"";
27 const string project_end = "EndProject";
29 Dictionary<string, string> libraries = new Dictionary<string, string> ();
31 public void Add (string library)
34 libraries.Add (library, Guid.NewGuid ().ToString ().ToUpper ());
36 catch (Exception ex) {
37 Console.WriteLine (ex);
41 public void Write (string filename)
43 using (var sln = new StreamWriter (filename)) {
45 sln.WriteLine (header);
46 foreach (var library in libraries) {
47 var library_name = Path.GetFileNameWithoutExtension (library.Key);
48 sln.WriteLine (project_start, library_name, library.Key, library.Value);
49 sln.WriteLine (project_end);
51 sln.WriteLine ("Global");
53 sln.WriteLine ("\tGlobalSection(SolutionConfigurationPlatforms) = preSolution");
54 sln.WriteLine ("\t\tDebug|Any CPU = Debug|Any CPU");
55 sln.WriteLine ("\t\tRelease|Any CPU = Release|Any CPU");
56 sln.WriteLine ("\tEndGlobalSection");
58 sln.WriteLine ("\tGlobalSection(ProjectConfigurationPlatforms) = postSolution");
59 foreach (var library in libraries) {
60 sln.WriteLine ("\t\t{{{0}}}.Debug|Any CPU.ActiveCfg = Debug|Any CPU", library.Value);
61 sln.WriteLine ("\t\t{{{0}}}.Debug|Any CPU.Build.0 = Debug|Any CPU", library.Value);
62 sln.WriteLine ("\t\t{{{0}}}.Release|Any CPU.ActiveCfg = Release|Any CPU", library.Value);
63 sln.WriteLine ("\t\t{{{0}}}.Release|Any CPU.Build.0 = Release|Any CPU", library.Value);
65 sln.WriteLine ("\tEndGlobalSection");
67 sln.WriteLine ("\tGlobalSection(SolutionProperties) = preSolution");
68 sln.WriteLine ("\t\tHideSolutionNode = FALSE");
69 sln.WriteLine ("\tEndGlobalSection");
71 sln.WriteLine ("EndGlobal");
76 class MsbuildGenerator {
79 Console.WriteLine ("Invalid argument");
82 static string template;
83 static MsbuildGenerator ()
85 using (var input = new StreamReader ("csproj.tmpl")){
86 template = input.ReadToEnd ();
90 // The directory as specified in order.xml
94 // Our base directory, this is relative to our exectution point mono/msvc/scripts
99 // Class directory, relative to
102 public MsbuildGenerator (string dir)
108 class_dir = "..\\class\\";
109 base_dir = "..\\..\\..\\mcs\\mcs";
113 foreach (char c in dir){
115 mcs_topdir = "..\\" + mcs_topdir;
117 class_dir = mcs_topdir.Substring (3);
119 base_dir = "..\\..\\..\\mcs\\" + dir;
125 StringBuilder defines = new StringBuilder ();
129 Target Target = Target.Exe;
130 string TargetExt = ".exe";
132 bool Optimize = true;
133 bool VerifyClsCompliance = true;
135 string win32IconFile;
136 bool want_debugging_support = false;
137 bool Checked = false;
138 bool WarningsAreErrors;
139 Dictionary<string,string> embedded_resources = new Dictionary<string,string> ();
140 List<string> references = new List<string> ();
141 List<string> reference_aliases = new List<string> ();
142 List<string> warning_as_error = new List<string> ();
143 int WarningLevel = 4;
144 List<int> ignore_warning = new List<int> ();
145 bool load_default_config = true;
146 string StrongNameKeyFile;
147 string StrongNameKeyContainer;
148 bool StrongNameDelaySign = false;
149 LanguageVersion Version = LanguageVersion.Default;
152 readonly char[] argument_value_separator = new char [] { ';', ',' };
155 // This parses the -arg and /arg options to the compiler, even if the strings
156 // in the following text use "/arg" on the strings.
158 bool CSCParseOption (string option, ref string [] args)
160 int idx = option.IndexOf (':');
167 arg = option.Substring (0, idx);
169 value = option.Substring (idx + 1);
172 switch (arg.ToLower (CultureInfo.InvariantCulture)){
184 Target = Target.WinExe;
188 Target = Target.Library;
193 Target = Target.Module;
194 TargetExt = ".netmodule";
203 if (value.Length == 0){
205 Environment.Exit (1);
223 case "/incremental+":
224 case "/incremental-":
230 if (value.Length == 0){
232 Environment.Exit (1);
235 foreach (string d in value.Split (argument_value_separator)){
236 if (defines.Length != 0)
237 defines.Append (";");
246 // We should collect data, runtime, etc and store in the file specified
250 case "/linkresource":
253 bool embeded = arg [1] == 'r' || arg [1] == 'R';
254 string[] s = value.Split (argument_value_separator);
257 if (s[0].Length == 0)
259 embedded_resources [s[0]] = Path.GetFileName (s[0]);
262 embedded_resources [s [0]] = s [1];
265 Console.WriteLine ("Does not support this method yet: {0}", arg);
266 Environment.Exit (1);
269 Console.WriteLine ("Wrong number of arguments for option `{0}'", option);
270 Environment.Exit (1);
278 Console.WriteLine ("/recurse not supported");
279 Environment.Exit (1);
284 if (value.Length == 0){
285 Console.WriteLine ("-reference requires an argument");
286 Environment.Exit (1);
289 string[] refs = value.Split (argument_value_separator);
290 foreach (string r in refs){
292 int index = val.IndexOf ('=');
294 reference_aliases.Add (r);
299 references.Add (val);
310 Console.WriteLine ("{0} = not supported", arg);
311 throw new Exception ();
314 win32IconFile = value;
318 want_debugging_support = false;
323 want_debugging_support = true;
340 VerifyClsCompliance = false;
353 case "/warnaserror+":
354 if (value.Length == 0) {
355 WarningsAreErrors = true;
357 foreach (string wid in value.Split (argument_value_separator))
358 warning_as_error.Add (wid);
362 case "/warnaserror-":
363 if (value.Length == 0) {
364 WarningsAreErrors = false;
366 foreach (string wid in value.Split (argument_value_separator))
367 warning_as_error.Remove (wid);
372 WarningLevel = Int32.Parse (value);
378 if (value.Length == 0){
379 Console.WriteLine ("/nowarn requires an argument");
380 Environment.Exit (1);
383 warns = value.Split (argument_value_separator);
384 foreach (string wc in warns){
386 if (wc.Trim ().Length == 0)
389 int warn = Int32.Parse (wc);
391 throw new ArgumentOutOfRangeException("warn");
393 ignore_warning.Add (warn);
395 Console.WriteLine (String.Format("`{0}' is not a valid warning number", wc));
396 Environment.Exit (1);
403 load_default_config = false;
419 if (value == String.Empty) {
420 Console.WriteLine ("{0} requires an argument", arg);
421 Environment.Exit (1);
423 StrongNameKeyFile = value;
425 case "/keycontainer":
426 if (value == String.Empty) {
427 Console.WriteLine ("{0} requires an argument", arg);
428 Environment.Exit (1);
430 StrongNameKeyContainer = value;
433 StrongNameDelaySign = true;
436 StrongNameDelaySign = false;
440 switch (value.ToLower (CultureInfo.InvariantCulture)) {
442 Version = LanguageVersion.ISO_1;
446 Version = LanguageVersion.Default;
449 Version = LanguageVersion.ISO_2;
452 Version = LanguageVersion.Future;
455 Console.WriteLine ("Invalid option `{0}' for /langversion. It must be either `ISO-1', `ISO-2' or `Default'", value);
456 Environment.Exit (1);
467 static string [] LoadArgs (string file)
470 var args = new List<string> ();
473 f = new StreamReader (file);
478 StringBuilder sb = new StringBuilder ();
480 while ((line = f.ReadLine ()) != null){
483 for (int i = 0; i < t; i++){
486 if (c == '"' || c == '\''){
489 for (i++; i < t; i++){
496 } else if (c == ' '){
498 args.Add (sb.ToString ());
505 args.Add (sb.ToString ());
510 string [] ret_value = new string [args.Count];
511 args.CopyTo (ret_value, 0);
516 static string Load (string f)
518 if (File.Exists (f)){
519 using (var sr = new StreamReader (f)){
520 return sr.ReadToEnd ();
526 public string Generate (XElement xproject)
528 string library = xproject.Attribute ("library").Value;
529 string boot, mcs, flags, output_name, built_sources, library_output, response;
531 boot = xproject.Element ("boot").Value;
532 mcs = xproject.Element ("mcs").Value;
533 flags = xproject.Element ("flags").Value;
534 output_name =xproject.Element ("output").Value;
535 built_sources = xproject.Element ("built_sources").Value;
536 library_output = xproject.Element ("library_output").Value;
537 response = xproject.Element ("response").Value;
540 // Prebuild code, might be in inputs, check:
541 // inputs/LIBRARY-PROFILE.pre
542 // inputs/LIBRARY.pre
544 string prebuild = Load (library + ".pre");
546 int q = library.IndexOf ("-");
548 prebuild = prebuild + Load (library.Substring (0, q) + ".pre");
550 var all_args = new Queue<string []> ();
551 all_args.Enqueue (flags.Split ());
552 while (all_args.Count > 0){
553 string [] f = all_args.Dequeue ();
555 for (int i = 0; i < f.Length; i++){
557 f [i] = "/" + f [i].Substring (1);
559 if (f [i][0] == '@') {
560 string [] extra_args;
561 string response_file = f [i].Substring (1);
563 extra_args = LoadArgs (base_dir + "\\" + response_file);
564 if (extra_args == null) {
565 Console.WriteLine ("Unable to open response file: " + response_file);
566 Environment.Exit (1);
569 all_args.Enqueue (extra_args);
573 if (CSCParseOption (f [i], ref f))
575 Console.WriteLine ("Failure with {0}", f [i]);
576 Environment.Exit (1);
580 string [] source_files;
581 using (var reader = new StreamReader (base_dir + "\\" + response)){
582 source_files = reader.ReadToEnd ().Split ();
584 StringBuilder sources = new StringBuilder ();
585 foreach (string s in source_files){
588 sources.Append (String.Format (" <Compile Include=\"{0}\" />\n", s.Replace ("/", "\\")));
590 foreach (string s in built_sources.Split ()){
594 sources.Append (String.Format (" <Compile Include=\"{0}\" />\n", s.Replace ("/", "\\")));
598 // Compute the csc command that we need to use
600 // The mcs string is formatted like this:
601 // MONO_PATH=./../../class/lib/basic: /cvs/mono/runtime/mono-wrapper ./../../class/lib/basic/mcs.exe
603 // The first block is a set of MONO_PATHs, the last part is the compiler
605 if (mcs.StartsWith ("MONO_PATH="))
606 mcs = mcs.Substring (10);
608 var compiler = mcs.Substring (mcs.LastIndexOf (' ') + 1);
609 if (compiler.EndsWith ("class/lib/basic/mcs.exe"))
611 else if (compiler.EndsWith ("class/lib/net_1_1_bootstrap/mcs.exe"))
612 compiler = "net_1_1_bootstrap";
613 else if (compiler.EndsWith ("class/lib/net_1_1/mcs.exe"))
614 compiler = "net_1_1";
615 else if (compiler.EndsWith ("class/lib/net_2_0_bootstrap/gmcs.exe"))
616 compiler = "net_2_0_bootstrap";
617 else if (compiler.EndsWith ("mcs/gmcs.exe"))
619 else if (compiler.EndsWith ("class/lib/net_2_1_bootstrap/smcs.exe"))
620 compiler = "net_2_1_bootstrap";
621 else if (compiler.EndsWith ("class/lib/net_2_1_raw/smcs.exe"))
622 compiler = "net_2_1_raw";
624 Console.WriteLine ("Can not determine compiler from {0}", compiler);
625 Environment.Exit (1);
628 var mono_paths = mcs.Substring (0, mcs.IndexOf (' ')).Split (new char [] {':'});
629 for (int i = 0; i < mono_paths.Length; i++){
630 int p = mono_paths [i].LastIndexOf ('/');
632 mono_paths [i] = mono_paths [i].Substring (p + 1);
635 var encoded_mono_paths = string.Join ("-", mono_paths).Replace ("--", "-");
636 var encoded_mp_compiler = (encoded_mono_paths + "-" + compiler).Replace ("--", "-");
638 string csc_tool_path = mcs_topdir + "..\\mono\\msvc\\scripts\\" + encoded_mp_compiler;
639 if (!Directory.Exists (encoded_mp_compiler)){
640 Console.WriteLine ("Created {0}", encoded_mp_compiler);
641 Directory.CreateDirectory (encoded_mp_compiler);
643 if (!File.Exists (Path.Combine (encoded_mp_compiler, "csc.exe"))){
644 File.Copy ("monowrap.exe", Path.Combine (encoded_mp_compiler, "csc.exe"));
645 File.Copy ("monowrap.pdb", Path.Combine (encoded_mp_compiler, "csc.pdb"));
648 var refs = new StringBuilder ();
650 // mcs is different that csc in this regard, somehow with -noconfig we still import System and System.XML
652 if (dir == "mcs" && !load_default_config){
653 references.Add ("System.dll");
654 references.Add ("System.Xml.dll");
657 if (references.Count > 0 || reference_aliases.Count > 0){
658 refs.Append ("<ItemGroup>\n");
659 string last = mono_paths [0].Substring (mono_paths [0].LastIndexOf ('/') + 1);
661 string hint_path = class_dir + "\\lib\\" + last;
663 foreach (string r in references){
664 refs.Append (" <Reference Include=\"" + r + "\">\n");
665 refs.Append (" <SpecificVersion>False</SpecificVersion>\n");
666 refs.Append (" <HintPath>" + hint_path + "\\" + r + "</HintPath>\n");
667 refs.Append (" </Reference>\n");
670 foreach (string r in reference_aliases){
671 int index = r.IndexOf ('=');
672 string alias = r.Substring (0, index);
673 string assembly = r.Substring (index + 1);
675 refs.Append (" <Reference Include=\"" + assembly + "\">\n");
676 refs.Append (" <SpecificVersion>False</SpecificVersion>\n");
677 refs.Append (" <HintPath>" + hint_path + "\\" + r + "</HintPath>\n");
678 refs.Append (" <Aliases>" + alias + "</Aliases>\n");
679 refs.Append (" </Reference>\n");
682 refs.Append (" </ItemGroup>\n");
686 Path.GetDirectoryName (library_output);
688 Console.WriteLine ("Error in path: {0} while processing {1}", library_output, library);
692 // Replace the template values
694 string output = template.
695 Replace ("@DEFINES@", defines.ToString ()).
696 Replace ("@NOSTDLIB@", StdLib ? "" : "<NoStdLib>true</NoStdLib>").
697 Replace ("@ALLOWUNSAFE@", Unsafe ? "<AllowUnsafeBlocks>true</AllowUnsafeBlocks>" : "").
698 Replace ("@ASSEMBLYNAME@", Path.GetFileNameWithoutExtension (output_name)).
699 Replace ("@OUTPUTDIR@", Path.GetDirectoryName (library_output)).
700 Replace ("@DEFINECONSTANTS@", defines.ToString ()).
701 Replace ("@CSCTOOLPATH@", csc_tool_path).
702 Replace ("@DEBUG@", want_debugging_support ? "true" : "false").
703 Replace ("@DEBUGTYPE@", want_debugging_support ? "full" : "pdbonly").
704 Replace ("@REFERENCES@", refs.ToString ()).
705 Replace ("@PREBUILD@", prebuild).
706 Replace ("@SOURCES@", sources.ToString ());
709 string ofile = "..\\..\\..\\mcs\\" + dir + "\\" + library + ".csproj";
710 ofile = ofile.Replace ('/', '\\');
711 //Console.WriteLine ("Generated {0}", ofile.Replace ("\\", "/"));
712 using (var o = new StreamWriter (ofile)){
713 o.WriteLine (output);
721 public class Driver {
723 static void Main (string [] args)
725 if (!File.Exists ("genproj.cs") || !File.Exists ("monowrap.cs")){
726 Console.WriteLine ("This command should be ran from mono/msvc/scripts");
727 Environment.Exit (1);
730 var sln_gen = new SlnGenerator ();
731 XDocument doc = XDocument.Load ("order.xml");
732 foreach (XElement project in doc.Root.Elements ()){
733 string dir = project.Attribute ("dir").Value;
734 string library = project.Attribute ("library").Value;
737 // Do only class libraries for now
739 if (!(dir.StartsWith ("class") || dir.StartsWith ("mcs")))
743 // Do not do 2.1, it is not working yet
744 // Do not do basic, as there is no point (requires a system mcs to be installed).
746 if (library.Contains ("net_2_1") || library.Contains ("-basic"))
749 var gen = new MsbuildGenerator (dir);
751 sln_gen.Add (gen.Generate (project));
752 } catch (Exception e) {
753 Console.WriteLine ("Error in {0}\n{1}", dir, e);
756 sln_gen.Write ("mcs_full.sln");