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"
12 #include "cmCustomCommand.h"
13 #include "cmCustomCommandGenerator.h"
14 #include "cmGeneratedFileStream.h"
15 #include "cmGeneratorTarget.h"
16 #include "cmGlobalGhsMultiGenerator.h"
17 #include "cmLinkLineComputer.h" // IWYU pragma: keep
18 #include "cmLocalGenerator.h"
19 #include "cmLocalGhsMultiGenerator.h"
20 #include "cmMakefile.h"
21 #include "cmOutputConverter.h"
22 #include "cmSourceFile.h"
23 #include "cmSourceFileLocation.h"
24 #include "cmSourceGroup.h"
25 #include "cmStateDirectory.h"
26 #include "cmStateSnapshot.h"
27 #include "cmStateTypes.h"
28 #include "cmStringAlgorithms.h"
29 #include "cmSystemTools.h"
33 cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget* target)
34 : GeneratorTarget(target)
36 static_cast<cmLocalGhsMultiGenerator*>(target->GetLocalGenerator()))
37 , Makefile(target->Target->GetMakefile())
38 , Name(target->GetName())
40 // Store the configuration name that is being used
41 if (cmValue config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE")) {
42 // Use the build type given by the user.
43 this->ConfigName = *config;
45 // No configuration type given.
46 this->ConfigName.clear();
50 cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator() = default;
52 void cmGhsMultiTargetGenerator::Generate()
54 // Determine type of target for this project
55 switch (this->GeneratorTarget->GetType()) {
56 case cmStateEnums::EXECUTABLE: {
57 // Get the name of the executable to generate.
58 this->TargetNameReal =
59 this->GeneratorTarget->GetExecutableNames(this->ConfigName).Real;
60 if (this->cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()) {
61 this->TagType = GhsMultiGpj::INTERGRITY_APPLICATION;
63 this->TagType = GhsMultiGpj::PROGRAM;
67 case cmStateEnums::STATIC_LIBRARY: {
68 this->TargetNameReal =
69 this->GeneratorTarget->GetLibraryNames(this->ConfigName).Real;
70 this->TagType = GhsMultiGpj::LIBRARY;
73 case cmStateEnums::SHARED_LIBRARY: {
75 cmStrCat("add_library(<name> SHARED ...) not supported: ", this->Name);
76 cmSystemTools::Message(msg);
79 case cmStateEnums::OBJECT_LIBRARY: {
80 this->TargetNameReal =
81 this->GeneratorTarget->GetLibraryNames(this->ConfigName).Real;
82 this->TagType = GhsMultiGpj::SUBPROJECT;
85 case cmStateEnums::MODULE_LIBRARY: {
87 cmStrCat("add_library(<name> MODULE ...) not supported: ", this->Name);
88 cmSystemTools::Message(msg);
91 case cmStateEnums::UTILITY: {
92 this->TargetNameReal = this->GeneratorTarget->GetName();
93 this->TagType = GhsMultiGpj::CUSTOM_TARGET;
96 case cmStateEnums::GLOBAL_TARGET: {
97 this->TargetNameReal = this->GeneratorTarget->GetName();
98 if (this->TargetNameReal ==
99 this->GetGlobalGenerator()->GetInstallTargetName()) {
100 this->TagType = GhsMultiGpj::CUSTOM_TARGET;
110 this->GenerateTarget();
113 void cmGhsMultiTargetGenerator::GenerateTarget()
115 // Open the target file in copy-if-different mode.
117 cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
118 this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget),
119 '/', this->Name, cmGlobalGhsMultiGenerator::FILE_EXTENSION);
121 // Tell the global generator the name of the project file
122 this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME", fproj);
123 this->GeneratorTarget->Target->SetProperty(
124 "GENERATOR_FILE_NAME_EXT", GhsMultiGpj::GetGpjTag(this->TagType));
126 cmGeneratedFileStream fout(fproj);
127 fout.SetCopyIfDifferent(true);
129 this->GetGlobalGenerator()->WriteFileHeader(fout);
130 GhsMultiGpj::WriteGpjTag(this->TagType, fout);
132 if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
133 const std::string language(
134 this->GeneratorTarget->GetLinkerLanguage(this->ConfigName));
135 this->WriteTargetSpecifics(fout, this->ConfigName);
136 this->SetCompilerFlags(this->ConfigName, language);
137 this->WriteCompilerFlags(fout, this->ConfigName, language);
138 this->WriteCompilerDefinitions(fout, this->ConfigName, language);
139 this->WriteIncludes(fout, this->ConfigName, language);
140 this->WriteTargetLinkLine(fout, this->ConfigName);
141 this->WriteBuildEvents(fout);
143 this->WriteSources(fout);
147 cmGlobalGhsMultiGenerator* cmGhsMultiTargetGenerator::GetGlobalGenerator()
150 return static_cast<cmGlobalGhsMultiGenerator*>(
151 this->LocalGenerator->GetGlobalGenerator());
154 void cmGhsMultiTargetGenerator::WriteTargetSpecifics(std::ostream& fout,
155 const std::string& config)
159 /* Determine paths from the target project file to where the output artifacts
160 * need to be located.
162 if (this->TagType != GhsMultiGpj::SUBPROJECT) {
163 // set target binary file destination
164 std::string binpath = cmStrCat(
165 this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
166 this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget));
167 outpath = cmSystemTools::RelativePath(
168 binpath, this->GeneratorTarget->GetDirectory(config));
169 /* clang-format off */
170 fout << " :binDirRelative=\"" << outpath << "\"\n"
171 " -o \"" << this->TargetNameReal << "\"\n";
172 /* clang-format on */
175 // set target object file destination
177 fout << " :outputDirRelative=\"" << outpath << "\"\n";
180 void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config,
181 const std::string& language)
183 auto i = this->FlagsByLanguage.find(language);
184 if (i == this->FlagsByLanguage.end()) {
186 this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
188 this->LocalGenerator->AddCMP0018Flags(flags, this->GeneratorTarget,
190 this->LocalGenerator->AddVisibilityPresetFlags(
191 flags, this->GeneratorTarget, language);
192 this->LocalGenerator->AddColorDiagnosticsFlags(flags, language);
194 // Append old-style preprocessor definition flags.
195 if (this->Makefile->GetDefineFlags() != " ") {
196 this->LocalGenerator->AppendFlags(flags,
197 this->Makefile->GetDefineFlags());
200 // Add target-specific flags.
201 this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget,
204 std::map<std::string, std::string>::value_type entry(language, flags);
205 i = this->FlagsByLanguage.insert(entry).first;
209 std::string cmGhsMultiTargetGenerator::GetDefines(const std::string& language,
210 std::string const& config)
212 auto i = this->DefinesByLanguage.find(language);
213 if (i == this->DefinesByLanguage.end()) {
214 std::set<std::string> defines;
215 // Add preprocessor definitions for this target and configuration.
216 this->LocalGenerator->GetTargetDefines(this->GeneratorTarget, config,
219 std::string definesString;
220 this->LocalGenerator->JoinDefines(defines, definesString, language);
222 std::map<std::string, std::string>::value_type entry(language,
224 i = this->DefinesByLanguage.insert(entry).first;
229 void cmGhsMultiTargetGenerator::WriteCompilerFlags(std::ostream& fout,
231 const std::string& language)
233 auto flagsByLangI = this->FlagsByLanguage.find(language);
234 if (flagsByLangI != this->FlagsByLanguage.end()) {
235 if (!flagsByLangI->second.empty()) {
236 std::vector<std::string> ghsCompFlags =
237 cmSystemTools::ParseArguments(flagsByLangI->second);
238 for (const std::string& f : ghsCompFlags) {
239 fout << " " << f << '\n';
245 void cmGhsMultiTargetGenerator::WriteCompilerDefinitions(
246 std::ostream& fout, const std::string& config, const std::string& language)
248 std::vector<std::string> compileDefinitions;
249 this->GeneratorTarget->GetCompileDefinitions(compileDefinitions, config,
251 for (std::string const& compileDefinition : compileDefinitions) {
252 fout << " -D" << compileDefinition << '\n';
256 void cmGhsMultiTargetGenerator::WriteIncludes(std::ostream& fout,
257 const std::string& config,
258 const std::string& language)
260 std::vector<std::string> includes;
261 this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
264 for (std::string const& include : includes) {
265 fout << " -I\"" << include << "\"\n";
269 void cmGhsMultiTargetGenerator::WriteTargetLinkLine(std::ostream& fout,
270 std::string const& config)
272 if (this->TagType == GhsMultiGpj::INTERGRITY_APPLICATION) {
276 std::string linkLibraries;
278 std::string linkFlags;
279 std::string frameworkPath;
280 std::string linkPath;
282 std::unique_ptr<cmLinkLineComputer> linkLineComputer =
283 this->GetGlobalGenerator()->CreateLinkLineComputer(
284 this->LocalGenerator,
285 this->LocalGenerator->GetStateSnapshot().GetDirectory());
287 this->LocalGenerator->GetTargetFlags(
288 linkLineComputer.get(), config, linkLibraries, flags, linkFlags,
289 frameworkPath, linkPath, this->GeneratorTarget);
291 // write out link options
292 std::vector<std::string> lopts = cmSystemTools::ParseArguments(linkFlags);
293 for (const std::string& l : lopts) {
294 fout << " " << l << '\n';
297 // write out link search paths
298 // must be quoted for paths that contain spaces
299 std::vector<std::string> lpath = cmSystemTools::ParseArguments(linkPath);
300 for (const std::string& l : lpath) {
301 fout << " -L\"" << l << "\"\n";
304 // write out link libs
305 // must be quoted for filepaths that contains spaces
306 std::string cbd = this->LocalGenerator->GetCurrentBinaryDirectory();
308 std::vector<std::string> llibs =
309 cmSystemTools::ParseArguments(linkLibraries);
310 for (const std::string& l : llibs) {
311 if (l.compare(0, 2, "-l") == 0) {
312 fout << " \"" << l << "\"\n";
314 std::string rl = cmSystemTools::CollapseFullPath(l, cbd);
315 fout << " -l\"" << rl << "\"\n";
320 void cmGhsMultiTargetGenerator::WriteBuildEvents(std::ostream& fout)
322 this->WriteBuildEventsHelper(fout,
323 this->GeneratorTarget->GetPreBuildCommands(),
324 std::string("prebuild"),
326 std::string("preexecShell")
328 std::string("preexec")
332 if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
333 this->WriteBuildEventsHelper(fout,
334 this->GeneratorTarget->GetPreLinkCommands(),
335 std::string("prelink"),
337 std::string("preexecShell")
339 std::string("preexec")
344 this->WriteBuildEventsHelper(fout,
345 this->GeneratorTarget->GetPostBuildCommands(),
346 std::string("postbuild"),
348 std::string("postexecShell")
350 std::string("postexec")
355 void cmGhsMultiTargetGenerator::WriteBuildEventsHelper(
356 std::ostream& fout, const std::vector<cmCustomCommand>& ccv,
357 std::string const& name, std::string const& cmd)
361 std::string fext = ".bat";
364 std::string fext = ".sh";
365 std::string shell = "/bin/sh ";
368 for (cmCustomCommand const& cc : ccv) {
369 cmCustomCommandGenerator ccg(cc, this->ConfigName, this->LocalGenerator);
370 // Open the filestream for this custom command
372 cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
373 this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget),
374 '/', this->Name, '_', name, cmdcount++, fext);
376 cmGeneratedFileStream f(fname);
377 f.SetCopyIfDifferent(true);
378 this->WriteCustomCommandsHelper(f, ccg);
380 if (this->TagType != GhsMultiGpj::CUSTOM_TARGET) {
381 fout << " :" << cmd << "=\"" << shell << fname << "\"\n";
383 fout << fname << "\n :outputName=\"" << fname << ".rule\"\n";
385 for (const auto& byp : ccg.GetByproducts()) {
386 fout << " :extraOutputFile=\"" << byp << "\"\n";
391 void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
392 std::ostream& fout, cmCustomCommandGenerator const& ccg)
394 std::vector<std::string> cmdLines;
396 // if the command specified a working directory use it.
397 std::string dir = this->LocalGenerator->GetCurrentBinaryDirectory();
398 std::string workingDir = ccg.GetWorkingDirectory();
399 if (!workingDir.empty()) {
403 // Line to check for error between commands.
405 std::string check_error = "if %errorlevel% neq 0 exit /b %errorlevel%";
407 std::string check_error = "if [ $? -ne 0 ]; then exit 1; fi";
411 cmdLines.push_back("@echo off");
413 // Echo the custom command's comment text.
414 const char* comment = ccg.GetComment();
415 if (comment && *comment) {
416 std::string echocmd = cmStrCat("echo ", comment);
417 cmdLines.push_back(std::move(echocmd));
420 // Switch to working directory
423 std::string cdStr = "cd /D ";
425 std::string cdStr = "cd ";
428 this->LocalGenerator->ConvertToOutputFormat(dir, cmOutputConverter::SHELL);
429 cmdLines.push_back(std::move(cdCmd));
431 for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) {
432 // Build the command line in a single string.
433 std::string cmd = ccg.GetCommand(c);
435 // Use "call " before any invocations of .bat or .cmd files
436 // invoked as custom commands in the WindowsShell.
438 bool useCall = false;
442 if (cmd.size() > 4) {
443 suffix = cmSystemTools::LowerCase(cmd.substr(cmd.size() - 4));
444 if (suffix == ".bat" || suffix == ".cmd") {
450 cmSystemTools::ReplaceString(cmd, "/./", "/");
451 // Convert the command to a relative path only if the current
452 // working directory will be the start-output directory.
453 bool had_slash = cmd.find('/') != std::string::npos;
454 if (workingDir.empty()) {
455 cmd = this->LocalGenerator->MaybeRelativeToCurBinDir(cmd);
457 bool has_slash = cmd.find('/') != std::string::npos;
458 if (had_slash && !has_slash) {
459 // This command was specified as a path to a file in the
460 // current directory. Add a leading "./" so it can run
461 // without the current directory being in the search path.
462 cmd = cmStrCat("./", cmd);
464 cmd = this->LocalGenerator->ConvertToOutputFormat(
465 cmd, cmOutputConverter::SHELL);
467 cmd = cmStrCat("call ", cmd);
469 ccg.AppendArguments(c, cmd);
470 cmdLines.push_back(std::move(cmd));
474 // push back the custom commands
475 for (auto const& c : cmdLines) {
476 fout << c << '\n' << check_error << '\n';
480 void cmGhsMultiTargetGenerator::WriteSourceProperty(
481 std::ostream& fout, const cmSourceFile* sf, std::string const& propName,
482 std::string const& propFlag)
484 cmValue prop = sf->GetProperty(propName);
486 std::vector<std::string> list = cmExpandedList(*prop);
487 for (const std::string& p : list) {
488 fout << " " << propFlag << p << '\n';
493 void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
495 /* vector of all sources for this target */
496 std::vector<cmSourceFile*> sources;
497 this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
499 /* vector of all groups defined for this target
500 * -- but the vector is not expanded with sub groups or in any useful order
502 std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
504 /* for each source file assign it to its group */
505 std::map<std::string, std::vector<cmSourceFile*>> groupFiles;
506 std::set<std::string> groupNames;
507 for (cmSourceFile* sf : sources) {
508 cmSourceGroup* sourceGroup =
509 this->Makefile->FindSourceGroup(sf->ResolveFullPath(), sourceGroups);
510 std::string gn = sourceGroup->GetFullName();
511 groupFiles[gn].push_back(sf);
512 groupNames.insert(std::move(gn));
515 /* list of known groups and the order they are displayed in a project file */
516 const std::vector<std::string> standardGroups = {
517 "CMake Rules", "Header Files", "Source Files",
518 "Object Files", "Object Libraries", "Resources"
521 /* list of groups in the order they are displayed in a project file*/
522 std::vector<std::string> groupFilesList(groupFiles.size());
524 /* put the groups in the order they should be listed
525 * - standard groups first, and then everything else
526 * in the order used by std::map.
529 for (const std::string& gn : standardGroups) {
530 auto n = groupNames.find(gn);
531 if (n != groupNames.end()) {
532 groupFilesList[i] = *n;
534 groupNames.erase(gn);
535 } else if (this->TagType == GhsMultiGpj::CUSTOM_TARGET &&
536 gn == "CMake Rules") {
537 /* make sure that rules folder always exists in case of custom targets
538 * that have no custom commands except for pre or post build events.
540 groupFilesList.resize(groupFilesList.size() + 1);
541 groupFilesList[i] = gn;
546 { /* catch-all group - is last item */
548 auto n = groupNames.find(gn);
549 if (n != groupNames.end()) {
550 groupFilesList.back() = *n;
551 groupNames.erase(gn);
555 for (const auto& n : groupNames) {
556 groupFilesList[i] = n;
560 /* sort the files within each group */
561 for (auto& n : groupFilesList) {
562 std::sort(groupFiles[n].begin(), groupFiles[n].end(),
563 [](cmSourceFile* l, cmSourceFile* r) {
564 return l->ResolveFullPath() < r->ResolveFullPath();
568 /* list of open project files */
569 std::vector<cmGeneratedFileStream*> gfiles;
571 /* write files into the proper project file
572 * -- groups go into main project file
573 * unless NO_SOURCE_GROUP_FILE property or variable is set.
575 for (auto& sg : groupFilesList) {
577 bool useProjectFile =
578 cmIsOn(this->GeneratorTarget->GetProperty("GHS_NO_SOURCE_GROUP_FILE")) ||
579 this->Makefile->IsOn("CMAKE_GHS_NO_SOURCE_GROUP_FILE");
580 if (useProjectFile || sg.empty()) {
583 // Open the filestream in copy-if-different mode.
584 std::string gname = sg;
585 cmsys::SystemTools::ReplaceString(gname, "\\", "_");
587 cmStrCat(gname, cmGlobalGhsMultiGenerator::FILE_EXTENSION);
588 std::string fpath = cmStrCat(
589 this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
590 this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), '/',
592 cmGeneratedFileStream* f = new cmGeneratedFileStream(fpath);
593 f->SetCopyIfDifferent(true);
596 this->GetGlobalGenerator()->WriteFileHeader(*f);
597 GhsMultiGpj::WriteGpjTag(GhsMultiGpj::SUBPROJECT, *f);
598 fout_proj << lpath << " ";
599 GhsMultiGpj::WriteGpjTag(GhsMultiGpj::SUBPROJECT, fout_proj);
602 if (useProjectFile) {
604 *fout << "{comment} Others" << '\n';
606 *fout << "{comment} " << sg << '\n';
608 } else if (sg.empty()) {
609 *fout << "{comment} Others\n";
612 if (sg != "CMake Rules") {
613 /* output rule for each source file */
614 for (const cmSourceFile* si : groupFiles[sg]) {
616 // Convert filename to native system
617 // WORKAROUND: GHS MULTI 6.1.4 and 6.1.6 are known to need backslash on
618 // windows when opening some files from the search window.
619 std::string fname(si->GetFullPath());
620 cmSystemTools::ConvertToOutputSlashes(fname);
622 /* For custom targets list any associated sources,
623 * comment out source code to prevent it from being
624 * compiled when processing this target.
625 * Otherwise, comment out any custom command (main) dependencies that
626 * are listed as source files to prevent them from being considered
630 if ((this->TagType == GhsMultiGpj::CUSTOM_TARGET &&
631 !si->GetLanguage().empty()) ||
632 si->GetCustomCommand()) {
633 comment = "{comment} ";
637 *fout << comment << fname << WriteObjectLangOverride(si) << '\n';
639 this->WriteSourceProperty(*fout, si, "INCLUDE_DIRECTORIES", "-I");
640 this->WriteSourceProperty(*fout, si, "COMPILE_DEFINITIONS", "-D");
641 this->WriteSourceProperty(*fout, si, "COMPILE_OPTIONS", "");
643 /* to avoid clutter in the GUI only print out the objectName if it
644 * has been renamed */
645 std::string objectName = this->GeneratorTarget->GetObjectName(si);
646 if (!objectName.empty() &&
647 this->GeneratorTarget->HasExplicitObjectName(si)) {
648 *fout << " -o " << objectName << '\n';
653 std::vector<cmSourceFile const*> customCommands;
654 if (this->ComputeCustomCommandOrder(customCommands)) {
655 std::string message = "The custom commands for target [" +
656 this->GeneratorTarget->GetName() + "] had a cycle.\n";
657 cmSystemTools::Error(message);
659 /* Custom targets do not have a dependency on SOURCES files.
660 * Therefore the dependency list may include SOURCES files after the
661 * custom target. Because nothing can depend on the custom target just
662 * move it to the last item.
664 for (auto sf = customCommands.begin(); sf != customCommands.end();
666 if (((*sf)->GetLocation()).GetName() == this->Name + ".rule") {
667 std::rotate(sf, sf + 1, customCommands.end());
673 std::string fext = ".bat";
675 std::string fext = ".sh";
677 for (auto& sf : customCommands) {
678 const cmCustomCommand* cc = sf->GetCustomCommand();
679 cmCustomCommandGenerator ccg(*cc, this->ConfigName,
680 this->LocalGenerator);
682 // Open the filestream for this custom command
683 std::string fname = cmStrCat(
684 this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
685 this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget),
686 '/', this->Name, "_cc", cmdcount++, '_',
687 (sf->GetLocation()).GetName(), fext);
689 cmGeneratedFileStream f(fname);
690 f.SetCopyIfDifferent(true);
691 this->WriteCustomCommandsHelper(f, ccg);
693 this->WriteCustomCommandLine(*fout, fname, ccg);
696 if (this->TagType == GhsMultiGpj::CUSTOM_TARGET) {
697 this->WriteBuildEvents(*fout);
702 for (cmGeneratedFileStream* f : gfiles) {
707 void cmGhsMultiTargetGenerator::WriteCustomCommandLine(
708 std::ostream& fout, std::string& fname, cmCustomCommandGenerator const& ccg)
710 /* NOTE: Customization Files are not well documented. Testing showed
711 * that ":outputName=file" can only be used once per script. The
712 * script will only run if ":outputName=file" is missing or just run
713 * once if ":outputName=file" is not specified. If there are
714 * multiple outputs then the script needs to be listed multiple times
715 * for each output. Otherwise it won't rerun the script if one of
716 * the outputs is manually deleted.
718 bool specifyExtra = true;
719 for (const auto& out : ccg.GetOutputs()) {
720 fout << fname << '\n';
721 fout << " :outputName=\"" << out << "\"\n";
723 for (const auto& byp : ccg.GetByproducts()) {
724 fout << " :extraOutputFile=\"" << byp << "\"\n";
726 for (const auto& dep : ccg.GetDepends()) {
727 fout << " :depends=\"" << dep << "\"\n";
729 specifyExtra = false;
734 std::string cmGhsMultiTargetGenerator::WriteObjectLangOverride(
735 const cmSourceFile* sourceFile)
738 cmValue rawLangProp = sourceFile->GetProperty("LANGUAGE");
740 ret = cmStrCat(" [", *rawLangProp, "]");
746 bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()
748 if (cmValue p = this->GeneratorTarget->GetProperty("ghs_integrity_app")) {
751 std::vector<cmSourceFile*> sources;
752 this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
753 return std::any_of(sources.begin(), sources.end(),
754 [](cmSourceFile const* sf) -> bool {
755 return "int" == sf->GetExtension();
759 bool cmGhsMultiTargetGenerator::ComputeCustomCommandOrder(
760 std::vector<cmSourceFile const*>& order)
762 std::set<cmSourceFile const*> temp;
763 std::set<cmSourceFile const*> perm;
765 // Collect all custom commands for this target
766 std::vector<cmSourceFile const*> customCommands;
767 this->GeneratorTarget->GetCustomCommands(customCommands, this->ConfigName);
769 for (cmSourceFile const* si : customCommands) {
770 bool r = this->VisitCustomCommand(temp, perm, order, si);
778 bool cmGhsMultiTargetGenerator::VisitCustomCommand(
779 std::set<cmSourceFile const*>& temp, std::set<cmSourceFile const*>& perm,
780 std::vector<cmSourceFile const*>& order, cmSourceFile const* si)
782 /* check if permanent mark is set*/
783 if (perm.find(si) == perm.end()) {
784 /* set temporary mark; check if revisit*/
785 if (temp.insert(si).second) {
786 for (const auto& di : si->GetCustomCommand()->GetDepends()) {
787 cmSourceFile const* sf =
788 this->GeneratorTarget->GetLocalGenerator()->GetSourceFileWithOutput(
790 /* if sf exists then visit */
791 if (sf && this->VisitCustomCommand(temp, perm, order, sf)) {
795 /* mark as complete; insert into beginning of list*/
800 /* revisiting item - not a DAG */
803 /* already complete */