NETProjectGen.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946
  1. //
  2. // Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include <Poco/UUID.h>
  23. #include <Poco/UUIDGenerator.h>
  24. #include <Atomic/IO/Log.h>
  25. #include <Atomic/IO/File.h>
  26. #include <Atomic/IO/FileSystem.h>
  27. #include "../ToolEnvironment.h"
  28. #include "../ToolSystem.h"
  29. #include "../Project/Project.h"
  30. #include "NETProjectGen.h"
  31. namespace ToolCore
  32. {
  33. NETProjectBase::NETProjectBase(Context* context, NETProjectGen* projectGen) :
  34. Object(context), xmlFile_(new XMLFile(context)), projectGen_(projectGen)
  35. {
  36. }
  37. NETProjectBase::~NETProjectBase()
  38. {
  39. }
  40. void NETProjectBase::ReplacePathStrings(String& path)
  41. {
  42. ToolEnvironment* tenv = GetSubsystem<ToolEnvironment>();
  43. String atomicRoot = tenv->GetRootSourceDir();
  44. atomicRoot = RemoveTrailingSlash(atomicRoot);
  45. const String& scriptPlatform = projectGen_->GetScriptPlatform();
  46. path.Replace("$ATOMIC_ROOT$", atomicRoot, false);
  47. path.Replace("$SCRIPT_PLATFORM$", scriptPlatform, false);
  48. }
  49. NETCSProject::NETCSProject(Context* context, NETProjectGen* projectGen) : NETProjectBase(context, projectGen)
  50. {
  51. }
  52. NETCSProject::~NETCSProject()
  53. {
  54. }
  55. bool NETCSProject::CreateProjectFolder(const String& path)
  56. {
  57. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  58. if (fileSystem->DirExists(path))
  59. return true;
  60. fileSystem->CreateDirsRecursive(path);
  61. if (!fileSystem->DirExists(path))
  62. {
  63. ATOMIC_LOGERRORF("Unable to create dir: %s", path.CString());
  64. return false;
  65. }
  66. return true;
  67. }
  68. void NETCSProject::CreateCompileItemGroup(XMLElement &projectRoot)
  69. {
  70. FileSystem* fs = GetSubsystem<FileSystem>();
  71. XMLElement igroup = projectRoot.CreateChild("ItemGroup");
  72. // Compile AssemblyInfo.cs
  73. igroup.CreateChild("Compile").SetAttribute("Include", "Properties\\AssemblyInfo.cs");
  74. for (unsigned i = 0; i < sourceFolders_.Size(); i++)
  75. {
  76. const String& sourceFolder = sourceFolders_[i];
  77. Vector<String> result;
  78. fs->ScanDir(result, sourceFolder, "*.cs", SCAN_FILES, true);
  79. for (unsigned j = 0; j < result.Size(); j++)
  80. {
  81. XMLElement compile = igroup.CreateChild("Compile");
  82. String path = sourceFolder + result[j];
  83. String relativePath;
  84. if (GetRelativePath(projectPath_, GetPath(path), relativePath))
  85. {
  86. path = relativePath + GetFileName(path) + GetExtension(path);
  87. }
  88. // IMPORTANT: / Slash direction breaks intellisense :/
  89. path.Replace('/', '\\');
  90. compile.SetAttribute("Include", path.CString());
  91. // put generated files into generated folder
  92. if (sourceFolder.Contains("Generated") && sourceFolder.Contains("CSharp") && sourceFolder.Contains("Packages"))
  93. {
  94. compile.CreateChild("Link").SetValue("Generated\\" + result[j]);
  95. }
  96. else
  97. {
  98. compile.CreateChild("Link").SetValue(result[j]);
  99. }
  100. }
  101. }
  102. }
  103. void NETProjectBase::CopyXMLElementRecursive(XMLElement source, XMLElement dest)
  104. {
  105. Vector<String> attrNames = source.GetAttributeNames();
  106. for (unsigned i = 0; i < attrNames.Size(); i++)
  107. {
  108. String value = source.GetAttribute(attrNames[i]);
  109. dest.SetAttribute(attrNames[i], value);
  110. }
  111. dest.SetValue(source.GetValue());
  112. XMLElement child = source.GetChild();
  113. while (child.NotNull() && child.GetName().Length())
  114. {
  115. XMLElement childDest = dest.CreateChild(child.GetName());
  116. CopyXMLElementRecursive(child, childDest);
  117. child = child.GetNext();
  118. }
  119. }
  120. void NETCSProject::CreateReferencesItemGroup(XMLElement &projectRoot)
  121. {
  122. XMLElement xref;
  123. XMLElement igroup = projectRoot.CreateChild("ItemGroup");
  124. for (unsigned i = 0; i < references_.Size(); i++)
  125. {
  126. String ref = references_[i];
  127. // project reference
  128. if (projectGen_->GetCSProjectByName(ref))
  129. continue;
  130. // NuGet project
  131. if (ref.StartsWith("<"))
  132. {
  133. XMLFile xmlFile(context_);
  134. if (!xmlFile.FromString(ref))
  135. {
  136. ATOMIC_LOGERROR("NETCSProject::CreateReferencesItemGroup - Unable to parse reference XML");
  137. }
  138. xref = igroup.CreateChild("Reference");
  139. CopyXMLElementRecursive(xmlFile.GetRoot(), xref);
  140. continue;
  141. }
  142. xref = igroup.CreateChild("Reference");
  143. xref.SetAttribute("Include", ref);
  144. }
  145. Project* project = projectGen_->GetAtomicProject();
  146. if (project)
  147. {
  148. Vector<String> result;
  149. GetSubsystem<FileSystem>()->ScanDir(result, project->GetResourcePath(), "*.dll", SCAN_FILES, true);
  150. for (unsigned j = 0; j < result.Size(); j++)
  151. {
  152. String path = project->GetResourcePath() + result[j];
  153. String relativePath;
  154. if (GetRelativePath(projectPath_, GetPath(path), relativePath))
  155. {
  156. if (projectGen_->GetCSProjectByName(GetFileName(path)))
  157. continue;
  158. path = relativePath + GetFileName(path) + GetExtension(path);
  159. }
  160. xref = igroup.CreateChild("Reference");
  161. xref.SetAttribute("Include", path);
  162. }
  163. }
  164. }
  165. void NETCSProject::CreateProjectReferencesItemGroup(XMLElement &projectRoot)
  166. {
  167. XMLElement igroup = projectRoot.CreateChild("ItemGroup");
  168. for (unsigned i = 0; i < references_.Size(); i++)
  169. {
  170. const String& ref = references_[i];
  171. NETCSProject* project = projectGen_->GetCSProjectByName(ref);
  172. if (!project)
  173. continue;
  174. XMLElement projectRef = igroup.CreateChild("ProjectReference");
  175. projectRef.SetAttribute("Include", ToString("..\\%s\\%s.csproj", ref.CString(), ref.CString()));
  176. XMLElement xproject = projectRef.CreateChild("Project");
  177. xproject.SetValue(ToString("{%s}", project->GetProjectGUID().ToLower().CString()));
  178. XMLElement xname = projectRef.CreateChild("Name");
  179. xname.SetValue(project->GetName());
  180. }
  181. }
  182. void NETCSProject::CreatePackagesItemGroup(XMLElement &projectRoot)
  183. {
  184. if (!packages_.Size())
  185. return;
  186. XMLElement xref;
  187. XMLElement igroup = projectRoot.CreateChild("ItemGroup");
  188. xref = igroup.CreateChild("None");
  189. xref.SetAttribute("Include", "packages.config");
  190. XMLFile packageConfig(context_);
  191. XMLElement packageRoot = packageConfig.CreateRoot("packages");
  192. for (unsigned i = 0; i < packages_.Size(); i++)
  193. {
  194. XMLFile xmlFile(context_);
  195. if (!xmlFile.FromString(packages_[i]))
  196. {
  197. ATOMIC_LOGERROR("NETCSProject::CreatePackagesItemGroup - Unable to parse package xml");
  198. }
  199. xref = packageRoot.CreateChild("package");
  200. CopyXMLElementRecursive(xmlFile.GetRoot(), xref);
  201. }
  202. SharedPtr<File> output(new File(context_, projectPath_ + "packages.config", FILE_WRITE));
  203. String source = packageConfig.ToString();
  204. output->Write(source.CString(), source.Length());
  205. }
  206. void NETCSProject::GetAssemblySearchPaths(String& paths)
  207. {
  208. paths.Clear();
  209. ToolEnvironment* tenv = GetSubsystem<ToolEnvironment>();
  210. Vector<String> searchPaths;
  211. if (assemblySearchPaths_.Length())
  212. searchPaths.Push(assemblySearchPaths_);
  213. paths.Join(searchPaths, ";");
  214. }
  215. void NETCSProject::CreateCustomCommands(XMLElement &propertyGroup, const String& cfg)
  216. {
  217. Project* atomicProject = projectGen_->GetAtomicProject();
  218. if (!atomicProject)
  219. return;
  220. ToolEnvironment* tenv = GetSubsystem<ToolEnvironment>();
  221. XMLElement customCommands = propertyGroup.CreateChild("CustomCommands").CreateChild("CustomCommands");
  222. XMLElement xcommand = customCommands.CreateChild("Command");
  223. xcommand.SetAttribute("type", "Execute");
  224. String startArguments;
  225. #ifdef ATOMIC_DEV_BUILD
  226. String playerBin = tenv->GetAtomicNETRootDir() + cfg + "/AtomicIPCPlayer.exe";
  227. #else
  228. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  229. String playerBin = tenv->GetAtomicNETRootDir() + "Release/AtomicIPCPlayer.exe";
  230. #ifdef ATOMIC_PLATFORM_OSX
  231. startArguments += ToString("--resourcePrefix \"%s\" ", (fileSystem->GetProgramDir() + "../Resources/").CString());
  232. #else
  233. startArguments += ToString("--resourcePrefix \"%s\" ", (fileSystem->GetProgramDir() + "Resources/").CString());
  234. #endif
  235. #endif
  236. startArguments += ToString("--project \"%s\"", atomicProject->GetProjectPath().CString());
  237. String command = ToString("\"%s\"", playerBin.CString()) + " " + startArguments;
  238. xcommand.SetAttribute("command", command);
  239. }
  240. void NETCSProject::CreateReleasePropertyGroup(XMLElement &projectRoot)
  241. {
  242. XMLElement pgroup = projectRoot.CreateChild("PropertyGroup");
  243. pgroup.SetAttribute("Condition", " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ");
  244. pgroup.CreateChild("DebugType").SetValue("full");
  245. pgroup.CreateChild("Optimize").SetValue("true");
  246. pgroup.CreateChild("OutputPath").SetValue(assemblyOutputPath_ + "Release\\");
  247. pgroup.CreateChild("DefineConstants").SetValue("TRACE");
  248. pgroup.CreateChild("ErrorReport").SetValue("prompt");
  249. pgroup.CreateChild("WarningLevel").SetValue("4");
  250. pgroup.CreateChild("ConsolePause").SetValue("false");
  251. pgroup.CreateChild("AllowUnsafeBlocks").SetValue("true");
  252. pgroup.CreateChild("PlatformTarget").SetValue("x64");
  253. #ifndef ATOMIC_PLATFORM_WINDOWS
  254. CreateCustomCommands(pgroup, "Debug");
  255. #endif
  256. }
  257. void NETCSProject::CreateDebugPropertyGroup(XMLElement &projectRoot)
  258. {
  259. XMLElement pgroup = projectRoot.CreateChild("PropertyGroup");
  260. pgroup.SetAttribute("Condition", " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ");
  261. pgroup.CreateChild("DebugSymbols").SetValue("true");
  262. pgroup.CreateChild("DebugType").SetValue("full");
  263. pgroup.CreateChild("Optimize").SetValue("false");
  264. pgroup.CreateChild("OutputPath").SetValue(assemblyOutputPath_ + "Debug\\");
  265. pgroup.CreateChild("DefineConstants").SetValue("DEBUG;TRACE");
  266. pgroup.CreateChild("ErrorReport").SetValue("prompt");
  267. pgroup.CreateChild("WarningLevel").SetValue("4");
  268. pgroup.CreateChild("ConsolePause").SetValue("false");
  269. pgroup.CreateChild("AllowUnsafeBlocks").SetValue("true");
  270. pgroup.CreateChild("PlatformTarget").SetValue("x64");
  271. #ifndef ATOMIC_PLATFORM_WINDOWS
  272. CreateCustomCommands(pgroup, "Release");
  273. #endif
  274. }
  275. void NETCSProject::CreateAssemblyInfo()
  276. {
  277. String info = "using System.Reflection;\nusing System.Runtime.CompilerServices;\nusing System.Runtime.InteropServices;\n\n\n";
  278. info += ToString("[assembly:AssemblyTitle(\"%s\")]\n", name_.CString());
  279. info += "[assembly:AssemblyDescription(\"\")]\n";
  280. info += "[assembly:AssemblyConfiguration(\"\")]\n";
  281. info += "[assembly:AssemblyCompany(\"\")]\n";
  282. info += ToString("[assembly:AssemblyProduct(\"%s\")]\n", name_.CString());
  283. info += "\n\n\n";
  284. info += "[assembly:ComVisible(false)]\n";
  285. info += "\n\n";
  286. info += ToString("[assembly:Guid(\"%s\")]\n", projectGuid_.CString());
  287. info += "\n\n";
  288. info += "[assembly:AssemblyVersion(\"1.0.0.0\")]\n";
  289. info += "[assembly:AssemblyFileVersion(\"1.0.0.0\")]\n";
  290. SharedPtr<File> output(new File(context_, projectPath_ + "Properties/AssemblyInfo.cs", FILE_WRITE));
  291. output->Write(info.CString(), info.Length());
  292. }
  293. void NETCSProject::CreateMainPropertyGroup(XMLElement& projectRoot)
  294. {
  295. XMLElement pgroup = projectRoot.CreateChild("PropertyGroup");
  296. // Configuration
  297. XMLElement config = pgroup.CreateChild("Configuration");
  298. config.SetAttribute("Condition", " '$(Configuration)' == '' ");
  299. config.SetValue("Debug");
  300. // Platform
  301. XMLElement platform = pgroup.CreateChild("Platform");
  302. platform.SetAttribute("Condition", " '$(Platform)' == '' ");
  303. platform.SetValue("AnyCPU");
  304. // ProjectGuid
  305. XMLElement guid = pgroup.CreateChild("ProjectGuid");
  306. guid.SetValue("{" + projectGuid_ + "}");
  307. // OutputType
  308. XMLElement outputType = pgroup.CreateChild("OutputType");
  309. outputType.SetValue(outputType_);
  310. pgroup.CreateChild("AppDesignerFolder").SetValue("Properties");
  311. // RootNamespace
  312. XMLElement rootNamespace = pgroup.CreateChild("RootNamespace");
  313. rootNamespace.SetValue(rootNamespace_);
  314. // AssemblyName
  315. XMLElement assemblyName = pgroup.CreateChild("AssemblyName");
  316. assemblyName.SetValue(assemblyName_);
  317. // TargetFrameworkVersion
  318. XMLElement targetFrameWork = pgroup.CreateChild("TargetFrameworkVersion");
  319. targetFrameWork.SetValue("v4.6");
  320. pgroup.CreateChild("FileAlignment").SetValue("512");
  321. }
  322. bool NETCSProject::Generate()
  323. {
  324. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  325. NETSolution* solution = projectGen_->GetSolution();
  326. ToolEnvironment* tenv = GetSubsystem<ToolEnvironment>();
  327. projectPath_ = solution->GetOutputPath() + name_ + "/";
  328. if (!CreateProjectFolder(projectPath_))
  329. return false;
  330. if (!CreateProjectFolder(projectPath_ + "Properties"))
  331. return false;
  332. XMLElement project = xmlFile_->CreateRoot("Project");
  333. project.SetAttribute("DefaultTargets", "Build");
  334. project.SetAttribute("ToolsVersion", "14.0");
  335. project.SetAttribute("DefaultTargets", "Build");
  336. project.SetAttribute("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003");
  337. XMLElement import = project.CreateChild("Import");
  338. import.SetAttribute("Project", "$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props");
  339. import.SetAttribute("Condition", "Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')");
  340. CreateMainPropertyGroup(project);
  341. CreateDebugPropertyGroup(project);
  342. CreateReleasePropertyGroup(project);
  343. CreateReferencesItemGroup(project);
  344. CreateProjectReferencesItemGroup(project);
  345. CreateCompileItemGroup(project);
  346. CreatePackagesItemGroup(project);
  347. CreateAssemblyInfo();
  348. project.CreateChild("Import").SetAttribute("Project", "$(MSBuildToolsPath)\\Microsoft.CSharp.targets");
  349. Project* atomicProject = projectGen_->GetAtomicProject();
  350. if (atomicProject)
  351. {
  352. XMLElement afterBuild = project.CreateChild("Target");
  353. afterBuild.SetAttribute("Name", "AfterBuild");
  354. XMLElement copy = afterBuild.CreateChild("Copy");
  355. copy.SetAttribute("SourceFiles", "$(TargetPath)");
  356. String destPath = projectPath_ + "../../../Resources/";
  357. String relativePath;
  358. if (GetRelativePath(projectPath_, atomicProject->GetResourcePath(), relativePath))
  359. {
  360. destPath = AddTrailingSlash(relativePath);
  361. }
  362. copy.SetAttribute("DestinationFolder", destPath);
  363. #ifndef ATOMIC_PLATFORM_WINDOWS
  364. copy = afterBuild.CreateChild("Copy");
  365. copy.SetAttribute("SourceFiles", "$(TargetPath).mdb");
  366. copy.SetAttribute("DestinationFolder", destPath);
  367. #endif
  368. // Create the AtomicProject.csproj.user file if it doesn't exist
  369. String userSettingsFilename = projectPath_ + name_ + ".csproj.user";
  370. if (!fileSystem->FileExists(userSettingsFilename))
  371. {
  372. SharedPtr<XMLFile> userSettings(new XMLFile(context_));
  373. XMLElement project = userSettings->CreateRoot("Project");
  374. //XMLElement xml = userRoot.CreateChild("?xml");
  375. //xml.SetAttribute("version", "1.0");
  376. //xml.SetAttribute("encoding", "utf-8");
  377. project.SetAttribute("ToolsVersion", "14.0");
  378. project.SetAttribute("xmlns", "http://schemas.microsoft.com/developer/msbuild/2003");
  379. StringVector configs;
  380. configs.Push("Debug");
  381. configs.Push("Release");
  382. for (unsigned i = 0; i < configs.Size(); i++)
  383. {
  384. String cfg = configs[i];
  385. XMLElement propertyGroup = project.CreateChild("PropertyGroup");
  386. propertyGroup.SetAttribute("Condition", ToString("'$(Configuration)|$(Platform)' == '%s|AnyCPU'", cfg.CString()));
  387. String startArguments;
  388. #ifdef ATOMIC_DEV_BUILD
  389. String playerBin = tenv->GetAtomicNETRootDir() + cfg + "/AtomicIPCPlayer.exe";
  390. #else
  391. String playerBin = tenv->GetAtomicNETRootDir() + "Release/AtomicIPCPlayer.exe";
  392. startArguments += ToString("--resourcePrefix \"%s\" ", (fileSystem->GetProgramDir() + "Resources/").CString());
  393. #endif
  394. propertyGroup.CreateChild("StartAction").SetValue("Program");
  395. propertyGroup.CreateChild("StartProgram").SetValue(playerBin );
  396. startArguments += ToString("--project \"%s\"", atomicProject->GetProjectPath().CString());
  397. propertyGroup.CreateChild("StartArguments").SetValue(startArguments);
  398. }
  399. String userSettingsSource = userSettings->ToString();
  400. SharedPtr<File> output(new File(context_, userSettingsFilename, FILE_WRITE));
  401. output->Write(userSettingsSource.CString(), userSettingsSource.Length());
  402. output->Close();
  403. }
  404. }
  405. String projectSource = xmlFile_->ToString();
  406. SharedPtr<File> output(new File(context_, projectPath_ + name_ + ".csproj", FILE_WRITE));
  407. output->Write(projectSource.CString(), projectSource.Length());
  408. return true;
  409. }
  410. bool NETCSProject::Load(const JSONValue& root)
  411. {
  412. name_ = root["name"].GetString();
  413. projectGuid_ = projectGen_->GenerateUUID();
  414. outputType_ = root["outputType"].GetString();
  415. rootNamespace_ = root["rootNamespace"].GetString();
  416. assemblyName_ = root["assemblyName"].GetString();
  417. assemblyOutputPath_ = root["assemblyOutputPath"].GetString();
  418. ReplacePathStrings(assemblyOutputPath_);
  419. assemblySearchPaths_ = root["assemblySearchPaths"].GetString();
  420. ReplacePathStrings(assemblySearchPaths_);
  421. const JSONArray& references = root["references"].GetArray();
  422. for (unsigned i = 0; i < references.Size(); i++)
  423. {
  424. String reference = references[i].GetString();
  425. ReplacePathStrings(reference);
  426. references_.Push(reference);
  427. }
  428. const JSONArray& packages = root["packages"].GetArray();
  429. for (unsigned i = 0; i < packages.Size(); i++)
  430. {
  431. String package = packages[i].GetString();
  432. if (packages_.Find(package) != packages_.End())
  433. {
  434. ATOMIC_LOGERRORF("Duplicate package found %s", package.CString());
  435. continue;
  436. }
  437. projectGen_->GetSolution()->RegisterPackage(package);
  438. packages_.Push(package);
  439. }
  440. const JSONArray& sources = root["sources"].GetArray();
  441. for (unsigned i = 0; i < sources.Size(); i++)
  442. {
  443. String source = sources[i].GetString();
  444. ReplacePathStrings(source);
  445. sourceFolders_.Push(AddTrailingSlash(source));
  446. }
  447. return true;
  448. }
  449. NETSolution::NETSolution(Context* context, NETProjectGen* projectGen, bool rewrite) : NETProjectBase(context, projectGen),
  450. rewriteSolution_(rewrite)
  451. {
  452. }
  453. NETSolution::~NETSolution()
  454. {
  455. }
  456. bool NETSolution::Generate()
  457. {
  458. String slnPath = outputPath_ + name_ + ".sln";
  459. GenerateSolution(slnPath);
  460. return true;
  461. }
  462. void NETSolution::GenerateSolution(const String &slnPath)
  463. {
  464. String source = "Microsoft Visual Studio Solution File, Format Version 12.00\n";
  465. source += "# Visual Studio 14\n";
  466. source += "VisualStudioVersion = 14.0.25420.1\n";
  467. source += "MinimumVisualStudioVersion = 10.0.40219.1\n";
  468. solutionGUID_ = projectGen_->GenerateUUID();
  469. PODVector<NETCSProject*> depends;
  470. const Vector<SharedPtr<NETCSProject>>& projects = projectGen_->GetCSProjects();
  471. for (unsigned i = 0; i < projects.Size(); i++)
  472. {
  473. NETCSProject* p = projects.At(i);
  474. const String& projectName = p->GetName();
  475. const String& projectGUID = p->GetProjectGUID();
  476. const String CSharpProjectGUID = "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC";
  477. source += ToString("Project(\"{%s}\") = \"%s\", \"%s\\%s.csproj\", \"{%s}\"\n",
  478. CSharpProjectGUID.CString(), projectName.CString(), projectName.CString(),
  479. projectName.CString(), projectGUID.CString());
  480. projectGen_->GetCSProjectDependencies(p, depends);
  481. if (depends.Size())
  482. {
  483. source += "\tProjectSection(ProjectDependencies) = postProject\n";
  484. for (unsigned j = 0; j < depends.Size(); j++)
  485. {
  486. source += ToString("\t{%s} = {%s}\n",
  487. depends[j]->GetProjectGUID().CString(), depends[j]->GetProjectGUID().CString());
  488. }
  489. source += "\tEndProjectSection\n";
  490. }
  491. source += "EndProject\n";
  492. }
  493. source += "Global\n";
  494. source += " GlobalSection(SolutionConfigurationPlatforms) = preSolution\n";
  495. source += " Debug|Any CPU = Debug|Any CPU\n";
  496. source += " Release|Any CPU = Release|Any CPU\n";
  497. source += " EndGlobalSection\n";
  498. source += " GlobalSection(ProjectConfigurationPlatforms) = postSolution\n";
  499. for (unsigned i = 0; i < projects.Size(); i++)
  500. {
  501. NETCSProject* p = projects.At(i);
  502. source += ToString(" {%s}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n", p->GetProjectGUID().CString());
  503. source += ToString(" {%s}.Debug|Any CPU.Build.0 = Debug|Any CPU\n", p->GetProjectGUID().CString());
  504. source += ToString(" {%s}.Release|Any CPU.ActiveCfg = Release|Any CPU\n", p->GetProjectGUID().CString());
  505. source += ToString(" {%s}.Release|Any CPU.Build.0 = Release|Any CPU\n", p->GetProjectGUID().CString());
  506. }
  507. source += " EndGlobalSection\n";
  508. source += "EndGlobal\n";
  509. if (!rewriteSolution_)
  510. {
  511. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  512. if (fileSystem->Exists(slnPath))
  513. return;
  514. }
  515. SharedPtr<File> output(new File(context_, slnPath, FILE_WRITE));
  516. output->Write(source.CString(), source.Length());
  517. output->Close();
  518. }
  519. bool NETSolution::Load(const JSONValue& root)
  520. {
  521. FileSystem* fs = GetSubsystem<FileSystem>();
  522. name_ = root["name"].GetString();
  523. outputPath_ = AddTrailingSlash(root["outputPath"].GetString());
  524. ReplacePathStrings(outputPath_);
  525. // TODO: use poco mkdirs
  526. if (!fs->DirExists(outputPath_))
  527. fs->CreateDirsRecursive(outputPath_);
  528. return true;
  529. }
  530. bool NETSolution::RegisterPackage(const String& package)
  531. {
  532. if (packages_.Find(package) != packages_.End())
  533. return false;
  534. packages_.Push(package);
  535. return true;
  536. }
  537. NETProjectGen::NETProjectGen(Context* context) : Object(context),
  538. rewriteSolution_(false)
  539. {
  540. }
  541. NETProjectGen::~NETProjectGen()
  542. {
  543. }
  544. NETCSProject* NETProjectGen::GetCSProjectByName(const String & name)
  545. {
  546. for (unsigned i = 0; i < projects_.Size(); i++)
  547. {
  548. if (projects_[i]->GetName() == name)
  549. return projects_[i];
  550. }
  551. return nullptr;
  552. }
  553. bool NETProjectGen::GetCSProjectDependencies(NETCSProject* source, PODVector<NETCSProject*>& depends) const
  554. {
  555. depends.Clear();
  556. const Vector<String>& references = source->GetReferences();
  557. for (unsigned i = 0; i < projects_.Size(); i++)
  558. {
  559. NETCSProject* pdepend = projects_.At(i);
  560. if (source == pdepend)
  561. continue;
  562. for (unsigned j = 0; j < references.Size(); j++)
  563. {
  564. if (pdepend->GetName() == references[j])
  565. {
  566. depends.Push(pdepend);
  567. }
  568. }
  569. }
  570. return depends.Size() != 0;
  571. }
  572. bool NETProjectGen::Generate()
  573. {
  574. solution_->Generate();
  575. for (unsigned i = 0; i < projects_.Size(); i++)
  576. {
  577. if (!projects_[i]->Generate())
  578. return false;
  579. }
  580. return true;
  581. }
  582. void NETProjectGen::SetRewriteSolution(bool rewrite)
  583. {
  584. rewriteSolution_ = rewrite;
  585. if (solution_.NotNull())
  586. solution_->SetRewriteSolution(rewrite);
  587. }
  588. bool NETProjectGen::LoadProject(const JSONValue &root)
  589. {
  590. solution_ = new NETSolution(context_, this, rewriteSolution_);
  591. solution_->Load(root["solution"]);
  592. const JSONValue& jprojects = root["projects"];
  593. if (!jprojects.IsArray() || !jprojects.Size())
  594. return false;
  595. for (unsigned i = 0; i < jprojects.Size(); i++)
  596. {
  597. const JSONValue& jproject = jprojects[i];
  598. if (!jproject.IsObject())
  599. return false;
  600. SharedPtr<NETCSProject> csProject(new NETCSProject(context_, this));
  601. if (!csProject->Load(jproject))
  602. return false;
  603. projects_.Push(csProject);
  604. }
  605. return true;
  606. }
  607. bool NETProjectGen::LoadProject(const String& projectPath)
  608. {
  609. SharedPtr<File> file(new File(context_));
  610. if (!file->Open(projectPath))
  611. return false;
  612. String json;
  613. file->ReadText(json);
  614. JSONValue jvalue;
  615. if (!JSONFile::ParseJSON(json, jvalue))
  616. return false;
  617. return LoadProject(jvalue);
  618. }
  619. bool NETProjectGen::LoadProject(Project* project)
  620. {
  621. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  622. ToolEnvironment* tenv = GetSubsystem<ToolEnvironment>();
  623. atomicProject_ = project;
  624. JSONValue root;
  625. JSONValue solution;
  626. solution["name"] = "AtomicProject";
  627. solution["outputPath"] = AddTrailingSlash(project->GetProjectPath()) + "AtomicNET/Solution/";
  628. JSONArray projects;
  629. JSONObject jproject;
  630. jproject["name"] = "AtomicProject";
  631. jproject["outputType"] = "Library";
  632. jproject["assemblyName"] = "AtomicProject";
  633. jproject["assemblyOutputPath"] = AddTrailingSlash(project->GetProjectPath()) + "AtomicNET/Bin/";
  634. JSONArray references;
  635. references.Push(JSONValue("System"));
  636. references.Push(JSONValue("System.Core"));
  637. references.Push(JSONValue("System.Xml.Linq"));
  638. references.Push(JSONValue("System.XML"));
  639. String atomicNETAssembly = tenv->GetAtomicNETCoreAssemblyDir() + "AtomicNET.dll";
  640. if (!fileSystem->FileExists(atomicNETAssembly))
  641. {
  642. ATOMIC_LOGERRORF("NETProjectGen::LoadProject - AtomicNET assembly does not exist: %s", atomicNETAssembly.CString());
  643. return false;
  644. }
  645. references.Push(JSONValue(atomicNETAssembly));
  646. jproject["references"] = references;
  647. JSONArray sources;
  648. sources.Push(JSONValue(ToString("%s", project->GetResourcePath().CString())));
  649. jproject["sources"] = sources;
  650. projects.Push(jproject);
  651. root["projects"] = projects;
  652. root["solution"] = solution;
  653. return LoadProject(root);
  654. }
  655. bool NETProjectGen::GetRequiresNuGet()
  656. {
  657. if (solution_.Null())
  658. {
  659. ATOMIC_LOGERROR("NETProjectGen::GetRequiresNuGet() - called without a solution loaded");
  660. return false;
  661. }
  662. return solution_->GetPackages().Size() != 0;
  663. }
  664. String NETProjectGen::GenerateUUID()
  665. {
  666. Poco::UUIDGenerator& generator = Poco::UUIDGenerator::defaultGenerator();
  667. Poco::UUID uuid(generator.create()); // time based
  668. return String(uuid.toString().c_str()).ToUpper();
  669. }
  670. }