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