Add prebuild source files
This commit is contained in:
parent
cbcd8b2bd3
commit
4f5e7942e1
86 changed files with 18185 additions and 0 deletions
450
src/Core/Targets/MakefileTarget.cs
Normal file
450
src/Core/Targets/MakefileTarget.cs
Normal file
|
@ -0,0 +1,450 @@
|
|||
#region BSD License
|
||||
|
||||
/*
|
||||
Copyright (c) 2004 Crestez Leonard (cleonard@go.ro)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions
|
||||
and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
||||
and the following disclaimer in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* The name of the author may not be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
|
||||
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
using System.IO;
|
||||
using Prebuild.Core.Attributes;
|
||||
using Prebuild.Core.Interfaces;
|
||||
using Prebuild.Core.Nodes;
|
||||
using Prebuild.Core.Utilities;
|
||||
|
||||
namespace Prebuild.Core.Targets;
|
||||
|
||||
[Target("makefile")]
|
||||
public class MakefileTarget : ITarget
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private Kernel m_Kernel;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
// This converts a path relative to the path of a project to
|
||||
// a path relative to the solution path.
|
||||
private string NicePath(ProjectNode proj, string path)
|
||||
{
|
||||
string res;
|
||||
var solution = (SolutionNode)proj.Parent;
|
||||
res = Path.Combine(Helper.NormalizePath(proj.FullPath, '/'), Helper.NormalizePath(path, '/'));
|
||||
res = Helper.NormalizePath(res, '/');
|
||||
res = res.Replace("/./", "/");
|
||||
while (res.IndexOf("/../") >= 0)
|
||||
{
|
||||
var a = res.IndexOf("/../");
|
||||
var b = res.LastIndexOf("/", a - 1);
|
||||
res = res.Remove(b, a - b + 3);
|
||||
}
|
||||
|
||||
res = Helper.MakePathRelativeTo(solution.FullPath, res);
|
||||
if (res.StartsWith("./"))
|
||||
res = res.Substring(2, res.Length - 2);
|
||||
res = Helper.NormalizePath(res, '/');
|
||||
return res;
|
||||
}
|
||||
|
||||
private void WriteProjectFiles(StreamWriter f, SolutionNode solution, ProjectNode project)
|
||||
{
|
||||
// Write list of source code files
|
||||
f.WriteLine("SOURCES_{0} = \\", project.Name);
|
||||
foreach (var file in project.Files)
|
||||
if (project.Files.GetBuildAction(file) == BuildAction.Compile)
|
||||
f.WriteLine("\t{0} \\", NicePath(project, file));
|
||||
f.WriteLine();
|
||||
|
||||
// Write list of resource files
|
||||
f.WriteLine("RESOURCES_{0} = \\", project.Name);
|
||||
foreach (var file in project.Files)
|
||||
if (project.Files.GetBuildAction(file) == BuildAction.EmbeddedResource)
|
||||
{
|
||||
var path = NicePath(project, file);
|
||||
f.WriteLine("\t-resource:{0},{1} \\", path, Path.GetFileName(path));
|
||||
}
|
||||
|
||||
f.WriteLine();
|
||||
|
||||
// There's also Content and None in BuildAction.
|
||||
// What am I supposed to do with that?
|
||||
}
|
||||
|
||||
private string FindFileReference(string refName, ProjectNode project)
|
||||
{
|
||||
foreach (var refPath in project.ReferencePaths)
|
||||
{
|
||||
var fullPath = NicePath(project, Helper.MakeFilePath(refPath.Path, refName, "dll"));
|
||||
if (File.Exists(fullPath))
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void WriteProjectReferences(StreamWriter f, SolutionNode solution, ProjectNode project)
|
||||
{
|
||||
f.WriteLine("REFERENCES_{0} = \\", project.Name);
|
||||
foreach (var refr in project.References)
|
||||
{
|
||||
string path;
|
||||
// Project references change with configurations.
|
||||
if (solution.ProjectsTable.ContainsKey(refr.Name))
|
||||
continue;
|
||||
path = FindFileReference(refr.Name, project);
|
||||
if (path != null)
|
||||
f.WriteLine("\t-r:{0} \\", path);
|
||||
else
|
||||
f.WriteLine("\t-r:{0} \\", refr.Name);
|
||||
}
|
||||
|
||||
f.WriteLine();
|
||||
}
|
||||
|
||||
private void WriteProjectDependencies(StreamWriter f, SolutionNode solution, ProjectNode project)
|
||||
{
|
||||
f.WriteLine("DEPENDENCIES_{0} = \\", project.Name);
|
||||
f.WriteLine("\t$(SOURCES_{0}) \\", project.Name);
|
||||
foreach (var file in project.Files)
|
||||
if (project.Files.GetBuildAction(file) == BuildAction.EmbeddedResource)
|
||||
f.WriteLine("\t{0} \\", NicePath(project, file));
|
||||
f.WriteLine();
|
||||
}
|
||||
|
||||
private string ProjectTypeToExtension(ProjectType t)
|
||||
{
|
||||
if (t == ProjectType.Exe || t == ProjectType.WinExe)
|
||||
return "exe";
|
||||
if (t == ProjectType.Library)
|
||||
return "dll";
|
||||
throw new FatalException("Bad ProjectType: {0}", t);
|
||||
}
|
||||
|
||||
private string ProjectTypeToTarget(ProjectType t)
|
||||
{
|
||||
if (t == ProjectType.Exe)
|
||||
return "exe";
|
||||
if (t == ProjectType.WinExe)
|
||||
return "winexe";
|
||||
if (t == ProjectType.Library)
|
||||
return "library";
|
||||
throw new FatalException("Bad ProjectType: {0}", t);
|
||||
}
|
||||
|
||||
private string ProjectOutput(ProjectNode project, ConfigurationNode config)
|
||||
{
|
||||
string filepath;
|
||||
filepath = Helper.MakeFilePath((string)config.Options["OutputPath"],
|
||||
project.AssemblyName, ProjectTypeToExtension(project.Type));
|
||||
return NicePath(project, filepath);
|
||||
}
|
||||
|
||||
// Returns true if two configs in one project have the same output.
|
||||
private bool ProjectClashes(ProjectNode project)
|
||||
{
|
||||
foreach (var conf1 in project.Configurations)
|
||||
foreach (var conf2 in project.Configurations)
|
||||
if (ProjectOutput(project, conf1) == ProjectOutput(project, conf2) && conf1 != conf2)
|
||||
{
|
||||
m_Kernel.Log.Write("Warning: Configurations {0} and {1} for project {2} output the same file",
|
||||
conf1.Name, conf2.Name, project.Name);
|
||||
m_Kernel.Log.Write("Warning: I'm going to use some timestamps(extra empty files).");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void WriteProject(StreamWriter f, SolutionNode solution, ProjectNode project)
|
||||
{
|
||||
f.WriteLine("# This is for project {0}", project.Name);
|
||||
f.WriteLine();
|
||||
|
||||
WriteProjectFiles(f, solution, project);
|
||||
WriteProjectReferences(f, solution, project);
|
||||
WriteProjectDependencies(f, solution, project);
|
||||
|
||||
var clash = ProjectClashes(project);
|
||||
|
||||
foreach (var conf in project.Configurations)
|
||||
{
|
||||
var outpath = ProjectOutput(project, conf);
|
||||
var filesToClean = outpath;
|
||||
|
||||
if (clash)
|
||||
{
|
||||
f.WriteLine("{0}-{1}: .{0}-{1}-timestamp", project.Name, conf.Name);
|
||||
f.WriteLine();
|
||||
f.Write(".{0}-{1}-timestamp: $(DEPENDENCIES_{0})", project.Name, conf.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
f.WriteLine("{0}-{1}: {2}", project.Name, conf.Name, outpath);
|
||||
f.WriteLine();
|
||||
f.Write("{2}: $(DEPENDENCIES_{0})", project.Name, conf.Name, outpath);
|
||||
}
|
||||
|
||||
// Dependencies on other projects.
|
||||
foreach (var refr in project.References)
|
||||
if (solution.ProjectsTable.ContainsKey(refr.Name))
|
||||
{
|
||||
var refProj = solution.ProjectsTable[refr.Name];
|
||||
if (ProjectClashes(refProj))
|
||||
f.Write(" .{0}-{1}-timestamp", refProj.Name, conf.Name);
|
||||
else
|
||||
f.Write(" {0}", ProjectOutput(refProj, conf));
|
||||
}
|
||||
|
||||
f.WriteLine();
|
||||
|
||||
// make directory for output.
|
||||
if (Path.GetDirectoryName(outpath) != "") f.WriteLine("\tmkdir -p {0}", Path.GetDirectoryName(outpath));
|
||||
// mcs command line.
|
||||
f.Write("\tgmcs", project.Name);
|
||||
f.Write(" -warn:{0}", conf.Options["WarningLevel"]);
|
||||
if ((bool)conf.Options["DebugInformation"])
|
||||
f.Write(" -debug");
|
||||
if ((bool)conf.Options["AllowUnsafe"])
|
||||
f.Write(" -unsafe");
|
||||
if ((bool)conf.Options["CheckUnderflowOverflow"])
|
||||
f.Write(" -checked");
|
||||
if (project.StartupObject != "")
|
||||
f.Write(" -main:{0}", project.StartupObject);
|
||||
if ((string)conf.Options["CompilerDefines"] != "")
|
||||
f.Write(" -define:\"{0}\"", conf.Options["CompilerDefines"]);
|
||||
|
||||
f.Write(" -target:{0} -out:{1}", ProjectTypeToTarget(project.Type), outpath);
|
||||
|
||||
// Build references to other projects. Now that sux.
|
||||
// We have to reference the other project in the same conf.
|
||||
foreach (var refr in project.References)
|
||||
if (solution.ProjectsTable.ContainsKey(refr.Name))
|
||||
{
|
||||
ProjectNode refProj;
|
||||
refProj = solution.ProjectsTable[refr.Name];
|
||||
f.Write(" -r:{0}", ProjectOutput(refProj, conf));
|
||||
}
|
||||
|
||||
f.Write(" $(REFERENCES_{0})", project.Name);
|
||||
f.Write(" $(RESOURCES_{0})", project.Name);
|
||||
f.Write(" $(SOURCES_{0})", project.Name);
|
||||
f.WriteLine();
|
||||
|
||||
// Copy references with localcopy.
|
||||
foreach (var refr in project.References)
|
||||
if (refr.LocalCopy)
|
||||
{
|
||||
string outPath, srcPath, destPath;
|
||||
outPath = Helper.NormalizePath((string)conf.Options["OutputPath"]);
|
||||
if (solution.ProjectsTable.ContainsKey(refr.Name))
|
||||
{
|
||||
ProjectNode refProj;
|
||||
refProj = solution.ProjectsTable[refr.Name];
|
||||
srcPath = ProjectOutput(refProj, conf);
|
||||
destPath = Path.Combine(outPath, Path.GetFileName(srcPath));
|
||||
destPath = NicePath(project, destPath);
|
||||
if (srcPath != destPath)
|
||||
{
|
||||
f.WriteLine("\tcp -f {0} {1}", srcPath, destPath);
|
||||
filesToClean += " " + destPath;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
srcPath = FindFileReference(refr.Name, project);
|
||||
if (srcPath != null)
|
||||
{
|
||||
destPath = Path.Combine(outPath, Path.GetFileName(srcPath));
|
||||
destPath = NicePath(project, destPath);
|
||||
f.WriteLine("\tcp -f {0} {1}", srcPath, destPath);
|
||||
filesToClean += " " + destPath;
|
||||
}
|
||||
}
|
||||
|
||||
if (clash)
|
||||
{
|
||||
filesToClean += string.Format(" .{0}-{1}-timestamp", project.Name, conf.Name);
|
||||
f.WriteLine("\ttouch .{0}-{1}-timestamp", project.Name, conf.Name);
|
||||
f.Write("\trm -rf");
|
||||
foreach (var otherConf in project.Configurations)
|
||||
if (otherConf != conf)
|
||||
f.WriteLine(" .{0}-{1}-timestamp", project.Name, otherConf.Name);
|
||||
f.WriteLine();
|
||||
}
|
||||
|
||||
f.WriteLine();
|
||||
f.WriteLine("{0}-{1}-clean:", project.Name, conf.Name);
|
||||
f.WriteLine("\trm -rf {0}", filesToClean);
|
||||
f.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteIntro(StreamWriter f, SolutionNode solution)
|
||||
{
|
||||
f.WriteLine("# Makefile for {0} generated by Prebuild ( http://dnpb.sf.net )", solution.Name);
|
||||
f.WriteLine("# Do not edit.");
|
||||
f.WriteLine("#");
|
||||
|
||||
f.Write("# Configurations:");
|
||||
foreach (var conf in solution.Configurations)
|
||||
f.Write(" {0}", conf.Name);
|
||||
f.WriteLine();
|
||||
|
||||
f.WriteLine("# Projects:");
|
||||
foreach (var proj in solution.Projects)
|
||||
f.WriteLine("#\t{0}", proj.Name);
|
||||
|
||||
f.WriteLine("#");
|
||||
f.WriteLine("# Building:");
|
||||
f.WriteLine("#\t\"make\" to build everything under the default(first) configuration");
|
||||
f.WriteLine("#\t\"make CONF\" to build every project under configuration CONF");
|
||||
f.WriteLine("#\t\"make PROJ\" to build project PROJ under the default(first) configuration");
|
||||
f.WriteLine("#\t\"make PROJ-CONF\" to build project PROJ under configuration CONF");
|
||||
f.WriteLine("#");
|
||||
f.WriteLine("# Cleaning (removing results of build):");
|
||||
f.WriteLine("#\t\"make clean\" to clean everything, that's what you probably want");
|
||||
f.WriteLine("#\t\"make CONF\" to clean everything for a configuration");
|
||||
f.WriteLine("#\t\"make PROJ\" to clean everything for a project");
|
||||
f.WriteLine("#\t\"make PROJ-CONF\" to clea project PROJ under configuration CONF");
|
||||
f.WriteLine();
|
||||
}
|
||||
|
||||
private void WritePhony(StreamWriter f, SolutionNode solution)
|
||||
{
|
||||
var defconf = "";
|
||||
foreach (var conf in solution.Configurations)
|
||||
{
|
||||
defconf = conf.Name;
|
||||
break;
|
||||
}
|
||||
|
||||
f.Write(".PHONY: all");
|
||||
foreach (var proj in solution.Projects)
|
||||
f.Write(" {0} {0}-clean", proj.Name);
|
||||
foreach (var conf in solution.Configurations)
|
||||
f.Write(" {0} {0}-clean", conf.Name);
|
||||
foreach (var proj in solution.Projects)
|
||||
foreach (var conf in solution.Configurations)
|
||||
f.Write(" {0}-{1} {0}-{1}-clean", proj.Name, conf.Name);
|
||||
f.WriteLine();
|
||||
f.WriteLine();
|
||||
|
||||
f.WriteLine("all: {0}", defconf);
|
||||
f.WriteLine();
|
||||
|
||||
f.Write("clean:");
|
||||
foreach (var conf in solution.Configurations)
|
||||
f.Write(" {0}-clean", conf.Name);
|
||||
f.WriteLine();
|
||||
f.WriteLine();
|
||||
|
||||
foreach (var conf in solution.Configurations)
|
||||
{
|
||||
f.Write("{0}: ", conf.Name);
|
||||
foreach (var proj in solution.Projects)
|
||||
f.Write(" {0}-{1}", proj.Name, conf.Name);
|
||||
f.WriteLine();
|
||||
f.WriteLine();
|
||||
|
||||
f.Write("{0}-clean: ", conf.Name);
|
||||
foreach (var proj in solution.Projects)
|
||||
f.Write(" {0}-{1}-clean", proj.Name, conf.Name);
|
||||
f.WriteLine();
|
||||
f.WriteLine();
|
||||
}
|
||||
|
||||
foreach (var proj in solution.Projects)
|
||||
{
|
||||
f.WriteLine("{0}: {0}-{1}", proj.Name, defconf);
|
||||
f.WriteLine();
|
||||
|
||||
f.Write("{0}-clean:", proj.Name);
|
||||
foreach (var conf in proj.Configurations)
|
||||
f.Write(" {0}-{1}-clean", proj.Name, conf.Name);
|
||||
f.WriteLine();
|
||||
f.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteSolution(SolutionNode solution)
|
||||
{
|
||||
m_Kernel.Log.Write("Creating makefile for {0}", solution.Name);
|
||||
m_Kernel.CurrentWorkingDirectory.Push();
|
||||
|
||||
var file = "Makefile"; // Helper.MakeFilePath(solution.FullPath, solution.Name, "make");
|
||||
var f = new StreamWriter(file);
|
||||
|
||||
Helper.SetCurrentDir(Path.GetDirectoryName(file));
|
||||
|
||||
using (f)
|
||||
{
|
||||
WriteIntro(f, solution);
|
||||
WritePhony(f, solution);
|
||||
|
||||
foreach (var project in solution.Projects)
|
||||
{
|
||||
m_Kernel.Log.Write("...Creating Project: {0}", project.Name);
|
||||
WriteProject(f, solution, project);
|
||||
}
|
||||
}
|
||||
|
||||
m_Kernel.Log.Write("");
|
||||
m_Kernel.CurrentWorkingDirectory.Pop();
|
||||
}
|
||||
|
||||
private void CleanSolution(SolutionNode solution)
|
||||
{
|
||||
m_Kernel.Log.Write("Cleaning makefile for {0}", solution.Name);
|
||||
|
||||
var file = Helper.MakeFilePath(solution.FullPath, solution.Name, "make");
|
||||
Helper.DeleteIfExists(file);
|
||||
|
||||
m_Kernel.Log.Write("");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ITarget Members
|
||||
|
||||
public void Write(Kernel kern)
|
||||
{
|
||||
m_Kernel = kern;
|
||||
foreach (var solution in kern.Solutions)
|
||||
WriteSolution(solution);
|
||||
m_Kernel = null;
|
||||
}
|
||||
|
||||
public virtual void Clean(Kernel kern)
|
||||
{
|
||||
m_Kernel = kern;
|
||||
foreach (var sol in kern.Solutions)
|
||||
CleanSolution(sol);
|
||||
m_Kernel = null;
|
||||
}
|
||||
|
||||
public string Name => "makefile";
|
||||
|
||||
#endregion
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue