3 using System
.Collections
.Generic
;
5 using System
.Globalization
;
7 using System
.Xml
.XPath
;
12 Library
, Exe
, Module
, WinExe
15 public enum LanguageVersion
{
25 public static readonly string NewLine
= "\r\n"; //Environment.NewLine; // "\n";
26 public SlnGenerator (string formatVersion
= "2012")
28 switch (formatVersion
) {
30 this.header
= MakeHeader ("10.00", "2008");
33 this.header
= MakeHeader ("12.00", "2012");
38 const string project_start
= "Project(\"{{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}}\") = \"{0}\", \"{1}\", \"{2}\""; // Note: No need to double up on {} around {2}
39 const string project_end
= "EndProject";
41 public List
<MsbuildGenerator
.VsCsproj
> libraries
= new List
<MsbuildGenerator
.VsCsproj
> ();
44 string MakeHeader (string formatVersion
, string yearTag
)
46 return string.Format ("Microsoft Visual Studio Solution File, Format Version {0}" + NewLine
+ "# Visual Studio {1}", formatVersion
, yearTag
);
49 public void Add (MsbuildGenerator
.VsCsproj vsproj
)
52 libraries
.Add (vsproj
);
53 } catch (Exception ex
) {
54 Console
.WriteLine (ex
);
58 public void Write (string filename
)
60 using (var sln
= new StreamWriter (filename
)) {
62 sln
.WriteLine (header
);
63 foreach (var proj
in libraries
) {
64 sln
.WriteLine (project_start
, proj
.library
, proj
.csProjFilename
, proj
.projectGuid
);
65 sln
.WriteLine (project_end
);
67 sln
.WriteLine ("Global");
69 sln
.WriteLine ("\tGlobalSection(SolutionConfigurationPlatforms) = preSolution");
70 sln
.WriteLine ("\t\tDebug|Any CPU = Debug|Any CPU");
71 sln
.WriteLine ("\t\tRelease|Any CPU = Release|Any CPU");
72 sln
.WriteLine ("\tEndGlobalSection");
74 sln
.WriteLine ("\tGlobalSection(ProjectConfigurationPlatforms) = postSolution");
75 foreach (var proj
in libraries
) {
76 var guid
= proj
.projectGuid
;
77 sln
.WriteLine ("\t\t{0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU", guid
);
78 sln
.WriteLine ("\t\t{0}.Debug|Any CPU.Build.0 = Debug|Any CPU", guid
);
79 sln
.WriteLine ("\t\t{0}.Release|Any CPU.ActiveCfg = Release|Any CPU", guid
);
80 sln
.WriteLine ("\t\t{0}.Release|Any CPU.Build.0 = Release|Any CPU", guid
);
82 sln
.WriteLine ("\tEndGlobalSection");
84 sln
.WriteLine ("\tGlobalSection(SolutionProperties) = preSolution");
85 sln
.WriteLine ("\t\tHideSolutionNode = FALSE");
86 sln
.WriteLine ("\tEndGlobalSection");
88 sln
.WriteLine ("EndGlobal");
92 internal bool ContainsProjectIdentifier (string projId
)
94 return libraries
.FindIndex (x
=> (x
.library
== projId
)) >= 0;
97 public int Count { get { return libraries.Count; }
}
100 class MsbuildGenerator
{
101 static readonly string NewLine
= SlnGenerator
.NewLine
;
102 static XmlNamespaceManager xmlns
;
104 public const string profile_2_0
= "_2_0";
105 public const string profile_3_5
= "_3_5";
106 public const string profile_4_0
= "_4_0";
107 public const string profile_4_5
= "_4_5";
111 Console
.WriteLine ("Invalid argument");
114 static string template
;
115 static MsbuildGenerator ()
117 using (var input
= new StreamReader ("csproj.tmpl")) {
118 template
= input
.ReadToEnd ();
121 xmlns
= new XmlNamespaceManager (new NameTable ());
122 xmlns
.AddNamespace ("x", "http://schemas.microsoft.com/developer/msbuild/2003");
125 // The directory as specified in order.xml
132 public string CsprojFilename
;
135 // Our base directory, this is relative to our exectution point mono/msvc/scripts
139 public string LibraryOutput
, AbsoluteLibraryOutput
;
141 public MsbuildGenerator (XElement xproject
)
143 this.xproject
= xproject
;
144 dir
= xproject
.Attribute ("dir").Value
;
145 library
= xproject
.Attribute ("library").Value
;
146 CsprojFilename
= "..\\..\\mcs\\" + dir
+ "\\" + library
+ ".csproj";
147 LibraryOutput
= xproject
.Element ("library_output").Value
;
149 projectGuid
= LookupOrGenerateGuid ();
150 fx_version
= xproject
.Element ("fx_version").Value
;
151 Csproj
= new VsCsproj () {
152 csProjFilename
= this.CsprojFilename
,
153 projectGuid
= this.projectGuid
,
154 library_output
= this.LibraryOutput
,
155 fx_version
= double.Parse (fx_version
),
156 library
= this.library
,
157 MsbuildGenerator
= this
162 class_dir
= "../class/";
163 base_dir
= "../../mcs/mcs";
167 foreach (char c
in dir
) {
169 mcs_topdir
= "..//" + mcs_topdir
;
171 class_dir
= mcs_topdir
.Substring (3);
173 base_dir
= Path
.Combine ("..", "..", "mcs", dir
);
175 AbsoluteLibraryOutput
= Path
.GetFullPath (Path
.Combine (base_dir
, LibraryOutput
));
178 string LookupOrGenerateGuid ()
180 var projectFile
= NativeName (CsprojFilename
);
181 if (File
.Exists (projectFile
)){
182 var doc
= XDocument
.Load (projectFile
);
183 return doc
.XPathSelectElement ("x:Project/x:PropertyGroup/x:ProjectGuid", xmlns
).Value
;
185 return "{" + Guid.NewGuid ().ToString ().ToUpper () + "}";
190 StringBuilder defines
= new StringBuilder ();
191 bool Optimize
= true;
192 bool want_debugging_support
= false;
193 Dictionary
<string, string> embedded_resources
= new Dictionary
<string, string> ();
194 List
<string> warning_as_error
= new List
<string> ();
195 List
<int> ignore_warning
= new List
<int> ();
196 bool load_default_config
= true;
198 List
<string> references
= new List
<string> ();
199 List
<string> libs
= new List
<string> ();
200 List
<string> reference_aliases
= new List
<string> ();
201 bool showWarnings
= false;
204 #pragma warning disable 0219, 0414
205 int WarningLevel
= 4;
207 bool Checked
= false;
208 bool WarningsAreErrors
;
209 bool VerifyClsCompliance
= true;
210 string win32IconFile
;
211 string StrongNameKeyFile
;
212 bool copyLocal
= true;
213 Target Target
= Target
.Exe
;
214 string TargetExt
= ".exe";
216 string StrongNameKeyContainer
;
217 bool StrongNameDelaySign
= false;
218 LanguageVersion Version
= LanguageVersion
.Default
;
221 // Class directory, relative to
223 #pragma warning restore 0219,414
225 readonly char [] argument_value_separator
= new char [] { ';', ',' }
;
228 // This parses the -arg and /arg options to the compiler, even if the strings
229 // in the following text use "/arg" on the strings.
231 bool CSCParseOption (string option
, ref string [] args
)
233 int idx
= option
.IndexOf (':');
240 arg
= option
.Substring (0, idx
);
242 value = option
.Substring (idx
+ 1);
245 switch (arg
.ToLower (CultureInfo
.InvariantCulture
)) {
257 Target
= Target
.WinExe
;
261 Target
= Target
.Library
;
266 Target
= Target
.Module
;
267 TargetExt
= ".netmodule";
276 if (value.Length
== 0) {
278 Environment
.Exit (1);
296 case "/incremental+":
297 case "/incremental-":
303 if (value.Length
== 0) {
305 Environment
.Exit (1);
308 foreach (string d
in value.Split (argument_value_separator
)) {
309 if (defines
.Length
!= 0)
310 defines
.Append (";");
319 // We should collect data, runtime, etc and store in the file specified
323 case "/linkresource":
326 bool embeded
= arg
[1] == 'r' || arg
[1] == 'R';
327 string [] s
= value.Split (argument_value_separator
);
330 if (s
[0].Length
== 0)
332 embedded_resources
[s
[0]] = Path
.GetFileName (s
[0]);
335 embedded_resources
[s
[0]] = s
[1];
338 Console
.WriteLine ("Does not support this method yet: {0}", arg
);
339 Environment
.Exit (1);
342 Console
.WriteLine ("Wrong number of arguments for option `{0}'", option
);
343 Environment
.Exit (1);
350 Console
.WriteLine ("/recurse not supported");
351 Environment
.Exit (1);
356 if (value.Length
== 0) {
357 Console
.WriteLine ("-reference requires an argument");
358 Environment
.Exit (1);
361 string [] refs
= value.Split (argument_value_separator
);
362 foreach (string r
in refs
) {
364 int index
= val
.IndexOf ('=');
366 reference_aliases
.Add (r
);
371 references
.Add (val
);
381 Console
.WriteLine ("{0} = not supported", arg
);
389 win32IconFile
= value;
393 want_debugging_support
= false;
398 want_debugging_support
= true;
415 VerifyClsCompliance
= false;
428 case "/warnaserror+":
429 if (value.Length
== 0) {
430 WarningsAreErrors
= true;
432 foreach (string wid
in value.Split (argument_value_separator
))
433 warning_as_error
.Add (wid
);
438 // Console.WriteLine ("Warning ignoring /runtime:v4");
441 case "/warnaserror-":
442 if (value.Length
== 0) {
443 WarningsAreErrors
= false;
445 foreach (string wid
in value.Split (argument_value_separator
))
446 warning_as_error
.Remove (wid
);
451 WarningLevel
= Int32
.Parse (value);
457 if (value.Length
== 0) {
458 Console
.WriteLine ("/nowarn requires an argument");
459 Environment
.Exit (1);
462 warns
= value.Split (argument_value_separator
);
463 foreach (string wc
in warns
) {
465 if (wc
.Trim ().Length
== 0)
468 int warn
= Int32
.Parse (wc
);
470 throw new ArgumentOutOfRangeException ("warn");
472 ignore_warning
.Add (warn
);
474 Console
.WriteLine (String
.Format ("`{0}' is not a valid warning number", wc
));
475 Environment
.Exit (1);
482 load_default_config
= false;
498 if (value == String
.Empty
) {
499 Console
.WriteLine ("{0} requires an argument", arg
);
500 Environment
.Exit (1);
502 StrongNameKeyFile
= value;
504 case "/keycontainer":
505 if (value == String
.Empty
) {
506 Console
.WriteLine ("{0} requires an argument", arg
);
507 Environment
.Exit (1);
509 StrongNameKeyContainer
= value;
513 StrongNameDelaySign
= true;
516 StrongNameDelaySign
= false;
520 switch (value.ToLower (CultureInfo
.InvariantCulture
)) {
522 Version
= LanguageVersion
.ISO_1
;
526 Version
= LanguageVersion
.Default
;
529 Version
= LanguageVersion
.ISO_2
;
532 Version
= LanguageVersion
.Future
;
535 Console
.WriteLine ("Invalid option `{0}' for /langversion. It must be either `ISO-1', `ISO-2' or `Default'", value);
536 Environment
.Exit (1);
543 case "/-getresourcestrings":
547 Console
.WriteLine ("Failing with : {0}", arg
);
551 static string [] LoadArgs (string file
)
554 var args
= new List
<string> ();
557 f
= new StreamReader (file
);
562 StringBuilder sb
= new StringBuilder ();
564 while ((line
= f
.ReadLine ()) != null) {
567 for (int i
= 0; i
< t
; i
++) {
570 if (c
== '"' || c
== '\'') {
573 for (i
++; i
< t
; i
++) {
580 } else if (c
== ' ') {
582 args
.Add (sb
.ToString ());
589 args
.Add (sb
.ToString ());
594 string [] ret_value
= new string [args
.Count
];
595 args
.CopyTo (ret_value
, 0);
600 static string Load (string f
)
602 var native
= NativeName (f
);
604 if (File
.Exists (native
)) {
605 using (var sr
= new StreamReader (native
)) {
606 return sr
.ReadToEnd ();
612 public static string NativeName (string path
)
614 if (System
.IO
.Path
.DirectorySeparatorChar
== '/')
615 return path
.Replace ("\\", "/");
617 return path
.Replace ("/", "\\");
620 public class VsCsproj
{
621 public string projectGuid
;
622 public string output
;
623 public string library_output
;
624 public string csProjFilename
;
625 public double fx_version
;
626 public List
<VsCsproj
> projReferences
= new List
<VsCsproj
> ();
627 public string library
;
628 public MsbuildGenerator MsbuildGenerator
;
631 public VsCsproj Csproj
;
633 public VsCsproj
Generate (Dictionary
<string,MsbuildGenerator
> projects
, bool showWarnings
= false)
635 var generatedProjFile
= NativeName (Csproj
.csProjFilename
);
636 //Console.WriteLine ("Generating: {0}", generatedProjFile);
638 string boot
, flags
, output_name
, built_sources
, response
, profile
;
640 boot
= xproject
.Element ("boot").Value
;
641 flags
= xproject
.Element ("flags").Value
;
642 output_name
= xproject
.Element ("output").Value
;
643 built_sources
= xproject
.Element ("built_sources").Value
;
644 response
= xproject
.Element ("response").Value
;
645 //if (library.EndsWith("-build")) fx_version = "2.0"; // otherwise problem if .NET4.5 is installed, seems. (https://github.com/nikhilk/scriptsharp/issues/156)
646 profile
= xproject
.Element ("profile").Value
;
647 if (string.IsNullOrEmpty (response
)) {
648 // Address the issue where entries are missing the fx_version
649 // Should be fixed in the Makefile or elsewhere; this is a workaround
650 //<fx_version>basic</fx_version>
651 //<profile>./../build/deps/mcs.exe.sources.response</profile>
652 //<response></response>
654 profile
= fx_version
;
655 if (response
.Contains ("build") || response
.Contains ("basic") || response
.Contains (profile_2_0
)) {
657 if (response
.Contains (profile_2_0
)) profile
= "net_2_0";
658 } if (response
.Contains ("build") || response
.Contains ("basic") || response
.Contains (profile_2_0
)) {
660 } else if (response
.Contains (profile_3_5
)) {
663 } else if (response
.Contains (profile_4_0
)) {
666 } else if (response
.Contains (profile_4_5
)) {
672 // Prebuild code, might be in inputs, check:
673 // inputs/LIBRARY-PROFILE.pre
674 // inputs/LIBRARY.pre
676 string prebuild
= Load (library
+ ".pre");
677 string prebuild_windows
, prebuild_unix
;
679 int q
= library
.IndexOf ("-");
681 prebuild
= prebuild
+ Load (library
.Substring (0, q
) + ".pre");
683 if (prebuild
.IndexOf ("@MONO@") != -1){
684 prebuild_unix
= prebuild
.Replace ("@MONO@", "mono").Replace ("@CAT@", "cat");
685 prebuild_windows
= prebuild
.Replace ("@MONO@", "").Replace ("@CAT@", "type");
687 prebuild_unix
= prebuild
.Replace ("jay.exe", "jay");
688 prebuild_windows
= prebuild
;
691 const string condition_unix
= "Condition=\" '$(OS)' != 'Windows_NT' \"";
692 const string condition_windows
= "Condition=\" '$(OS)' == 'Windows_NT' \"";
694 " <PreBuildEvent " + condition_unix
+ ">" + NewLine
+ prebuild_unix
+ NewLine
+ " </PreBuildEvent>" + NewLine
+
695 " <PreBuildEvent " + condition_windows
+ ">" + NewLine
+ prebuild_windows
+ NewLine
+ " </PreBuildEvent>" + NewLine
;
697 var all_args
= new Queue
<string []> ();
698 all_args
.Enqueue (flags
.Split ());
699 while (all_args
.Count
> 0) {
700 string [] f
= all_args
.Dequeue ();
702 for (int i
= 0; i
< f
.Length
; i
++) {
703 if (f
[i
].Length
> 0 && f
[i
][0] == '-')
704 f
[i
] = "/" + f
[i
].Substring (1);
706 if (f
[i
] [0] == '@') {
707 string [] extra_args
;
708 string response_file
= f
[i
].Substring (1);
710 var resp_file_full
= Path
.Combine (base_dir
, response_file
);
711 extra_args
= LoadArgs (resp_file_full
);
712 if (extra_args
== null) {
713 Console
.WriteLine ("Unable to open response file: " + resp_file_full
);
714 Environment
.Exit (1);
717 all_args
.Enqueue (extra_args
);
721 if (CSCParseOption (f
[i
], ref f
))
723 Console
.WriteLine ("Failure with {0}", f
[i
]);
724 Environment
.Exit (1);
728 string [] source_files
;
729 //Console.WriteLine ("Base: {0} res: {1}", base_dir, response);
730 using (var reader
= new StreamReader (NativeName (base_dir
+ "\\" + response
))) {
731 source_files
= reader
.ReadToEnd ().Split ();
734 Array
.Sort (source_files
);
736 StringBuilder sources
= new StringBuilder ();
737 foreach (string s
in source_files
) {
741 string src
= s
.Replace ("/", "\\");
742 if (src
.StartsWith (@"Test\..\"))
743 src
= src
.Substring (8, src
.Length
- 8);
745 sources
.AppendFormat (" <Compile Include=\"{0}\" />" + NewLine
, src
);
748 source_files
= built_sources
.Split ();
749 Array
.Sort (source_files
);
751 foreach (string s
in source_files
) {
755 string src
= s
.Replace ("/", "\\");
756 if (src
.StartsWith (@"Test\..\"))
757 src
= src
.Substring (8, src
.Length
- 8);
759 sources
.AppendFormat (" <Compile Include=\"{0}\" />" + NewLine
, src
);
761 sources
.Remove (sources
.Length
- 1, 1);
763 //if (library == "corlib-build") // otherwise, does not compile on fx_version == 4.0
765 // references.Add("System.dll");
766 // references.Add("System.Xml.dll");
769 //if (library == "System.Core-build") // otherwise, slow compile. May be a transient need.
771 // this.ignore_warning.Add(1685);
772 // this.ignore_warning.Add(0436);
775 var refs
= new StringBuilder ();
777 bool is_test
= response
.Contains ("_test_");
779 // F:\src\mono\mcs\class\lib\net_2_0\nunit.framework.dll
780 // F:\src\mono\mcs\class\SomeProject\SomeProject_test_-net_2_0.csproj
781 var nunitLibPath
= string.Format (@"..\lib\{0}\nunit.framework.dll", profile
);
782 refs
.Append (string.Format (" <Reference Include=\"{0}\" />" + NewLine
, nunitLibPath
));
785 var resources
= new StringBuilder ();
786 if (embedded_resources
.Count
> 0) {
787 resources
.AppendFormat (" <ItemGroup>" + NewLine
);
788 foreach (var dk
in embedded_resources
) {
789 resources
.AppendFormat (" <EmbeddedResource Include=\"{0}\">" + NewLine
, dk
.Key
);
790 resources
.AppendFormat (" <LogicalName>{0}</LogicalName>" + NewLine
, dk
.Value
);
791 resources
.AppendFormat (" </EmbeddedResource>" + NewLine
);
793 resources
.AppendFormat (" </ItemGroup>" + NewLine
);
797 if (references
.Count
> 0 || reference_aliases
.Count
> 0) {
798 // -r:mscorlib.dll -r:System.dll
799 //<ProjectReference Include="..\corlib\corlib-basic.csproj">
800 // <Project>{155aef28-c81f-405d-9072-9d52780e3e70}</Project>
801 // <Name>corlib-basic</Name>
802 //</ProjectReference>
803 //<ProjectReference Include="..\System\System-basic.csproj">
804 // <Project>{2094e859-db2f-481f-9630-f89d31d9ed48}</Project>
805 // <Name>System-basic</Name>
806 //</ProjectReference>
807 var refdistinct
= references
.Distinct ();
808 foreach (string r
in refdistinct
) {
809 var match
= GetMatchingCsproj (Path
.GetFileName (r
), projects
);
811 AddProjectReference (refs
, Csproj
, match
, r
, null);
814 Console
.WriteLine ("{0}: Could not find a matching project reference for {1}", library
, Path
.GetFileName (r
));
815 Console
.WriteLine (" --> Adding reference with hintpath instead");
817 refs
.Append (" <Reference Include=\"" + r
+ "\">" + NewLine
);
818 refs
.Append (" <SpecificVersion>False</SpecificVersion>" + NewLine
);
819 refs
.Append (" <HintPath>" + r
+ "</HintPath>" + NewLine
);
820 refs
.Append (" <Private>False</Private>" + NewLine
);
821 refs
.Append (" </Reference>" + NewLine
);
825 foreach (string r
in reference_aliases
) {
826 int index
= r
.IndexOf ('=');
827 string alias = r
.Substring (0, index
);
828 string assembly
= r
.Substring (index
+ 1);
829 var match
= GetMatchingCsproj (assembly
, projects
, explicitPath
: true);
831 AddProjectReference (refs
, Csproj
, match
, r
, alias);
833 throw new NotSupportedException (string.Format ("From {0}, could not find a matching project reference for {1}", library
, r
));
834 refs
.Append (" <Reference Include=\"" + assembly
+ "\">" + NewLine
);
835 refs
.Append (" <SpecificVersion>False</SpecificVersion>" + NewLine
);
836 refs
.Append (" <HintPath>" + r
+ "</HintPath>" + NewLine
);
837 refs
.Append (" <Aliases>" + alias + "</Aliases>" + NewLine
);
838 refs
.Append (" </Reference>" + NewLine
);
845 // ../class/lib/build/tmp/System.Xml.dll [No longer possible, we should be removing this from order.xml]
846 // /class/lib/basic/System.Core.dll
847 // <library_output>mcs.exe</library_output>
848 string build_output_dir
;
849 if (LibraryOutput
.Contains ("/"))
850 build_output_dir
= Path
.GetDirectoryName (LibraryOutput
);
852 build_output_dir
= "bin\\Debug\\" + library
;
855 string postbuild_unix
= string.Empty
;
856 string postbuild_windows
= string.Empty
;
859 " <PostBuildEvent " + condition_unix
+ ">" + NewLine
+ postbuild_unix
+ NewLine
+ " </PostBuildEvent>" + NewLine
+
860 " <PostBuildEvent " + condition_windows
+ ">" + NewLine
+ postbuild_windows
+ NewLine
+ " </PostBuildEvent>";
863 bool basic_or_build
= (library
.Contains ("-basic") || library
.Contains ("-build"));
866 // Replace the template values
869 string strongNameSection
= "";
870 if (StrongNameKeyFile
!= null){
871 strongNameSection
= String
.Format (
872 " <PropertyGroup>" + NewLine
+
873 " <SignAssembly>true</SignAssembly>" + NewLine
+
875 " </PropertyGroup>" + NewLine
+
876 " <PropertyGroup>" + NewLine
+
877 " <AssemblyOriginatorKeyFile>{0}</AssemblyOriginatorKeyFile>" + NewLine
+
878 " </PropertyGroup>", StrongNameKeyFile
, StrongNameDelaySign
? " <DelaySign>true</DelaySign>" + NewLine
: "");
880 Csproj
.output
= template
.
881 Replace ("@SIGNATURE@", strongNameSection
).
882 Replace ("@PROJECTGUID@", Csproj
.projectGuid
).
883 Replace ("@DEFINES@", defines
.ToString ()).
884 Replace ("@DISABLEDWARNINGS@", string.Join (",", (from i
in ignore_warning
select i
.ToString ()).ToArray ())).
885 //Replace("@NOSTDLIB@", (basic_or_build || (!StdLib)) ? "<NoStdLib>true</NoStdLib>" : string.Empty).
886 Replace ("@NOSTDLIB@", "<NoStdLib>" + (!StdLib
).ToString () + "</NoStdLib>").
887 Replace ("@NOCONFIG@", "<NoConfig>" + (!load_default_config
).ToString () + "</NoConfig>").
888 Replace ("@ALLOWUNSAFE@", Unsafe
? "<AllowUnsafeBlocks>true</AllowUnsafeBlocks>" : "").
889 Replace ("@FX_VERSION", fx_version
).
890 Replace ("@ASSEMBLYNAME@", Path
.GetFileNameWithoutExtension (output_name
)).
891 Replace ("@OUTPUTDIR@", build_output_dir
).
892 Replace ("@DEFINECONSTANTS@", defines
.ToString ()).
893 Replace ("@DEBUG@", want_debugging_support
? "true" : "false").
894 Replace ("@DEBUGTYPE@", want_debugging_support
? "full" : "pdbonly").
895 Replace ("@REFERENCES@", refs
.ToString ()).
896 Replace ("@PREBUILD@", prebuild
).
897 Replace ("@POSTBUILD@", postbuild
).
898 //Replace ("@ADDITIONALLIBPATHS@", String.Format ("<AdditionalLibPaths>{0}</AdditionalLibPaths>", string.Join (",", libs.ToArray ()))).
899 Replace ("@ADDITIONALLIBPATHS@", String
.Empty
).
900 Replace ("@RESOURCES@", resources
.ToString ()).
901 Replace ("@OPTIMIZE@", Optimize
? "true" : "false").
902 Replace ("@SOURCES@", sources
.ToString ());
904 //Console.WriteLine ("Generated {0}", ofile.Replace ("\\", "/"));
905 using (var o
= new StreamWriter (generatedProjFile
)) {
906 o
.WriteLine (Csproj
.output
);
912 void AddProjectReference (StringBuilder refs
, VsCsproj result
, MsbuildGenerator match
, string r
, string alias)
914 refs
.AppendFormat (" <ProjectReference Include=\"{0}\">{1}", GetRelativePath (result
.csProjFilename
, match
.CsprojFilename
), NewLine
);
915 refs
.Append (" <Project>" + match
.projectGuid
+ "</Project>" + NewLine
);
916 refs
.Append (" <Name>" + Path
.GetFileNameWithoutExtension (match
.CsprojFilename
.Replace ('\\', Path
.DirectorySeparatorChar
)) + "</Name>" + NewLine
);
918 refs
.Append (" <Aliases>" + alias + "</Aliases>");
919 refs
.Append (" </ProjectReference>" + NewLine
);
920 if (!result
.projReferences
.Contains (match
.Csproj
))
921 result
.projReferences
.Add (match
.Csproj
);
924 public static string GetRelativePath (string from, string to
)
926 from = from.Replace ("\\", "/");
927 to
= to
.Replace ("\\", "/");
928 var fromUri
= new Uri (Path
.GetFullPath (from));
929 var toUri
= new Uri (Path
.GetFullPath (to
));
931 var ret
= fromUri
.MakeRelativeUri (toUri
).ToString ().Replace ("%5C", "\x5c");
935 MsbuildGenerator
GetMatchingCsproj (string dllReferenceName
, Dictionary
<string,MsbuildGenerator
> projects
, bool explicitPath
= false)
937 // libDir would be "./../../class/lib/net_4_5 for example
939 if (!dllReferenceName
.EndsWith (".dll"))
940 dllReferenceName
+= ".dll";
943 var probe
= Path
.GetFullPath (Path
.Combine (base_dir
, dllReferenceName
));
944 foreach (var project
in projects
){
945 if (probe
== project
.Value
.AbsoluteLibraryOutput
)
946 return project
.Value
;
950 // not explicit, search for the library in the lib path order specified
952 foreach (var libDir
in libs
) {
953 var abs
= Path
.GetFullPath (Path
.Combine (base_dir
, libDir
));
954 foreach (var project
in projects
){
955 var probe
= Path
.Combine (abs
, dllReferenceName
);
957 if (probe
== project
.Value
.AbsoluteLibraryOutput
)
958 return project
.Value
;
961 Console
.WriteLine ("Did not find referenced {0} with libs={1}", dllReferenceName
, String
.Join (", ", libs
));
962 foreach (var p
in projects
) {
963 Console
.WriteLine (" => {0}", p
.Value
.AbsoluteLibraryOutput
);
970 public class Driver
{
972 static IEnumerable
<XElement
> GetProjects (bool full
= false)
974 XDocument doc
= XDocument
.Load ("order.xml");
975 foreach (XElement project
in doc
.Root
.Elements ()) {
976 string dir
= project
.Attribute ("dir").Value
;
977 string library
= project
.Attribute ("library").Value
;
978 var profile
= project
.Element ("profile").Value
;
981 // Do only class libraries for now
983 if (!(dir
.StartsWith ("class") || dir
.StartsWith ("mcs") || dir
.StartsWith ("basic")))
987 if (!library
.Contains ("tests"))
988 yield return project
;
993 // Do not do 2.1, it is not working yet
994 // Do not do basic, as there is no point (requires a system mcs to be installed).
996 if (library
.Contains ("moonlight") || library
.Contains ("-basic") || library
.EndsWith ("bootstrap") || library
.Contains ("build"))
999 // The next ones are to make debugging easier for now
1000 if (profile
== "basic")
1002 if (profile
!= "net_4_5" || library
.Contains ("tests"))
1005 yield return project
;
1009 static void Main (string [] args
)
1011 if (!File
.Exists ("genproj.cs")) {
1012 Console
.WriteLine ("This command must be executed from mono/msvc/scripts");
1013 Environment
.Exit (1);
1016 if (args
.Length
== 1 && args
[0].ToLower ().Contains ("-h")) {
1017 Console
.WriteLine ("Usage:");
1018 Console
.WriteLine ("genproj.exe [visual_studio_release] [output_full_solutions]");
1019 Console
.WriteLine ("If output_full_solutions is false, only the main System*.dll");
1020 Console
.WriteLine (" assemblies (and dependencies) is included in the solution.");
1021 Console
.WriteLine ("Example:");
1022 Console
.WriteLine ("genproj.exe 2012 false");
1023 Console
.WriteLine ("genproj.exe with no arguments is equivalent to 'genproj.exe 2012 true'\n\n");
1024 Console
.WriteLine ("genproj.exe deps");
1025 Console
.WriteLine ("Generates a Makefile dependency file from the projects input");
1026 Environment
.Exit (0);
1029 var slnVersion
= (args
.Length
> 0) ? args
[0] : "2012";
1030 bool fullSolutions
= (args
.Length
> 1) ? bool.Parse (args
[1]) : true;
1032 // To generate makefile depenedencies
1033 var makefileDeps
= (args
.Length
> 0 && args
[0] == "deps");
1035 var sln_gen
= new SlnGenerator (slnVersion
);
1036 var four_five_sln_gen
= new SlnGenerator (slnVersion
);
1037 var projects
= new Dictionary
<string,MsbuildGenerator
> ();
1039 var duplicates
= new List
<string> ();
1040 foreach (var project
in GetProjects (makefileDeps
)) {
1041 var library_output
= project
.Element ("library_output").Value
;
1042 projects
[library_output
] = new MsbuildGenerator (project
);
1044 foreach (var project
in GetProjects (makefileDeps
)){
1045 var library_output
= project
.Element ("library_output").Value
;
1046 var gen
= projects
[library_output
];
1048 var csproj
= gen
.Generate (projects
);
1049 var csprojFilename
= csproj
.csProjFilename
;
1050 if (!sln_gen
.ContainsProjectIdentifier (csproj
.library
)) {
1051 sln_gen
.Add (csproj
);
1053 duplicates
.Add (csprojFilename
);
1056 } catch (Exception e
) {
1057 Console
.WriteLine ("Error in {0}\n{1}", project
, e
);
1061 Func
<MsbuildGenerator
.VsCsproj
, bool> additionalFilter
;
1062 additionalFilter
= fullSolutions
? (Func
<MsbuildGenerator
.VsCsproj
, bool>)null : IsCommonLibrary
;
1064 FillSolution (four_five_sln_gen
, MsbuildGenerator
.profile_4_5
, projects
.Values
, additionalFilter
);
1066 var sb
= new StringBuilder ();
1067 sb
.AppendLine ("WARNING: Skipped some project references, apparent duplicates in order.xml:");
1068 foreach (var item
in duplicates
) {
1069 sb
.AppendLine (item
);
1071 Console
.WriteLine (sb
.ToString ());
1073 WriteSolution (four_five_sln_gen
, MakeSolutionName (MsbuildGenerator
.profile_4_5
));
1076 const string classDirPrefix
= "./../../";
1077 Console
.WriteLine ("here {0}", sln_gen
.libraries
.Count
);
1078 foreach (var p
in sln_gen
.libraries
){
1079 string rebasedOutput
= RebaseToClassDirectory (MsbuildGenerator
.GetRelativePath ("../../mcs/class", p
.library_output
));
1081 Console
.Write ("{0}: ", rebasedOutput
);
1082 foreach (var r
in p
.projReferences
){
1083 var lo
= r
.library_output
;
1084 if (lo
.StartsWith (classDirPrefix
))
1085 lo
= lo
.Substring (classDirPrefix
.Length
);
1087 lo
= "<<ERROR-dependency is not a class library>>";
1088 Console
.Write ("{0} ", lo
);
1090 Console
.Write ("\n\t(cd {0}; make {1})", p
.MsbuildGenerator
.dir
, p
.library_output
);
1091 Console
.WriteLine ("\n");
1095 // A few other optional solutions
1096 // Solutions with 'everything' and the most common libraries used in development may be of interest
1097 //WriteSolution (sln_gen, "mcs_full.sln");
1098 //WriteSolution (small_full_sln_gen, "small_full.sln");
1099 // The following may be useful if lacking visual studio or MonoDevelop, to bootstrap mono compiler self-hosting
1100 //WriteSolution (basic_sln_gen, "mcs_basic.sln");
1101 //WriteSolution (build_sln_gen, "mcs_build.sln");
1104 // Rebases a path, assuming that execution is taking place in the "class" subdirectory,
1105 // so it strips ../class/ from a path, which is a no-op
1106 static string RebaseToClassDirectory (string path
)
1108 const string prefix
= "../class/";
1109 int p
= path
.IndexOf (prefix
);
1112 return path
.Substring (0, p
) + path
.Substring (p
+prefix
.Length
);
1116 static string MakeSolutionName (string profileTag
)
1118 return "net" + profileTag
+ ".sln";
1121 static void FillSolution (SlnGenerator solution
, string profileString
, IEnumerable
<MsbuildGenerator
> projects
, Func
<MsbuildGenerator
.VsCsproj
, bool> additionalFilter
= null)
1123 foreach (var generator
in projects
) {
1124 var vsCsproj
= generator
.Csproj
;
1125 if (!vsCsproj
.library
.Contains (profileString
))
1127 if (additionalFilter
!= null && !additionalFilter (vsCsproj
))
1129 var csprojFilename
= vsCsproj
.csProjFilename
;
1130 if (!solution
.ContainsProjectIdentifier (vsCsproj
.library
)) {
1131 solution
.Add (vsCsproj
);
1132 RecursiveAddProj (solution
, vsCsproj
);
1137 static void RecursiveAddProj (SlnGenerator solution
, MsbuildGenerator
.VsCsproj vsCsproj
, int recursiveDepth
= 1)
1139 const int max_recursive
= 16;
1140 if (recursiveDepth
> max_recursive
) throw new Exception (string.Format ("Reached {0} levels of project dependency", max_recursive
));
1141 foreach (var projRef
in vsCsproj
.projReferences
) {
1142 if (!solution
.ContainsProjectIdentifier (projRef
.library
)) {
1143 solution
.Add (projRef
);
1144 RecursiveAddProj (solution
, projRef
, recursiveDepth
+ 1);
1149 static void WriteSolution (SlnGenerator sln_gen
, string slnfilename
)
1151 Console
.WriteLine (String
.Format ("Writing solution {1}, with {0} projects", sln_gen
.Count
, slnfilename
));
1152 sln_gen
.Write (slnfilename
);
1155 static bool IsCommonLibrary (MsbuildGenerator
.VsCsproj proj
)
1157 var library
= proj
.library
;
1158 //if (library.Contains ("-basic"))
1160 //if (library.Contains ("-build"))
1162 //if (library.StartsWith ("corlib"))
1164 if (library
.StartsWith ("System-"))
1166 if (library
.StartsWith ("System.Xml"))
1168 if (library
.StartsWith ("System.Secu"))
1170 if (library
.StartsWith ("System.Configuration"))
1172 if (library
.StartsWith ("System.Core"))
1174 //if (library.StartsWith ("Mono."))