diff options
Diffstat (limited to 'Source/cmMakefile.cxx')
-rw-r--r-- | Source/cmMakefile.cxx | 258 |
1 files changed, 177 insertions, 81 deletions
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 604ca2ca5..3c7a4cf2b 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -6,12 +6,12 @@ #include "cmsys/RegularExpression.hxx" #include <algorithm> #include <assert.h> +#include <cstring> #include <ctype.h> #include <iterator> #include <memory> // IWYU pragma: keep #include <sstream> #include <stdlib.h> -#include <string.h> #include <utility> #include "cmAlgorithms.h" @@ -43,7 +43,7 @@ #include "cmake.h" #ifdef CMAKE_BUILD_WITH_CMAKE -#include "cmVariableWatch.h" +# include "cmVariableWatch.h" #endif class cmMessenger; @@ -158,6 +158,32 @@ bool cmMakefile::CheckCMP0037(std::string const& targetName, return true; } +void cmMakefile::MaybeWarnCMP0074(std::string const& pkg) +{ + // Warn if a <pkg>_ROOT variable we may use is set. + std::string const varName = pkg + "_ROOT"; + const char* var = this->GetDefinition(varName); + std::string env; + cmSystemTools::GetEnv(varName, env); + + bool const haveVar = var && *var; + bool const haveEnv = !env.empty(); + if ((haveVar || haveEnv) && this->WarnedCMP0074.insert(varName).second) { + std::ostringstream w; + w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0074) << "\n"; + if (haveVar) { + w << "CMake variable " << varName << " is set to:\n" + << " " << var << "\n"; + } + if (haveEnv) { + w << "Environment variable " << varName << " is set to:\n" + << " " << env << "\n"; + } + w << "For compatibility, CMake is ignoring the variable."; + this->IssueMessage(cmake::AUTHOR_WARNING, w.str()); + } +} + cmStringRange cmMakefile::GetIncludeDirectoriesEntries() const { return this->StateSnapshot.GetDirectory().GetIncludeDirectoriesEntries(); @@ -198,7 +224,7 @@ cmListFileBacktrace cmMakefile::GetBacktrace() const cmListFileBacktrace cmMakefile::GetBacktrace(cmCommandContext const& cc) const { cmListFileContext lfc; - lfc.Name = cc.Name; + lfc.Name = cc.Name.Original; lfc.Line = cc.Line; lfc.FilePath = this->StateSnapshot.GetExecutionListFile(); return this->Backtrace.Push(lfc); @@ -239,7 +265,7 @@ void cmMakefile::PrintCommandTrace(const cmListFileFunction& lff) const std::ostringstream msg; msg << full_path << "(" << lff.Line << "): "; - msg << lff.Name << "("; + msg << lff.Name.Original << "("; bool expand = this->GetCMakeInstance()->GetTraceExpand(); std::string temp; for (cmListFileArgument const& arg : lff.Arguments) { @@ -291,14 +317,13 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, return result; } - std::string name = lff.Name; - // Place this call on the call stack. cmMakefileCall stack_manager(this, lff, status); static_cast<void>(stack_manager); // Lookup the command prototype. - if (cmCommand* proto = this->GetState()->GetCommand(name)) { + if (cmCommand* proto = + this->GetState()->GetCommandByExactName(lff.Name.Lower)) { // Clone the prototype. std::unique_ptr<cmCommand> pcmd(proto->Clone()); pcmd->SetMakefile(this); @@ -315,7 +340,8 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, if (!invokeSucceeded || hadNestedError) { if (!hadNestedError) { // The command invocation requested that we report an error. - std::string const error = name + " " + pcmd->GetError(); + std::string const error = + std::string(lff.Name.Original) + " " + pcmd->GetError(); this->IssueMessage(cmake::FATAL_ERROR, error); } result = false; @@ -330,7 +356,7 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, } else { if (!cmSystemTools::GetFatalErrorOccured()) { std::string error = "Unknown CMake command \""; - error += lff.Name; + error += lff.Name.Original; error += "\"."; this->IssueMessage(cmake::FATAL_ERROR, error); result = false; @@ -1104,6 +1130,17 @@ cmTarget* cmMakefile::AddUtilityCommand( return target; } +static void s_AddDefineFlag(std::string const& flag, std::string& dflags) +{ + // remove any \n\r + std::string::size_type initSize = dflags.size(); + dflags += ' '; + dflags += flag; + std::string::iterator flagStart = dflags.begin() + initSize + 1; + std::replace(flagStart, dflags.end(), '\n', ' '); + std::replace(flagStart, dflags.end(), '\r', ' '); +} + void cmMakefile::AddDefineFlag(std::string const& flag) { if (flag.empty()) { @@ -1111,7 +1148,7 @@ void cmMakefile::AddDefineFlag(std::string const& flag) } // Update the string used for the old DEFINITIONS property. - this->AddDefineFlag(flag, this->DefineFlagsOrig); + s_AddDefineFlag(flag, this->DefineFlagsOrig); // If this is really a definition, update COMPILE_DEFINITIONS. if (this->ParseDefineFlag(flag, false)) { @@ -1119,17 +1156,24 @@ void cmMakefile::AddDefineFlag(std::string const& flag) } // Add this flag that does not look like a definition. - this->AddDefineFlag(flag, this->DefineFlags); + s_AddDefineFlag(flag, this->DefineFlags); } -void cmMakefile::AddDefineFlag(std::string const& flag, std::string& dflags) +static void s_RemoveDefineFlag(std::string const& flag, std::string& dflags) { - // remove any \n\r - std::string::size_type initSize = dflags.size(); - dflags += std::string(" ") + flag; - std::string::iterator flagStart = dflags.begin() + initSize + 1; - std::replace(flagStart, dflags.end(), '\n', ' '); - std::replace(flagStart, dflags.end(), '\r', ' '); + std::string::size_type const len = flag.length(); + // Remove all instances of the flag that are surrounded by + // whitespace or the beginning/end of the string. + for (std::string::size_type lpos = dflags.find(flag, 0); + lpos != std::string::npos; lpos = dflags.find(flag, lpos)) { + std::string::size_type rpos = lpos + len; + if ((lpos <= 0 || isspace(dflags[lpos - 1])) && + (rpos >= dflags.size() || isspace(dflags[rpos]))) { + dflags.erase(lpos, len); + } else { + ++lpos; + } + } } void cmMakefile::RemoveDefineFlag(std::string const& flag) @@ -1138,9 +1182,9 @@ void cmMakefile::RemoveDefineFlag(std::string const& flag) if (flag.empty()) { return; } - std::string::size_type const len = flag.length(); + // Update the string used for the old DEFINITIONS property. - this->RemoveDefineFlag(flag, len, this->DefineFlagsOrig); + s_RemoveDefineFlag(flag, this->DefineFlagsOrig); // If this is really a definition, update COMPILE_DEFINITIONS. if (this->ParseDefineFlag(flag, true)) { @@ -1148,25 +1192,12 @@ void cmMakefile::RemoveDefineFlag(std::string const& flag) } // Remove this flag that does not look like a definition. - this->RemoveDefineFlag(flag, len, this->DefineFlags); + s_RemoveDefineFlag(flag, this->DefineFlags); } -void cmMakefile::RemoveDefineFlag(std::string const& flag, - std::string::size_type len, - std::string& dflags) +void cmMakefile::AddCompileDefinition(std::string const& option) { - // Remove all instances of the flag that are surrounded by - // whitespace or the beginning/end of the string. - for (std::string::size_type lpos = dflags.find(flag, 0); - lpos != std::string::npos; lpos = dflags.find(flag, lpos)) { - std::string::size_type rpos = lpos + len; - if ((lpos <= 0 || isspace(dflags[lpos - 1])) && - (rpos >= dflags.size() || isspace(dflags[rpos]))) { - dflags.erase(lpos, len); - } else { - ++lpos; - } - } + this->AppendProperty("COMPILE_DEFINITIONS", option.c_str()); } void cmMakefile::AddCompileOption(std::string const& option) @@ -1423,7 +1454,7 @@ void cmMakefile::Configure() bool hasVersion = false; // search for the right policy command for (cmListFileFunction const& func : listFile.Functions) { - if (cmSystemTools::LowerCase(func.Name) == "cmake_minimum_required") { + if (func.Name.Lower == "cmake_minimum_required") { hasVersion = true; break; } @@ -1450,8 +1481,7 @@ void cmMakefile::Configure() allowedCommands.insert("message"); isProblem = false; for (cmListFileFunction const& func : listFile.Functions) { - std::string name = cmSystemTools::LowerCase(func.Name); - if (allowedCommands.find(name) == allowedCommands.end()) { + if (allowedCommands.find(func.Name.Lower) == allowedCommands.end()) { isProblem = true; break; } @@ -1464,13 +1494,13 @@ void cmMakefile::Configure() this->SetCheckCMP0000(true); // Implicitly set the version for the user. - this->SetPolicyVersion("2.4"); + this->SetPolicyVersion("2.4", std::string()); } } bool hasProject = false; // search for a project command for (cmListFileFunction const& func : listFile.Functions) { - if (cmSystemTools::LowerCase(func.Name) == "project") { + if (func.Name.Lower == "project") { hasProject = true; break; } @@ -1478,7 +1508,7 @@ void cmMakefile::Configure() // if no project command is found, add one if (!hasProject) { cmListFileFunction project; - project.Name = "PROJECT"; + project.Name.Lower = "project"; project.Arguments.emplace_back("Project", cmListFileArgument::Unquoted, 0); listFile.Functions.insert(listFile.Functions.begin(), project); @@ -1675,8 +1705,9 @@ void cmMakefile::AddCacheDefinition(const std::string& name, const char* value, // must be outside the following if() to keep it alive long enough std::string nvalue; - if (existingValue && (this->GetState()->GetCacheEntryType(name) == - cmStateEnums::UNINITIALIZED)) { + if (existingValue && + (this->GetState()->GetCacheEntryType(name) == + cmStateEnums::UNINITIALIZED)) { // if this is not a force, then use the value from the cache // if it is a force, then use the value being passed in if (!force) { @@ -1810,12 +1841,10 @@ void cmMakefile::AddGlobalLinkInformation(cmTarget& target) std::vector<std::string> linkDirs; cmSystemTools::ExpandListArgument(linkDirsProp, linkDirs); - for (std::string const& linkDir : linkDirs) { - std::string newdir = linkDir; - // remove trailing slashes - if (*linkDir.rbegin() == '/') { - newdir = linkDir.substr(0, linkDir.size() - 1); - } + for (std::string& linkDir : linkDirs) { + // Sanitize the path the same way the link_directories command does + // in case projects set the LINK_DIRECTORIES property directly. + cmSystemTools::ConvertToUnixSlashes(linkDir); target.AddLinkDirectory(linkDir); } } @@ -1867,7 +1896,7 @@ cmTarget* cmMakefile::AddLibrary(const std::string& lname, // Clear its dependencies. Otherwise, dependencies might persist // over changes in CMakeLists.txt, making the information stale and // hence useless. - target->ClearDependencyInformation(*this, lname); + target->ClearDependencyInformation(*this); if (excludeFromAll) { target->SetProperty("EXCLUDE_FROM_ALL", "TRUE"); } @@ -2346,10 +2375,11 @@ const char* cmMakefile::GetDefinition(const std::string& name) const #ifdef CMAKE_BUILD_WITH_CMAKE cmVariableWatch* vv = this->GetVariableWatch(); if (vv && !this->SuppressWatches) { - bool const watch_function_executed = vv->VariableAccessed( - name, def ? cmVariableWatch::VARIABLE_READ_ACCESS - : cmVariableWatch::UNKNOWN_VARIABLE_READ_ACCESS, - def, this); + bool const watch_function_executed = + vv->VariableAccessed(name, + def ? cmVariableWatch::VARIABLE_READ_ACCESS + : cmVariableWatch::UNKNOWN_VARIABLE_READ_ACCESS, + def, this); if (watch_function_executed) { // A callback was executed and may have caused re-allocation of the @@ -2383,12 +2413,13 @@ std::vector<std::string> cmMakefile::GetDefinitions() const return res; } -const char* cmMakefile::ExpandVariablesInString(std::string& source) const +const std::string& cmMakefile::ExpandVariablesInString( + std::string& source) const { return this->ExpandVariablesInString(source, false, false); } -const char* cmMakefile::ExpandVariablesInString( +const std::string& cmMakefile::ExpandVariablesInString( std::string& source, bool escapeQuotes, bool noEscapes, bool atOnly, const char* filename, long line, bool removeEmpty, bool replaceAt) const { @@ -2404,7 +2435,7 @@ const char* cmMakefile::ExpandVariablesInString( this->IssueMessage(cmake::INTERNAL_ERROR, "ExpandVariablesInString @ONLY called " "on something with escapes."); - return source.c_str(); + return source; } // Variables used in the WARN case. @@ -2486,7 +2517,7 @@ const char* cmMakefile::ExpandVariablesInString( this->IssueMessage(cmake::AUTHOR_WARNING, msg); } - return source.c_str(); + return source; } cmake::MessageType cmMakefile::ExpandVariablesInStringOld( @@ -2601,7 +2632,12 @@ cmake::MessageType cmMakefile::ExpandVariablesInStringOld( return mtype; } -typedef enum { NORMAL, ENVIRONMENT, CACHE } t_domain; +typedef enum +{ + NORMAL, + ENVIRONMENT, + CACHE +} t_domain; struct t_lookup { t_lookup() @@ -2790,9 +2826,11 @@ cmake::MessageType cmMakefile::ExpandVariablesInStringNew( const char* nextAt = strchr(in + 1, '@'); if (nextAt && nextAt != in + 1 && nextAt == - in + 1 + strspn(in + 1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789/_.+-")) { + in + 1 + + strspn(in + 1, + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789/_.+-")) { std::string variable(in + 1, nextAt - in - 1); std::string varresult = this->GetSafeDefinition(variable); if (escapeQuotes) { @@ -3140,6 +3178,14 @@ void cmMakefile::SetArgcArgv(const std::vector<std::string>& args) cmSourceFile* cmMakefile::GetSource(const std::string& sourceName, cmSourceFileLocationKind kind) const { + // First check "Known" paths (avoids the creation of cmSourceFileLocation) + if (kind == cmSourceFileLocationKind::Known) { + auto sfsi = this->KnownFileSearchIndex.find(sourceName); + if (sfsi != this->KnownFileSearchIndex.end()) { + return sfsi->second; + } + } + cmSourceFileLocation sfl(this, sourceName, kind); auto name = this->GetCMakeInstance()->StripExtension(sfl.GetName()); #if defined(_WIN32) || defined(__APPLE__) @@ -3172,6 +3218,10 @@ cmSourceFile* cmMakefile::CreateSource(const std::string& sourceName, name = cmSystemTools::LowerCase(name); #endif this->SourceFileSearchIndex[name].push_back(sf); + // for "Known" paths add direct lookup (used for faster lookup in GetSource) + if (kind == cmSourceFileLocationKind::Known) { + this->KnownFileSearchIndex[sourceName] = sf; + } return sf; } @@ -3227,7 +3277,7 @@ void cmMakefile::EnableLanguage(std::vector<std::string> const& lang, int cmMakefile::TryCompile(const std::string& srcdir, const std::string& bindir, const std::string& projectName, - const std::string& targetName, bool fast, + const std::string& targetName, bool fast, int jobs, const std::vector<std::string>* cmakeArgs, std::string& output) { @@ -3240,6 +3290,14 @@ int cmMakefile::TryCompile(const std::string& srcdir, // change to the tests directory and run cmake // use the cmake object instead of calling cmake cmWorkingDirectory workdir(bindir); + if (workdir.Failed()) { + this->IssueMessage(cmake::FATAL_ERROR, + "Failed to set working directory to " + bindir + " : " + + std::strerror(workdir.GetLastResult())); + cmSystemTools::SetFatalErrorOccured(); + this->IsSourceFileTryCompile = false; + return 1; + } // make sure the same generator is used // use this program as the cmake to be run, it should not @@ -3249,7 +3307,8 @@ int cmMakefile::TryCompile(const std::string& srcdir, cmGlobalGenerator* gg = cm.CreateGlobalGenerator(this->GetGlobalGenerator()->GetName()); if (!gg) { - this->IssueMessage(cmake::INTERNAL_ERROR, "Global generator '" + + this->IssueMessage(cmake::INTERNAL_ERROR, + "Global generator '" + this->GetGlobalGenerator()->GetName() + "' could not be created."); cmSystemTools::SetFatalErrorOccured(); @@ -3331,7 +3390,7 @@ int cmMakefile::TryCompile(const std::string& srcdir, // finally call the generator to actually build the resulting project int ret = this->GetGlobalGenerator()->TryCompile( - srcdir, bindir, projectName, targetName, fast, output, this); + jobs, srcdir, bindir, projectName, targetName, fast, output, this); this->IsSourceFileTryCompile = false; return ret; @@ -3643,6 +3702,20 @@ void cmMakefile::AppendProperty(const std::string& prop, const char* value, const char* cmMakefile::GetProperty(const std::string& prop) const { + // Check for computed properties. + static std::string output; + if (prop == "TESTS") { + std::vector<std::string> keys; + // get list of keys + std::transform(this->Tests.begin(), this->Tests.end(), + std::back_inserter(keys), + [](decltype(this->Tests)::value_type const& pair) { + return pair.first; + }); + output = cmJoin(keys, ";"); + return output.c_str(); + } + return this->StateSnapshot.GetDirectory().GetProperty(prop); } @@ -3782,7 +3855,16 @@ void cmMakefile::RaiseScope(const std::string& var, const char* varDef) std::ostringstream m; m << "Cannot set \"" << var << "\": current scope has no parent."; this->IssueMessage(cmake::AUTHOR_WARNING, m.str()); + return; } + +#ifdef CMAKE_BUILD_WITH_CMAKE + cmVariableWatch* vv = this->GetVariableWatch(); + if (vv) { + vv->VariableAccessed(var, cmVariableWatch::VARIABLE_MODIFIED_ACCESS, + varDef, this); + } +#endif } cmTarget* cmMakefile::AddImportedTarget(const std::string& name, @@ -3791,8 +3873,9 @@ cmTarget* cmMakefile::AddImportedTarget(const std::string& name, { // Create the target. std::unique_ptr<cmTarget> target( - new cmTarget(name, type, global ? cmTarget::VisibilityImportedGlobally - : cmTarget::VisibilityImported, + new cmTarget(name, type, + global ? cmTarget::VisibilityImportedGlobally + : cmTarget::VisibilityImported, this)); // Add to the set of available imported targets. @@ -4023,10 +4106,10 @@ const char* cmMakefile::GetDefineFlagsCMP0059() const return this->DefineFlagsOrig.c_str(); } -cmPolicies::PolicyStatus cmMakefile::GetPolicyStatus( - cmPolicies::PolicyID id) const +cmPolicies::PolicyStatus cmMakefile::GetPolicyStatus(cmPolicies::PolicyID id, + bool parent_scope) const { - return this->StateSnapshot.GetPolicy(id); + return this->StateSnapshot.GetPolicy(id, parent_scope); } bool cmMakefile::PolicyOptionalWarningEnabled(std::string const& var) @@ -4117,9 +4200,10 @@ void cmMakefile::PopSnapshot(bool reportError) assert(this->StateSnapshot.IsValid()); } -bool cmMakefile::SetPolicyVersion(const char* version) +bool cmMakefile::SetPolicyVersion(std::string const& version_min, + std::string const& version_max) { - return cmPolicies::ApplyPolicyVersion(this, version); + return cmPolicies::ApplyPolicyVersion(this, version_min, version_max); } bool cmMakefile::HasCMP0054AlreadyBeenReported( @@ -4164,7 +4248,7 @@ static const char* const CXX_FEATURES[] = { nullptr FOR_EACH_CXX_FEATURE( #undef FEATURE_STRING static const char* const C_STANDARDS[] = { "90", "99", "11" }; -static const char* const CXX_STANDARDS[] = { "98", "11", "14", "17" }; +static const char* const CXX_STANDARDS[] = { "98", "11", "14", "17", "20" }; bool cmMakefile::AddRequiredTargetFeature(cmTarget* target, const std::string& feature, @@ -4238,8 +4322,9 @@ bool cmMakefile::CompileFeatureKnown(cmTarget const* target, } else { e << "Specified"; } - e << " unknown feature \"" << feature << "\" for " - "target \"" + e << " unknown feature \"" << feature + << "\" for " + "target \"" << target->GetName() << "\"."; if (error) { *error = e.str(); @@ -4414,8 +4499,9 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, bool needCxx11 = false; bool needCxx14 = false; bool needCxx17 = false; + bool needCxx20 = false; this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11, needCxx14, - needCxx17); + needCxx17, needCxx20); const char* existingCxxStandard = target->GetProperty("CXX_STANDARD"); if (!existingCxxStandard) { @@ -4435,7 +4521,8 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, /* clang-format off */ const char* const* needCxxLevel = - needCxx17 ? &CXX_STANDARDS[3] + needCxx20 ? &CXX_STANDARDS[4] + : needCxx17 ? &CXX_STANDARDS[3] : needCxx14 ? &CXX_STANDARDS[2] : needCxx11 ? &CXX_STANDARDS[1] : needCxx98 ? &CXX_STANDARDS[0] @@ -4447,7 +4534,8 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, void cmMakefile::CheckNeededCxxLanguage(const std::string& feature, bool& needCxx98, bool& needCxx11, - bool& needCxx14, bool& needCxx17) const + bool& needCxx14, bool& needCxx17, + bool& needCxx20) const { if (const char* propCxx98 = this->GetDefinition("CMAKE_CXX98_COMPILE_FEATURES")) { @@ -4473,6 +4561,12 @@ void cmMakefile::CheckNeededCxxLanguage(const std::string& feature, cmSystemTools::ExpandListArgument(propCxx17, props); needCxx17 = std::find(props.begin(), props.end(), feature) != props.end(); } + if (const char* propCxx20 = + this->GetDefinition("CMAKE_CXX20_COMPILE_FEATURES")) { + std::vector<std::string> props; + cmSystemTools::ExpandListArgument(propCxx20, props); + needCxx20 = std::find(props.begin(), props.end(), feature) != props.end(); + } } bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, @@ -4483,9 +4577,10 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, bool needCxx11 = false; bool needCxx14 = false; bool needCxx17 = false; + bool needCxx20 = false; this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11, needCxx14, - needCxx17); + needCxx17, needCxx20); const char* existingCxxStandard = target->GetProperty("CXX_STANDARD"); const char* const* existingCxxLevel = nullptr; @@ -4530,7 +4625,8 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, /* clang-format off */ const char* const* needCxxLevel = - needCxx17 ? &CXX_STANDARDS[3] + needCxx20 ? &CXX_STANDARDS[4] + : needCxx17 ? &CXX_STANDARDS[3] : needCxx14 ? &CXX_STANDARDS[2] : needCxx11 ? &CXX_STANDARDS[1] : needCxx98 ? &CXX_STANDARDS[0] |