summaryrefslogtreecommitdiffstats
path: root/Source/cmMakefile.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmMakefile.cxx')
-rw-r--r--Source/cmMakefile.cxx828
1 files changed, 495 insertions, 333 deletions
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index f143ef7..dc741d3 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -7,6 +7,7 @@
#include <algorithm>
#include <cassert>
#include <cctype>
+#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
@@ -15,10 +16,15 @@
#include <cm/iterator>
#include <cm/memory>
+#include <cm/optional>
+#include <cm/vector>
+#include <cmext/algorithm>
#include "cmsys/FStream.hxx"
#include "cmsys/RegularExpression.hxx"
+#include "cm_jsoncpp_value.h"
+#include "cm_jsoncpp_writer.h"
#include "cm_sys_stat.h"
#include "cmAlgorithms.h"
@@ -36,6 +42,7 @@
#include "cmInstallGenerator.h" // IWYU pragma: keep
#include "cmInstallSubdirectoryGenerator.h"
#include "cmListFileCache.h"
+#include "cmLocalGenerator.h"
#include "cmMessageType.h"
#include "cmRange.h"
#include "cmSourceFile.h"
@@ -117,15 +124,7 @@ cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator,
#endif
}
-cmMakefile::~cmMakefile()
-{
- cmDeleteAll(this->InstallGenerators);
- cmDeleteAll(this->TestGenerators);
- cmDeleteAll(this->SourceFiles);
- cmDeleteAll(this->Tests);
- cmDeleteAll(this->ImportedTargetsOwned);
- cmDeleteAll(this->EvaluationFiles);
-}
+cmMakefile::~cmMakefile() = default;
cmDirectoryId cmMakefile::GetDirectoryId() const
{
@@ -133,7 +132,7 @@ cmDirectoryId cmMakefile::GetDirectoryId() const
// If we ever need to expose this to CMake language code we should
// add a read-only property in cmMakefile::GetProperty.
char buf[32];
- sprintf(buf, "<%p>",
+ sprintf(buf, "(%p)",
static_cast<void const*>(this)); // cast avoids format warning
return std::string(buf);
}
@@ -146,7 +145,7 @@ void cmMakefile::IssueMessage(MessageType t, std::string const& text) const
this->ExecutionStatusStack.back()->SetNestedError();
}
}
- this->GetCMakeInstance()->IssueMessage(t, text, this->GetBacktrace());
+ this->GetCMakeInstance()->IssueMessage(t, text, this->Backtrace);
}
bool cmMakefile::CheckCMP0037(std::string const& targetName,
@@ -313,21 +312,51 @@ void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const
}
std::ostringstream msg;
- msg << full_path << "(" << lff.Line << "): ";
- msg << lff.Name.Original << "(";
- bool expand = this->GetCMakeInstance()->GetTraceExpand();
+ std::vector<std::string> args;
std::string temp;
+ bool expand = this->GetCMakeInstance()->GetTraceExpand();
+
+ args.reserve(lff.Arguments.size());
for (cmListFileArgument const& arg : lff.Arguments) {
if (expand) {
temp = arg.Value;
this->ExpandVariablesInString(temp);
- msg << temp;
+ args.push_back(temp);
} else {
- msg << arg.Value;
+ args.push_back(arg.Value);
}
- msg << " ";
}
- msg << ")";
+
+ switch (this->GetCMakeInstance()->GetTraceFormat()) {
+ case cmake::TraceFormat::TRACE_JSON_V1: {
+#ifndef CMAKE_BOOTSTRAP
+ Json::Value val;
+ Json::StreamWriterBuilder builder;
+ builder["indentation"] = "";
+ val["file"] = full_path;
+ val["line"] = static_cast<std::int64_t>(lff.Line);
+ val["cmd"] = lff.Name.Original;
+ val["args"] = Json::Value(Json::arrayValue);
+ for (std::string const& arg : args) {
+ val["args"].append(arg);
+ }
+ msg << Json::writeString(builder, val);
+#endif
+ break;
+ }
+ case cmake::TraceFormat::TRACE_HUMAN:
+ msg << full_path << "(" << lff.Line << "): ";
+ msg << lff.Name.Original << "(";
+
+ for (std::string const& arg : args) {
+ msg << arg << " ";
+ }
+ msg << ")";
+ break;
+ case cmake::TraceFormat::TRACE_UNDEFINED:
+ msg << "INTERNAL ERROR: Trace format is TRACE_UNDEFINED";
+ break;
+ }
auto& f = this->GetCMakeInstance()->GetTraceFile();
if (f) {
@@ -737,12 +766,13 @@ void cmMakefile::AddEvaluationFile(
std::unique_ptr<cmCompiledGeneratorExpression> condition,
bool inputIsContent)
{
- this->EvaluationFiles.push_back(new cmGeneratorExpressionEvaluationFile(
- inputFile, std::move(outputName), std::move(condition), inputIsContent,
- this->GetPolicyStatus(cmPolicies::CMP0070)));
+ this->EvaluationFiles.push_back(
+ cm::make_unique<cmGeneratorExpressionEvaluationFile>(
+ inputFile, std::move(outputName), std::move(condition), inputIsContent,
+ this->GetPolicyStatus(cmPolicies::CMP0070)));
}
-std::vector<cmGeneratorExpressionEvaluationFile*>
+const std::vector<std::unique_ptr<cmGeneratorExpressionEvaluationFile>>&
cmMakefile::GetEvaluationFiles() const
{
return this->EvaluationFiles;
@@ -780,38 +810,42 @@ struct file_not_persistent
};
}
-void cmMakefile::AddFinalAction(FinalAction action)
+void cmMakefile::AddGeneratorAction(GeneratorAction action)
{
- this->FinalActions.push_back(std::move(action));
+ assert(!this->GeneratorActionsInvoked);
+ this->GeneratorActions.emplace_back(std::move(action), this->Backtrace);
}
-void cmMakefile::FinalPass()
+void cmMakefile::DoGenerate(cmLocalGenerator& lg)
{
// do all the variable expansions here
this->ExpandVariablesCMP0019();
// give all the commands a chance to do something
// after the file has been parsed before generation
- for (FinalAction& action : this->FinalActions) {
- action(*this);
+ for (const BT<GeneratorAction>& action : this->GeneratorActions) {
+ action.Value(lg, action.Backtrace);
}
+ this->GeneratorActionsInvoked = true;
+ this->DelayedOutputFiles.clear();
+ this->DelayedOutputFilesHaveGenex = false;
// go through all configured files and see which ones still exist.
// we don't want cmake to re-run if a configured file is created and deleted
// during processing as that would make it a transient file that can't
// influence the build process
- cmEraseIf(this->OutputFiles, file_not_persistent());
+ cm::erase_if(this->OutputFiles, file_not_persistent());
// if a configured file is used as input for another configured file,
// and then deleted it will show up in the input list files so we
// need to scan those too
- cmEraseIf(this->ListFiles, file_not_persistent());
+ cm::erase_if(this->ListFiles, file_not_persistent());
}
// Generate the output file
-void cmMakefile::ConfigureFinalPass()
+void cmMakefile::Generate(cmLocalGenerator& lg)
{
- this->FinalPass();
+ this->DoGenerate(lg);
const char* oldValue = this->GetDefinition("CMAKE_BACKWARDS_COMPATIBILITY");
if (oldValue &&
cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, oldValue, "2.4")) {
@@ -825,6 +859,39 @@ void cmMakefile::ConfigureFinalPass()
}
}
+namespace {
+// There are still too many implicit backtraces through cmMakefile. As a
+// workaround we reset the backtrace temporarily.
+struct BacktraceGuard
+{
+ BacktraceGuard(cmListFileBacktrace& lfbt, cmListFileBacktrace current)
+ : Backtrace(lfbt)
+ , Previous(lfbt)
+ {
+ this->Backtrace = std::move(current);
+ }
+
+ ~BacktraceGuard() { this->Backtrace = std::move(Previous); }
+
+private:
+ cmListFileBacktrace& Backtrace;
+ cmListFileBacktrace Previous;
+};
+
+cm::optional<std::string> MakeOptionalString(const char* str)
+{
+ if (str) {
+ return str;
+ }
+ return cm::nullopt;
+}
+
+const char* GetCStrOrNull(const cm::optional<std::string>& str)
+{
+ return str ? str->c_str() : nullptr;
+}
+}
+
bool cmMakefile::ValidateCustomCommand(
const cmCustomCommandLines& commandLines) const
{
@@ -842,7 +909,8 @@ bool cmMakefile::ValidateCustomCommand(
}
cmTarget* cmMakefile::GetCustomCommandTarget(
- const std::string& target, cmObjectLibraryCommands objLibCommands) const
+ const std::string& target, cmObjectLibraryCommands objLibCommands,
+ const cmListFileBacktrace& lfbt) const
{
// Find the target to which to add the custom command.
auto ti = this->Targets.find(target);
@@ -876,7 +944,7 @@ cmTarget* cmMakefile::GetCustomCommandTarget(
e << "No TARGET '" << target
<< "' has been created in this directory.";
}
- this->IssueMessage(messageType, e.str());
+ this->GetCMakeInstance()->IssueMessage(messageType, e.str(), lfbt);
}
return nullptr;
@@ -889,7 +957,8 @@ cmTarget* cmMakefile::GetCustomCommandTarget(
e << "Target \"" << target
<< "\" is an OBJECT library "
"that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
- this->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(),
+ lfbt);
return nullptr;
}
if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
@@ -897,7 +966,8 @@ cmTarget* cmMakefile::GetCustomCommandTarget(
e << "Target \"" << target
<< "\" is an INTERFACE library "
"that may not have PRE_BUILD, PRE_LINK, or POST_BUILD commands.";
- this->IssueMessage(MessageType::FATAL_ERROR, e.str());
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e.str(),
+ lfbt);
return nullptr;
}
@@ -910,9 +980,10 @@ cmTarget* cmMakefile::AddCustomCommandToTarget(
const cmCustomCommandLines& commandLines, cmCustomCommandType type,
const char* comment, const char* workingDir, bool escapeOldStyle,
bool uses_terminal, const std::string& depfile, const std::string& job_pool,
- bool command_expand_lists, cmObjectLibraryCommands objLibCommands)
+ bool command_expand_lists)
{
- cmTarget* t = this->GetCustomCommandTarget(target, objLibCommands);
+ cmTarget* t = this->GetCustomCommandTarget(
+ target, cmObjectLibraryCommands::Reject, this->Backtrace);
// Validate custom commands.
if (!t || !this->ValidateCustomCommand(commandLines)) {
@@ -920,175 +991,83 @@ cmTarget* cmMakefile::AddCustomCommandToTarget(
}
// Always create the byproduct sources and mark them generated.
- this->CreateGeneratedSources(byproducts);
-
- this->CommitCustomCommandToTarget(
- t, byproducts, depends, commandLines, type, comment, workingDir,
- escapeOldStyle, uses_terminal, depfile, job_pool, command_expand_lists);
+ this->CreateGeneratedByproducts(byproducts);
+
+ // Strings could be moved into the callback function with C++14.
+ cm::optional<std::string> commentStr = MakeOptionalString(comment);
+ cm::optional<std::string> workingStr = MakeOptionalString(workingDir);
+
+ // Dispatch command creation to allow generator expressions in outputs.
+ this->AddGeneratorAction([=](cmLocalGenerator& lg,
+ const cmListFileBacktrace& lfbt) {
+ BacktraceGuard guard(this->Backtrace, lfbt);
+ detail::AddCustomCommandToTarget(
+ lg, lfbt, cmCommandOrigin::Project, t, byproducts, depends, commandLines,
+ type, GetCStrOrNull(commentStr), GetCStrOrNull(workingStr),
+ escapeOldStyle, uses_terminal, depfile, job_pool, command_expand_lists);
+ });
return t;
}
-void cmMakefile::CommitCustomCommandToTarget(
- cmTarget* target, const std::vector<std::string>& byproducts,
- const std::vector<std::string>& depends,
- const cmCustomCommandLines& commandLines, cmCustomCommandType type,
- const char* comment, const char* workingDir, bool escapeOldStyle,
- bool uses_terminal, const std::string& depfile, const std::string& job_pool,
- bool command_expand_lists)
-{
- // Add the command to the appropriate build step for the target.
- std::vector<std::string> no_output;
- cmCustomCommand cc(this, no_output, byproducts, depends, commandLines,
- comment, workingDir);
- cc.SetEscapeOldStyle(escapeOldStyle);
- cc.SetEscapeAllowMakeVars(true);
- cc.SetUsesTerminal(uses_terminal);
- cc.SetCommandExpandLists(command_expand_lists);
- cc.SetDepfile(depfile);
- cc.SetJobPool(job_pool);
- switch (type) {
- case cmCustomCommandType::PRE_BUILD:
- target->AddPreBuildCommand(std::move(cc));
- break;
- case cmCustomCommandType::PRE_LINK:
- target->AddPreLinkCommand(std::move(cc));
- break;
- case cmCustomCommandType::POST_BUILD:
- target->AddPostBuildCommand(std::move(cc));
- break;
- }
-
- this->AddTargetByproducts(target, byproducts);
-}
-
-cmSourceFile* cmMakefile::AddCustomCommandToOutput(
+void cmMakefile::AddCustomCommandToOutput(
const std::string& output, const std::vector<std::string>& depends,
const std::string& main_dependency, const cmCustomCommandLines& commandLines,
- const char* comment, const char* workingDir, bool replace,
- bool escapeOldStyle, bool uses_terminal, bool command_expand_lists,
- const std::string& depfile, const std::string& job_pool)
+ const char* comment, const char* workingDir,
+ const CommandSourceCallback& callback, bool replace, bool escapeOldStyle,
+ bool uses_terminal, bool command_expand_lists, const std::string& depfile,
+ const std::string& job_pool)
{
- std::vector<std::string> outputs;
- outputs.push_back(output);
std::vector<std::string> no_byproducts;
cmImplicitDependsList no_implicit_depends;
- return this->AddCustomCommandToOutput(
- outputs, no_byproducts, depends, main_dependency, no_implicit_depends,
- commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal,
- command_expand_lists, depfile, job_pool);
+ this->AddCustomCommandToOutput(
+ { output }, no_byproducts, depends, main_dependency, no_implicit_depends,
+ commandLines, comment, workingDir, callback, replace, escapeOldStyle,
+ uses_terminal, command_expand_lists, depfile, job_pool);
}
-cmSourceFile* cmMakefile::AddCustomCommandToOutput(
+void cmMakefile::AddCustomCommandToOutput(
const std::vector<std::string>& outputs,
const std::vector<std::string>& byproducts,
const std::vector<std::string>& depends, const std::string& main_dependency,
const cmImplicitDependsList& implicit_depends,
const cmCustomCommandLines& commandLines, const char* comment,
- const char* workingDir, bool replace, bool escapeOldStyle,
- bool uses_terminal, bool command_expand_lists, const std::string& depfile,
- const std::string& job_pool)
+ const char* workingDir, const CommandSourceCallback& callback, bool replace,
+ bool escapeOldStyle, bool uses_terminal, bool command_expand_lists,
+ const std::string& depfile, const std::string& job_pool)
{
// Make sure there is at least one output.
if (outputs.empty()) {
cmSystemTools::Error("Attempt to add a custom rule with no output!");
- return nullptr;
+ return;
}
// Validate custom commands.
if (!this->ValidateCustomCommand(commandLines)) {
- return nullptr;
+ return;
}
// Always create the output sources and mark them generated.
- this->CreateGeneratedSources(outputs);
- this->CreateGeneratedSources(byproducts);
-
- return this->CommitCustomCommandToOutput(
- outputs, byproducts, depends, main_dependency, implicit_depends,
- commandLines, comment, workingDir, replace, escapeOldStyle, uses_terminal,
- command_expand_lists, depfile, job_pool);
-}
-
-cmSourceFile* cmMakefile::CommitCustomCommandToOutput(
- const std::vector<std::string>& outputs,
- const std::vector<std::string>& byproducts,
- const std::vector<std::string>& depends, const std::string& main_dependency,
- const cmImplicitDependsList& implicit_depends,
- const cmCustomCommandLines& commandLines, const char* comment,
- const char* workingDir, bool replace, bool escapeOldStyle,
- bool uses_terminal, bool command_expand_lists, const std::string& depfile,
- const std::string& job_pool)
-{
- // Choose a source file on which to store the custom command.
- cmSourceFile* file = nullptr;
- if (!commandLines.empty() && !main_dependency.empty()) {
- // The main dependency was specified. Use it unless a different
- // custom command already used it.
- file = this->GetSource(main_dependency);
- if (file && file->GetCustomCommand() && !replace) {
- // The main dependency already has a custom command.
- if (commandLines == file->GetCustomCommand()->GetCommandLines()) {
- // The existing custom command is identical. Silently ignore
- // the duplicate.
- return file;
- }
- // The existing custom command is different. We need to
- // generate a rule file for this new command.
- file = nullptr;
- } else if (!file) {
- file = this->CreateSource(main_dependency);
- }
- }
-
- // Generate a rule file if the main dependency is not available.
- if (!file) {
- cmGlobalGenerator* gg = this->GetGlobalGenerator();
-
- // Construct a rule file associated with the first output produced.
- std::string outName = gg->GenerateRuleFile(outputs[0]);
-
- // Check if the rule file already exists.
- file = this->GetSource(outName, cmSourceFileLocationKind::Known);
- if (file && file->GetCustomCommand() && !replace) {
- // The rule file already exists.
- if (commandLines != file->GetCustomCommand()->GetCommandLines()) {
- cmSystemTools::Error("Attempt to add a custom rule to output \"" +
- outName + "\" which already has a custom rule.");
- }
- return file;
+ this->CreateGeneratedOutputs(outputs);
+ this->CreateGeneratedByproducts(byproducts);
+
+ // Strings could be moved into the callback function with C++14.
+ cm::optional<std::string> commentStr = MakeOptionalString(comment);
+ cm::optional<std::string> workingStr = MakeOptionalString(workingDir);
+
+ // Dispatch command creation to allow generator expressions in outputs.
+ this->AddGeneratorAction([=](cmLocalGenerator& lg,
+ const cmListFileBacktrace& lfbt) {
+ BacktraceGuard guard(this->Backtrace, lfbt);
+ cmSourceFile* sf = detail::AddCustomCommandToOutput(
+ lg, lfbt, cmCommandOrigin::Project, outputs, byproducts, depends,
+ main_dependency, implicit_depends, commandLines,
+ GetCStrOrNull(commentStr), GetCStrOrNull(workingStr), replace,
+ escapeOldStyle, uses_terminal, command_expand_lists, depfile, job_pool);
+ if (callback && sf) {
+ callback(sf);
}
-
- // Create a cmSourceFile for the rule file.
- if (!file) {
- file =
- this->CreateSource(outName, true, cmSourceFileLocationKind::Known);
- }
- file->SetProperty("__CMAKE_RULE", "1");
- }
-
- // Attach the custom command to the file.
- if (file) {
- // Construct a complete list of dependencies.
- std::vector<std::string> depends2(depends);
- if (!main_dependency.empty()) {
- depends2.push_back(main_dependency);
- }
-
- std::unique_ptr<cmCustomCommand> cc = cm::make_unique<cmCustomCommand>(
- this, outputs, byproducts, depends2, commandLines, comment, workingDir);
- cc->SetEscapeOldStyle(escapeOldStyle);
- cc->SetEscapeAllowMakeVars(true);
- cc->SetImplicitDepends(implicit_depends);
- cc->SetUsesTerminal(uses_terminal);
- cc->SetCommandExpandLists(command_expand_lists);
- cc->SetDepfile(depfile);
- cc->SetJobPool(job_pool);
- file->SetCustomCommand(std::move(cc));
-
- this->AddSourceOutputs(file, outputs, byproducts);
- }
- return file;
+ });
}
void cmMakefile::AddCustomCommandOldStyle(
@@ -1136,11 +1115,8 @@ void cmMakefile::AddCustomCommandOldStyle(
if (sourceFiles.find(source)) {
// The source looks like a real file. Use it as the main dependency.
for (std::string const& output : outputs) {
- cmSourceFile* sf = this->AddCustomCommandToOutput(
- output, depends, source, commandLines, comment, nullptr);
- if (sf) {
- addRuleFileToTarget(sf);
- }
+ this->AddCustomCommandToOutput(output, depends, source, commandLines,
+ comment, nullptr, addRuleFileToTarget);
}
} else {
std::string no_main_dependency;
@@ -1149,11 +1125,9 @@ void cmMakefile::AddCustomCommandOldStyle(
// The source may not be a real file. Do not use a main dependency.
for (std::string const& output : outputs) {
- cmSourceFile* sf = this->AddCustomCommandToOutput(
- output, depends2, no_main_dependency, commandLines, comment, nullptr);
- if (sf) {
- addRuleFileToTarget(sf);
- }
+ this->AddCustomCommandToOutput(output, depends2, no_main_dependency,
+ commandLines, comment, nullptr,
+ addRuleFileToTarget);
}
}
}
@@ -1170,29 +1144,18 @@ bool cmMakefile::AppendCustomCommandToOutput(
// Validate custom commands.
if (this->ValidateCustomCommand(commandLines)) {
- // Add command factory to allow generator expressions in output.
- this->CommitAppendCustomCommandToOutput(output, depends, implicit_depends,
- commandLines);
+ // Dispatch command creation to allow generator expressions in outputs.
+ this->AddGeneratorAction(
+ [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) {
+ BacktraceGuard guard(this->Backtrace, lfbt);
+ detail::AppendCustomCommandToOutput(lg, lfbt, output, depends,
+ implicit_depends, commandLines);
+ });
}
return true;
}
-void cmMakefile::CommitAppendCustomCommandToOutput(
- const std::string& output, const std::vector<std::string>& depends,
- const cmImplicitDependsList& implicit_depends,
- const cmCustomCommandLines& commandLines)
-{
- // Lookup an existing command.
- if (cmSourceFile* sf = this->GetSourceFileWithOutput(output)) {
- if (cmCustomCommand* cc = sf->GetCustomCommand()) {
- cc->AppendCommands(commandLines);
- cc->AppendDepends(depends);
- cc->AppendImplicitDepends(implicit_depends);
- }
- }
-}
-
cmUtilityOutput cmMakefile::GetUtilityOutput(cmTarget* target)
{
std::string force = cmStrCat(this->GetCurrentBinaryDirectory(),
@@ -1215,15 +1178,14 @@ cmUtilityOutput cmMakefile::GetUtilityOutput(cmTarget* target)
}
cmTarget* cmMakefile::AddUtilityCommand(
- const std::string& utilityName, cmCommandOrigin origin, bool excludeFromAll,
- const char* workingDirectory, const std::vector<std::string>& byproducts,
+ const std::string& utilityName, bool excludeFromAll, const char* workingDir,
+ const std::vector<std::string>& byproducts,
const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines, bool escapeOldStyle,
const char* comment, bool uses_terminal, bool command_expand_lists,
const std::string& job_pool)
{
- cmTarget* target =
- this->AddNewUtilityTarget(utilityName, origin, excludeFromAll);
+ cmTarget* target = this->AddNewUtilityTarget(utilityName, excludeFromAll);
// Validate custom commands.
if ((commandLines.empty() && depends.empty()) ||
@@ -1236,45 +1198,26 @@ cmTarget* cmMakefile::AddUtilityCommand(
this->GetOrCreateGeneratedSource(force.Name);
// Always create the byproduct sources and mark them generated.
- this->CreateGeneratedSources(byproducts);
-
- if (!comment) {
- // Use an empty comment to avoid generation of default comment.
- comment = "";
- }
-
- this->CommitUtilityCommand(target, force, workingDirectory, byproducts,
- depends, commandLines, escapeOldStyle, comment,
- uses_terminal, command_expand_lists, job_pool);
+ this->CreateGeneratedByproducts(byproducts);
+
+ // Strings could be moved into the callback function with C++14.
+ cm::optional<std::string> commentStr = MakeOptionalString(comment);
+ cm::optional<std::string> workingStr = MakeOptionalString(workingDir);
+
+ // Dispatch command creation to allow generator expressions in outputs.
+ this->AddGeneratorAction(
+ [=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) {
+ BacktraceGuard guard(this->Backtrace, lfbt);
+ detail::AddUtilityCommand(lg, lfbt, cmCommandOrigin::Project, target,
+ force, GetCStrOrNull(workingStr), byproducts,
+ depends, commandLines, escapeOldStyle,
+ GetCStrOrNull(commentStr), uses_terminal,
+ command_expand_lists, job_pool);
+ });
return target;
}
-void cmMakefile::CommitUtilityCommand(
- cmTarget* target, const cmUtilityOutput& force, const char* workingDirectory,
- const std::vector<std::string>& byproducts,
- const std::vector<std::string>& depends,
- const cmCustomCommandLines& commandLines, bool escapeOldStyle,
- const char* comment, bool uses_terminal, bool command_expand_lists,
- const std::string& job_pool)
-{
- std::vector<std::string> forced;
- forced.push_back(force.Name);
- std::string no_main_dependency;
- cmImplicitDependsList no_implicit_depends;
- bool no_replace = false;
- cmSourceFile* sf = this->AddCustomCommandToOutput(
- forced, byproducts, depends, no_main_dependency, no_implicit_depends,
- commandLines, comment, workingDirectory, no_replace, escapeOldStyle,
- uses_terminal, command_expand_lists, /*depfile=*/"", job_pool);
- if (!force.NameCMP0049.empty()) {
- target->AddSource(force.NameCMP0049);
- }
- if (sf) {
- this->AddTargetByproducts(target, byproducts);
- }
-}
-
static void s_AddDefineFlag(std::string const& flag, std::string& dflags)
{
// remove any \n\r
@@ -1357,13 +1300,12 @@ void cmMakefile::AddLinkOption(std::string const& option)
void cmMakefile::AddLinkDirectory(std::string const& directory, bool before)
{
- cmListFileBacktrace lfbt = this->GetBacktrace();
if (before) {
- this->StateSnapshot.GetDirectory().PrependLinkDirectoriesEntry(directory,
- lfbt);
+ this->StateSnapshot.GetDirectory().PrependLinkDirectoriesEntry(
+ directory, this->Backtrace);
} else {
- this->StateSnapshot.GetDirectory().AppendLinkDirectoriesEntry(directory,
- lfbt);
+ this->StateSnapshot.GetDirectory().AppendLinkDirectoriesEntry(
+ directory, this->Backtrace);
}
}
@@ -1476,6 +1418,20 @@ void cmMakefile::InitializeFromParent(cmMakefile* parent)
this->RecursionDepth = parent->RecursionDepth;
}
+void cmMakefile::AddInstallGenerator(std::unique_ptr<cmInstallGenerator> g)
+{
+ if (g) {
+ this->InstallGenerators.push_back(std::move(g));
+ }
+}
+
+void cmMakefile::AddTestGenerator(std::unique_ptr<cmTestGenerator> g)
+{
+ if (g) {
+ this->TestGenerators.push_back(std::move(g));
+ }
+}
+
void cmMakefile::PushFunctionScope(std::string const& fileName,
const cmPolicies::PolicyMap& pm)
{
@@ -1776,8 +1732,10 @@ void cmMakefile::AddSubDirectory(const std::string& srcPath,
cmSystemTools::MakeDirectory(binPath);
- cmMakefile* subMf = new cmMakefile(this->GlobalGenerator, newSnapshot);
- this->GetGlobalGenerator()->AddMakefile(subMf);
+ auto subMfu =
+ cm::make_unique<cmMakefile>(this->GlobalGenerator, newSnapshot);
+ auto subMf = subMfu.get();
+ this->GetGlobalGenerator()->AddMakefile(std::move(subMfu));
if (excludeFromAll) {
subMf->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
@@ -1789,7 +1747,7 @@ void cmMakefile::AddSubDirectory(const std::string& srcPath,
this->UnConfiguredDirectories.push_back(subMf);
}
- this->AddInstallGenerator(new cmInstallSubdirectoryGenerator(
+ this->AddInstallGenerator(cm::make_unique<cmInstallSubdirectoryGenerator>(
subMf, binPath.c_str(), excludeFromAll));
}
@@ -1820,20 +1778,19 @@ void cmMakefile::AddIncludeDirectories(const std::vector<std::string>& incs,
return;
}
- cmListFileBacktrace lfbt = this->GetBacktrace();
std::string entryString = cmJoin(incs, ";");
if (before) {
this->StateSnapshot.GetDirectory().PrependIncludeDirectoriesEntry(
- entryString, lfbt);
+ entryString, this->Backtrace);
} else {
this->StateSnapshot.GetDirectory().AppendIncludeDirectoriesEntry(
- entryString, lfbt);
+ entryString, this->Backtrace);
}
// Property on each target:
for (auto& target : this->Targets) {
cmTarget& t = target.second;
- t.InsertInclude(entryString, lfbt, before);
+ t.InsertInclude(entryString, this->Backtrace, before);
}
}
@@ -2027,7 +1984,7 @@ void cmMakefile::AddGlobalLinkInformation(cmTarget& target)
target.AddLinkLibrary(*this, libraryName, libType);
target.AppendProperty(
"INTERFACE_LINK_LIBRARIES",
- target.GetDebugGeneratorExpressions(libraryName, libType).c_str());
+ target.GetDebugGeneratorExpressions(libraryName, libType));
}
}
}
@@ -2080,7 +2037,8 @@ cmTarget* cmMakefile::AddNewTarget(cmStateEnums::TargetType type,
{
auto it =
this->Targets
- .emplace(name, cmTarget(name, type, cmTarget::VisibilityNormal, this))
+ .emplace(name,
+ cmTarget(name, type, cmTarget::VisibilityNormal, this, true))
.first;
this->OrderedTargets.push_back(&it->second);
this->GetGlobalGenerator()->IndexTarget(&it->second);
@@ -2089,11 +2047,9 @@ cmTarget* cmMakefile::AddNewTarget(cmStateEnums::TargetType type,
}
cmTarget* cmMakefile::AddNewUtilityTarget(const std::string& utilityName,
- cmCommandOrigin origin,
bool excludeFromAll)
{
cmTarget* target = this->AddNewTarget(cmStateEnums::UTILITY, utilityName);
- target->SetIsGeneratorProvided(origin == cmCommandOrigin::Generator);
if (excludeFromAll) {
target->SetProperty("EXCLUDE_FROM_ALL", "TRUE");
}
@@ -2155,18 +2111,18 @@ cmSourceFile* cmMakefile::LinearGetSourceFileWithOutput(
// Look through all the source files that have custom commands and see if the
// custom command has the passed source file as an output.
- for (cmSourceFile* src : this->SourceFiles) {
+ for (const auto& src : this->SourceFiles) {
// Does this source file have a custom command?
if (src->GetCustomCommand()) {
// Does the output of the custom command match the source file name?
if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) {
// Return the first matching output.
- return src;
+ return src.get();
}
if (kind == cmSourceOutputKind::OutputOrByproduct) {
if (AnyOutputMatches(name, src->GetCustomCommand()->GetByproducts())) {
// Do not return the source yet as there might be a matching output.
- fallback = src;
+ fallback = src.get();
}
}
}
@@ -2211,8 +2167,8 @@ cmSourceFile* cmMakefile::GetSourceFileWithOutput(
(!o->second.Sources.SourceIsByproduct ||
kind == cmSourceOutputKind::OutputOrByproduct)) {
// Source file could also be null pointer for example if we found the
- // byproduct of a utility target or a PRE_BUILD, PRE_LINK, or POST_BUILD
- // command of a target.
+ // byproduct of a utility target, a PRE_BUILD, PRE_LINK, or POST_BUILD
+ // command of a target, or a not yet created custom command.
return o->second.Sources.Source;
}
return nullptr;
@@ -2220,12 +2176,20 @@ cmSourceFile* cmMakefile::GetSourceFileWithOutput(
bool cmMakefile::MightHaveCustomCommand(const std::string& name) const
{
- // This will have to be changed for delaying custom command creation, because
- // GetSourceFileWithOutput requires the command to be already created.
- if (cmSourceFile* sf = this->GetSourceFileWithOutput(name)) {
- if (sf->GetCustomCommand()) {
- return true;
- }
+ if (this->DelayedOutputFilesHaveGenex ||
+ cmGeneratorExpression::Find(name) != std::string::npos) {
+ // Could be more restrictive, but for now we assume that there could always
+ // be a match when generator expressions are involved.
+ return true;
+ }
+ // Also see LinearGetSourceFileWithOutput.
+ if (!cmSystemTools::FileIsFullPath(name)) {
+ return AnyOutputMatches(name, this->DelayedOutputFiles);
+ }
+ // Otherwise we use an efficient lookup map.
+ auto o = this->OutputToSource.find(name);
+ if (o != this->OutputToSource.end()) {
+ return o->second.SourceMightBeOutput;
}
return false;
}
@@ -2278,6 +2242,7 @@ void cmMakefile::UpdateOutputToSourceMap(std::string const& output,
SourceEntry entry;
entry.Sources.Source = source;
entry.Sources.SourceIsByproduct = byproduct;
+ entry.SourceMightBeOutput = !byproduct;
auto pr = this->OutputToSource.emplace(output, entry);
if (!pr.second) {
@@ -2287,6 +2252,7 @@ void cmMakefile::UpdateOutputToSourceMap(std::string const& output,
(current.Sources.SourceIsByproduct && !byproduct)) {
current.Sources.Source = source;
current.Sources.SourceIsByproduct = false;
+ current.SourceMightBeOutput = true;
} else {
// Multiple custom commands produce the same output but may
// be attached to a different source file (MAIN_DEPENDENCY).
@@ -2478,7 +2444,7 @@ void cmMakefile::ExpandVariablesCMP0019()
<< " " << dirs << "\n";
/* clang-format on */
}
- t.SetProperty("INCLUDE_DIRECTORIES", dirs.c_str());
+ t.SetProperty("INCLUDE_DIRECTORIES", dirs);
}
}
@@ -2739,7 +2705,7 @@ const std::string& cmMakefile::GetSafeDefinition(const std::string& name) const
std::vector<std::string> cmMakefile::GetDefinitions() const
{
std::vector<std::string> res = this->StateSnapshot.ClosureKeys();
- cmAppend(res, this->GetState()->GetCacheEntryKeys());
+ cm::append(res, this->GetState()->GetCacheEntryKeys());
std::sort(res.begin(), res.end());
return res;
}
@@ -3514,24 +3480,25 @@ cmSourceFile* cmMakefile::CreateSource(const std::string& sourceName,
bool generated,
cmSourceFileLocationKind kind)
{
- cmSourceFile* sf = new cmSourceFile(this, sourceName, kind);
+ auto sf = cm::make_unique<cmSourceFile>(this, sourceName, kind);
if (generated) {
sf->SetProperty("GENERATED", "1");
}
- this->SourceFiles.push_back(sf);
auto name =
this->GetCMakeInstance()->StripExtension(sf->GetLocation().GetName());
#if defined(_WIN32) || defined(__APPLE__)
name = cmSystemTools::LowerCase(name);
#endif
- this->SourceFileSearchIndex[name].push_back(sf);
+ this->SourceFileSearchIndex[name].push_back(sf.get());
// for "Known" paths add direct lookup (used for faster lookup in GetSource)
if (kind == cmSourceFileLocationKind::Known) {
- this->KnownFileSearchIndex[sourceName] = sf;
+ this->KnownFileSearchIndex[sourceName] = sf.get();
}
- return sf;
+ this->SourceFiles.push_back(std::move(sf));
+
+ return this->SourceFiles.back().get();
}
cmSourceFile* cmMakefile::GetOrCreateSource(const std::string& sourceName,
@@ -3553,11 +3520,41 @@ cmSourceFile* cmMakefile::GetOrCreateGeneratedSource(
return sf;
}
-void cmMakefile::CreateGeneratedSources(
+void cmMakefile::CreateGeneratedOutputs(
const std::vector<std::string>& outputs)
{
- for (std::string const& output : outputs) {
- this->GetOrCreateGeneratedSource(output);
+ for (std::string const& o : outputs) {
+ if (cmGeneratorExpression::Find(o) == std::string::npos) {
+ this->GetOrCreateGeneratedSource(o);
+ this->AddDelayedOutput(o);
+ } else {
+ this->DelayedOutputFilesHaveGenex = true;
+ }
+ }
+}
+
+void cmMakefile::CreateGeneratedByproducts(
+ const std::vector<std::string>& byproducts)
+{
+ for (std::string const& o : byproducts) {
+ if (cmGeneratorExpression::Find(o) == std::string::npos) {
+ this->GetOrCreateGeneratedSource(o);
+ }
+ }
+}
+
+void cmMakefile::AddDelayedOutput(std::string const& output)
+{
+ // Note that this vector might contain the output names in a different order
+ // than in source file iteration order.
+ this->DelayedOutputFiles.push_back(output);
+
+ SourceEntry entry;
+ entry.SourceMightBeOutput = true;
+
+ auto pr = this->OutputToSource.emplace(output, entry);
+ if (!pr.second) {
+ pr.first->second.SourceMightBeOutput = true;
}
}
@@ -3630,8 +3627,7 @@ int cmMakefile::TryCompile(const std::string& srcdir,
// be run that way but the cmake object requires a vailid path
cmake cm(cmake::RoleProject, cmState::Project);
cm.SetIsInTryCompile(true);
- cmGlobalGenerator* gg =
- cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName());
+ auto gg = cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName());
if (!gg) {
this->IssueMessage(MessageType::INTERNAL_ERROR,
"Global generator '" +
@@ -3642,7 +3638,7 @@ int cmMakefile::TryCompile(const std::string& srcdir,
return 1;
}
gg->RecursionDepth = this->RecursionDepth;
- cm.SetGlobalGenerator(gg);
+ cm.SetGlobalGenerator(std::move(gg));
// do a configure
cm.SetHomeDirectory(srcdir);
@@ -3651,7 +3647,7 @@ int cmMakefile::TryCompile(const std::string& srcdir,
cm.SetGeneratorPlatform(this->GetSafeDefinition("CMAKE_GENERATOR_PLATFORM"));
cm.SetGeneratorToolset(this->GetSafeDefinition("CMAKE_GENERATOR_TOOLSET"));
cm.LoadCache();
- if (!gg->IsMultiConfig()) {
+ if (!cm.GetGlobalGenerator()->IsMultiConfig()) {
if (const char* config =
this->GetDefinition("CMAKE_TRY_COMPILE_CONFIGURATION")) {
// Tell the single-configuration generator which one to use.
@@ -3697,7 +3693,8 @@ int cmMakefile::TryCompile(const std::string& srcdir,
cm.SetCacheArgs(*cmakeArgs);
}
// to save time we pass the EnableLanguage info directly
- gg->EnableLanguagesFromGenerator(this->GetGlobalGenerator(), this);
+ cm.GetGlobalGenerator()->EnableLanguagesFromGenerator(
+ this->GetGlobalGenerator(), this);
if (this->IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
cm.AddCacheEntry("CMAKE_SUPPRESS_DEVELOPER_WARNINGS", "TRUE", "",
cmStateEnums::INTERNAL);
@@ -3777,7 +3774,8 @@ void cmMakefile::DisplayStatus(const std::string& message, float s) const
}
std::string cmMakefile::GetModulesFile(const std::string& filename,
- bool& system) const
+ bool& system, bool debug,
+ std::string& debugBuffer) const
{
std::string result;
@@ -3808,6 +3806,9 @@ std::string cmMakefile::GetModulesFile(const std::string& filename,
moduleInCMakeModulePath = itempl;
break;
}
+ if (debug) {
+ debugBuffer = cmStrCat(debugBuffer, " ", itempl, "\n");
+ }
}
}
@@ -3816,6 +3817,9 @@ std::string cmMakefile::GetModulesFile(const std::string& filename,
cmStrCat(cmSystemTools::GetCMakeRoot(), "/Modules/", filename);
cmSystemTools::ConvertToUnixSlashes(moduleInCMakeRoot);
if (!cmSystemTools::FileExists(moduleInCMakeRoot)) {
+ if (debug) {
+ debugBuffer = cmStrCat(debugBuffer, " ", moduleInCMakeRoot, "\n");
+ }
moduleInCMakeRoot.clear();
}
@@ -4029,16 +4033,14 @@ int cmMakefile::ConfigureFile(const std::string& infile,
void cmMakefile::SetProperty(const std::string& prop, const char* value)
{
- cmListFileBacktrace lfbt = this->GetBacktrace();
- this->StateSnapshot.GetDirectory().SetProperty(prop, value, lfbt);
+ this->StateSnapshot.GetDirectory().SetProperty(prop, value, this->Backtrace);
}
void cmMakefile::AppendProperty(const std::string& prop, const char* value,
bool asString)
{
- cmListFileBacktrace lfbt = this->GetBacktrace();
this->StateSnapshot.GetDirectory().AppendProperty(prop, value, asString,
- lfbt);
+ this->Backtrace);
}
const char* cmMakefile::GetProperty(const std::string& prop) const
@@ -4090,9 +4092,10 @@ cmTest* cmMakefile::CreateTest(const std::string& testName)
if (test) {
return test;
}
- test = new cmTest(this);
- test->SetName(testName);
- this->Tests[testName] = test;
+ auto newTest = cm::make_unique<cmTest>(this);
+ test = newTest.get();
+ newTest->SetName(testName);
+ this->Tests[testName] = std::move(newTest);
return test;
}
@@ -4100,7 +4103,7 @@ cmTest* cmMakefile::GetTest(const std::string& testName) const
{
auto mi = this->Tests.find(testName);
if (mi != this->Tests.end()) {
- return mi->second;
+ return mi->second.get();
}
return nullptr;
}
@@ -4108,7 +4111,7 @@ cmTest* cmMakefile::GetTest(const std::string& testName) const
void cmMakefile::GetTests(const std::string& config,
std::vector<cmTest*>& tests)
{
- for (auto generator : this->GetTestGenerators()) {
+ for (const auto& generator : this->GetTestGenerators()) {
if (generator->TestsForConfig(config)) {
tests.push_back(generator->GetTest());
}
@@ -4214,15 +4217,15 @@ cmTarget* cmMakefile::AddImportedTarget(const std::string& name,
new cmTarget(name, type,
global ? cmTarget::VisibilityImportedGlobally
: cmTarget::VisibilityImported,
- this));
+ this, true));
// Add to the set of available imported targets.
this->ImportedTargets[name] = target.get();
this->GetGlobalGenerator()->IndexTarget(target.get());
// Transfer ownership to this cmMakefile object.
- this->ImportedTargetsOwned.push_back(target.get());
- return target.release();
+ this->ImportedTargetsOwned.push_back(std::move(target));
+ return this->ImportedTargetsOwned.back().get();
}
cmTarget* cmMakefile::FindTargetToUse(const std::string& name,
@@ -4487,7 +4490,7 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id,
// Deprecate old policies, especially those that require a lot
// of code to maintain the old behavior.
- if (status == cmPolicies::OLD && id <= cmPolicies::CMP0067 &&
+ if (status == cmPolicies::OLD && id <= cmPolicies::CMP0069 &&
!(this->GetCMakeInstance()->GetIsInTryCompile() &&
(
// Policies set by cmCoreTryCompile::TryCompileCode.
@@ -4587,17 +4590,21 @@ static const char* const C_FEATURES[] = { nullptr FOR_EACH_C_FEATURE(
static const char* const CXX_FEATURES[] = { nullptr FOR_EACH_CXX_FEATURE(
FEATURE_STRING) };
+
+static const char* const CUDA_FEATURES[] = { nullptr FOR_EACH_CUDA_FEATURE(
+ FEATURE_STRING) };
#undef FEATURE_STRING
static const char* const C_STANDARDS[] = { "90", "99", "11" };
static const char* const CXX_STANDARDS[] = { "98", "11", "14", "17", "20" };
+static const char* const CUDA_STANDARDS[] = { "03", "11", "14", "17", "20" };
bool cmMakefile::AddRequiredTargetFeature(cmTarget* target,
const std::string& feature,
std::string* error) const
{
if (cmGeneratorExpression::Find(feature) != std::string::npos) {
- target->AppendProperty("COMPILE_FEATURES", feature.c_str());
+ target->AppendProperty("COMPILE_FEATURES", feature);
return true;
}
@@ -4628,11 +4635,15 @@ bool cmMakefile::AddRequiredTargetFeature(cmTarget* target,
return false;
}
- target->AppendProperty("COMPILE_FEATURES", feature.c_str());
+ target->AppendProperty("COMPILE_FEATURES", feature);
- return lang == "C" || lang == "OBJC"
- ? this->AddRequiredTargetCFeature(target, feature, lang, error)
- : this->AddRequiredTargetCxxFeature(target, feature, lang, error);
+ if (lang == "C" || lang == "OBJC") {
+ return this->AddRequiredTargetCFeature(target, feature, lang, error);
+ }
+ if (lang == "CUDA") {
+ return this->AddRequiredTargetCudaFeature(target, feature, lang, error);
+ }
+ return this->AddRequiredTargetCxxFeature(target, feature, lang, error);
}
bool cmMakefile::CompileFeatureKnown(cmTarget const* target,
@@ -4656,6 +4667,13 @@ bool cmMakefile::CompileFeatureKnown(cmTarget const* target,
lang = "CXX";
return true;
}
+ bool isCudaFeature =
+ std::find_if(cm::cbegin(CUDA_FEATURES) + 1, cm::cend(CUDA_FEATURES),
+ cmStrCmp(feature)) != cm::cend(CUDA_FEATURES);
+ if (isCudaFeature) {
+ lang = "CUDA";
+ return true;
+ }
std::ostringstream e;
if (error) {
e << "specified";
@@ -4724,9 +4742,13 @@ bool cmMakefile::HaveStandardAvailable(cmTarget const* target,
std::string const& lang,
const std::string& feature) const
{
- return lang == "C" || lang == "OBJC"
- ? this->HaveCStandardAvailable(target, feature, lang)
- : this->HaveCxxStandardAvailable(target, feature, lang);
+ if (lang == "C" || lang == "OBJC") {
+ return this->HaveCStandardAvailable(target, feature, lang);
+ }
+ if (lang == "CUDA") {
+ return this->HaveCudaStandardAvailable(target, feature, lang);
+ }
+ return this->HaveCxxStandardAvailable(target, feature, lang);
}
bool cmMakefile::HaveCStandardAvailable(cmTarget const* target,
@@ -4809,6 +4831,14 @@ bool cmMakefile::IsLaterStandard(std::string const& lang,
return std::find_if(rhsIt, cm::cend(C_STANDARDS), cmStrCmp(lhs)) !=
cm::cend(C_STANDARDS);
}
+ if (lang == "CUDA") {
+ const char* const* rhsIt = std::find_if(
+ cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS), cmStrCmp(rhs));
+
+ return std::find_if(rhsIt, cm::cend(CUDA_STANDARDS), cmStrCmp(lhs)) !=
+ cm::cend(CUDA_STANDARDS);
+ }
+
const char* const* rhsIt = std::find_if(
cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), cmStrCmp(rhs));
@@ -4953,27 +4983,6 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target,
}
}
- const char* existingCudaStandard = target->GetProperty("CUDA_STANDARD");
- const char* const* existingCudaLevel = nullptr;
- if (existingCudaStandard) {
- existingCudaLevel =
- std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS),
- cmStrCmp(existingCudaStandard));
- if (existingCudaLevel == cm::cend(CXX_STANDARDS)) {
- std::ostringstream e;
- e << "The CUDA_STANDARD property on target \"" << target->GetName()
- << "\" contained an invalid value: \"" << existingCudaStandard
- << "\".";
- if (error) {
- *error = e.str();
- } else {
- this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR,
- e.str(), this->Backtrace);
- }
- return false;
- }
- }
-
/* clang-format off */
const char* const* needCxxLevel =
needCxx20 ? &CXX_STANDARDS[4]
@@ -4990,11 +4999,164 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target,
if (!existingCxxLevel || existingCxxLevel < needCxxLevel) {
target->SetProperty(cmStrCat(lang, "_STANDARD"), *needCxxLevel);
}
+ }
+
+ return true;
+}
+
+bool cmMakefile::HaveCudaStandardAvailable(cmTarget const* target,
+ const std::string& feature,
+ std::string const& lang) const
+{
+ const char* defaultCudaStandard =
+ this->GetDefinition(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT"));
+ if (!defaultCudaStandard) {
+ this->IssueMessage(
+ MessageType::INTERNAL_ERROR,
+ cmStrCat("CMAKE_", lang,
+ "_STANDARD_DEFAULT is not set. COMPILE_FEATURES support "
+ "not fully configured for this compiler."));
+ // Return true so the caller does not try to lookup the default standard.
+ return true;
+ }
+ if (std::find_if(cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS),
+ cmStrCmp(defaultCudaStandard)) ==
+ cm::cend(CUDA_STANDARDS)) {
+ const std::string e =
+ cmStrCat("The CMAKE_", lang, "_STANDARD_DEFAULT variable contains an ",
+ "invalid value: \"", defaultCudaStandard, "\".");
+ this->IssueMessage(MessageType::INTERNAL_ERROR, e);
+ return false;
+ }
+
+ bool needCuda03 = false;
+ bool needCuda11 = false;
+ bool needCuda14 = false;
+ bool needCuda17 = false;
+ bool needCuda20 = false;
+ this->CheckNeededCudaLanguage(feature, lang, needCuda03, needCuda11,
+ needCuda14, needCuda17, needCuda20);
+
+ const char* existingCudaStandard =
+ target->GetProperty(cmStrCat(lang, "_STANDARD"));
+ if (!existingCudaStandard) {
+ existingCudaStandard = defaultCudaStandard;
+ }
+
+ const char* const* existingCudaLevel =
+ std::find_if(cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS),
+ cmStrCmp(existingCudaStandard));
+ if (existingCudaLevel == cm::cend(CUDA_STANDARDS)) {
+ const std::string e = cmStrCat(
+ "The ", lang, "_STANDARD property on target \"", target->GetName(),
+ "\" contained an invalid value: \"", existingCudaStandard, "\".");
+ this->IssueMessage(MessageType::FATAL_ERROR, e);
+ return false;
+ }
+
+ /* clang-format off */
+ const char* const* needCudaLevel =
+ needCuda20 ? &CUDA_STANDARDS[4]
+ : needCuda17 ? &CUDA_STANDARDS[3]
+ : needCuda14 ? &CUDA_STANDARDS[2]
+ : needCuda11 ? &CUDA_STANDARDS[1]
+ : needCuda03 ? &CUDA_STANDARDS[0]
+ : nullptr;
+ /* clang-format on */
+
+ return !needCudaLevel || needCudaLevel <= existingCudaLevel;
+}
+
+void cmMakefile::CheckNeededCudaLanguage(const std::string& feature,
+ std::string const& lang,
+ bool& needCuda03, bool& needCuda11,
+ bool& needCuda14, bool& needCuda17,
+ bool& needCuda20) const
+{
+ if (const char* propCuda03 =
+ this->GetDefinition(cmStrCat("CMAKE_", lang, "03_COMPILE_FEATURES"))) {
+ std::vector<std::string> props = cmExpandedList(propCuda03);
+ needCuda03 = cmContains(props, feature);
+ }
+ if (const char* propCuda11 =
+ this->GetDefinition(cmStrCat("CMAKE_", lang, "11_COMPILE_FEATURES"))) {
+ std::vector<std::string> props = cmExpandedList(propCuda11);
+ needCuda11 = cmContains(props, feature);
+ }
+ if (const char* propCuda14 =
+ this->GetDefinition(cmStrCat("CMAKE_", lang, "14_COMPILE_FEATURES"))) {
+ std::vector<std::string> props = cmExpandedList(propCuda14);
+ needCuda14 = cmContains(props, feature);
+ }
+ if (const char* propCuda17 =
+ this->GetDefinition(cmStrCat("CMAKE_", lang, "17_COMPILE_FEATURES"))) {
+ std::vector<std::string> props = cmExpandedList(propCuda17);
+ needCuda17 = cmContains(props, feature);
+ }
+ if (const char* propCuda20 =
+ this->GetDefinition(cmStrCat("CMAKE_", lang, "20_COMPILE_FEATURES"))) {
+ std::vector<std::string> props = cmExpandedList(propCuda20);
+ needCuda20 = cmContains(props, feature);
+ }
+}
+
+bool cmMakefile::AddRequiredTargetCudaFeature(cmTarget* target,
+ const std::string& feature,
+ std::string const& lang,
+ std::string* error) const
+{
+ bool needCuda03 = false;
+ bool needCuda11 = false;
+ bool needCuda14 = false;
+ bool needCuda17 = false;
+ bool needCuda20 = false;
+
+ this->CheckNeededCudaLanguage(feature, lang, needCuda03, needCuda11,
+ needCuda14, needCuda17, needCuda20);
+
+ const char* existingCudaStandard =
+ target->GetProperty(cmStrCat(lang, "_STANDARD"));
+ if (existingCudaStandard == nullptr) {
+ const char* defaultCudaStandard =
+ this->GetDefinition(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT"));
+ if (defaultCudaStandard && *defaultCudaStandard) {
+ existingCudaStandard = defaultCudaStandard;
+ }
+ }
+ const char* const* existingCudaLevel = nullptr;
+ if (existingCudaStandard) {
+ existingCudaLevel =
+ std::find_if(cm::cbegin(CUDA_STANDARDS), cm::cend(CUDA_STANDARDS),
+ cmStrCmp(existingCudaStandard));
+ if (existingCudaLevel == cm::cend(CUDA_STANDARDS)) {
+ const std::string e = cmStrCat(
+ "The ", lang, "_STANDARD property on target \"", target->GetName(),
+ "\" contained an invalid value: \"", existingCudaStandard, "\".");
+ if (error) {
+ *error = e;
+ } else {
+ this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e,
+ this->Backtrace);
+ }
+ return false;
+ }
+ }
+
+ /* clang-format off */
+ const char* const* needCudaLevel =
+ needCuda20 ? &CUDA_STANDARDS[4]
+ : needCuda17 ? &CUDA_STANDARDS[3]
+ : needCuda14 ? &CUDA_STANDARDS[2]
+ : needCuda11 ? &CUDA_STANDARDS[1]
+ : needCuda03 ? &CUDA_STANDARDS[0]
+ : nullptr;
+ /* clang-format on */
+ if (needCudaLevel) {
// Ensure the CUDA language level is high enough to support
- // the needed C++ features.
- if (!existingCudaLevel || existingCudaLevel < needCxxLevel) {
- target->SetProperty("CUDA_STANDARD", *needCxxLevel);
+ // the needed CUDA features.
+ if (!existingCudaLevel || existingCudaLevel < needCudaLevel) {
+ target->SetProperty("CUDA_STANDARD", *needCudaLevel);
}
}