cmGlobalGhsMultiGenerator.cxx 17 KB

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