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/gmcs.exe"))
611 else if (compiler
.EndsWith ("class/lib/net_2_0_bootstrap/gmcs.exe"))
612 compiler
= "net_2_0_bootstrap";
613 else if (compiler
.EndsWith ("mcs/gmcs.exe"))
615 else if (compiler
.EndsWith ("class/lib/moonlight_bootstrap/smcs.exe"))
616 compiler
= "moonlight_bootstrap";
617 else if (compiler
.EndsWith ("class/lib/moonlight_raw/smcs.exe"))
618 compiler
= "moonlight_raw";
619 else if (compiler
.EndsWith ("class/lib/net_4_0_bootstrap/dmcs.exe"))
620 compiler
= "net_4_0_bootstrap";
621 else if (compiler
.EndsWith ("class/lib/net_4_0/dmcs.exe"))
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 ("moonlight") || 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");