cmGlobalGhsMultiGenerator.cxx 17 KB

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