cmGlobalGhsMultiGenerator.cxx 17 KB

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