CMake Nightly Date Stamp
[kiteware-cmake.git] / Source / cmGlobalGhsMultiGenerator.cxx
blob37bcc2c0623ec1ca28c18232930d9f3f68a9101e
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"
5 #include <algorithm>
6 #include <functional>
7 #include <map>
8 #include <sstream>
9 #include <utility>
11 #include <cm/memory>
12 #include <cm/string>
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"
21 #include "cmList.h"
22 #include "cmLocalGenerator.h"
23 #include "cmLocalGhsMultiGenerator.h"
24 #include "cmMakefile.h"
25 #include "cmMessageType.h"
26 #include "cmSourceFile.h"
27 #include "cmState.h"
28 #include "cmStateTypes.h"
29 #include "cmStringAlgorithms.h"
30 #include "cmSystemTools.h"
31 #include "cmTarget.h"
32 #include "cmValue.h"
33 #include "cmVersion.h"
34 #include "cmake.h"
36 const char* cmGlobalGhsMultiGenerator::FILE_EXTENSION = ".gpj";
37 #ifdef __linux__
38 const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild";
39 #elif defined(_WIN32)
40 const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild.exe";
41 #endif
42 const char* cmGlobalGhsMultiGenerator::CHECK_BUILD_SYSTEM_TARGET =
43 "RERUN_CMAKE";
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()
62 return {
63 GetActualName(),
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.
72 std::string dir =
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.
84 if (build) {
85 return true;
88 /* Determine the absolute directory for the toolset */
89 std::string tsp;
90 this->GetToolset(mf, tsp, ts);
92 /* no toolset was found */
93 if (tsp.empty()) {
94 return false;
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);
110 return false;
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);
119 return true;
122 bool cmGlobalGhsMultiGenerator::SetGeneratorPlatform(std::string const& p,
123 cmMakefile* mf)
125 /* set primary target */
126 cmValue t = mf->GetDefinition("GHS_PRIMARY_TARGET");
127 if (t.IsOff()) {
128 /* Use the value from `-A` or use `arm` */
129 std::string arch = "arm";
130 if (!cmIsOff(p)) {
131 arch = p;
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);
139 return true;
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.
158 return true;
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
169 if (ts.empty()) {
170 // Enter toolset search mode
171 std::vector<std::string> output;
173 // Make sure root exists...
174 if (!cmSystemTools::PathExists(root)) {
175 std::string msg =
176 "GHS_TOOLSET_ROOT directory \"" + root + "\" does not exist.";
177 mf->IssueMessage(MessageType::FATAL_ERROR, msg);
178 tsp = "";
179 return;
182 // Add a directory separator
183 if (root.back() != '/') {
184 root += "/";
187 // Get all compiler directories in toolset root
188 cmSystemTools::Glob(root, "comp_[^;]+", output);
190 if (output.empty()) {
191 // No compiler directories found
192 std::string msg =
193 "No GHS toolsets found in GHS_TOOLSET_ROOT \"" + root + "\".";
194 mf->IssueMessage(MessageType::FATAL_ERROR, msg);
195 tsp = "";
196 } else {
197 // Use latest? version
198 tsp = root + output.back();
201 } else {
202 // Toolset was provided by user
203 std::string tryPath;
205 // NOTE: CollapseFullPath() will determine if user toolset was full path or
206 // or relative path.
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);
211 tsp = "";
212 } else {
213 tsp = tryPath;
218 void cmGlobalGhsMultiGenerator::WriteFileHeader(std::ostream& fout)
220 /* clang-format off */
221 fout << "#!gbuild\n"
222 "#\n"
223 "# CMAKE generated file: DO NOT EDIT!\n"
224 "# Generated by \"" << GetActualName() << "\""
225 " Generator, CMake Version " << cmVersion::GetMajorVersion() << '.'
226 << cmVersion::GetMinorVersion() << "\n"
227 "#\n\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"
236 " exec = \""
237 #ifdef _WIN32
238 "cmd.exe"
239 #else
240 "/bin/sh"
241 #endif
242 "\"\n"
243 " options = {\"SpecialOptions\"}\n"
244 " }\n"
245 "}\n"
247 "\n\n"
248 "FileTypes {\n"
249 " CmakeRule {\n"
250 " name = \"Custom Rule\"\n"
251 " action = \"&Run\"\n"
252 " extensions = {\""
253 #ifdef _WIN32
254 "bat"
255 #else
256 "sh"
257 #endif
258 "\"}\n"
259 " grepable = false\n"
260 " command = \"Custom Rule Command\"\n"
261 " commandLine = \"$COMMAND "
262 #ifdef _WIN32
263 "/c"
264 #endif
265 " $INPUTFILE\"\n"
266 " progress = \"Processing Custom Rule\"\n"
267 " promoteToFirstPass = true\n"
268 " outputType = \"None\"\n"
269 " color = \"#800080\"\n"
270 " }\n"
271 "}\n";
274 void cmGlobalGhsMultiGenerator::WriteCustomTargetBOD(std::ostream& fout)
276 fout << "FileTypes {\n"
277 " CmakeTarget {\n"
278 " name = \"Custom Target\"\n"
279 " action = \"&Execute\"\n"
280 " grepable = false\n"
281 " outputType = \"None\"\n"
282 " color = \"#800080\"\n"
283 " }\n"
284 "}\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");
310 fout << " ";
311 if (osDirOption.IsOff()) {
312 fout << "";
313 } else {
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));
328 // All known targets
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())) {
335 continue;
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);
359 fout << path;
360 fout << ' ' << *projType << '\n';
364 void cmGlobalGhsMultiGenerator::WriteTargets(cmLocalGenerator* root)
366 std::string rootBinaryDir = root->GetCurrentBinaryDirectory();
368 // All known targets
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())) {
375 continue;
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"));
390 } else {
391 for (auto& tgt : build) {
392 this->WriteProjectLine(fbld, tgt, rootBinaryDir);
395 fbld.Close();
399 void cmGlobalGhsMultiGenerator::Generate()
401 std::string fname;
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);
418 frule.Close();
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);
427 ftarget.Close();
430 void cmGlobalGhsMultiGenerator::OutputTopLevelProject(
431 cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
433 std::string fname;
435 if (generators.empty()) {
436 return;
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);
464 top.Close();
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");
482 } else {
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 */
493 proj = files.at(0);
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");
504 } else {
505 makeCommand.Add(tname + ".tgt.gpj");
507 } else {
508 build_all = true;
511 } else {
512 build_all = true;
515 if (build_all) {
516 /* transform name to default build */;
517 std::string all = std::string(this->GetAllTargetName()) + ".tgt.gpj";
518 makeCommand.Add(all);
521 if (verbose) {
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");
534 if (ghsGpjMacros) {
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)
567 cm::erase(str, '"');
568 return 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) {
578 return false;
580 if (l->GetName() == this->First) {
581 return true;
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);
609 if (r) {
610 return r;
613 return false;
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),
628 "");
629 for (auto const& di : sortedTargets) {
630 if (this->VisitTarget(temp, perm, order, di)) {
631 return true;
634 /* mark as complete; insert into beginning of list*/
635 perm.insert(ti);
636 order.push_back(ti);
637 return false;
639 /* revisiting item - not a DAG */
640 return true;
642 /* already complete */
643 return false;
646 bool cmGlobalGhsMultiGenerator::AddCheckTarget()
648 // Skip the target if no regeneration is to be done.
649 if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
650 return false;
653 // Get the generators.
654 std::vector<std::unique_ptr<cmLocalGenerator>> const& generators =
655 this->LocalGenerators;
656 auto& lg =
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
666 // project.
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,
682 msg.str());
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",
694 this->StampFile }));
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>();
708 cmTarget* tgt =
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));
714 // Add the rule.
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());
726 } else {
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());
735 return true;
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
745 if (!gen.empty()) {
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 ||
767 tgt->IsImported()) {
768 continue;
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
789 * check.
791 this->AddCheckTarget();