1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-06-20 11:47:23 +08:00
CMake/Source/cmGlobalGhsMultiGenerator.cxx
Kyle Edwards 480b363724 cmCustomCommand: Refactor custom command-specific policy values
Many custom commands are created by CMake itself rather than by
the user. These custom commands should always have their policies
set to NEW, and user-created custom commands should have their
policy values set only from the state snapshot. In addition, we
want to genericize the mechanism of recording a policy at the time
of custom command creation.

Add a CM_FOR_EACH_CUSTOM_COMMAND_POLICY macro to genericize
custom command policies. Use this to define all custom command
policies. Make all such policies NEW instead of WARN by default.
Remove individual policy modifier methods and add a single method
that records relevant values from a cmStateSnapshot. Remove the
no longer needed explicit policy settings from synthesized custom
commands.
2023-02-06 15:04:16 -05:00

792 lines
25 KiB
C++

/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmGlobalGhsMultiGenerator.h"
#include <algorithm>
#include <functional>
#include <map>
#include <sstream>
#include <utility>
#include <cm/memory>
#include <cm/string>
#include <cmext/algorithm>
#include <cmext/memory>
#include "cmCustomCommand.h"
#include "cmCustomCommandLines.h"
#include "cmGeneratedFileStream.h"
#include "cmGeneratorTarget.h"
#include "cmGhsMultiGpj.h"
#include "cmLocalGenerator.h"
#include "cmLocalGhsMultiGenerator.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmSourceFile.h"
#include "cmState.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmValue.h"
#include "cmVersion.h"
#include "cmake.h"
const char* cmGlobalGhsMultiGenerator::FILE_EXTENSION = ".gpj";
#ifdef __linux__
const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild";
#elif defined(_WIN32)
const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild.exe";
#endif
const char* cmGlobalGhsMultiGenerator::CHECK_BUILD_SYSTEM_TARGET =
"RERUN_CMAKE";
cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator(cmake* cm)
: cmGlobalGenerator(cm)
{
cm->GetState()->SetGhsMultiIDE(true);
}
cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator() = default;
std::unique_ptr<cmLocalGenerator>
cmGlobalGhsMultiGenerator::CreateLocalGenerator(cmMakefile* mf)
{
return std::unique_ptr<cmLocalGenerator>(
cm::make_unique<cmLocalGhsMultiGenerator>(this, mf));
}
cmDocumentationEntry cmGlobalGhsMultiGenerator::GetDocumentation()
{
return {
GetActualName(),
"Generates Green Hills MULTI files (experimental, work-in-progress)."
};
}
void cmGlobalGhsMultiGenerator::ComputeTargetObjectDirectory(
cmGeneratorTarget* gt) const
{
// Compute full path to object file directory for this target.
std::string dir =
cmStrCat(gt->LocalGenerator->GetCurrentBinaryDirectory(), '/',
gt->LocalGenerator->GetTargetDirectory(gt), '/');
gt->ObjectDirectory = dir;
}
bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts,
bool build, cmMakefile* mf)
{
/* In build mode nothing to be done.
* Toolset already determined and build tool absolute path is cached.
*/
if (build) {
return true;
}
/* Determine the absolute directory for the toolset */
std::string tsp;
this->GetToolset(mf, tsp, ts);
/* no toolset was found */
if (tsp.empty()) {
return false;
}
/* set the build tool to use */
std::string gbuild(tsp + ((tsp.back() == '/') ? "" : "/") +
DEFAULT_BUILD_PROGRAM);
cmValue prevTool = mf->GetDefinition("CMAKE_MAKE_PROGRAM");
/* check if the toolset changed from last generate */
if (cmNonempty(prevTool) && !cmSystemTools::ComparePath(gbuild, *prevTool)) {
std::string const& e =
cmStrCat("toolset build tool: ", gbuild,
"\nDoes not match the previously used build tool: ", *prevTool,
"\nEither remove the CMakeCache.txt file and CMakeFiles "
"directory or choose a different binary directory.");
mf->IssueMessage(MessageType::FATAL_ERROR, e);
return false;
}
/* store the toolset that is being used for this build */
mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", gbuild, "build program to use",
cmStateEnums::INTERNAL, true);
mf->AddDefinition("CMAKE_SYSTEM_VERSION", tsp);
return true;
}
bool cmGlobalGhsMultiGenerator::SetGeneratorPlatform(std::string const& p,
cmMakefile* mf)
{
/* set primary target */
cmValue t = mf->GetDefinition("GHS_PRIMARY_TARGET");
if (cmIsOff(t)) {
/* Use the value from `-A` or use `arm` */
std::string arch = "arm";
if (!cmIsOff(p)) {
arch = p;
}
cmValue platform = mf->GetDefinition("GHS_TARGET_PLATFORM");
std::string tgt = cmStrCat(arch, '_', platform, ".tgt");
/* update the primary target name*/
mf->AddDefinition("GHS_PRIMARY_TARGET", tgt);
}
return true;
}
void cmGlobalGhsMultiGenerator::EnableLanguage(
std::vector<std::string> const& l, cmMakefile* mf, bool optional)
{
mf->AddDefinition("CMAKE_SYSTEM_NAME", "GHS-MULTI");
mf->AddDefinition("GHSMULTI", "1"); // identifier for user CMake files
this->cmGlobalGenerator::EnableLanguage(l, mf, optional);
}
bool cmGlobalGhsMultiGenerator::FindMakeProgram(cmMakefile* /*mf*/)
{
// The GHS generator only knows how to lookup its build tool
// during generation of the project files, but this
// can only be done after the toolset is specified.
return true;
}
void cmGlobalGhsMultiGenerator::GetToolset(cmMakefile* mf, std::string& tsp,
const std::string& ts)
{
/* Determine tsp - full path of the toolset from ts (toolset hint via -T) */
std::string root = mf->GetSafeDefinition("GHS_TOOLSET_ROOT");
// Check if `-T` was set by user
if (ts.empty()) {
// Enter toolset search mode
std::vector<std::string> output;
// Make sure root exists...
if (!cmSystemTools::PathExists(root)) {
std::string msg =
"GHS_TOOLSET_ROOT directory \"" + root + "\" does not exist.";
mf->IssueMessage(MessageType::FATAL_ERROR, msg);
tsp = "";
return;
}
// Add a directory separator
if (root.back() != '/') {
root += "/";
}
// Get all compiler directories in toolset root
cmSystemTools::Glob(root, "comp_[^;]+", output);
if (output.empty()) {
// No compiler directories found
std::string msg =
"No GHS toolsets found in GHS_TOOLSET_ROOT \"" + root + "\".";
mf->IssueMessage(MessageType::FATAL_ERROR, msg);
tsp = "";
} else {
// Use latest? version
tsp = root + output.back();
}
} else {
// Toolset was provided by user
std::string tryPath;
// NOTE: CollapseFullPath() will determine if user toolset was full path or
// or relative path.
tryPath = cmSystemTools::CollapseFullPath(ts, root);
if (!cmSystemTools::FileExists(tryPath)) {
std::string msg = "GHS toolset \"" + tryPath + "\" does not exist.";
mf->IssueMessage(MessageType::FATAL_ERROR, msg);
tsp = "";
} else {
tsp = tryPath;
}
}
}
void cmGlobalGhsMultiGenerator::WriteFileHeader(std::ostream& fout)
{
/* clang-format off */
fout << "#!gbuild\n"
"#\n"
"# CMAKE generated file: DO NOT EDIT!\n"
"# Generated by \"" << GetActualName() << "\""
" Generator, CMake Version " << cmVersion::GetMajorVersion() << '.'
<< cmVersion::GetMinorVersion() << "\n"
"#\n\n";
/* clang-format on */
}
void cmGlobalGhsMultiGenerator::WriteCustomRuleBOD(std::ostream& fout)
{
fout << "Commands {\n"
" Custom_Rule_Command {\n"
" name = \"Custom Rule Command\"\n"
" exec = \""
#ifdef _WIN32
"cmd.exe"
#else
"/bin/sh"
#endif
"\"\n"
" options = {\"SpecialOptions\"}\n"
" }\n"
"}\n"
"\n\n"
"FileTypes {\n"
" CmakeRule {\n"
" name = \"Custom Rule\"\n"
" action = \"&Run\"\n"
" extensions = {\""
#ifdef _WIN32
"bat"
#else
"sh"
#endif
"\"}\n"
" grepable = false\n"
" command = \"Custom Rule Command\"\n"
" commandLine = \"$COMMAND "
#ifdef _WIN32
"/c"
#endif
" $INPUTFILE\"\n"
" progress = \"Processing Custom Rule\"\n"
" promoteToFirstPass = true\n"
" outputType = \"None\"\n"
" color = \"#800080\"\n"
" }\n"
"}\n";
}
void cmGlobalGhsMultiGenerator::WriteCustomTargetBOD(std::ostream& fout)
{
fout << "FileTypes {\n"
" CmakeTarget {\n"
" name = \"Custom Target\"\n"
" action = \"&Execute\"\n"
" grepable = false\n"
" outputType = \"None\"\n"
" color = \"#800080\"\n"
" }\n"
"}\n";
}
void cmGlobalGhsMultiGenerator::WriteTopLevelProject(std::ostream& fout,
cmLocalGenerator* root)
{
this->WriteFileHeader(fout);
this->WriteMacros(fout, root);
this->WriteHighLevelDirectives(fout, root);
GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fout);
fout << "# Top Level Project File\n";
// Specify BSP option if supplied by user
// -- not all platforms require this entry in the project file
cmValue bspName = root->GetMakefile()->GetDefinition("GHS_BSP_NAME");
if (!cmIsOff(bspName)) {
fout << " -bsp " << *bspName << '\n';
}
// Specify OS DIR if supplied by user
// -- not all platforms require this entry in the project file
cmValue osDir = root->GetMakefile()->GetDefinition("GHS_OS_DIR");
if (!cmIsOff(osDir)) {
cmValue osDirOption =
root->GetMakefile()->GetDefinition("GHS_OS_DIR_OPTION");
fout << " ";
if (cmIsOff(osDirOption)) {
fout << "";
} else {
fout << *osDirOption;
}
fout << "\"" << osDir << "\"\n";
}
}
void cmGlobalGhsMultiGenerator::WriteSubProjects(std::ostream& fout,
bool filterPredefined)
{
std::set<std::string> predefinedTargets;
predefinedTargets.insert(this->GetInstallTargetName());
predefinedTargets.insert(this->GetAllTargetName());
predefinedTargets.insert(std::string(CHECK_BUILD_SYSTEM_TARGET));
// All known targets
for (cmGeneratorTarget const* target : this->ProjectTargets) {
if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
target->GetType() == cmStateEnums::MODULE_LIBRARY ||
target->GetType() == cmStateEnums::SHARED_LIBRARY ||
(target->GetType() == cmStateEnums::GLOBAL_TARGET &&
target->GetName() != this->GetInstallTargetName())) {
continue;
}
/* Check if the current target is a predefined CMake target */
bool predefinedTarget =
predefinedTargets.find(target->GetName()) != predefinedTargets.end();
if ((filterPredefined && predefinedTarget) ||
(!filterPredefined && !predefinedTarget)) {
fout << target->GetName() + ".tgt" + FILE_EXTENSION << " [Project]\n";
}
}
}
void cmGlobalGhsMultiGenerator::WriteProjectLine(
std::ostream& fout, cmGeneratorTarget const* target,
std::string& rootBinaryDir)
{
cmValue projFile = target->GetProperty("GENERATOR_FILE_NAME");
cmValue projType = target->GetProperty("GENERATOR_FILE_NAME_EXT");
/* If either value is not valid then this particular target is an
* unsupported target type and should be skipped.
*/
if (projFile && projType) {
std::string path = cmSystemTools::RelativePath(rootBinaryDir, *projFile);
fout << path;
fout << ' ' << *projType << '\n';
}
}
void cmGlobalGhsMultiGenerator::WriteTargets(cmLocalGenerator* root)
{
std::string rootBinaryDir = root->GetCurrentBinaryDirectory();
// All known targets
for (cmGeneratorTarget const* target : this->ProjectTargets) {
if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
target->GetType() == cmStateEnums::MODULE_LIBRARY ||
target->GetType() == cmStateEnums::SHARED_LIBRARY ||
(target->GetType() == cmStateEnums::GLOBAL_TARGET &&
target->GetName() != this->GetInstallTargetName())) {
continue;
}
// create target build file
std::string name = cmStrCat(target->GetName(), ".tgt", FILE_EXTENSION);
std::string fname = cmStrCat(rootBinaryDir, "/", name);
cmGeneratedFileStream fbld(fname);
fbld.SetCopyIfDifferent(true);
this->WriteFileHeader(fbld);
GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fbld);
std::vector<cmGeneratorTarget const*> build;
if (this->ComputeTargetBuildOrder(target, build)) {
cmSystemTools::Error(
cmStrCat("The inter-target dependency graph for target [",
target->GetName(), "] had a cycle.\n"));
} else {
for (auto& tgt : build) {
this->WriteProjectLine(fbld, tgt, rootBinaryDir);
}
}
fbld.Close();
}
}
void cmGlobalGhsMultiGenerator::Generate()
{
std::string fname;
// first do the superclass method
this->cmGlobalGenerator::Generate();
// output top-level projects
for (auto& it : this->ProjectMap) {
this->OutputTopLevelProject(it.second[0], it.second);
}
// create custom rule BOD file
fname = this->GetCMakeInstance()->GetHomeOutputDirectory() +
"/CMakeFiles/custom_rule.bod";
cmGeneratedFileStream frule(fname);
frule.SetCopyIfDifferent(true);
this->WriteFileHeader(frule);
this->WriteCustomRuleBOD(frule);
frule.Close();
// create custom target BOD file
fname = this->GetCMakeInstance()->GetHomeOutputDirectory() +
"/CMakeFiles/custom_target.bod";
cmGeneratedFileStream ftarget(fname);
ftarget.SetCopyIfDifferent(true);
this->WriteFileHeader(ftarget);
this->WriteCustomTargetBOD(ftarget);
ftarget.Close();
}
void cmGlobalGhsMultiGenerator::OutputTopLevelProject(
cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
{
std::string fname;
if (generators.empty()) {
return;
}
// Collect all targets under this root generator and the transitive
// closure of their dependencies.
TargetDependSet projectTargets;
TargetDependSet originalTargets;
this->GetTargetSets(projectTargets, originalTargets, root, generators);
OrderedTargetDependSet sortedProjectTargets(projectTargets, "");
this->ProjectTargets.clear();
for (cmGeneratorTarget const* t : sortedProjectTargets) {
/* save list of all targets in sorted order */
this->ProjectTargets.push_back(t);
}
/* Name top-level projects as filename.top.gpj to avoid name clashes
* with target projects. This avoid the issue where the project has
* the same name as the executable target.
*/
fname = cmStrCat(root->GetCurrentBinaryDirectory(), '/',
root->GetProjectName(), ".top", FILE_EXTENSION);
cmGeneratedFileStream top(fname);
top.SetCopyIfDifferent(true);
this->WriteTopLevelProject(top, root);
this->WriteTargets(root);
this->WriteSubProjects(top, true);
this->WriteSubProjects(top, false);
top.Close();
}
std::vector<cmGlobalGenerator::GeneratedMakeCommand>
cmGlobalGhsMultiGenerator::GenerateBuildCommand(
const std::string& makeProgram, const std::string& projectName,
const std::string& projectDir, std::vector<std::string> const& targetNames,
const std::string& /*config*/, int jobs, bool verbose,
const cmBuildOptions& /*buildOptions*/,
std::vector<std::string> const& makeOptions)
{
GeneratedMakeCommand makeCommand;
makeCommand.Add(this->SelectMakeProgram(makeProgram));
if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
makeCommand.Add("-parallel");
} else {
makeCommand.Add(std::string("-parallel=") + std::to_string(jobs));
}
}
/* determine the top-project file in the project directory */
std::string proj = projectName + ".top" + FILE_EXTENSION;
std::vector<std::string> files;
cmSystemTools::Glob(projectDir, ".*\\.top\\.gpj", files);
if (!files.empty()) {
/* use the real top-level project in the directory */
proj = files.at(0);
}
makeCommand.Add("-top", proj);
/* determine targets to build */
bool build_all = false;
if (!targetNames.empty()) {
for (const auto& tname : targetNames) {
if (!tname.empty()) {
if (tname == "clean") {
makeCommand.Add("-clean");
} else {
makeCommand.Add(tname + ".tgt.gpj");
}
} else {
build_all = true;
}
}
} else {
build_all = true;
}
if (build_all) {
/* transform name to default build */;
std::string all = std::string(this->GetAllTargetName()) + ".tgt.gpj";
makeCommand.Add(all);
}
if (verbose) {
makeCommand.Add("-commands");
}
makeCommand.Add(makeOptions.begin(), makeOptions.end());
return { std::move(makeCommand) };
}
void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout,
cmLocalGenerator* root)
{
fout << "macro PROJ_NAME=" << root->GetProjectName() << '\n';
cmValue ghsGpjMacros = root->GetMakefile()->GetDefinition("GHS_GPJ_MACROS");
if (ghsGpjMacros) {
std::vector<std::string> expandedList = cmExpandedList(*ghsGpjMacros);
for (std::string const& arg : expandedList) {
fout << "macro " << arg << '\n';
}
}
}
void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(
std::ostream& fout, cmLocalGenerator* root)
{
/* put primary target and customization files into project file */
cmValue const tgt = root->GetMakefile()->GetDefinition("GHS_PRIMARY_TARGET");
/* clang-format off */
fout << "primaryTarget=" << tgt << "\n"
"customization=" << root->GetBinaryDirectory()
<< "/CMakeFiles/custom_rule.bod\n"
"customization=" << root->GetBinaryDirectory()
<< "/CMakeFiles/custom_target.bod" << '\n';
/* clang-format on */
cmValue const customization =
root->GetMakefile()->GetDefinition("GHS_CUSTOMIZATION");
if (cmNonempty(customization)) {
fout << "customization="
<< cmGlobalGhsMultiGenerator::TrimQuotes(*customization) << '\n';
this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION");
}
}
std::string cmGlobalGhsMultiGenerator::TrimQuotes(std::string str)
{
cm::erase(str, '"');
return str;
}
bool cmGlobalGhsMultiGenerator::TargetCompare::operator()(
cmGeneratorTarget const* l, cmGeneratorTarget const* r) const
{
// Make sure a given named target is ordered first,
// e.g. to set ALL_BUILD as the default active project.
// When the empty string is named this is a no-op.
if (r->GetName() == this->First) {
return false;
}
if (l->GetName() == this->First) {
return true;
}
return l->GetName() < r->GetName();
}
cmGlobalGhsMultiGenerator::OrderedTargetDependSet::OrderedTargetDependSet(
TargetDependSet const& targets, std::string const& first)
: derived(TargetCompare(first))
{
this->insert(targets.begin(), targets.end());
}
bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder(
cmGeneratorTarget const* tgt, std::vector<cmGeneratorTarget const*>& build)
{
std::vector<cmGeneratorTarget const*> t{ tgt };
return this->ComputeTargetBuildOrder(t, build);
}
bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder(
std::vector<cmGeneratorTarget const*>& tgt,
std::vector<cmGeneratorTarget const*>& build)
{
std::set<cmGeneratorTarget const*> temp;
std::set<cmGeneratorTarget const*> perm;
for (const auto* const ti : tgt) {
bool r = this->VisitTarget(temp, perm, build, ti);
if (r) {
return r;
}
}
return false;
}
bool cmGlobalGhsMultiGenerator::VisitTarget(
std::set<cmGeneratorTarget const*>& temp,
std::set<cmGeneratorTarget const*>& perm,
std::vector<cmGeneratorTarget const*>& order, cmGeneratorTarget const* ti)
{
/* check if permanent mark is set*/
if (perm.find(ti) == perm.end()) {
/* set temporary mark; check if revisit*/
if (temp.insert(ti).second) {
/* sort targets lexicographically to ensure that nodes are always visited
* in the same order */
OrderedTargetDependSet sortedTargets(this->GetTargetDirectDepends(ti),
"");
for (auto const& di : sortedTargets) {
if (this->VisitTarget(temp, perm, order, di)) {
return true;
}
}
/* mark as complete; insert into beginning of list*/
perm.insert(ti);
order.push_back(ti);
return false;
}
/* revisiting item - not a DAG */
return true;
}
/* already complete */
return false;
}
bool cmGlobalGhsMultiGenerator::AddCheckTarget()
{
// Skip the target if no regeneration is to be done.
if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
return false;
}
// Get the generators.
std::vector<std::unique_ptr<cmLocalGenerator>> const& generators =
this->LocalGenerators;
auto& lg =
cm::static_reference_cast<cmLocalGhsMultiGenerator>(generators[0]);
// The name of the output file for the custom command.
this->StampFile = lg.GetBinaryDirectory() + std::string("/CMakeFiles/") +
CHECK_BUILD_SYSTEM_TARGET;
// Add a custom rule to re-run CMake if any input files changed.
{
// Collect the input files used to generate all targets in this
// project.
std::vector<std::string> listFiles;
for (const auto& gen : generators) {
cm::append(listFiles, gen->GetMakefile()->GetListFiles());
}
// Add the cache file.
listFiles.push_back(cmStrCat(
this->GetCMakeInstance()->GetHomeOutputDirectory(), "/CMakeCache.txt"));
// Print not implemented warning.
if (this->GetCMakeInstance()->DoWriteGlobVerifyTarget()) {
std::ostringstream msg;
msg << "Any pre-check scripts, such as those generated for file(GLOB "
"CONFIGURE_DEPENDS), will not be run by gbuild.";
this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
msg.str());
}
// Sort the list of input files and remove duplicates.
std::sort(listFiles.begin(), listFiles.end(), std::less<std::string>());
auto newEnd = std::unique(listFiles.begin(), listFiles.end());
listFiles.erase(newEnd, listFiles.end());
// Create a rule to re-run CMake and create output file.
cmCustomCommandLines commandLines;
commandLines.emplace_back(
cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E", "rm", "-f",
this->StampFile }));
std::string argS = cmStrCat("-S", lg.GetSourceDirectory());
std::string argB = cmStrCat("-B", lg.GetBinaryDirectory());
commandLines.emplace_back(
cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), argS, argB }));
commandLines.emplace_back(cmMakeCommandLine(
{ cmSystemTools::GetCMakeCommand(), "-E", "touch", this->StampFile }));
/* Create the target(Exclude from ALL_BUILD).
*
* The build tool, currently, does not support rereading the project files
* if they get updated. So do not run this target as part of ALL_BUILD.
*/
auto cc = cm::make_unique<cmCustomCommand>();
cmTarget* tgt =
lg.AddUtilityCommand(CHECK_BUILD_SYSTEM_TARGET, true, std::move(cc));
auto ptr = cm::make_unique<cmGeneratorTarget>(tgt, &lg);
auto* gt = ptr.get();
lg.AddGeneratorTarget(std::move(ptr));
// Add the rule.
cc = cm::make_unique<cmCustomCommand>();
cc->SetOutputs(this->StampFile);
cc->SetDepends(listFiles);
cc->SetCommandLines(commandLines);
cc->SetComment("Checking Build System");
cc->SetEscapeOldStyle(false);
cc->SetStdPipesUTF8(true);
if (cmSourceFile* file =
lg.AddCustomCommandToOutput(std::move(cc), true)) {
gt->AddSource(file->ResolveFullPath());
} else {
cmSystemTools::Error("Error adding rule for " + this->StampFile);
}
// Organize in the "predefined targets" folder:
if (this->UseFolderProperty()) {
tgt->SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
}
}
return true;
}
void cmGlobalGhsMultiGenerator::AddAllTarget()
{
// Add a special target that depends on ALL projects for easy build
// of one configuration only.
for (auto const& it : this->ProjectMap) {
std::vector<cmLocalGenerator*> const& gen = it.second;
// add the ALL_BUILD to the first local generator of each project
if (!gen.empty()) {
// Use no actual command lines so that the target itself is not
// considered always out of date.
auto cc = cm::make_unique<cmCustomCommand>();
cc->SetEscapeOldStyle(false);
cc->SetComment("Build all projects");
cmTarget* allBuild = gen[0]->AddUtilityCommand(this->GetAllTargetName(),
true, std::move(cc));
gen[0]->AddGeneratorTarget(
cm::make_unique<cmGeneratorTarget>(allBuild, gen[0]));
// Organize in the "predefined targets" folder:
if (this->UseFolderProperty()) {
allBuild->SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
}
// Now make all targets depend on the ALL_BUILD target
for (cmLocalGenerator const* i : gen) {
for (const auto& tgt : i->GetGeneratorTargets()) {
// Skip global or imported targets
if (tgt->GetType() == cmStateEnums::GLOBAL_TARGET ||
tgt->IsImported()) {
continue;
}
// Skip Exclude From All Targets
if (!this->IsExcluded(gen[0], tgt.get())) {
allBuild->AddUtility(tgt->GetName(), false);
}
}
}
}
}
}
void cmGlobalGhsMultiGenerator::AddExtraIDETargets()
{
// Add a special target that depends on ALL projects.
this->AddAllTarget();
/* Add Custom Target to check if CMake needs to be rerun.
*
* The build tool, currently, does not support rereading the project files
* if they get updated. So do not make the other targets dependent on this
* check.
*/
this->AddCheckTarget();
}