2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / tools / prj2make / MdPrjHelper.cs
1 using System;
2 using System.Collections;
3 using System.IO;
4 using System.Text;
5 using System.Text.RegularExpressions;
6 using System.Xml;
7 using System.Xml.Serialization;
8 using System.Diagnostics;
9
10 namespace Mfconsulting.General.Prj2Make
11 {
12     public class CmbxMaker
13     {
14                 public static string slash;
15                 static Hashtable projNameInfo = new Hashtable();
16                 static Hashtable projGuidInfo = new Hashtable();
17                 private Mfconsulting.General.Prj2Make.Schema.Cmbx.Combine m_cmbObject;
18                 private bool m_bIsUnix;
19                 private bool m_bIsMcs;
20                 private bool m_bIsUsingLib;
21  
22                 // Flag use to determine if the LIB variable will be used in
23                 // the Makefile that prj2make generates
24                 public bool IsUsingLib
25                 {
26                         get{ return m_bIsUsingLib; }
27                         set{ m_bIsUsingLib = value; }
28                 }
29
30                 // Determines if the makefile is intended for nmake or gmake for urposes of path separator character
31                 public bool IsUnix
32                 {
33                         get{ return m_bIsUnix; }
34                         set{ m_bIsUnix = value; }
35                 }
36
37                 // Determines if using MCS or CSC
38                 public bool IsMcs
39                 {
40                         get{ return m_bIsMcs; }
41                         set{ m_bIsMcs = value; }
42                 }
43
44         public Mfconsulting.General.Prj2Make.Schema.Cmbx.Combine Solucion {
45                 get { return m_cmbObject; }
46         }
47
48                 public CmbxMaker()
49                 {
50                         m_bIsUnix = false;
51                         m_bIsMcs = false;
52                         m_bIsUsingLib = false;
53                 }
54     
55                 // Combine desirialization 
56                 protected Mfconsulting.General.Prj2Make.Schema.Cmbx.Combine LoadCmbFromFile (string strIn)
57                 {
58                         FileStream fs = new FileStream (strIn, FileMode.Open);
59             
60                         XmlSerializer xmlSer = new XmlSerializer (typeof(Mfconsulting.General.Prj2Make.Schema.Cmbx.Combine));
61                         Mfconsulting.General.Prj2Make.Schema.Cmbx.Combine cmbObj = (Mfconsulting.General.Prj2Make.Schema.Cmbx.Combine) xmlSer.Deserialize (fs);
62             
63                         fs.Close();
64             
65                         return (cmbObj);
66                 }
67
68                 protected void ParseMdCsProj(string fname)
69         {
70                 string projectName;
71                 
72             PrjxInfo pi = new PrjxInfo(m_bIsUnix, m_bIsMcs, fname);
73             projectName = pi.name;            
74                         projNameInfo[projectName] = pi;            
75         }
76         
77         protected void ParseCombine(string fname)
78         {
79                 string CombineFilePath = fname;
80                 
81                 // convert backslashes to slashes               
82                 CombineFilePath = CombineFilePath.Replace("\\", "/");
83     
84                 // loads the file in order to deserialize and
85                 // build the object graph
86                 try {
87                         m_cmbObject = LoadCmbFromFile (CombineFilePath);
88                         } catch (Exception exc) {
89                         
90                                 Console.WriteLine (
91                                         String.Format ("Could not load the file {0}\nException: {1}",
92                                                 CombineFilePath,
93                                                 exc.Message)
94                                         );
95                                 return;                 
96                         }
97
98                 foreach(Mfconsulting.General.Prj2Make.Schema.Cmbx.Entry ent in m_cmbObject.Entries)
99                 {
100                                 string projectName = System.IO.Path.GetFileNameWithoutExtension(ent.filename);
101                                 string csprojPath = ent.filename;
102     
103                                 if (csprojPath.EndsWith(".prjx"))
104                                 {
105                                         PrjxInfo pi = new PrjxInfo(m_bIsUnix, m_bIsMcs, csprojPath);
106     
107                                         projNameInfo[projectName] = pi;
108                                 }    
109                 }
110         }
111     
112         public string MdCmbxHelper(bool isUnixMode, bool isMcsMode, bool isSln, string slnFile)
113         {
114                 bool noCommonTargets = false;
115                 bool noProjectTargets = false;
116                 bool noFlags = false;
117                         int nPos = -1;
118                 StringBuilder MakefileBuilder = new StringBuilder();
119
120                         m_bIsUnix = isUnixMode;
121                         m_bIsMcs =  isMcsMode;
122
123                         if(m_bIsUnix == true && m_bIsMcs == true)
124                         {
125                                 m_bIsUsingLib = true;
126                         }
127     
128                 if (m_bIsUnix)
129                 {
130                         slash = "/";
131                 }
132                 else
133                 {
134                         slash = "\\";
135                 }
136     
137                 try
138                 {
139                         string d = Path.GetDirectoryName(slnFile);
140                         
141                         if (d != "")
142                                 Directory.SetCurrentDirectory(d);
143
144                         if (isSln == true) {
145                                         // We invoke the ParseSolution 
146                                         // by passing the file obtained
147                                         ParseCombine (slnFile);
148                         } else {
149     
150                                         // We invoke the ParseMsCsProj 
151                                         // by passing the file obtained 
152                                         ParseMdCsProj (slnFile);
153                         }
154         
155                         if (!noFlags)
156                         {
157                         if (m_bIsUnix) // gmake
158                         {
159                                         MakefileBuilder.Append("ifndef TARGET\n");
160                                         MakefileBuilder.Append("\tTARGET=./bin/Debug\n");                                       
161                                         MakefileBuilder.Append("else\n");
162                                         MakefileBuilder.Append("\tTARGET=./bin/$(TARGET)\n");
163                                         MakefileBuilder.Append("endif\n\n");
164                                         
165                                         if (m_bIsMcs == false)
166                                         {
167                                                 MakefileBuilder.Append("MCS=csc\n");
168                                                 MakefileBuilder.Append("MCSFLAGS=-nologo\n\n");
169                                                 MakefileBuilder.Append("ifdef (RELEASE)\n");
170                                                 MakefileBuilder.Append("\tMCSFLAGS=$(MCSFLAGS) -optimize+ -d:TRACE\n");
171                                                 MakefileBuilder.Append("else\n");
172                                                 MakefileBuilder.Append("\tMCSFLAGS=$(MCSFLAGS) -debug+ -d:TRACE,DEBUG\n");
173                                                 MakefileBuilder.Append("endif\n");
174                                         }
175                                         else
176                                         {
177                                                 MakefileBuilder.Append("MCS=mcs\n");
178                                                 MakefileBuilder.Append("ifndef (RELEASE)\n");
179                                                 MakefileBuilder.Append("\tMCSFLAGS=-debug \n");
180                                                 MakefileBuilder.Append("endif\n");
181                                                         // Define and add the information used in the -lib: arguments passed to the
182                                                         // compiler to assist in finding non-fullyqualified assembly references.
183                                                         if(m_bIsUsingLib == true)
184                                                         {
185                                                                 string strlibDir = PkgConfigInvoker.GetPkgVariableValue("mono", "libdir");
186
187                                                                 if (strlibDir == null)
188                                                                 {
189                                                                         strlibDir = "/usr/lib";
190                                                                 }
191
192                                                                 MakefileBuilder.AppendFormat("\nLIBS=-lib:{0} -lib:{1}\n\n", 
193                                                                         Path.Combine(strlibDir.TrimEnd(), "mono/1.0"),
194                                                                         Path.Combine(strlibDir.TrimEnd(), "mono/gtk-sharp")
195                                                                         );
196                                                         }
197                                         }                       
198                         }
199                         else // nmake
200                         {
201                                         MakefileBuilder.Append("!if !defined (TARGET)\n");
202                                         MakefileBuilder.Append("TARGET=.\\bin\\Debug\n");                                       
203                                         MakefileBuilder.Append("!else\n");
204                                         MakefileBuilder.Append("TARGET=.\\bin\\$(TARGET)\n");
205                                         MakefileBuilder.Append("!endif\n\n");
206                                         
207                                         if (m_bIsMcs == false)
208                                         {
209                                                 MakefileBuilder.Append("MCS=csc\n");
210                                                 MakefileBuilder.Append("MCSFLAGS=-nologo\n\n");
211                                                 MakefileBuilder.Append("!if !defined(RELEASE)\n");
212                                                 MakefileBuilder.Append("MCSFLAGS=$(MCSFLAGS) -optimize+ -d:TRACE\n");
213                                                 MakefileBuilder.Append("!else\n");
214                                                 MakefileBuilder.Append("MCSFLAGS=$(MCSFLAGS) -debug+ -d:TRACE,DEBUG\n");
215                                                 MakefileBuilder.Append("!endif\n");
216                                         }
217                                         else
218                                         {
219                                                 MakefileBuilder.Append("MCS=mcs\n");
220                                                 MakefileBuilder.Append("!if !defined(RELEASE)\n");
221                                                 MakefileBuilder.Append("MCSFLAGS=-debug \n");
222                                                 MakefileBuilder.Append("!endif\n");
223                                         }                               
224                         }
225     
226                                 MakefileBuilder.Append("\n");
227                         }
228                         else
229                         {
230                                 MakefileBuilder.Append("!if !defined(MCS)\n");
231                                 MakefileBuilder.Append("!error You must provide MCS when making\n");
232                                 MakefileBuilder.Append("!endif\n\n");
233                         }
234     
235                         foreach (PrjxInfo prjI in projNameInfo.Values)
236                         {
237                                 MakefileBuilder.AppendFormat("{0}=$(TARGET){1}{2}\n", prjI.makename_ext, slash, prjI.assembly_name);
238                                 MakefileBuilder.AppendFormat("{0}_PDB=$(TARGET){1}{2}\n", prjI.makename, slash, prjI.assembly_name.Replace(".dll",".pdb"));
239                                 MakefileBuilder.AppendFormat("{0}_SRC={1}\n", prjI.makename, prjI.src);
240                                 MakefileBuilder.AppendFormat("{0}_RES={1}\n\n", prjI.makename, prjI.res);
241                         }
242
243     
244                         foreach (PrjxInfo pi in projNameInfo.Values)
245                         {
246                                 string refs = "";
247                                 string deps = "";
248                                 
249                                 foreach (Mfconsulting.General.Prj2Make.Schema.Prjx.Reference rf in pi.Proyecto.References)
250                                 {
251                                                 if (refs != "")
252                                                         refs += " ";
253    
254                                                 string assemblyName = rf.refto;
255    
256                                                 // HACK - under Unix filenames are case sensitive
257                                                 // Under Windows there's no agreement on Xml vs XML ;-)                                                 
258                                                 if (0 == String.Compare(assemblyName, "System.Xml", true))
259                                                 {
260                                                         assemblyName = "System.Xml";
261                                                 }
262
263                                                 // Check to see if there is a coma in the
264                                                 // reference. This could indicate a GAC
265                                                 // style reference
266                                                 nPos = assemblyName.IndexOf(',');
267                                                 if(nPos == -1)
268                                                 {
269                                                         if (System.IO.Path.GetExtension(assemblyName).ToUpper().CompareTo(".DLL") == 0) 
270                                                         {
271                                                                 refs += "-r:" + assemblyName;
272                                                         } 
273                                                         else 
274                                                         {
275                                                                 refs += "-r:" + assemblyName + ".dll";
276                                                         }
277                                                 }
278                                                 else
279                                                 {
280                                                         refs += "-r:" + assemblyName.Substring(0, nPos) + ".dll";
281                                                 }
282                                 }
283     
284                                 MakefileBuilder.AppendFormat("$({0}): $({1}_SRC) {2}\n", pi.makename_ext, pi.makename, deps);
285                 
286                         if (isUnixMode)
287                         {
288                                         MakefileBuilder.Append("\t-mkdir -p $(TARGET)\n");
289                         }
290                         else
291                         {
292                                         MakefileBuilder.Append("\t-md $(TARGET)\n");
293                         }
294                         
295                                         MakefileBuilder.Append("\t$(MCS) $(MCSFLAGS)");
296
297                                         // Test to see if any configuratino has the Allow unsafe blocks on
298                                         if(pi.AllowUnsafeCode == true ) {
299                                                 MakefileBuilder.Append(" -unsafe");
300                                         }
301
302                                         // Test for LIBS usage
303                                         if(m_bIsUsingLib == true) {
304                                         MakefileBuilder.Append(" $(LIBS)");
305                                         }
306
307                                         MakefileBuilder.AppendFormat(" {2}{3} -out:$({0}) $({1}_RES) $({1}_SRC)\n", 
308                                                         pi.makename_ext, pi.makename, refs, pi.switches);
309                                                                         
310                                         MakefileBuilder.Append("\n");
311                         }
312     
313                         if (!noCommonTargets)
314                         {
315                                 MakefileBuilder.Append("\n");
316                                 MakefileBuilder.Append("# common targets\n\n");
317                                 MakefileBuilder.Append("all:\t");
318     
319                                 bool first = true;
320     
321                                 foreach (PrjxInfo pi in projNameInfo.Values)
322                                 {
323                                         if (!first)
324                                         {
325                                                 MakefileBuilder.Append(" \\\n\t");
326                                         }
327                                         MakefileBuilder.AppendFormat("$({0})", pi.makename_ext);
328                                         first = false;
329                                 }
330                                 MakefileBuilder.Append("\n\n");
331     
332                                 MakefileBuilder.Append("clean:\n");
333     
334                                 foreach (PrjxInfo pi in projNameInfo.Values)
335                                 {
336                                         if (isUnixMode)
337                                         {
338                                                 MakefileBuilder.AppendFormat("\t-rm -f \"$({0})\" 2> /dev/null\n", pi.makename_ext);
339                                                 MakefileBuilder.AppendFormat("\t-rm -f \"$({0}_PDB)\" 2> /dev/null\n", pi.makename);
340                                         }
341                                         else
342                                         {
343                                                 MakefileBuilder.AppendFormat("\t-del \"$({0})\" 2> nul\n", pi.makename_ext);
344                                                 MakefileBuilder.AppendFormat("\t-del \"$({0}_PDB)\" 2> nul\n", pi.makename);
345                                         }
346                                 }
347                                 MakefileBuilder.Append("\n");
348                         }
349     
350                         if (!noProjectTargets)
351                         {
352                                 MakefileBuilder.Append("\n");
353                                 MakefileBuilder.Append("# project names as targets\n\n");
354                                 foreach (PrjxInfo pi in projNameInfo.Values)
355                                 {
356                                         MakefileBuilder.AppendFormat("{0}: $({1})\n", pi.name, pi.makename_ext);
357                                 }
358                         }
359                 }
360                 catch (Exception e)
361                 {
362                         Console.WriteLine("EXCEPTION: {0}\n", e);
363                         return "";
364                 }
365                 
366                         return MakefileBuilder.ToString();
367         }
368     }    
369 }