opensim-development – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 1 #region BSD License
2 /*
3 Copyright (c) 2004 Crestez Leonard (cleonard@go.ro)
4  
5 Redistribution and use in source and binary forms, with or without modification, are permitted
6 provided that the following conditions are met:
7  
8 * Redistributions of source code must retain the above copyright notice, this list of conditions
9 and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
11 and the following disclaimer in the documentation and/or other materials provided with the
12 distribution.
13 * The name of the author may not be used to endorse or promote products derived from this software
14 without specific prior written permission.
15  
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
17 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
22 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24 #endregion
25  
26 using System;
27 using System.IO;
28 using System.Text.RegularExpressions;
29  
30 using Prebuild.Core.Attributes;
31 using Prebuild.Core.Interfaces;
32 using Prebuild.Core.Nodes;
33 using Prebuild.Core.Utilities;
34  
35 namespace Prebuild.Core.Targets
36 {
37 [Target("makefile")]
38 public class MakefileTarget : ITarget
39 {
40 #region Fields
41  
42 private Kernel m_Kernel = null;
43  
44 #endregion
45  
46 #region Private Methods
47  
48 // This converts a path relative to the path of a project to
49 // a path relative to the solution path.
50 private string NicePath(ProjectNode proj, string path)
51 {
52 string res;
53 SolutionNode solution = (SolutionNode)proj.Parent;
54 res = Path.Combine(Helper.NormalizePath(proj.FullPath, '/'), Helper.NormalizePath(path, '/'));
55 res = Helper.NormalizePath(res, '/');
56 res = res.Replace("/./", "/");
57 while (res.IndexOf("/../") >= 0)
58 {
59 int a = res.IndexOf("/../");
60 int b = res.LastIndexOf("/", a - 1);
61 res = res.Remove(b, a - b + 3);
62 }
63 res = Helper.MakePathRelativeTo(solution.FullPath, res);
64 if (res.StartsWith("./"))
65 res = res.Substring(2, res.Length - 2);
66 res = Helper.NormalizePath(res, '/');
67 return res;
68 }
69  
70 private void WriteProjectFiles(StreamWriter f, SolutionNode solution, ProjectNode project)
71 {
72 // Write list of source code files
73 f.WriteLine("SOURCES_{0} = \\", project.Name);
74 foreach (string file in project.Files)
75 if (project.Files.GetBuildAction(file) == BuildAction.Compile)
76 f.WriteLine("\t{0} \\", NicePath(project, file));
77 f.WriteLine();
78  
79 // Write list of resource files
80 f.WriteLine("RESOURCES_{0} = \\", project.Name);
81 foreach (string file in project.Files)
82 if (project.Files.GetBuildAction(file) == BuildAction.EmbeddedResource)
83 {
84 string path = NicePath(project, file);
85 f.WriteLine("\t-resource:{0},{1} \\", path, Path.GetFileName(path));
86 }
87 f.WriteLine();
88  
89 // There's also Content and None in BuildAction.
90 // What am I supposed to do with that?
91 }
92  
93 private string FindFileReference(string refName, ProjectNode project)
94 {
95 foreach (ReferencePathNode refPath in project.ReferencePaths)
96 {
97 string fullPath = NicePath(project, Helper.MakeFilePath(refPath.Path, refName, "dll"));
98 if (File.Exists(fullPath))
99 return fullPath;
100 }
101 return null;
102 }
103  
104 private void WriteProjectReferences(StreamWriter f, SolutionNode solution, ProjectNode project)
105 {
106 f.WriteLine("REFERENCES_{0} = \\", project.Name);
107 foreach (ReferenceNode refr in project.References)
108 {
109 string path;
110 // Project references change with configurations.
111 if (solution.ProjectsTable.ContainsKey(refr.Name))
112 continue;
113 path = FindFileReference(refr.Name, project);
114 if (path != null)
115 f.WriteLine("\t-r:{0} \\", path);
116 else
117 f.WriteLine("\t-r:{0} \\", refr.Name);
118 }
119 f.WriteLine();
120 }
121  
122 private void WriteProjectDependencies(StreamWriter f, SolutionNode solution, ProjectNode project)
123 {
124 f.WriteLine("DEPENDENCIES_{0} = \\", project.Name);
125 f.WriteLine("\t$(SOURCES_{0}) \\", project.Name);
126 foreach (string file in project.Files)
127 if (project.Files.GetBuildAction(file) == BuildAction.EmbeddedResource)
128 f.WriteLine("\t{0} \\", NicePath(project, file));
129 f.WriteLine();
130 }
131  
132 private string ProjectTypeToExtension(ProjectType t)
133 {
134 if (t == ProjectType.Exe || t == ProjectType.WinExe)
135 {
136 return "exe";
137 }
138 else if (t == ProjectType.Library)
139 {
140 return "dll";
141 }
142 else
143 {
144 throw new FatalException("Bad ProjectType: {0}", t);
145 }
146 }
147  
148 private string ProjectTypeToTarget(ProjectType t)
149 {
150 if (t == ProjectType.Exe)
151 {
152 return "exe";
153 }
154 else if (t == ProjectType.WinExe)
155 {
156 return "winexe";
157 }
158 else if (t == ProjectType.Library)
159 {
160 return "library";
161 }
162 else
163 {
164 throw new FatalException("Bad ProjectType: {0}", t);
165 }
166 }
167  
168 private string ProjectOutput(ProjectNode project, ConfigurationNode config)
169 {
170 string filepath;
171 filepath = Helper.MakeFilePath((string)config.Options["OutputPath"],
172 project.AssemblyName, ProjectTypeToExtension(project.Type));
173 return NicePath(project, filepath);
174 }
175  
176 // Returns true if two configs in one project have the same output.
177 private bool ProjectClashes(ProjectNode project)
178 {
179 foreach (ConfigurationNode conf1 in project.Configurations)
180 foreach (ConfigurationNode conf2 in project.Configurations)
181 if (ProjectOutput(project, conf1) == ProjectOutput(project, conf2) && conf1 != conf2)
182 {
183 m_Kernel.Log.Write("Warning: Configurations {0} and {1} for project {2} output the same file",
184 conf1.Name, conf2.Name, project.Name);
185 m_Kernel.Log.Write("Warning: I'm going to use some timestamps(extra empty files).");
186 return true;
187 }
188 return false;
189 }
190  
191 private void WriteProject(StreamWriter f, SolutionNode solution, ProjectNode project)
192 {
193 f.WriteLine("# This is for project {0}", project.Name);
194 f.WriteLine();
195  
196 WriteProjectFiles(f, solution, project);
197 WriteProjectReferences(f, solution, project);
198 WriteProjectDependencies(f, solution, project);
199  
200 bool clash = ProjectClashes(project);
201  
202 foreach (ConfigurationNode conf in project.Configurations)
203 {
204 string outpath = ProjectOutput(project, conf);
205 string filesToClean = outpath;
206  
207 if (clash)
208 {
209 f.WriteLine("{0}-{1}: .{0}-{1}-timestamp", project.Name, conf.Name);
210 f.WriteLine();
211 f.Write(".{0}-{1}-timestamp: $(DEPENDENCIES_{0})", project.Name, conf.Name);
212 }
213 else
214 {
215 f.WriteLine("{0}-{1}: {2}", project.Name, conf.Name, outpath);
216 f.WriteLine();
217 f.Write("{2}: $(DEPENDENCIES_{0})", project.Name, conf.Name, outpath);
218 }
219 // Dependencies on other projects.
220 foreach (ReferenceNode refr in project.References)
221 if (solution.ProjectsTable.ContainsKey(refr.Name))
222 {
223 ProjectNode refProj = (ProjectNode)solution.ProjectsTable[refr.Name];
224 if (ProjectClashes(refProj))
225 f.Write(" .{0}-{1}-timestamp", refProj.Name, conf.Name);
226 else
227 f.Write(" {0}", ProjectOutput(refProj, conf));
228 }
229 f.WriteLine();
230  
231 // make directory for output.
232 if (Path.GetDirectoryName(outpath) != "")
233 {
234 f.WriteLine("\tmkdir -p {0}", Path.GetDirectoryName(outpath));
235 }
236 // mcs command line.
237 f.Write("\tgmcs", project.Name);
238 f.Write(" -warn:{0}", conf.Options["WarningLevel"]);
239 if ((bool)conf.Options["DebugInformation"])
240 f.Write(" -debug");
241 if ((bool)conf.Options["AllowUnsafe"])
242 f.Write(" -unsafe");
243 if ((bool)conf.Options["CheckUnderflowOverflow"])
244 f.Write(" -checked");
245 if (project.StartupObject != "")
246 f.Write(" -main:{0}", project.StartupObject);
247 if ((string)conf.Options["CompilerDefines"] != "")
248 {
249 f.Write(" -define:\"{0}\"", conf.Options["CompilerDefines"]);
250 }
251  
252 f.Write(" -target:{0} -out:{1}", ProjectTypeToTarget(project.Type), outpath);
253  
254 // Build references to other projects. Now that sux.
255 // We have to reference the other project in the same conf.
256 foreach (ReferenceNode refr in project.References)
257 if (solution.ProjectsTable.ContainsKey(refr.Name))
258 {
259 ProjectNode refProj;
260 refProj = (ProjectNode)solution.ProjectsTable[refr.Name];
261 f.Write(" -r:{0}", ProjectOutput(refProj, conf));
262 }
263  
264 f.Write(" $(REFERENCES_{0})", project.Name);
265 f.Write(" $(RESOURCES_{0})", project.Name);
266 f.Write(" $(SOURCES_{0})", project.Name);
267 f.WriteLine();
268  
269 // Copy references with localcopy.
270 foreach (ReferenceNode refr in project.References)
271 if (refr.LocalCopy)
272 {
273 string outPath, srcPath, destPath;
274 outPath = Helper.NormalizePath((string)conf.Options["OutputPath"]);
275 if (solution.ProjectsTable.ContainsKey(refr.Name))
276 {
277 ProjectNode refProj;
278 refProj = (ProjectNode)solution.ProjectsTable[refr.Name];
279 srcPath = ProjectOutput(refProj, conf);
280 destPath = Path.Combine(outPath, Path.GetFileName(srcPath));
281 destPath = NicePath(project, destPath);
282 if (srcPath != destPath)
283 {
284 f.WriteLine("\tcp -f {0} {1}", srcPath, destPath);
285 filesToClean += " " + destPath;
286 }
287 continue;
288 }
289 srcPath = FindFileReference(refr.Name, project);
290 if (srcPath != null)
291 {
292 destPath = Path.Combine(outPath, Path.GetFileName(srcPath));
293 destPath = NicePath(project, destPath);
294 f.WriteLine("\tcp -f {0} {1}", srcPath, destPath);
295 filesToClean += " " + destPath;
296 }
297 }
298  
299 if (clash)
300 {
301 filesToClean += String.Format(" .{0}-{1}-timestamp", project.Name, conf.Name);
302 f.WriteLine("\ttouch .{0}-{1}-timestamp", project.Name, conf.Name);
303 f.Write("\trm -rf");
304 foreach (ConfigurationNode otherConf in project.Configurations)
305 if (otherConf != conf)
306 f.WriteLine(" .{0}-{1}-timestamp", project.Name, otherConf.Name);
307 f.WriteLine();
308 }
309 f.WriteLine();
310 f.WriteLine("{0}-{1}-clean:", project.Name, conf.Name);
311 f.WriteLine("\trm -rf {0}", filesToClean);
312 f.WriteLine();
313 }
314 }
315  
316 private void WriteIntro(StreamWriter f, SolutionNode solution)
317 {
318 f.WriteLine("# Makefile for {0} generated by Prebuild ( http://dnpb.sf.net )", solution.Name);
319 f.WriteLine("# Do not edit.");
320 f.WriteLine("#");
321  
322 f.Write("# Configurations:");
323 foreach (ConfigurationNode conf in solution.Configurations)
324 f.Write(" {0}", conf.Name);
325 f.WriteLine();
326  
327 f.WriteLine("# Projects:");
328 foreach (ProjectNode proj in solution.Projects)
329 f.WriteLine("#\t{0}", proj.Name);
330  
331 f.WriteLine("#");
332 f.WriteLine("# Building:");
333 f.WriteLine("#\t\"make\" to build everything under the default(first) configuration");
334 f.WriteLine("#\t\"make CONF\" to build every project under configuration CONF");
335 f.WriteLine("#\t\"make PROJ\" to build project PROJ under the default(first) configuration");
336 f.WriteLine("#\t\"make PROJ-CONF\" to build project PROJ under configuration CONF");
337 f.WriteLine("#");
338 f.WriteLine("# Cleaning (removing results of build):");
339 f.WriteLine("#\t\"make clean\" to clean everything, that's what you probably want");
340 f.WriteLine("#\t\"make CONF\" to clean everything for a configuration");
341 f.WriteLine("#\t\"make PROJ\" to clean everything for a project");
342 f.WriteLine("#\t\"make PROJ-CONF\" to clea project PROJ under configuration CONF");
343 f.WriteLine();
344 }
345  
346 private void WritePhony(StreamWriter f, SolutionNode solution)
347 {
348 string defconf = "";
349 foreach (ConfigurationNode conf in solution.Configurations)
350 {
351 defconf = conf.Name;
352 break;
353 }
354  
355 f.Write(".PHONY: all");
356 foreach (ProjectNode proj in solution.Projects)
357 f.Write(" {0} {0}-clean", proj.Name);
358 foreach (ConfigurationNode conf in solution.Configurations)
359 f.Write(" {0} {0}-clean", conf.Name);
360 foreach (ProjectNode proj in solution.Projects)
361 foreach (ConfigurationNode conf in solution.Configurations)
362 f.Write(" {0}-{1} {0}-{1}-clean", proj.Name, conf.Name);
363 f.WriteLine();
364 f.WriteLine();
365  
366 f.WriteLine("all: {0}", defconf);
367 f.WriteLine();
368  
369 f.Write("clean:");
370 foreach (ConfigurationNode conf in solution.Configurations)
371 f.Write(" {0}-clean", conf.Name);
372 f.WriteLine();
373 f.WriteLine();
374  
375 foreach (ConfigurationNode conf in solution.Configurations)
376 {
377 f.Write("{0}: ", conf.Name);
378 foreach (ProjectNode proj in solution.Projects)
379 f.Write(" {0}-{1}", proj.Name, conf.Name);
380 f.WriteLine();
381 f.WriteLine();
382  
383 f.Write("{0}-clean: ", conf.Name);
384 foreach (ProjectNode proj in solution.Projects)
385 f.Write(" {0}-{1}-clean", proj.Name, conf.Name);
386 f.WriteLine();
387 f.WriteLine();
388 }
389  
390 foreach (ProjectNode proj in solution.Projects)
391 {
392 f.WriteLine("{0}: {0}-{1}", proj.Name, defconf);
393 f.WriteLine();
394  
395 f.Write("{0}-clean:", proj.Name);
396 foreach (ConfigurationNode conf in proj.Configurations)
397 f.Write(" {0}-{1}-clean", proj.Name, conf.Name);
398 f.WriteLine();
399 f.WriteLine();
400 }
401 }
402  
403 private void WriteSolution(SolutionNode solution)
404 {
405 m_Kernel.Log.Write("Creating makefile for {0}", solution.Name);
406 m_Kernel.CurrentWorkingDirectory.Push();
407  
408 string file = "Makefile";// Helper.MakeFilePath(solution.FullPath, solution.Name, "make");
409 StreamWriter f = new StreamWriter(file);
410  
411 Helper.SetCurrentDir(Path.GetDirectoryName(file));
412  
413 using (f)
414 {
415 WriteIntro(f, solution);
416 WritePhony(f, solution);
417  
418 foreach (ProjectNode project in solution.Projects)
419 {
420 m_Kernel.Log.Write("...Creating Project: {0}", project.Name);
421 WriteProject(f, solution, project);
422 }
423 }
424  
425 m_Kernel.Log.Write("");
426 m_Kernel.CurrentWorkingDirectory.Pop();
427 }
428  
429 private void CleanSolution(SolutionNode solution)
430 {
431 m_Kernel.Log.Write("Cleaning makefile for {0}", solution.Name);
432  
433 string file = Helper.MakeFilePath(solution.FullPath, solution.Name, "make");
434 Helper.DeleteIfExists(file);
435  
436 m_Kernel.Log.Write("");
437 }
438  
439 #endregion
440  
441 #region ITarget Members
442  
443 public void Write(Kernel kern)
444 {
445 m_Kernel = kern;
446 foreach (SolutionNode solution in kern.Solutions)
447 WriteSolution(solution);
448 m_Kernel = null;
449 }
450  
451 public virtual void Clean(Kernel kern)
452 {
453 m_Kernel = kern;
454 foreach (SolutionNode sol in kern.Solutions)
455 CleanSolution(sol);
456 m_Kernel = null;
457 }
458  
459 public string Name
460 {
461 get
462 {
463 return "makefile";
464 }
465 }
466  
467 #endregion
468 }
469 }