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"
13 #include <cmext/algorithm>
14 #include <cmext/memory>
16 #include "cmCustomCommand.h"
17 #include "cmCustomCommandLines.h"
18 #include "cmGeneratedFileStream.h"
19 #include "cmGeneratorTarget.h"
20 #include "cmGhsMultiGpj.h"
22 #include "cmLocalGenerator.h"
23 #include "cmLocalGhsMultiGenerator.h"
24 #include "cmMakefile.h"
25 #include "cmMessageType.h"
26 #include "cmSourceFile.h"
28 #include "cmStateTypes.h"
29 #include "cmStringAlgorithms.h"
30 #include "cmSystemTools.h"
33 #include "cmVersion.h"
36 const char* cmGlobalGhsMultiGenerator::FILE_EXTENSION
= ".gpj";
38 const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM
= "gbuild";
40 const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM
= "gbuild.exe";
42 const char* cmGlobalGhsMultiGenerator::CHECK_BUILD_SYSTEM_TARGET
=
45 cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator(cmake
* cm
)
46 : cmGlobalGenerator(cm
)
48 cm
->GetState()->SetGhsMultiIDE(true);
51 cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator() = default;
53 std::unique_ptr
<cmLocalGenerator
>
54 cmGlobalGhsMultiGenerator::CreateLocalGenerator(cmMakefile
* mf
)
56 return std::unique_ptr
<cmLocalGenerator
>(
57 cm::make_unique
<cmLocalGhsMultiGenerator
>(this, mf
));
60 cmDocumentationEntry
cmGlobalGhsMultiGenerator::GetDocumentation()
64 "Generates Green Hills MULTI files (experimental, work-in-progress)."
68 void cmGlobalGhsMultiGenerator::ComputeTargetObjectDirectory(
69 cmGeneratorTarget
* gt
) const
71 // Compute full path to object file directory for this target.
73 cmStrCat(gt
->LocalGenerator
->GetCurrentBinaryDirectory(), '/',
74 gt
->LocalGenerator
->GetTargetDirectory(gt
), '/');
75 gt
->ObjectDirectory
= dir
;
78 bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string
const& ts
,
79 bool build
, cmMakefile
* mf
)
81 /* In build mode nothing to be done.
82 * Toolset already determined and build tool absolute path is cached.
88 /* Determine the absolute directory for the toolset */
90 this->GetToolset(mf
, tsp
, ts
);
92 /* no toolset was found */
97 /* set the build tool to use */
98 std::string
gbuild(tsp
+ ((tsp
.back() == '/') ? "" : "/") +
99 DEFAULT_BUILD_PROGRAM
);
100 cmValue prevTool
= mf
->GetDefinition("CMAKE_MAKE_PROGRAM");
102 /* check if the toolset changed from last generate */
103 if (cmNonempty(prevTool
) && !cmSystemTools::ComparePath(gbuild
, *prevTool
)) {
104 std::string
const& e
= cmStrCat(
105 "toolset build tool: ", gbuild
, '\n',
106 "Does not match the previously used build tool: ", *prevTool
, '\n',
107 "Either remove the CMakeCache.txt file and CMakeFiles "
108 "directory or choose a different binary directory.");
109 mf
->IssueMessage(MessageType::FATAL_ERROR
, e
);
113 /* store the toolset that is being used for this build */
114 mf
->AddCacheDefinition("CMAKE_MAKE_PROGRAM", gbuild
, "build program to use",
115 cmStateEnums::INTERNAL
, true);
117 mf
->AddDefinition("CMAKE_SYSTEM_VERSION", tsp
);
122 bool cmGlobalGhsMultiGenerator::SetGeneratorPlatform(std::string
const& p
,
125 /* set primary target */
126 cmValue t
= mf
->GetDefinition("GHS_PRIMARY_TARGET");
128 /* Use the value from `-A` or use `arm` */
129 std::string arch
= "arm";
133 cmValue platform
= mf
->GetDefinition("GHS_TARGET_PLATFORM");
134 std::string tgt
= cmStrCat(arch
, '_', platform
, ".tgt");
136 /* update the primary target name*/
137 mf
->AddDefinition("GHS_PRIMARY_TARGET", tgt
);
142 void cmGlobalGhsMultiGenerator::EnableLanguage(
143 std::vector
<std::string
> const& l
, cmMakefile
* mf
, bool optional
)
145 mf
->AddDefinition("CMAKE_SYSTEM_NAME", "GHS-MULTI");
147 mf
->AddDefinition("GHSMULTI", "1"); // identifier for user CMake files
149 this->cmGlobalGenerator::EnableLanguage(l
, mf
, optional
);
152 bool cmGlobalGhsMultiGenerator::FindMakeProgram(cmMakefile
* /*mf*/)
154 // The GHS generator only knows how to lookup its build tool
155 // during generation of the project files, but this
156 // can only be done after the toolset is specified.
161 void cmGlobalGhsMultiGenerator::GetToolset(cmMakefile
* mf
, std::string
& tsp
,
162 const std::string
& ts
)
164 /* Determine tsp - full path of the toolset from ts (toolset hint via -T) */
166 std::string root
= mf
->GetSafeDefinition("GHS_TOOLSET_ROOT");
168 // Check if `-T` was set by user
170 // Enter toolset search mode
171 std::vector
<std::string
> output
;
173 // Make sure root exists...
174 if (!cmSystemTools::PathExists(root
)) {
176 "GHS_TOOLSET_ROOT directory \"" + root
+ "\" does not exist.";
177 mf
->IssueMessage(MessageType::FATAL_ERROR
, msg
);
182 // Add a directory separator
183 if (root
.back() != '/') {
187 // Get all compiler directories in toolset root
188 cmSystemTools::Glob(root
, "comp_[^;]+", output
);
190 if (output
.empty()) {
191 // No compiler directories found
193 "No GHS toolsets found in GHS_TOOLSET_ROOT \"" + root
+ "\".";
194 mf
->IssueMessage(MessageType::FATAL_ERROR
, msg
);
197 // Use latest? version
198 tsp
= root
+ output
.back();
202 // Toolset was provided by user
205 // NOTE: CollapseFullPath() will determine if user toolset was full path or
207 tryPath
= cmSystemTools::CollapseFullPath(ts
, root
);
208 if (!cmSystemTools::FileExists(tryPath
)) {
209 std::string msg
= "GHS toolset \"" + tryPath
+ "\" does not exist.";
210 mf
->IssueMessage(MessageType::FATAL_ERROR
, msg
);
218 void cmGlobalGhsMultiGenerator::WriteFileHeader(std::ostream
& fout
)
220 /* clang-format off */
223 "# CMAKE generated file: DO NOT EDIT!\n"
224 "# Generated by \"" << GetActualName() << "\""
225 " Generator, CMake Version " << cmVersion::GetMajorVersion() << '.'
226 << cmVersion::GetMinorVersion() << "\n"
228 /* clang-format on */
231 void cmGlobalGhsMultiGenerator::WriteCustomRuleBOD(std::ostream
& fout
)
233 fout
<< "Commands {\n"
234 " Custom_Rule_Command {\n"
235 " name = \"Custom Rule Command\"\n"
243 " options = {\"SpecialOptions\"}\n"
250 " name = \"Custom Rule\"\n"
251 " action = \"&Run\"\n"
259 " grepable = false\n"
260 " command = \"Custom Rule Command\"\n"
261 " commandLine = \"$COMMAND "
266 " progress = \"Processing Custom Rule\"\n"
267 " promoteToFirstPass = true\n"
268 " outputType = \"None\"\n"
269 " color = \"#800080\"\n"
274 void cmGlobalGhsMultiGenerator::WriteCustomTargetBOD(std::ostream
& fout
)
276 fout
<< "FileTypes {\n"
278 " name = \"Custom Target\"\n"
279 " action = \"&Execute\"\n"
280 " grepable = false\n"
281 " outputType = \"None\"\n"
282 " color = \"#800080\"\n"
287 void cmGlobalGhsMultiGenerator::WriteTopLevelProject(std::ostream
& fout
,
288 cmLocalGenerator
* root
)
290 this->WriteFileHeader(fout
);
291 this->WriteMacros(fout
, root
);
292 this->WriteHighLevelDirectives(fout
, root
);
293 GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT
, fout
);
295 fout
<< "# Top Level Project File\n";
297 // Specify BSP option if supplied by user
298 // -- not all platforms require this entry in the project file
299 cmValue bspName
= root
->GetMakefile()->GetDefinition("GHS_BSP_NAME");
300 if (!bspName
.IsOff()) {
301 fout
<< " -bsp " << *bspName
<< '\n';
304 // Specify OS DIR if supplied by user
305 // -- not all platforms require this entry in the project file
306 cmValue osDir
= root
->GetMakefile()->GetDefinition("GHS_OS_DIR");
307 if (!osDir
.IsOff()) {
308 cmValue osDirOption
=
309 root
->GetMakefile()->GetDefinition("GHS_OS_DIR_OPTION");
311 if (osDirOption
.IsOff()) {
314 fout
<< *osDirOption
;
316 fout
<< "\"" << osDir
<< "\"\n";
320 void cmGlobalGhsMultiGenerator::WriteSubProjects(std::ostream
& fout
,
321 bool filterPredefined
)
323 std::set
<std::string
> predefinedTargets
;
324 predefinedTargets
.insert(this->GetInstallTargetName());
325 predefinedTargets
.insert(this->GetAllTargetName());
326 predefinedTargets
.insert(std::string(CHECK_BUILD_SYSTEM_TARGET
));
329 for (cmGeneratorTarget
const* target
: this->ProjectTargets
) {
330 if (target
->GetType() == cmStateEnums::INTERFACE_LIBRARY
||
331 target
->GetType() == cmStateEnums::MODULE_LIBRARY
||
332 target
->GetType() == cmStateEnums::SHARED_LIBRARY
||
333 (target
->GetType() == cmStateEnums::GLOBAL_TARGET
&&
334 target
->GetName() != this->GetInstallTargetName())) {
337 /* Check if the current target is a predefined CMake target */
338 bool predefinedTarget
=
339 predefinedTargets
.find(target
->GetName()) != predefinedTargets
.end();
340 if ((filterPredefined
&& predefinedTarget
) ||
341 (!filterPredefined
&& !predefinedTarget
)) {
342 fout
<< target
->GetName() + ".tgt" + FILE_EXTENSION
<< " [Project]\n";
347 void cmGlobalGhsMultiGenerator::WriteProjectLine(
348 std::ostream
& fout
, cmGeneratorTarget
const* target
,
349 std::string
& rootBinaryDir
)
351 cmValue projFile
= target
->GetProperty("GENERATOR_FILE_NAME");
352 cmValue projType
= target
->GetProperty("GENERATOR_FILE_NAME_EXT");
353 /* If either value is not valid then this particular target is an
354 * unsupported target type and should be skipped.
356 if (projFile
&& projType
) {
357 std::string path
= cmSystemTools::RelativePath(rootBinaryDir
, *projFile
);
360 fout
<< ' ' << *projType
<< '\n';
364 void cmGlobalGhsMultiGenerator::WriteTargets(cmLocalGenerator
* root
)
366 std::string rootBinaryDir
= root
->GetCurrentBinaryDirectory();
369 for (cmGeneratorTarget
const* target
: this->ProjectTargets
) {
370 if (target
->GetType() == cmStateEnums::INTERFACE_LIBRARY
||
371 target
->GetType() == cmStateEnums::MODULE_LIBRARY
||
372 target
->GetType() == cmStateEnums::SHARED_LIBRARY
||
373 (target
->GetType() == cmStateEnums::GLOBAL_TARGET
&&
374 target
->GetName() != this->GetInstallTargetName())) {
378 // create target build file
379 std::string name
= cmStrCat(target
->GetName(), ".tgt", FILE_EXTENSION
);
380 std::string fname
= cmStrCat(rootBinaryDir
, "/", name
);
381 cmGeneratedFileStream
fbld(fname
);
382 fbld
.SetCopyIfDifferent(true);
383 this->WriteFileHeader(fbld
);
384 GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT
, fbld
);
385 std::vector
<cmGeneratorTarget
const*> build
;
386 if (this->ComputeTargetBuildOrder(target
, build
)) {
387 cmSystemTools::Error(
388 cmStrCat("The inter-target dependency graph for target [",
389 target
->GetName(), "] had a cycle.\n"));
391 for (auto& tgt
: build
) {
392 this->WriteProjectLine(fbld
, tgt
, rootBinaryDir
);
399 void cmGlobalGhsMultiGenerator::Generate()
403 // first do the superclass method
404 this->cmGlobalGenerator::Generate();
406 // output top-level projects
407 for (auto& it
: this->ProjectMap
) {
408 this->OutputTopLevelProject(it
.second
[0], it
.second
);
411 // create custom rule BOD file
412 fname
= this->GetCMakeInstance()->GetHomeOutputDirectory() +
413 "/CMakeFiles/custom_rule.bod";
414 cmGeneratedFileStream
frule(fname
);
415 frule
.SetCopyIfDifferent(true);
416 this->WriteFileHeader(frule
);
417 this->WriteCustomRuleBOD(frule
);
420 // create custom target BOD file
421 fname
= this->GetCMakeInstance()->GetHomeOutputDirectory() +
422 "/CMakeFiles/custom_target.bod";
423 cmGeneratedFileStream
ftarget(fname
);
424 ftarget
.SetCopyIfDifferent(true);
425 this->WriteFileHeader(ftarget
);
426 this->WriteCustomTargetBOD(ftarget
);
430 void cmGlobalGhsMultiGenerator::OutputTopLevelProject(
431 cmLocalGenerator
* root
, std::vector
<cmLocalGenerator
*>& generators
)
435 if (generators
.empty()) {
439 // Collect all targets under this root generator and the transitive
440 // closure of their dependencies.
441 TargetDependSet projectTargets
;
442 TargetDependSet originalTargets
;
443 this->GetTargetSets(projectTargets
, originalTargets
, root
, generators
);
444 OrderedTargetDependSet
sortedProjectTargets(projectTargets
, "");
445 this->ProjectTargets
.clear();
446 for (cmGeneratorTarget
const* t
: sortedProjectTargets
) {
447 /* save list of all targets in sorted order */
448 this->ProjectTargets
.push_back(t
);
451 /* Name top-level projects as filename.top.gpj to avoid name clashes
452 * with target projects. This avoid the issue where the project has
453 * the same name as the executable target.
455 fname
= cmStrCat(root
->GetCurrentBinaryDirectory(), '/',
456 root
->GetProjectName(), ".top", FILE_EXTENSION
);
458 cmGeneratedFileStream
top(fname
);
459 top
.SetCopyIfDifferent(true);
460 this->WriteTopLevelProject(top
, root
);
461 this->WriteTargets(root
);
462 this->WriteSubProjects(top
, true);
463 this->WriteSubProjects(top
, false);
467 std::vector
<cmGlobalGenerator::GeneratedMakeCommand
>
468 cmGlobalGhsMultiGenerator::GenerateBuildCommand(
469 const std::string
& makeProgram
, const std::string
& projectName
,
470 const std::string
& projectDir
, std::vector
<std::string
> const& targetNames
,
471 const std::string
& /*config*/, int jobs
, bool verbose
,
472 const cmBuildOptions
& /*buildOptions*/,
473 std::vector
<std::string
> const& makeOptions
)
475 GeneratedMakeCommand makeCommand
;
477 makeCommand
.Add(this->SelectMakeProgram(makeProgram
));
479 if (jobs
!= cmake::NO_BUILD_PARALLEL_LEVEL
) {
480 if (jobs
== cmake::DEFAULT_BUILD_PARALLEL_LEVEL
) {
481 makeCommand
.Add("-parallel");
483 makeCommand
.Add(std::string("-parallel=") + std::to_string(jobs
));
487 /* determine the top-project file in the project directory */
488 std::string proj
= projectName
+ ".top" + FILE_EXTENSION
;
489 std::vector
<std::string
> files
;
490 cmSystemTools::Glob(projectDir
, ".*\\.top\\.gpj", files
);
491 if (!files
.empty()) {
492 /* use the real top-level project in the directory */
495 makeCommand
.Add("-top", proj
);
497 /* determine targets to build */
498 bool build_all
= false;
499 if (!targetNames
.empty()) {
500 for (const auto& tname
: targetNames
) {
501 if (!tname
.empty()) {
502 if (tname
== "clean") {
503 makeCommand
.Add("-clean");
505 makeCommand
.Add(tname
+ ".tgt.gpj");
516 /* transform name to default build */;
517 std::string all
= std::string(this->GetAllTargetName()) + ".tgt.gpj";
518 makeCommand
.Add(all
);
522 makeCommand
.Add("-commands");
524 makeCommand
.Add(makeOptions
.begin(), makeOptions
.end());
526 return { std::move(makeCommand
) };
529 void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream
& fout
,
530 cmLocalGenerator
* root
)
532 fout
<< "macro PROJ_NAME=" << root
->GetProjectName() << '\n';
533 cmValue ghsGpjMacros
= root
->GetMakefile()->GetDefinition("GHS_GPJ_MACROS");
535 cmList expandedList
{ *ghsGpjMacros
};
536 for (std::string
const& arg
: expandedList
) {
537 fout
<< "macro " << arg
<< '\n';
542 void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(
543 std::ostream
& fout
, cmLocalGenerator
* root
)
545 /* put primary target and customization files into project file */
546 cmValue
const tgt
= root
->GetMakefile()->GetDefinition("GHS_PRIMARY_TARGET");
548 /* clang-format off */
549 fout
<< "primaryTarget=" << tgt
<< "\n"
550 "customization=" << root
->GetBinaryDirectory()
551 << "/CMakeFiles/custom_rule.bod\n"
552 "customization=" << root
->GetBinaryDirectory()
553 << "/CMakeFiles/custom_target.bod" << '\n';
554 /* clang-format on */
556 cmValue
const customization
=
557 root
->GetMakefile()->GetDefinition("GHS_CUSTOMIZATION");
558 if (cmNonempty(customization
)) {
559 fout
<< "customization="
560 << cmGlobalGhsMultiGenerator::TrimQuotes(*customization
) << '\n';
561 this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION");
565 std::string
cmGlobalGhsMultiGenerator::TrimQuotes(std::string str
)
571 bool cmGlobalGhsMultiGenerator::TargetCompare::operator()(
572 cmGeneratorTarget
const* l
, cmGeneratorTarget
const* r
) const
574 // Make sure a given named target is ordered first,
575 // e.g. to set ALL_BUILD as the default active project.
576 // When the empty string is named this is a no-op.
577 if (r
->GetName() == this->First
) {
580 if (l
->GetName() == this->First
) {
583 return l
->GetName() < r
->GetName();
586 cmGlobalGhsMultiGenerator::OrderedTargetDependSet::OrderedTargetDependSet(
587 TargetDependSet
const& targets
, std::string
const& first
)
588 : derived(TargetCompare(first
))
590 this->insert(targets
.begin(), targets
.end());
593 bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder(
594 cmGeneratorTarget
const* tgt
, std::vector
<cmGeneratorTarget
const*>& build
)
596 std::vector
<cmGeneratorTarget
const*> t
{ tgt
};
597 return this->ComputeTargetBuildOrder(t
, build
);
600 bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder(
601 std::vector
<cmGeneratorTarget
const*>& tgt
,
602 std::vector
<cmGeneratorTarget
const*>& build
)
604 std::set
<cmGeneratorTarget
const*> temp
;
605 std::set
<cmGeneratorTarget
const*> perm
;
607 for (const auto* const ti
: tgt
) {
608 bool r
= this->VisitTarget(temp
, perm
, build
, ti
);
616 bool cmGlobalGhsMultiGenerator::VisitTarget(
617 std::set
<cmGeneratorTarget
const*>& temp
,
618 std::set
<cmGeneratorTarget
const*>& perm
,
619 std::vector
<cmGeneratorTarget
const*>& order
, cmGeneratorTarget
const* ti
)
621 /* check if permanent mark is set*/
622 if (perm
.find(ti
) == perm
.end()) {
623 /* set temporary mark; check if revisit*/
624 if (temp
.insert(ti
).second
) {
625 /* sort targets lexicographically to ensure that nodes are always visited
626 * in the same order */
627 OrderedTargetDependSet
sortedTargets(this->GetTargetDirectDepends(ti
),
629 for (auto const& di
: sortedTargets
) {
630 if (this->VisitTarget(temp
, perm
, order
, di
)) {
634 /* mark as complete; insert into beginning of list*/
639 /* revisiting item - not a DAG */
642 /* already complete */
646 bool cmGlobalGhsMultiGenerator::AddCheckTarget()
648 // Skip the target if no regeneration is to be done.
649 if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
653 // Get the generators.
654 std::vector
<std::unique_ptr
<cmLocalGenerator
>> const& generators
=
655 this->LocalGenerators
;
657 cm::static_reference_cast
<cmLocalGhsMultiGenerator
>(generators
[0]);
659 // The name of the output file for the custom command.
660 this->StampFile
= lg
.GetBinaryDirectory() + std::string("/CMakeFiles/") +
661 CHECK_BUILD_SYSTEM_TARGET
;
663 // Add a custom rule to re-run CMake if any input files changed.
665 // Collect the input files used to generate all targets in this
667 std::vector
<std::string
> listFiles
;
668 for (const auto& gen
: generators
) {
669 cm::append(listFiles
, gen
->GetMakefile()->GetListFiles());
672 // Add the cache file.
673 listFiles
.emplace_back(cmStrCat(
674 this->GetCMakeInstance()->GetHomeOutputDirectory(), "/CMakeCache.txt"));
676 // Print not implemented warning.
677 if (this->GetCMakeInstance()->DoWriteGlobVerifyTarget()) {
678 std::ostringstream msg
;
679 msg
<< "Any pre-check scripts, such as those generated for file(GLOB "
680 "CONFIGURE_DEPENDS), will not be run by gbuild.";
681 this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING
,
685 // Sort the list of input files and remove duplicates.
686 std::sort(listFiles
.begin(), listFiles
.end(), std::less
<std::string
>());
687 auto newEnd
= std::unique(listFiles
.begin(), listFiles
.end());
688 listFiles
.erase(newEnd
, listFiles
.end());
690 // Create a rule to re-run CMake and create output file.
691 cmCustomCommandLines commandLines
;
692 commandLines
.emplace_back(
693 cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E", "rm", "-f",
695 std::string argS
= cmStrCat("-S", lg
.GetSourceDirectory());
696 std::string argB
= cmStrCat("-B", lg
.GetBinaryDirectory());
697 commandLines
.emplace_back(
698 cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), argS
, argB
}));
699 commandLines
.emplace_back(cmMakeCommandLine(
700 { cmSystemTools::GetCMakeCommand(), "-E", "touch", this->StampFile
}));
702 /* Create the target(Exclude from ALL_BUILD).
704 * The build tool, currently, does not support rereading the project files
705 * if they get updated. So do not run this target as part of ALL_BUILD.
707 auto cc
= cm::make_unique
<cmCustomCommand
>();
709 lg
.AddUtilityCommand(CHECK_BUILD_SYSTEM_TARGET
, true, std::move(cc
));
710 auto ptr
= cm::make_unique
<cmGeneratorTarget
>(tgt
, &lg
);
711 auto* gt
= ptr
.get();
712 lg
.AddGeneratorTarget(std::move(ptr
));
715 cc
= cm::make_unique
<cmCustomCommand
>();
716 cc
->SetOutputs(this->StampFile
);
717 cc
->SetDepends(listFiles
);
718 cc
->SetCommandLines(commandLines
);
719 cc
->SetComment("Checking Build System");
720 cc
->SetEscapeOldStyle(false);
721 cc
->SetStdPipesUTF8(true);
723 if (cmSourceFile
* file
=
724 lg
.AddCustomCommandToOutput(std::move(cc
), true)) {
725 gt
->AddSource(file
->ResolveFullPath());
727 cmSystemTools::Error("Error adding rule for " + this->StampFile
);
729 // Organize in the "predefined targets" folder:
730 if (this->UseFolderProperty()) {
731 tgt
->SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
738 void cmGlobalGhsMultiGenerator::AddAllTarget()
740 // Add a special target that depends on ALL projects for easy build
741 // of one configuration only.
742 for (auto const& it
: this->ProjectMap
) {
743 std::vector
<cmLocalGenerator
*> const& gen
= it
.second
;
744 // add the ALL_BUILD to the first local generator of each project
746 // Use no actual command lines so that the target itself is not
747 // considered always out of date.
748 auto cc
= cm::make_unique
<cmCustomCommand
>();
749 cc
->SetEscapeOldStyle(false);
750 cc
->SetComment("Build all projects");
751 cmTarget
* allBuild
= gen
[0]->AddUtilityCommand(this->GetAllTargetName(),
752 true, std::move(cc
));
754 gen
[0]->AddGeneratorTarget(
755 cm::make_unique
<cmGeneratorTarget
>(allBuild
, gen
[0]));
757 // Organize in the "predefined targets" folder:
758 if (this->UseFolderProperty()) {
759 allBuild
->SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
762 // Now make all targets depend on the ALL_BUILD target
763 for (cmLocalGenerator
const* i
: gen
) {
764 for (const auto& tgt
: i
->GetGeneratorTargets()) {
765 // Skip global or imported targets
766 if (tgt
->GetType() == cmStateEnums::GLOBAL_TARGET
||
770 // Skip Exclude From All Targets
771 if (!this->IsExcluded(gen
[0], tgt
.get())) {
772 allBuild
->AddUtility(tgt
->GetName(), false);
780 void cmGlobalGhsMultiGenerator::AddExtraIDETargets()
782 // Add a special target that depends on ALL projects.
783 this->AddAllTarget();
785 /* Add Custom Target to check if CMake needs to be rerun.
787 * The build tool, currently, does not support rereading the project files
788 * if they get updated. So do not make the other targets dependent on this
791 this->AddCheckTarget();