diff options
Diffstat (limited to 'Source/cmMakefile.cxx')
-rw-r--r-- | Source/cmMakefile.cxx | 828 |
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); } } |