NETProjectGen.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. //
  2. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  3. // LICENSE: Atomic Game Engine Editor and Tools EULA
  4. // Please see LICENSE_ATOMIC_EDITOR_AND_TOOLS.md in repository root for
  5. // license information: https://github.com/AtomicGameEngine/AtomicGameEngine
  6. //
  7. #include <Atomic/IO/Log.h>
  8. #include <Atomic/IO/File.h>
  9. #include <Atomic/IO/FileSystem.h>
  10. #include "../ToolEnvironment.h"
  11. #include "../ToolSystem.h"
  12. #include "../Project/Project.h"
  13. #include "NETProjectGen.h"
  14. namespace ToolCore
  15. {
  16. NETProjectBase::NETProjectBase(Context* context, NETProjectGen* projectGen):
  17. Object(context), xmlFile_(new XMLFile(context)), projectGen_(projectGen)
  18. {
  19. }
  20. NETProjectBase::~NETProjectBase()
  21. {
  22. }
  23. void NETProjectBase::ReplacePathStrings(String& path)
  24. {
  25. ToolEnvironment* tenv = GetSubsystem<ToolEnvironment>();
  26. ToolSystem* tsys = GetSubsystem<ToolSystem>();
  27. const String& atomicRoot = tenv->GetRootSourceDir();
  28. const String& scriptPlatform = projectGen_->GetScriptPlatform();
  29. path.Replace("$ATOMIC_ROOT$", atomicRoot, false);
  30. path.Replace("$SCRIPT_PLATFORM$", scriptPlatform, false);
  31. Project* project = tsys->GetProject();
  32. if (project)
  33. {
  34. path.Replace("$PROJECT_ROOT$", project->GetProjectPath(), false);
  35. }
  36. }
  37. NETCSProject::NETCSProject(Context* context, NETProjectGen* projectGen) : NETProjectBase(context, projectGen)
  38. {
  39. }
  40. NETCSProject::~NETCSProject()
  41. {
  42. }
  43. void NETCSProject::CreateCompileItemGroup(XMLElement &projectRoot)
  44. {
  45. FileSystem* fs = GetSubsystem<FileSystem>();
  46. XMLElement igroup = projectRoot.CreateChild("ItemGroup");
  47. for (unsigned i = 0; i < sourceFolders_.Size(); i++)
  48. {
  49. const String& sourceFolder = sourceFolders_[i];
  50. Vector<String> result;
  51. fs->ScanDir(result, sourceFolder, "*.cs", SCAN_FILES, true);
  52. for (unsigned j = 0; j < result.Size(); j++)
  53. {
  54. igroup.CreateChild("Compile").SetAttribute("Include", sourceFolder + result[j]);
  55. }
  56. }
  57. }
  58. void NETCSProject::CreateReferencesItemGroup(XMLElement &projectRoot)
  59. {
  60. ToolEnvironment* tenv = GetSubsystem<ToolEnvironment>();
  61. FileSystem* fs = GetSubsystem<FileSystem>();
  62. const String& coreCLRAbsPath = tenv->GetNETCoreCLRAbsPath();
  63. XMLElement igroup = projectRoot.CreateChild("ItemGroup");
  64. XMLElement mscorlibref = igroup.CreateChild("Reference");
  65. mscorlibref.SetAttribute("Include", "mscorlib");
  66. mscorlibref.CreateChild("HintPath").SetValue(coreCLRAbsPath + "mscorlib.dll");
  67. mscorlibref.CreateChild("Private").SetValue("False");
  68. for (unsigned i = 0; i < references_.Size(); i++)
  69. {
  70. String ref = references_[i];
  71. String refpath = ref + ".dll";
  72. // we explicitly add mscorlib
  73. if (ref == "mscorlib")
  74. continue;
  75. XMLElement xref = igroup.CreateChild("Reference");
  76. xref.SetAttribute("Include", ref);
  77. // if we're a coreclr assembly, qualify it
  78. if (fs->FileExists(coreCLRAbsPath + refpath))
  79. {
  80. refpath = coreCLRAbsPath + refpath;
  81. }
  82. xref.CreateChild("HintPath").SetValue(refpath);
  83. xref.CreateChild("Private").SetValue("False");
  84. }
  85. }
  86. void NETCSProject::GetAssemblySearchPaths(String& paths)
  87. {
  88. paths.Clear();
  89. ToolEnvironment* tenv = GetSubsystem<ToolEnvironment>();
  90. const String& coreCLRAbsPath = tenv->GetNETCoreCLRAbsPath();
  91. Vector<String> searchPaths;
  92. searchPaths.Push(coreCLRAbsPath);
  93. if (assemblySearchPaths_.Length())
  94. searchPaths.Push(assemblySearchPaths_);
  95. paths.Join(searchPaths, ";");
  96. }
  97. void NETCSProject::CreateReleasePropertyGroup(XMLElement &projectRoot)
  98. {
  99. XMLElement pgroup = projectRoot.CreateChild("PropertyGroup");
  100. pgroup.SetAttribute("Condition", " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ");
  101. pgroup.CreateChild("DebugType").SetValue("full");
  102. pgroup.CreateChild("Optimize").SetValue("true");
  103. pgroup.CreateChild("OutputPath").SetValue(assemblyOutputPath_);
  104. pgroup.CreateChild("ErrorReport").SetValue("prompt");
  105. pgroup.CreateChild("WarningLevel").SetValue("4");
  106. pgroup.CreateChild("ConsolePause").SetValue("false");
  107. pgroup.CreateChild("AllowUnsafeBlocks").SetValue("true");
  108. pgroup.CreateChild("NoStdLib").SetValue("true");
  109. pgroup.CreateChild("NoConfig").SetValue("true");
  110. pgroup.CreateChild("NoCompilerStandardLib").SetValue("true");
  111. String assemblySearchPaths;
  112. GetAssemblySearchPaths(assemblySearchPaths);
  113. pgroup.CreateChild("AssemblySearchPaths").SetValue(assemblySearchPaths);
  114. }
  115. void NETCSProject::CreateDebugPropertyGroup(XMLElement &projectRoot)
  116. {
  117. XMLElement pgroup = projectRoot.CreateChild("PropertyGroup");
  118. pgroup.SetAttribute("Condition", " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ");
  119. pgroup.CreateChild("DebugSymbols").SetValue("true");
  120. pgroup.CreateChild("DebugType").SetValue("full");
  121. pgroup.CreateChild("Optimize").SetValue("false");
  122. pgroup.CreateChild("OutputPath").SetValue(assemblyOutputPath_);
  123. pgroup.CreateChild("DefineConstants").SetValue("DEBUG;");
  124. pgroup.CreateChild("ErrorReport").SetValue("prompt");
  125. pgroup.CreateChild("WarningLevel").SetValue("4");
  126. pgroup.CreateChild("ConsolePause").SetValue("false");
  127. pgroup.CreateChild("AllowUnsafeBlocks").SetValue("true");
  128. pgroup.CreateChild("NoStdLib").SetValue("true");
  129. pgroup.CreateChild("NoConfig").SetValue("true");
  130. pgroup.CreateChild("NoCompilerStandardLib").SetValue("true");
  131. String assemblySearchPaths;
  132. GetAssemblySearchPaths(assemblySearchPaths);
  133. pgroup.CreateChild("AssemblySearchPaths").SetValue(assemblySearchPaths);
  134. }
  135. void NETCSProject::CreateMainPropertyGroup(XMLElement& projectRoot)
  136. {
  137. XMLElement pgroup = projectRoot.CreateChild("PropertyGroup");
  138. // Configuration
  139. XMLElement config = pgroup.CreateChild("Configuration");
  140. config.SetAttribute("Condition", " '$(Configuration)' == '' ");
  141. config.SetValue("Debug");
  142. // Platform
  143. XMLElement platform = pgroup.CreateChild("Platform");
  144. platform.SetAttribute("Condition", " '$(Platform)' == '' ");
  145. platform.SetValue("AnyCPU");
  146. // ProjectGuid
  147. XMLElement guid = pgroup.CreateChild("ProjectGuid");
  148. guid.SetValue(projectGuid_);
  149. // OutputType
  150. XMLElement outputType = pgroup.CreateChild("OutputType");
  151. outputType.SetValue(outputType_);
  152. // RootNamespace
  153. XMLElement rootNamespace = pgroup.CreateChild("RootNamespace");
  154. rootNamespace.SetValue(rootNamespace_);
  155. // AssemblyName
  156. XMLElement assemblyName = pgroup.CreateChild("AssemblyName");
  157. assemblyName.SetValue(assemblyName_);
  158. // TargetFrameworkVersion
  159. XMLElement targetFrameWork = pgroup.CreateChild("TargetFrameworkVersion");
  160. targetFrameWork.SetValue("4.5");
  161. }
  162. bool NETCSProject::Generate()
  163. {
  164. XMLElement project = xmlFile_->CreateRoot("Project");
  165. project.SetAttribute("DefaultTargets", "Build");
  166. project.SetAttribute("ToolsVersion", "4.0");
  167. project.SetAttribute("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003");
  168. CreateMainPropertyGroup(project);
  169. CreateDebugPropertyGroup(project);
  170. CreateReleasePropertyGroup(project);
  171. CreateReferencesItemGroup(project);
  172. CreateCompileItemGroup(project);
  173. project.CreateChild("Import").SetAttribute("Project", "$(MSBuildBinPath)\\Microsoft.CSharp.targets");
  174. // on msbuild this seems to stop referencing of framework assemblies
  175. project.CreateChild("Target").SetAttribute("Name", "GetReferenceAssemblyPaths");
  176. project.CreateChild("Target").SetAttribute("Name", "GetFrameworkPaths");
  177. String projectSource = xmlFile_->ToString();
  178. NETSolution* solution = projectGen_->GetSolution();
  179. String projectPath = solution->GetOutputPath() + name_ + ".csproj";
  180. SharedPtr<File> output(new File(context_, projectPath, FILE_WRITE));
  181. output->Write(projectSource.CString(), projectSource.Length());
  182. return true;
  183. }
  184. bool NETCSProject::Load(const JSONValue& root)
  185. {
  186. bool gameBuild = projectGen_->GetGameBuild();
  187. name_ = root["name"].GetString();
  188. projectGuid_ = root["projectGuid"].GetString();
  189. if (gameBuild)
  190. outputType_ = "Library";
  191. else
  192. outputType_ = root["outputType"].GetString();
  193. rootNamespace_ = root["rootNamespace"].GetString();
  194. assemblyName_ = root["assemblyName"].GetString();
  195. assemblyOutputPath_ = root["assemblyOutputPath"].GetString();
  196. ReplacePathStrings(assemblyOutputPath_);
  197. assemblySearchPaths_ = root["assemblySearchPaths"].GetString();
  198. if (gameBuild)
  199. {
  200. ToolEnvironment* tenv = GetSubsystem<ToolEnvironment>();
  201. const String& engineAssemblyPath = tenv->GetAtomicNETEngineAssemblyPath();
  202. if (assemblySearchPaths_.Length())
  203. {
  204. assemblySearchPaths_ += ";";
  205. assemblySearchPaths_ += engineAssemblyPath;
  206. }
  207. else
  208. {
  209. assemblySearchPaths_ = engineAssemblyPath;
  210. }
  211. }
  212. ReplacePathStrings(assemblySearchPaths_);
  213. const JSONArray& references = root["references"].GetArray();
  214. for (unsigned i = 0; i < references.Size(); i++)
  215. {
  216. String reference = references[i].GetString();
  217. ReplacePathStrings(reference);
  218. references_.Push(reference);
  219. }
  220. if (gameBuild)
  221. {
  222. references_.Push("AtomicNETEngine");
  223. }
  224. // msvc doesn't like including these
  225. if (projectGen_->GetMonoBuild())
  226. {
  227. references_.Push("System.Console");
  228. references_.Push("System.IO");
  229. references_.Push("System.IO.FileSystem");
  230. }
  231. const JSONArray& sources = root["sources"].GetArray();
  232. for (unsigned i = 0; i < sources.Size(); i++)
  233. {
  234. String source = sources[i].GetString();
  235. ReplacePathStrings(source);
  236. sourceFolders_.Push(AddTrailingSlash(source));
  237. }
  238. return true;
  239. }
  240. NETSolution::NETSolution(Context* context, NETProjectGen* projectGen) : NETProjectBase(context, projectGen)
  241. {
  242. }
  243. NETSolution::~NETSolution()
  244. {
  245. }
  246. bool NETSolution::Generate()
  247. {
  248. String slnPath = outputPath_ + name_ + ".sln";
  249. GenerateXamarinStudio(slnPath);
  250. return true;
  251. }
  252. void NETSolution::GenerateXamarinStudio(const String &slnPath)
  253. {
  254. String source = "Microsoft Visual Studio Solution File, Format Version 12.00\n";
  255. source += "# Visual Studio 2012\n";
  256. const Vector<SharedPtr<NETCSProject>>& projects = projectGen_->GetCSProjects();
  257. for (unsigned i = 0; i < projects.Size(); i++)
  258. {
  259. NETCSProject* p = projects.At(i);
  260. source += ToString("Project(\"{%s}\") = \"%s\", \"%s.csproj\", \"{%s}\"\n",
  261. p->GetProjectGUID().CString(), p->GetName().CString(), p->GetName().CString(),
  262. p->GetProjectGUID().CString());
  263. source += "EndProject\n";
  264. }
  265. source += "Global\n";
  266. source += " GlobalSection(SolutionConfigurationPlatforms) = preSolution\n";
  267. source += " Debug|Any CPU = Debug|Any CPU\n";
  268. source += " Release|Any CPU = Release|Any CPU\n";
  269. source += " EndGlobalSection\n";
  270. source += " GlobalSection(ProjectConfigurationPlatforms) = postSolution\n";
  271. for (unsigned i = 0; i < projects.Size(); i++)
  272. {
  273. NETCSProject* p = projects.At(i);
  274. source += ToString(" {%s}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n", p->GetProjectGUID().CString());
  275. source += ToString(" {%s}.Debug|Any CPU.Build.0 = Debug|Any CPU\n", p->GetProjectGUID().CString());
  276. source += ToString(" {%s}.Release|Any CPU.ActiveCfg = Release|Any CPU\n", p->GetProjectGUID().CString());
  277. source += ToString(" {%s}.Release|Any CPU.Build.0 = Release|Any CPU\n", p->GetProjectGUID().CString());
  278. }
  279. source += " EndGlobalSection\n";
  280. source += "EndGlobal\n";
  281. SharedPtr<File> output(new File(context_, slnPath, FILE_WRITE));
  282. output->Write(source.CString(), source.Length());
  283. output->Close();
  284. }
  285. bool NETSolution::Load(const JSONValue& root)
  286. {
  287. FileSystem* fs = GetSubsystem<FileSystem>();
  288. name_ = root["name"].GetString();
  289. outputPath_ = AddTrailingSlash(root["outputPath"].GetString());
  290. ReplacePathStrings(outputPath_);
  291. // TODO: use poco mkdirs
  292. if (!fs->DirExists(outputPath_))
  293. fs->CreateDir(outputPath_);
  294. return true;
  295. }
  296. NETProjectGen::NETProjectGen(Context* context) : Object(context),
  297. monoBuild_(false), gameBuild_(false)
  298. {
  299. #ifndef ATOMIC_PLATFORM_WINDOWS
  300. monoBuild_ = true;
  301. #endif
  302. }
  303. NETProjectGen::~NETProjectGen()
  304. {
  305. }
  306. bool NETProjectGen::Generate()
  307. {
  308. solution_->Generate();
  309. for (unsigned i = 0; i < projects_.Size(); i++)
  310. {
  311. if (!projects_[i]->Generate())
  312. return false;
  313. }
  314. return true;
  315. }
  316. bool NETProjectGen::LoadProject(const JSONValue &root, bool gameBuild)
  317. {
  318. gameBuild_ = gameBuild;
  319. solution_ = new NETSolution(context_, this);
  320. solution_->Load(root["solution"]);
  321. const JSONValue& jprojects = root["projects"];
  322. if (!jprojects.IsArray() || ! jprojects.Size())
  323. return false;
  324. for (unsigned i = 0; i < jprojects.Size(); i++)
  325. {
  326. const JSONValue& jproject = jprojects[i];
  327. if (!jproject.IsObject())
  328. return false;
  329. SharedPtr<NETCSProject> csProject(new NETCSProject(context_, this));
  330. if (!csProject->Load(jproject))
  331. return false;
  332. projects_.Push(csProject);
  333. }
  334. return true;
  335. }
  336. bool NETProjectGen::LoadProject(const String& projectPath, bool gameBuild)
  337. {
  338. SharedPtr<File> file(new File(context_));
  339. if (!file->Open(projectPath))
  340. return false;
  341. String json;
  342. file->ReadText(json);
  343. JSONValue jvalue;
  344. if (!JSONFile::ParseJSON(json, jvalue))
  345. return false;
  346. return LoadProject(jvalue, gameBuild);
  347. }
  348. }