cmGhsMultiTargetGenerator.cxx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  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 "cmGhsMultiTargetGenerator.h"
  4. #include "cmComputeLinkInformation.h"
  5. #include "cmGeneratedFileStream.h"
  6. #include "cmGeneratorTarget.h"
  7. #include "cmGlobalGhsMultiGenerator.h"
  8. #include "cmLinkLineComputer.h"
  9. #include "cmLocalGhsMultiGenerator.h"
  10. #include "cmMakefile.h"
  11. #include "cmSourceFile.h"
  12. #include "cmSourceGroup.h"
  13. #include "cmTarget.h"
  14. cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget* target)
  15. : GeneratorTarget(target)
  16. , LocalGenerator(
  17. static_cast<cmLocalGhsMultiGenerator*>(target->GetLocalGenerator()))
  18. , Makefile(target->Target->GetMakefile())
  19. , Name(target->GetName())
  20. {
  21. // Store the configuration name that is being used
  22. if (const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE")) {
  23. // Use the build type given by the user.
  24. this->ConfigName = config;
  25. } else {
  26. // No configuration type given.
  27. this->ConfigName.clear();
  28. }
  29. }
  30. cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator()
  31. {
  32. }
  33. void cmGhsMultiTargetGenerator::Generate()
  34. {
  35. // Determine type of target for this project
  36. switch (this->GeneratorTarget->GetType()) {
  37. case cmStateEnums::EXECUTABLE: {
  38. // Get the name of the executable to generate.
  39. this->TargetNameReal =
  40. this->GeneratorTarget->GetExecutableNames(this->ConfigName).Real;
  41. if (cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()) {
  42. this->TagType = GhsMultiGpj::INTERGRITY_APPLICATION;
  43. } else {
  44. this->TagType = GhsMultiGpj::PROGRAM;
  45. }
  46. break;
  47. }
  48. case cmStateEnums::STATIC_LIBRARY: {
  49. this->TargetNameReal =
  50. this->GeneratorTarget->GetLibraryNames(this->ConfigName).Real;
  51. this->TagType = GhsMultiGpj::LIBRARY;
  52. break;
  53. }
  54. case cmStateEnums::SHARED_LIBRARY: {
  55. std::string msg = "add_library(<name> SHARED ...) not supported: ";
  56. msg += this->Name;
  57. cmSystemTools::Message(msg);
  58. return;
  59. }
  60. case cmStateEnums::OBJECT_LIBRARY: {
  61. this->TargetNameReal =
  62. this->GeneratorTarget->GetLibraryNames(this->ConfigName).Real;
  63. this->TagType = GhsMultiGpj::SUBPROJECT;
  64. break;
  65. }
  66. case cmStateEnums::MODULE_LIBRARY: {
  67. std::string msg = "add_library(<name> MODULE ...) not supported: ";
  68. msg += this->Name;
  69. cmSystemTools::Message(msg);
  70. return;
  71. }
  72. case cmStateEnums::UTILITY: {
  73. std::string msg = "add_custom_target(<name> ...) not supported: ";
  74. msg += this->Name;
  75. cmSystemTools::Message(msg);
  76. return;
  77. }
  78. default:
  79. return;
  80. }
  81. // Tell the global generator the name of the project file
  82. this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME",
  83. this->Name.c_str());
  84. this->GeneratorTarget->Target->SetProperty(
  85. "GENERATOR_FILE_NAME_EXT", GhsMultiGpj::GetGpjTag(this->TagType));
  86. this->GenerateTarget();
  87. }
  88. void cmGhsMultiTargetGenerator::GenerateTarget()
  89. {
  90. // Open the filestream in copy-if-different mode.
  91. std::string fname = this->LocalGenerator->GetCurrentBinaryDirectory();
  92. fname += "/";
  93. fname += this->Name;
  94. fname += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
  95. cmGeneratedFileStream fout(fname.c_str());
  96. fout.SetCopyIfDifferent(true);
  97. this->GetGlobalGenerator()->WriteFileHeader(fout);
  98. GhsMultiGpj::WriteGpjTag(this->TagType, fout);
  99. const std::string language(
  100. this->GeneratorTarget->GetLinkerLanguage(this->ConfigName));
  101. this->WriteTargetSpecifics(fout, this->ConfigName);
  102. this->SetCompilerFlags(this->ConfigName, language);
  103. this->WriteCompilerFlags(fout, this->ConfigName, language);
  104. this->WriteCompilerDefinitions(fout, this->ConfigName, language);
  105. this->WriteIncludes(fout, this->ConfigName, language);
  106. this->WriteTargetLinkLine(fout, this->ConfigName);
  107. this->WriteCustomCommands(fout);
  108. this->WriteSources(fout);
  109. this->WriteReferences(fout);
  110. fout.Close();
  111. }
  112. cmGlobalGhsMultiGenerator* cmGhsMultiTargetGenerator::GetGlobalGenerator()
  113. const
  114. {
  115. return static_cast<cmGlobalGhsMultiGenerator*>(
  116. this->LocalGenerator->GetGlobalGenerator());
  117. }
  118. void cmGhsMultiTargetGenerator::WriteTargetSpecifics(std::ostream& fout,
  119. const std::string& config)
  120. {
  121. std::string outpath;
  122. std::string rootpath = this->LocalGenerator->GetCurrentBinaryDirectory();
  123. if (this->TagType != GhsMultiGpj::SUBPROJECT) {
  124. // set target binary file destination
  125. outpath = this->GeneratorTarget->GetDirectory(config);
  126. outpath =
  127. this->LocalGenerator->MaybeConvertToRelativePath(rootpath, outpath);
  128. fout << " :binDirRelative=\"" << outpath << "\"" << std::endl;
  129. fout << " -o \"" << this->TargetNameReal << "\"" << std::endl;
  130. }
  131. // set target object file destination
  132. outpath = this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
  133. fout << " :outputDirRelative=\"" << outpath << "\"" << std::endl;
  134. }
  135. void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config,
  136. const std::string& language)
  137. {
  138. std::map<std::string, std::string>::iterator i =
  139. this->FlagsByLanguage.find(language);
  140. if (i == this->FlagsByLanguage.end()) {
  141. std::string flags;
  142. const char* lang = language.c_str();
  143. this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget, lang,
  144. config);
  145. this->LocalGenerator->AddCMP0018Flags(flags, this->GeneratorTarget, lang,
  146. config);
  147. this->LocalGenerator->AddVisibilityPresetFlags(
  148. flags, this->GeneratorTarget, lang);
  149. // Append old-style preprocessor definition flags.
  150. if (this->Makefile->GetDefineFlags() != " ") {
  151. this->LocalGenerator->AppendFlags(flags,
  152. this->Makefile->GetDefineFlags());
  153. }
  154. // Add target-specific flags.
  155. this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, lang,
  156. config);
  157. std::map<std::string, std::string>::value_type entry(language, flags);
  158. i = this->FlagsByLanguage.insert(entry).first;
  159. }
  160. }
  161. std::string cmGhsMultiTargetGenerator::GetDefines(const std::string& language,
  162. std::string const& config)
  163. {
  164. std::map<std::string, std::string>::iterator i =
  165. this->DefinesByLanguage.find(language);
  166. if (i == this->DefinesByLanguage.end()) {
  167. std::set<std::string> defines;
  168. const char* lang = language.c_str();
  169. // Add preprocessor definitions for this target and configuration.
  170. this->LocalGenerator->GetTargetDefines(this->GeneratorTarget, config,
  171. language, defines);
  172. std::string definesString;
  173. this->LocalGenerator->JoinDefines(defines, definesString, lang);
  174. std::map<std::string, std::string>::value_type entry(language,
  175. definesString);
  176. i = this->DefinesByLanguage.insert(entry).first;
  177. }
  178. return i->second;
  179. }
  180. void cmGhsMultiTargetGenerator::WriteCompilerFlags(std::ostream& fout,
  181. std::string const&,
  182. const std::string& language)
  183. {
  184. std::map<std::string, std::string>::iterator flagsByLangI =
  185. this->FlagsByLanguage.find(language);
  186. if (flagsByLangI != this->FlagsByLanguage.end()) {
  187. if (!flagsByLangI->second.empty()) {
  188. std::vector<std::string> ghsCompFlags =
  189. cmSystemTools::ParseArguments(flagsByLangI->second);
  190. for (auto& f : ghsCompFlags) {
  191. fout << " " << f << std::endl;
  192. }
  193. }
  194. }
  195. }
  196. void cmGhsMultiTargetGenerator::WriteCompilerDefinitions(
  197. std::ostream& fout, const std::string& config, const std::string& language)
  198. {
  199. std::vector<std::string> compileDefinitions;
  200. this->GeneratorTarget->GetCompileDefinitions(compileDefinitions, config,
  201. language);
  202. for (std::string const& compileDefinition : compileDefinitions) {
  203. fout << " -D" << compileDefinition << std::endl;
  204. }
  205. }
  206. void cmGhsMultiTargetGenerator::WriteIncludes(std::ostream& fout,
  207. const std::string& config,
  208. const std::string& language)
  209. {
  210. std::vector<std::string> includes;
  211. this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
  212. language, config);
  213. for (std::string const& include : includes) {
  214. fout << " -I\"" << include << "\"" << std::endl;
  215. }
  216. }
  217. void cmGhsMultiTargetGenerator::WriteTargetLinkLine(std::ostream& fout,
  218. std::string const& config)
  219. {
  220. if (this->TagType == GhsMultiGpj::INTERGRITY_APPLICATION) {
  221. return;
  222. }
  223. std::string linkLibraries;
  224. std::string flags;
  225. std::string linkFlags;
  226. std::string frameworkPath;
  227. std::string linkPath;
  228. std::unique_ptr<cmLinkLineComputer> linkLineComputer(
  229. this->GetGlobalGenerator()->CreateLinkLineComputer(
  230. this->LocalGenerator,
  231. this->LocalGenerator->GetStateSnapshot().GetDirectory()));
  232. this->LocalGenerator->GetTargetFlags(
  233. linkLineComputer.get(), config, linkLibraries, flags, linkFlags,
  234. frameworkPath, linkPath, this->GeneratorTarget);
  235. // write out link options
  236. std::vector<std::string> lopts = cmSystemTools::ParseArguments(linkFlags);
  237. for (auto& l : lopts) {
  238. fout << " " << l << std::endl;
  239. }
  240. // write out link search paths
  241. // must be quoted for paths that contain spaces
  242. std::vector<std::string> lpath = cmSystemTools::ParseArguments(linkPath);
  243. for (auto& l : lpath) {
  244. fout << " -L\"" << l << "\"" << std::endl;
  245. }
  246. // write out link libs
  247. // must be quoted for filepaths that contains spaces
  248. std::string cbd = this->LocalGenerator->GetCurrentBinaryDirectory();
  249. std::vector<std::string> llibs =
  250. cmSystemTools::ParseArguments(linkLibraries);
  251. for (auto& l : llibs) {
  252. if (l.compare(0, 2, "-l") == 0) {
  253. fout << " \"" << l << "\"" << std::endl;
  254. } else {
  255. std::string rl = cmSystemTools::CollapseFullPath(l, cbd);
  256. fout << " -l\"" << rl << "\"" << std::endl;
  257. }
  258. }
  259. }
  260. void cmGhsMultiTargetGenerator::WriteCustomCommands(std::ostream& fout)
  261. {
  262. WriteCustomCommandsHelper(fout, this->GeneratorTarget->GetPreBuildCommands(),
  263. cmTarget::PRE_BUILD);
  264. WriteCustomCommandsHelper(
  265. fout, this->GeneratorTarget->GetPostBuildCommands(), cmTarget::POST_BUILD);
  266. }
  267. void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
  268. std::ostream& fout, std::vector<cmCustomCommand> const& commandsSet,
  269. cmTarget::CustomCommandType const commandType)
  270. {
  271. for (cmCustomCommand const& customCommand : commandsSet) {
  272. cmCustomCommandLines const& commandLines = customCommand.GetCommandLines();
  273. for (cmCustomCommandLine const& command : commandLines) {
  274. switch (commandType) {
  275. case cmTarget::PRE_BUILD:
  276. fout << " :preexecShellSafe=";
  277. break;
  278. case cmTarget::POST_BUILD:
  279. fout << " :postexecShellSafe=";
  280. break;
  281. default:
  282. assert("Only pre and post are supported");
  283. }
  284. bool firstIteration = true;
  285. for (std::string const& commandLine : command) {
  286. std::string subCommandE =
  287. this->LocalGenerator->EscapeForShell(commandLine, true);
  288. fout << (firstIteration ? "'" : " ");
  289. // Need to double escape backslashes
  290. cmSystemTools::ReplaceString(subCommandE, "\\", "\\\\");
  291. fout << subCommandE;
  292. firstIteration = false;
  293. }
  294. if (!command.empty()) {
  295. fout << "'" << std::endl;
  296. }
  297. }
  298. }
  299. }
  300. void cmGhsMultiTargetGenerator::WriteSourceProperty(std::ostream& fout,
  301. const cmSourceFile* sf,
  302. std::string propName,
  303. std::string propFlag)
  304. {
  305. const char* prop = sf->GetProperty(propName);
  306. if (prop) {
  307. std::vector<std::string> list;
  308. cmSystemTools::ExpandListArgument(prop, list);
  309. for (auto& p : list) {
  310. fout << " " << propFlag << p << std::endl;
  311. }
  312. }
  313. }
  314. void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
  315. {
  316. /* vector of all sources for this target */
  317. std::vector<cmSourceFile*> sources;
  318. this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
  319. /* vector of all groups defined for this target
  320. * -- but the vector is not expanded with sub groups or in any useful order
  321. */
  322. std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
  323. /* for each source file assign it to its group */
  324. std::map<std::string, std::vector<cmSourceFile*>> groupFiles;
  325. std::set<std::string> groupNames;
  326. for (auto& sf : sources) {
  327. cmSourceGroup* sourceGroup =
  328. this->Makefile->FindSourceGroup(sf->GetFullPath(), sourceGroups);
  329. std::string gn = sourceGroup->GetFullName();
  330. groupFiles[gn].push_back(sf);
  331. groupNames.insert(gn);
  332. }
  333. /* list of known groups and the order they are displayed in a project file */
  334. const std::vector<std::string> standardGroups = {
  335. "Header Files", "Source Files", "CMake Rules",
  336. "Object Files", "Object Libraries", "Resources"
  337. };
  338. /* list of groups in the order they are displayed in a project file*/
  339. std::vector<std::string> groupFilesList(groupFiles.size());
  340. /* put the groups in the order they should be listed
  341. * - standard groups first, and then everything else
  342. * in the order used by std::map.
  343. */
  344. int i = 0;
  345. for (const std::string& gn : standardGroups) {
  346. auto n = groupNames.find(gn);
  347. if (n != groupNames.end()) {
  348. groupFilesList[i] = *n;
  349. i += 1;
  350. groupNames.erase(gn);
  351. }
  352. }
  353. { /* catch-all group - is last item */
  354. std::string gn = "";
  355. auto n = groupNames.find(gn);
  356. if (n != groupNames.end()) {
  357. groupFilesList.back() = *n;
  358. groupNames.erase(gn);
  359. }
  360. }
  361. for (auto& n : groupNames) {
  362. groupFilesList[i] = n;
  363. i += 1;
  364. }
  365. /* sort the files within each group */
  366. for (auto& n : groupFilesList) {
  367. std::sort(groupFiles[n].begin(), groupFiles[n].end(),
  368. [](cmSourceFile* l, cmSourceFile* r) {
  369. return l->GetFullPath() < r->GetFullPath();
  370. });
  371. }
  372. /* list of open project files */
  373. std::vector<cmGeneratedFileStream*> gfiles;
  374. /* write files into the proper project file
  375. * -- groups go into main project file
  376. * unless FOLDER property or variable is set.
  377. */
  378. for (auto& sg : groupFilesList) {
  379. std::ostream* fout;
  380. bool useProjectFile =
  381. cmSystemTools::IsOn(
  382. this->GeneratorTarget->GetProperty("GHS_NO_SOURCE_GROUP_FILE")) ||
  383. cmSystemTools::IsOn(
  384. this->Makefile->GetDefinition("CMAKE_GHS_NO_SOURCE_GROUP_FILE"));
  385. if (useProjectFile || sg.empty()) {
  386. fout = &fout_proj;
  387. } else {
  388. // Open the filestream in copy-if-different mode.
  389. std::string gname = sg;
  390. cmsys::SystemTools::ReplaceString(gname, "\\", "_");
  391. std::string lpath =
  392. this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
  393. lpath += "/";
  394. lpath += gname;
  395. lpath += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
  396. std::string fpath = this->LocalGenerator->GetCurrentBinaryDirectory();
  397. fpath += "/";
  398. fpath += lpath;
  399. cmGeneratedFileStream* f = new cmGeneratedFileStream(fpath.c_str());
  400. f->SetCopyIfDifferent(true);
  401. gfiles.push_back(f);
  402. fout = f;
  403. this->GetGlobalGenerator()->WriteFileHeader(*f);
  404. GhsMultiGpj::WriteGpjTag(GhsMultiGpj::SUBPROJECT, *f);
  405. fout_proj << lpath << " ";
  406. GhsMultiGpj::WriteGpjTag(GhsMultiGpj::SUBPROJECT, fout_proj);
  407. }
  408. if (useProjectFile) {
  409. if (sg.empty()) {
  410. *fout << "{comment} Others" << std::endl;
  411. } else {
  412. *fout << "{comment} " << sg << std::endl;
  413. }
  414. }
  415. /* output rule for each source file */
  416. for (const cmSourceFile* si : groupFiles[sg]) {
  417. // Convert filename to native system
  418. // WORKAROUND: GHS MULTI 6.1.4 and 6.1.6 are known to need backslash on
  419. // windows when opening some files from the search window.
  420. std::string fname(si->GetFullPath());
  421. cmSystemTools::ConvertToOutputSlashes(fname);
  422. *fout << fname << std::endl;
  423. if ("ld" != si->GetExtension() && "int" != si->GetExtension() &&
  424. "bsp" != si->GetExtension()) {
  425. this->WriteObjectLangOverride(*fout, si);
  426. }
  427. this->WriteSourceProperty(*fout, si, "INCLUDE_DIRECTORIES", "-I");
  428. this->WriteSourceProperty(*fout, si, "COMPILE_DEFINITIONS", "-D");
  429. this->WriteSourceProperty(*fout, si, "COMPILE_OPTIONS", "");
  430. /* to avoid clutter in the gui only print out the objectName if it has
  431. * been renamed */
  432. std::string objectName = this->GeneratorTarget->GetObjectName(si);
  433. if (!objectName.empty() &&
  434. this->GeneratorTarget->HasExplicitObjectName(si)) {
  435. *fout << " -o " << objectName << std::endl;
  436. }
  437. }
  438. }
  439. for (cmGeneratedFileStream* f : gfiles) {
  440. f->Close();
  441. }
  442. }
  443. void cmGhsMultiTargetGenerator::WriteObjectLangOverride(
  444. std::ostream& fout, const cmSourceFile* sourceFile)
  445. {
  446. const char* rawLangProp = sourceFile->GetProperty("LANGUAGE");
  447. if (NULL != rawLangProp) {
  448. std::string sourceLangProp(rawLangProp);
  449. std::string extension(sourceFile->GetExtension());
  450. if ("CXX" == sourceLangProp && ("c" == extension || "C" == extension)) {
  451. fout << " -dotciscxx" << std::endl;
  452. }
  453. }
  454. }
  455. void cmGhsMultiTargetGenerator::WriteReferences(std::ostream& fout)
  456. {
  457. // This only applies to INTEGRITY Applications
  458. if (this->TagType != GhsMultiGpj::INTERGRITY_APPLICATION) {
  459. return;
  460. }
  461. // Get the targets that this one depends upon
  462. cmTargetDependSet unordered =
  463. this->GetGlobalGenerator()->GetTargetDirectDepends(this->GeneratorTarget);
  464. cmGlobalGhsMultiGenerator::OrderedTargetDependSet ordered(unordered,
  465. this->Name);
  466. for (auto& t : ordered) {
  467. std::string tname = t->GetName();
  468. std::string tpath = t->LocalGenerator->GetCurrentBinaryDirectory();
  469. std::string rootpath = this->LocalGenerator->GetCurrentBinaryDirectory();
  470. std::string outpath =
  471. this->LocalGenerator->MaybeConvertToRelativePath(rootpath, tpath) + "/" +
  472. tname + "REF" + cmGlobalGhsMultiGenerator::FILE_EXTENSION;
  473. fout << outpath;
  474. fout << " ";
  475. GhsMultiGpj::WriteGpjTag(GhsMultiGpj::REFERENCE, fout);
  476. // Tell the global generator that a refernce project needs to be created
  477. t->Target->SetProperty("GHS_REFERENCE_PROJECT", "ON");
  478. }
  479. }
  480. bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp(void)
  481. {
  482. const char* p = this->GeneratorTarget->GetProperty("ghs_integrity_app");
  483. if (p) {
  484. return cmSystemTools::IsOn(
  485. this->GeneratorTarget->GetProperty("ghs_integrity_app"));
  486. } else {
  487. std::vector<cmSourceFile*> sources;
  488. this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
  489. for (auto& sf : sources) {
  490. if ("int" == sf->GetExtension()) {
  491. return true;
  492. }
  493. }
  494. return false;
  495. }
  496. }