cmGlobalGhsMultiGenerator.cxx 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2015 Geoffrey Viola <[email protected]>
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmGlobalGhsMultiGenerator.h"
  11. #include "cmGeneratedFileStream.h"
  12. #include "cmGeneratorTarget.h"
  13. #include "cmGhsMultiTargetGenerator.h"
  14. #include "cmLocalGhsMultiGenerator.h"
  15. #include "cmMakefile.h"
  16. #include "cmVersion.h"
  17. #include <cmAlgorithms.h>
  18. #include <cmsys/SystemTools.hxx>
  19. const char* cmGlobalGhsMultiGenerator::FILE_EXTENSION = ".gpj";
  20. const char* cmGlobalGhsMultiGenerator::DEFAULT_MAKE_PROGRAM = "gbuild";
  21. cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator(cmake* cm)
  22. : cmGlobalGenerator(cm)
  23. , OSDirRelative(false)
  24. {
  25. this->GhsBuildCommandInitialized = false;
  26. }
  27. cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator()
  28. {
  29. cmDeleteAll(TargetFolderBuildStreams);
  30. }
  31. cmLocalGenerator* cmGlobalGhsMultiGenerator::CreateLocalGenerator(
  32. cmMakefile* mf)
  33. {
  34. return new cmLocalGhsMultiGenerator(this, mf);
  35. }
  36. void cmGlobalGhsMultiGenerator::GetDocumentation(cmDocumentationEntry& entry)
  37. {
  38. entry.Name = GetActualName();
  39. entry.Brief =
  40. "Generates Green Hills MULTI files (experimental, work-in-progress).";
  41. }
  42. void cmGlobalGhsMultiGenerator::EnableLanguage(
  43. std::vector<std::string> const& l, cmMakefile* mf, bool optional)
  44. {
  45. mf->AddDefinition("CMAKE_SYSTEM_NAME", "GHS-MULTI");
  46. mf->AddDefinition("CMAKE_SYSTEM_PROCESSOR", "ARM");
  47. const std::string ghsCompRoot(GetCompRoot());
  48. mf->AddDefinition("GHS_COMP_ROOT", ghsCompRoot.c_str());
  49. std::string ghsCompRootStart =
  50. 0 == ghsCompRootStart.size() ? "" : ghsCompRoot + "/";
  51. mf->AddDefinition("CMAKE_C_COMPILER",
  52. std::string(ghsCompRootStart + "ccarm.exe").c_str());
  53. mf->AddDefinition("CMAKE_C_COMPILER_ID_RUN", "TRUE");
  54. mf->AddDefinition("CMAKE_C_COMPILER_ID", "GHS");
  55. mf->AddDefinition("CMAKE_C_COMPILER_FORCED", "TRUE");
  56. mf->AddDefinition("CMAKE_CXX_COMPILER",
  57. std::string(ghsCompRootStart + "cxarm.exe").c_str());
  58. mf->AddDefinition("CMAKE_CXX_COMPILER_ID_RUN", "TRUE");
  59. mf->AddDefinition("CMAKE_CXX_COMPILER_ID", "GHS");
  60. mf->AddDefinition("CMAKE_CXX_COMPILER_FORCED", "TRUE");
  61. if (!ghsCompRoot.empty()) {
  62. static const char* compPreFix = "comp_";
  63. std::string compFilename =
  64. cmsys::SystemTools::FindLastString(ghsCompRoot.c_str(), compPreFix);
  65. cmsys::SystemTools::ReplaceString(compFilename, compPreFix, "");
  66. mf->AddDefinition("CMAKE_SYSTEM_VERSION", compFilename.c_str());
  67. }
  68. mf->AddDefinition("GHSMULTI", "1"); // identifier for user CMake files
  69. this->cmGlobalGenerator::EnableLanguage(l, mf, optional);
  70. }
  71. void cmGlobalGhsMultiGenerator::FindMakeProgram(cmMakefile* mf)
  72. {
  73. // The GHS generator knows how to lookup its build tool
  74. // directly instead of needing a helper module to do it, so we
  75. // do not actually need to put CMAKE_MAKE_PROGRAM into the cache.
  76. if (cmSystemTools::IsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
  77. mf->AddDefinition("CMAKE_MAKE_PROGRAM",
  78. this->GetGhsBuildCommand().c_str());
  79. }
  80. }
  81. std::string const& cmGlobalGhsMultiGenerator::GetGhsBuildCommand()
  82. {
  83. if (!this->GhsBuildCommandInitialized) {
  84. this->GhsBuildCommandInitialized = true;
  85. this->GhsBuildCommand = this->FindGhsBuildCommand();
  86. }
  87. return this->GhsBuildCommand;
  88. }
  89. std::string cmGlobalGhsMultiGenerator::FindGhsBuildCommand()
  90. {
  91. std::vector<std::string> userPaths;
  92. userPaths.push_back(this->GetCompRoot());
  93. std::string makeProgram =
  94. cmSystemTools::FindProgram(DEFAULT_MAKE_PROGRAM, userPaths);
  95. if (makeProgram.empty()) {
  96. makeProgram = DEFAULT_MAKE_PROGRAM;
  97. }
  98. return makeProgram;
  99. }
  100. std::string cmGlobalGhsMultiGenerator::GetCompRoot()
  101. {
  102. std::string output;
  103. const std::vector<std::string> potentialDirsHardPaths(
  104. GetCompRootHardPaths());
  105. const std::vector<std::string> potentialDirsRegistry(GetCompRootRegistry());
  106. std::vector<std::string> potentialDirsComplete;
  107. potentialDirsComplete.insert(potentialDirsComplete.end(),
  108. potentialDirsHardPaths.begin(),
  109. potentialDirsHardPaths.end());
  110. potentialDirsComplete.insert(potentialDirsComplete.end(),
  111. potentialDirsRegistry.begin(),
  112. potentialDirsRegistry.end());
  113. // Use latest version
  114. std::string outputDirName;
  115. for (std::vector<std::string>::const_iterator potentialDirsCompleteIt =
  116. potentialDirsComplete.begin();
  117. potentialDirsCompleteIt != potentialDirsComplete.end();
  118. ++potentialDirsCompleteIt) {
  119. const std::string dirName(
  120. cmsys::SystemTools::GetFilenameName(*potentialDirsCompleteIt));
  121. if (dirName.compare(outputDirName) > 0) {
  122. output = *potentialDirsCompleteIt;
  123. outputDirName = dirName;
  124. }
  125. }
  126. return output;
  127. }
  128. std::vector<std::string> cmGlobalGhsMultiGenerator::GetCompRootHardPaths()
  129. {
  130. std::vector<std::string> output;
  131. cmSystemTools::Glob("C:/ghs", "comp_[^;]+", output);
  132. for (std::vector<std::string>::iterator outputIt = output.begin();
  133. outputIt != output.end(); ++outputIt) {
  134. *outputIt = "C:/ghs/" + *outputIt;
  135. }
  136. return output;
  137. }
  138. std::vector<std::string> cmGlobalGhsMultiGenerator::GetCompRootRegistry()
  139. {
  140. std::vector<std::string> output(2);
  141. cmsys::SystemTools::ReadRegistryValue(
  142. "HKEY_LOCAL_"
  143. "MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\"
  144. "Windows\\CurrentVersion\\Uninstall\\"
  145. "GreenHillsSoftwared771f1b4;InstallLocation",
  146. output[0]);
  147. cmsys::SystemTools::ReadRegistryValue(
  148. "HKEY_LOCAL_"
  149. "MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\"
  150. "Windows\\CurrentVersion\\Uninstall\\"
  151. "GreenHillsSoftware9881cef6;InstallLocation",
  152. output[1]);
  153. return output;
  154. }
  155. void cmGlobalGhsMultiGenerator::OpenBuildFileStream(
  156. std::string const& filepath, cmGeneratedFileStream** filestream)
  157. {
  158. // Get a stream where to generate things.
  159. if (NULL == *filestream) {
  160. *filestream = new cmGeneratedFileStream(filepath.c_str());
  161. if (NULL != *filestream) {
  162. OpenBuildFileStream(*filestream);
  163. }
  164. }
  165. }
  166. void cmGlobalGhsMultiGenerator::OpenBuildFileStream(
  167. cmGeneratedFileStream* filestream)
  168. {
  169. *filestream << "#!gbuild" << std::endl;
  170. }
  171. void cmGlobalGhsMultiGenerator::OpenBuildFileStream()
  172. {
  173. // Compute GHS MULTI's build file path.
  174. std::string buildFilePath =
  175. this->GetCMakeInstance()->GetHomeOutputDirectory();
  176. buildFilePath += "/";
  177. buildFilePath += "default";
  178. buildFilePath += FILE_EXTENSION;
  179. this->Open(std::string(""), buildFilePath, &this->TargetFolderBuildStreams);
  180. OpenBuildFileStream(GetBuildFileStream());
  181. char const* osDir =
  182. this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR");
  183. if (NULL == osDir) {
  184. osDir = "";
  185. cmSystemTools::Error("GHS_OS_DIR cache variable must be set");
  186. } else {
  187. this->GetCMakeInstance()->MarkCliAsUsed("GHS_OS_DIR");
  188. }
  189. std::string fOSDir(this->trimQuotes(osDir));
  190. std::replace(fOSDir.begin(), fOSDir.end(), '\\', '/');
  191. if (!fOSDir.empty() && ('c' == fOSDir[0] || 'C' == fOSDir[0])) {
  192. this->OSDirRelative = false;
  193. } else {
  194. this->OSDirRelative = true;
  195. }
  196. char const* bspName =
  197. this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME");
  198. if (NULL == bspName) {
  199. bspName = "";
  200. cmSystemTools::Error("GHS_BSP_NAME cache variable must be set");
  201. } else {
  202. this->GetCMakeInstance()->MarkCliAsUsed("GHS_BSP_NAME");
  203. }
  204. std::string fBspName(this->trimQuotes(bspName));
  205. std::replace(fBspName.begin(), fBspName.end(), '\\', '/');
  206. this->WriteMacros();
  207. this->WriteHighLevelDirectives();
  208. GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, this->GetBuildFileStream());
  209. this->WriteDisclaimer(this->GetBuildFileStream());
  210. *this->GetBuildFileStream() << "# Top Level Project File" << std::endl;
  211. if (!fBspName.empty()) {
  212. *this->GetBuildFileStream() << " -bsp " << fBspName << std::endl;
  213. }
  214. this->WriteCompilerOptions(fOSDir);
  215. }
  216. void cmGlobalGhsMultiGenerator::CloseBuildFileStream(
  217. cmGeneratedFileStream** filestream)
  218. {
  219. if (filestream) {
  220. delete *filestream;
  221. *filestream = NULL;
  222. } else {
  223. cmSystemTools::Error("Build file stream was not open.");
  224. }
  225. }
  226. void cmGlobalGhsMultiGenerator::Generate()
  227. {
  228. this->cmGlobalGenerator::Generate();
  229. if (!this->LocalGenerators.empty()) {
  230. this->OpenBuildFileStream();
  231. // Build all the folder build files
  232. for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
  233. cmLocalGhsMultiGenerator* lg =
  234. static_cast<cmLocalGhsMultiGenerator*>(this->LocalGenerators[i]);
  235. std::vector<cmGeneratorTarget*> tgts = lg->GetGeneratorTargets();
  236. this->UpdateBuildFiles(tgts);
  237. }
  238. }
  239. cmDeleteAll(TargetFolderBuildStreams);
  240. this->TargetFolderBuildStreams.clear();
  241. }
  242. void cmGlobalGhsMultiGenerator::GenerateBuildCommand(
  243. std::vector<std::string>& makeCommand, const std::string& makeProgram,
  244. const std::string& /*projectName*/, const std::string& /*projectDir*/,
  245. const std::string& targetName, const std::string& /*config*/, bool /*fast*/,
  246. bool /*verbose*/, std::vector<std::string> const& makeOptions)
  247. {
  248. makeCommand.push_back(
  249. this->SelectMakeProgram(makeProgram, this->GetGhsBuildCommand()));
  250. makeCommand.insert(makeCommand.end(), makeOptions.begin(),
  251. makeOptions.end());
  252. if (!targetName.empty()) {
  253. if (targetName == "clean") {
  254. makeCommand.push_back("-clean");
  255. } else {
  256. makeCommand.push_back(targetName);
  257. }
  258. }
  259. }
  260. void cmGlobalGhsMultiGenerator::WriteMacros()
  261. {
  262. char const* ghsGpjMacros =
  263. this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS");
  264. if (NULL != ghsGpjMacros) {
  265. std::vector<std::string> expandedList;
  266. cmSystemTools::ExpandListArgument(std::string(ghsGpjMacros), expandedList);
  267. for (std::vector<std::string>::const_iterator expandedListI =
  268. expandedList.begin();
  269. expandedListI != expandedList.end(); ++expandedListI) {
  270. *this->GetBuildFileStream() << "macro " << *expandedListI << std::endl;
  271. }
  272. }
  273. }
  274. void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives()
  275. {
  276. *this->GetBuildFileStream() << "primaryTarget=arm_integrity.tgt"
  277. << std::endl;
  278. char const* const customization =
  279. this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION");
  280. if (NULL != customization && strlen(customization) > 0) {
  281. *this->GetBuildFileStream()
  282. << "customization=" << trimQuotes(customization) << std::endl;
  283. this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION");
  284. }
  285. }
  286. void cmGlobalGhsMultiGenerator::WriteCompilerOptions(std::string const& fOSDir)
  287. {
  288. *this->GetBuildFileStream() << " -os_dir=\"" << fOSDir << "\""
  289. << std::endl;
  290. }
  291. void cmGlobalGhsMultiGenerator::WriteDisclaimer(std::ostream* os)
  292. {
  293. (*os) << "#" << std::endl
  294. << "# CMAKE generated file: DO NOT EDIT!" << std::endl
  295. << "# Generated by \"" << GetActualName() << "\""
  296. << " Generator, CMake Version " << cmVersion::GetMajorVersion() << "."
  297. << cmVersion::GetMinorVersion() << std::endl
  298. << "#" << std::endl;
  299. }
  300. void cmGlobalGhsMultiGenerator::AddFilesUpToPath(
  301. cmGeneratedFileStream* mainBuildFile,
  302. std::map<std::string, cmGeneratedFileStream*>* targetFolderBuildStreams,
  303. char const* homeOutputDirectory, std::string const& path,
  304. GhsMultiGpj::Types projType, std::string const& relPath)
  305. {
  306. std::string workingPath(path);
  307. cmSystemTools::ConvertToUnixSlashes(workingPath);
  308. std::vector<cmsys::String> splitPath =
  309. cmSystemTools::SplitString(workingPath);
  310. std::string workingRelPath(relPath);
  311. cmSystemTools::ConvertToUnixSlashes(workingRelPath);
  312. if (!workingRelPath.empty()) {
  313. workingRelPath += "/";
  314. }
  315. std::string pathUpTo;
  316. for (std::vector<cmsys::String>::const_iterator splitPathI =
  317. splitPath.begin();
  318. splitPath.end() != splitPathI; ++splitPathI) {
  319. pathUpTo += *splitPathI;
  320. if (targetFolderBuildStreams->end() ==
  321. targetFolderBuildStreams->find(pathUpTo)) {
  322. AddFilesUpToPathNewBuildFile(
  323. mainBuildFile, targetFolderBuildStreams, homeOutputDirectory, pathUpTo,
  324. splitPath.begin() == splitPathI, workingRelPath, projType);
  325. }
  326. AddFilesUpToPathAppendNextFile(targetFolderBuildStreams, pathUpTo,
  327. splitPathI, splitPath.end(), projType);
  328. pathUpTo += "/";
  329. }
  330. }
  331. void cmGlobalGhsMultiGenerator::Open(
  332. std::string const& mapKeyName, std::string const& fileName,
  333. std::map<std::string, cmGeneratedFileStream*>* fileMap)
  334. {
  335. if (fileMap->end() == fileMap->find(fileName)) {
  336. cmGeneratedFileStream* temp(new cmGeneratedFileStream);
  337. temp->open(fileName.c_str());
  338. (*fileMap)[mapKeyName] = temp;
  339. }
  340. }
  341. void cmGlobalGhsMultiGenerator::AddFilesUpToPathNewBuildFile(
  342. cmGeneratedFileStream* mainBuildFile,
  343. std::map<std::string, cmGeneratedFileStream*>* targetFolderBuildStreams,
  344. char const* homeOutputDirectory, std::string const& pathUpTo,
  345. bool const isFirst, std::string const& relPath,
  346. GhsMultiGpj::Types const projType)
  347. {
  348. // create folders up to file path
  349. std::string absPath = std::string(homeOutputDirectory) + "/" + relPath;
  350. std::string newPath = absPath + pathUpTo;
  351. if (!cmSystemTools::FileExists(newPath.c_str())) {
  352. cmSystemTools::MakeDirectory(newPath.c_str());
  353. }
  354. // Write out to filename for first time
  355. std::string relFilename(GetFileNameFromPath(pathUpTo));
  356. std::string absFilename = absPath + relFilename;
  357. Open(pathUpTo, absFilename, targetFolderBuildStreams);
  358. OpenBuildFileStream((*targetFolderBuildStreams)[pathUpTo]);
  359. GhsMultiGpj::WriteGpjTag(projType, (*targetFolderBuildStreams)[pathUpTo]);
  360. WriteDisclaimer((*targetFolderBuildStreams)[pathUpTo]);
  361. // Add to main build file
  362. if (isFirst) {
  363. *mainBuildFile << relFilename << " ";
  364. GhsMultiGpj::WriteGpjTag(projType, mainBuildFile);
  365. }
  366. }
  367. void cmGlobalGhsMultiGenerator::AddFilesUpToPathAppendNextFile(
  368. std::map<std::string, cmGeneratedFileStream*>* targetFolderBuildStreams,
  369. std::string const& pathUpTo,
  370. std::vector<cmsys::String>::const_iterator splitPathI,
  371. std::vector<cmsys::String>::const_iterator end,
  372. GhsMultiGpj::Types const projType)
  373. {
  374. std::vector<cmsys::String>::const_iterator splitPathNextI = splitPathI + 1;
  375. if (end != splitPathNextI &&
  376. targetFolderBuildStreams->end() ==
  377. targetFolderBuildStreams->find(pathUpTo + "/" + *splitPathNextI)) {
  378. std::string nextFilename(*splitPathNextI);
  379. nextFilename = GetFileNameFromPath(nextFilename);
  380. *(*targetFolderBuildStreams)[pathUpTo] << nextFilename << " ";
  381. GhsMultiGpj::WriteGpjTag(projType, (*targetFolderBuildStreams)[pathUpTo]);
  382. }
  383. }
  384. std::string cmGlobalGhsMultiGenerator::GetFileNameFromPath(
  385. std::string const& path)
  386. {
  387. std::string output(path);
  388. if (!path.empty()) {
  389. cmSystemTools::ConvertToUnixSlashes(output);
  390. std::vector<cmsys::String> splitPath = cmSystemTools::SplitString(output);
  391. output += "/" + splitPath.back() + FILE_EXTENSION;
  392. }
  393. return output;
  394. }
  395. void cmGlobalGhsMultiGenerator::UpdateBuildFiles(
  396. std::vector<cmGeneratorTarget*> tgts)
  397. {
  398. for (std::vector<cmGeneratorTarget*>::iterator tgtsI = tgts.begin();
  399. tgtsI != tgts.end(); ++tgtsI) {
  400. const cmGeneratorTarget* tgt = *tgtsI;
  401. if (IsTgtForBuild(tgt)) {
  402. char const* rawFolderName = tgt->GetProperty("FOLDER");
  403. if (NULL == rawFolderName) {
  404. rawFolderName = "";
  405. }
  406. std::string folderName(rawFolderName);
  407. if (this->TargetFolderBuildStreams.end() ==
  408. this->TargetFolderBuildStreams.find(folderName)) {
  409. this->AddFilesUpToPath(
  410. GetBuildFileStream(), &this->TargetFolderBuildStreams,
  411. this->GetCMakeInstance()->GetHomeOutputDirectory(), folderName,
  412. GhsMultiGpj::PROJECT);
  413. }
  414. std::vector<cmsys::String> splitPath = cmSystemTools::SplitString(
  415. cmGhsMultiTargetGenerator::GetRelBuildFileName(tgt));
  416. std::string foldNameRelBuildFile(*(splitPath.end() - 2) + "/" +
  417. splitPath.back());
  418. *this->TargetFolderBuildStreams[folderName] << foldNameRelBuildFile
  419. << " ";
  420. GhsMultiGpj::WriteGpjTag(cmGhsMultiTargetGenerator::GetGpjTag(tgt),
  421. this->TargetFolderBuildStreams[folderName]);
  422. }
  423. }
  424. }
  425. bool cmGlobalGhsMultiGenerator::IsTgtForBuild(const cmGeneratorTarget* tgt)
  426. {
  427. const std::string config =
  428. tgt->Target->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
  429. std::vector<cmSourceFile*> tgtSources;
  430. tgt->GetSourceFiles(tgtSources, config);
  431. bool tgtInBuild = true;
  432. char const* excludeFromAll = tgt->GetProperty("EXCLUDE_FROM_ALL");
  433. if (NULL != excludeFromAll && '1' == excludeFromAll[0] &&
  434. '\0' == excludeFromAll[1]) {
  435. tgtInBuild = false;
  436. }
  437. return !tgtSources.empty() && tgtInBuild;
  438. }
  439. std::string cmGlobalGhsMultiGenerator::trimQuotes(std::string const& str)
  440. {
  441. std::string result;
  442. result.reserve(str.size());
  443. for (const char* ch = str.c_str(); *ch != '\0'; ++ch) {
  444. if (*ch != '"') {
  445. result += *ch;
  446. }
  447. }
  448. return result;
  449. }