NETProjectGen.cpp 15 KB

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