| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| #include "cmSetPropertyCommand.h" |
| |
| #include <set> |
| #include <sstream> |
| #include <unordered_set> |
| |
| #include "cmExecutionStatus.h" |
| #include "cmGlobalGenerator.h" |
| #include "cmInstalledFile.h" |
| #include "cmMakefile.h" |
| #include "cmMessageType.h" |
| #include "cmPolicies.h" |
| #include "cmProperty.h" |
| #include "cmRange.h" |
| #include "cmSourceFile.h" |
| #include "cmSourceFileLocation.h" |
| #include "cmState.h" |
| #include "cmStringAlgorithms.h" |
| #include "cmSystemTools.h" |
| #include "cmTarget.h" |
| #include "cmTest.h" |
| #include "cmValue.h" |
| #include "cmake.h" |
| |
| namespace { |
| bool HandleGlobalMode(cmExecutionStatus& status, |
| const std::set<std::string>& names, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove); |
| bool HandleDirectoryMode(cmExecutionStatus& status, |
| const std::set<std::string>& names, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove); |
| bool HandleTargetMode(cmExecutionStatus& status, |
| const std::set<std::string>& names, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove); |
| bool HandleTarget(cmTarget* target, cmMakefile& makefile, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove); |
| bool HandleSourceMode(cmExecutionStatus& status, |
| const std::set<std::string>& names, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove, |
| const std::vector<cmMakefile*>& directory_makefiles, |
| bool source_file_paths_should_be_absolute); |
| bool HandleSource(cmSourceFile* sf, const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove); |
| bool HandleTestMode(cmExecutionStatus& status, std::set<std::string>& names, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove); |
| bool HandleTest(cmTest* test, const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove); |
| bool HandleCacheMode(cmExecutionStatus& status, |
| const std::set<std::string>& names, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove); |
| bool HandleCacheEntry(std::string const& cacheKey, const cmMakefile& makefile, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove); |
| bool HandleInstallMode(cmExecutionStatus& status, |
| const std::set<std::string>& names, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove); |
| bool HandleInstall(cmInstalledFile* file, cmMakefile& makefile, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove); |
| } |
| |
| namespace SetPropertyCommand { |
| bool HandleSourceFileDirectoryScopes( |
| cmExecutionStatus& status, std::vector<std::string>& source_file_directories, |
| std::vector<std::string>& source_file_target_directories, |
| std::vector<cmMakefile*>& directory_makefiles) |
| { |
| std::unordered_set<cmMakefile*> directory_makefiles_set; |
| |
| cmMakefile* current_dir_mf = &status.GetMakefile(); |
| if (!source_file_directories.empty()) { |
| for (const std::string& dir_path : source_file_directories) { |
| const std::string absolute_dir_path = cmSystemTools::CollapseFullPath( |
| dir_path, current_dir_mf->GetCurrentSourceDirectory()); |
| cmMakefile* dir_mf = |
| status.GetMakefile().GetGlobalGenerator()->FindMakefile( |
| absolute_dir_path); |
| if (!dir_mf) { |
| status.SetError(cmStrCat("given non-existent DIRECTORY ", dir_path)); |
| return false; |
| } |
| if (directory_makefiles_set.find(dir_mf) == |
| directory_makefiles_set.end()) { |
| directory_makefiles.push_back(dir_mf); |
| directory_makefiles_set.insert(dir_mf); |
| } |
| } |
| } |
| |
| if (!source_file_target_directories.empty()) { |
| for (const std::string& target_name : source_file_target_directories) { |
| cmTarget* target = current_dir_mf->FindTargetToUse(target_name); |
| if (!target) { |
| status.SetError(cmStrCat( |
| "given non-existent target for TARGET_DIRECTORY ", target_name)); |
| return false; |
| } |
| cmValue target_source_dir = target->GetProperty("BINARY_DIR"); |
| cmMakefile* target_dir_mf = |
| status.GetMakefile().GetGlobalGenerator()->FindMakefile( |
| *target_source_dir); |
| |
| if (directory_makefiles_set.find(target_dir_mf) == |
| directory_makefiles_set.end()) { |
| directory_makefiles.push_back(target_dir_mf); |
| directory_makefiles_set.insert(target_dir_mf); |
| } |
| } |
| } |
| |
| if (source_file_directories.empty() && |
| source_file_target_directories.empty()) { |
| directory_makefiles.push_back(current_dir_mf); |
| } |
| return true; |
| } |
| |
| bool HandleSourceFileDirectoryScopeValidation( |
| cmExecutionStatus& status, bool source_file_directory_option_enabled, |
| bool source_file_target_option_enabled, |
| std::vector<std::string>& source_file_directories, |
| std::vector<std::string>& source_file_target_directories) |
| { |
| // Validate source file directory scopes. |
| if (source_file_directory_option_enabled && |
| source_file_directories.empty()) { |
| std::string errors = "called with incorrect number of arguments " |
| "no value provided to the DIRECTORY option"; |
| status.SetError(errors); |
| return false; |
| } |
| if (source_file_target_option_enabled && |
| source_file_target_directories.empty()) { |
| std::string errors = "called with incorrect number of arguments " |
| "no value provided to the TARGET_DIRECTORY option"; |
| status.SetError(errors); |
| return false; |
| } |
| return true; |
| } |
| |
| bool HandleAndValidateSourceFileDirectoryScopes( |
| cmExecutionStatus& status, bool source_file_directory_option_enabled, |
| bool source_file_target_option_enabled, |
| std::vector<std::string>& source_file_directories, |
| std::vector<std::string>& source_file_target_directories, |
| std::vector<cmMakefile*>& source_file_directory_makefiles) |
| { |
| bool scope_options_valid = |
| SetPropertyCommand::HandleSourceFileDirectoryScopeValidation( |
| status, source_file_directory_option_enabled, |
| source_file_target_option_enabled, source_file_directories, |
| source_file_target_directories); |
| if (!scope_options_valid) { |
| return false; |
| } |
| |
| scope_options_valid = SetPropertyCommand::HandleSourceFileDirectoryScopes( |
| status, source_file_directories, source_file_target_directories, |
| source_file_directory_makefiles); |
| return scope_options_valid; |
| } |
| |
| std::string MakeSourceFilePathAbsoluteIfNeeded( |
| cmExecutionStatus& status, const std::string& source_file_path, |
| const bool needed) |
| { |
| if (!needed) { |
| return source_file_path; |
| } |
| std::string absolute_file_path = cmSystemTools::CollapseFullPath( |
| source_file_path, status.GetMakefile().GetCurrentSourceDirectory()); |
| return absolute_file_path; |
| } |
| |
| void MakeSourceFilePathsAbsoluteIfNeeded( |
| cmExecutionStatus& status, |
| std::vector<std::string>& source_files_absolute_paths, |
| std::vector<std::string>::const_iterator files_it_begin, |
| std::vector<std::string>::const_iterator files_it_end, const bool needed) |
| { |
| |
| // Make the file paths absolute, so that relative source file paths are |
| // picked up relative to the command calling site, regardless of the |
| // directory scope. |
| std::vector<std::string>::difference_type num_files = |
| files_it_end - files_it_begin; |
| source_files_absolute_paths.reserve(num_files); |
| |
| if (!needed) { |
| source_files_absolute_paths.assign(files_it_begin, files_it_end); |
| return; |
| } |
| |
| for (; files_it_begin != files_it_end; ++files_it_begin) { |
| const std::string absolute_file_path = |
| MakeSourceFilePathAbsoluteIfNeeded(status, *files_it_begin, true); |
| source_files_absolute_paths.push_back(absolute_file_path); |
| } |
| } |
| |
| bool HandleAndValidateSourceFilePropertyGENERATED( |
| cmSourceFile* sf, std::string const& propertyValue, PropertyOp op) |
| { |
| const auto& mf = *sf->GetLocation().GetMakefile(); |
| auto policyStatus = mf.GetPolicyStatus(cmPolicies::CMP0118); |
| |
| const bool policyWARN = policyStatus == cmPolicies::WARN; |
| const bool policyNEW = policyStatus != cmPolicies::OLD && !policyWARN; |
| |
| if (policyWARN) { |
| if (!cmIsOn(propertyValue) && !cmIsOff(propertyValue)) { |
| mf.IssueMessage( |
| MessageType::AUTHOR_WARNING, |
| cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118), |
| "\nAttempt to set property 'GENERATED' with the following " |
| "non-boolean value (which will be interpreted as \"0\"):\n", |
| propertyValue, |
| "\nThat exact value will not be retrievable. A value of " |
| "\"0\" will be returned instead.\n" |
| "This will be an error under policy CMP0118.\n")); |
| } |
| if (cmIsOff(propertyValue)) { |
| mf.IssueMessage( |
| MessageType::AUTHOR_WARNING, |
| cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118), |
| "\nUnsetting property 'GENERATED' will not be allowed under " |
| "policy CMP0118!\n")); |
| } |
| if (op == PropertyOp::Append || op == PropertyOp::AppendAsString) { |
| mf.IssueMessage( |
| MessageType::AUTHOR_WARNING, |
| cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0118), |
| "\nAppending to property 'GENERATED' will not be allowed " |
| "under policy CMP0118!\n")); |
| } |
| } else if (policyNEW) { |
| if (!cmIsOn(propertyValue) && !cmIsOff(propertyValue)) { |
| mf.IssueMessage( |
| MessageType::AUTHOR_ERROR, |
| cmStrCat( |
| "Policy CMP0118 is set to NEW and the following non-boolean value " |
| "given for property 'GENERATED' is therefore not allowed:\n", |
| propertyValue, "\nReplace it with a boolean value!\n")); |
| return true; |
| } |
| if (cmIsOff(propertyValue)) { |
| mf.IssueMessage( |
| MessageType::AUTHOR_ERROR, |
| "Unsetting the 'GENERATED' property is not allowed under CMP0118!\n"); |
| return true; |
| } |
| if (op == PropertyOp::Append || op == PropertyOp::AppendAsString) { |
| mf.IssueMessage(MessageType::AUTHOR_ERROR, |
| "Policy CMP0118 is set to NEW and appending to the " |
| "'GENERATED' property is therefore not allowed. Only " |
| "setting it to \"1\" is allowed!\n"); |
| return true; |
| } |
| } |
| |
| // Set property. |
| if (!policyNEW) { |
| // Do it the traditional way. |
| switch (op) { |
| case PropertyOp::Append: |
| sf->AppendProperty("GENERATED", propertyValue, false); |
| break; |
| case PropertyOp::AppendAsString: |
| sf->AppendProperty("GENERATED", propertyValue, true); |
| break; |
| case PropertyOp::Remove: |
| sf->SetProperty("GENERATED", nullptr); |
| break; |
| case PropertyOp::Set: |
| sf->SetProperty("GENERATED", propertyValue); |
| break; |
| } |
| } else { |
| sf->MarkAsGenerated(); |
| } |
| return true; |
| } |
| |
| } // END: namespace SetPropertyCommand |
| |
| bool cmSetPropertyCommand(std::vector<std::string> const& args, |
| cmExecutionStatus& status) |
| { |
| if (args.size() < 2) { |
| status.SetError("called with incorrect number of arguments"); |
| return false; |
| } |
| |
| // Get the scope on which to set the property. |
| std::string const& scopeName = args.front(); |
| cmProperty::ScopeType scope; |
| if (scopeName == "GLOBAL") { |
| scope = cmProperty::GLOBAL; |
| } else if (scopeName == "DIRECTORY") { |
| scope = cmProperty::DIRECTORY; |
| } else if (scopeName == "TARGET") { |
| scope = cmProperty::TARGET; |
| } else if (scopeName == "SOURCE") { |
| scope = cmProperty::SOURCE_FILE; |
| } else if (scopeName == "TEST") { |
| scope = cmProperty::TEST; |
| } else if (scopeName == "CACHE") { |
| scope = cmProperty::CACHE; |
| } else if (scopeName == "INSTALL") { |
| scope = cmProperty::INSTALL; |
| } else { |
| status.SetError(cmStrCat("given invalid scope ", scopeName, |
| ". " |
| "Valid scopes are GLOBAL, DIRECTORY, " |
| "TARGET, SOURCE, TEST, CACHE, INSTALL.")); |
| return false; |
| } |
| |
| bool appendAsString = false; |
| bool appendMode = false; |
| bool remove = true; |
| std::set<std::string> names; |
| std::string propertyName; |
| std::string propertyValue; |
| |
| std::vector<std::string> source_file_directories; |
| std::vector<std::string> source_file_target_directories; |
| bool source_file_directory_option_enabled = false; |
| bool source_file_target_option_enabled = false; |
| |
| // Parse the rest of the arguments up to the values. |
| enum Doing |
| { |
| DoingNone, |
| DoingNames, |
| DoingProperty, |
| DoingValues, |
| DoingSourceDirectory, |
| DoingSourceTargetDirectory |
| }; |
| Doing doing = DoingNames; |
| const char* sep = ""; |
| for (std::string const& arg : cmMakeRange(args).advance(1)) { |
| if (arg == "PROPERTY") { |
| doing = DoingProperty; |
| } else if (arg == "APPEND") { |
| doing = DoingNone; |
| appendMode = true; |
| remove = false; |
| appendAsString = false; |
| } else if (arg == "APPEND_STRING") { |
| doing = DoingNone; |
| appendMode = true; |
| remove = false; |
| appendAsString = true; |
| } else if (doing != DoingProperty && doing != DoingValues && |
| scope == cmProperty::SOURCE_FILE && arg == "DIRECTORY") { |
| doing = DoingSourceDirectory; |
| source_file_directory_option_enabled = true; |
| } else if (doing != DoingProperty && doing != DoingValues && |
| scope == cmProperty::SOURCE_FILE && arg == "TARGET_DIRECTORY") { |
| doing = DoingSourceTargetDirectory; |
| source_file_target_option_enabled = true; |
| } else if (doing == DoingNames) { |
| names.insert(arg); |
| } else if (doing == DoingSourceDirectory) { |
| source_file_directories.push_back(arg); |
| } else if (doing == DoingSourceTargetDirectory) { |
| source_file_target_directories.push_back(arg); |
| } else if (doing == DoingProperty) { |
| propertyName = arg; |
| doing = DoingValues; |
| } else if (doing == DoingValues) { |
| propertyValue += sep; |
| sep = ";"; |
| propertyValue += arg; |
| remove = false; |
| } else { |
| status.SetError(cmStrCat("given invalid argument \"", arg, "\".")); |
| return false; |
| } |
| } |
| |
| // Make sure a property name was found. |
| if (propertyName.empty()) { |
| status.SetError("not given a PROPERTY <name> argument."); |
| return false; |
| } |
| |
| std::vector<cmMakefile*> source_file_directory_makefiles; |
| bool file_scopes_handled = |
| SetPropertyCommand::HandleAndValidateSourceFileDirectoryScopes( |
| status, source_file_directory_option_enabled, |
| source_file_target_option_enabled, source_file_directories, |
| source_file_target_directories, source_file_directory_makefiles); |
| if (!file_scopes_handled) { |
| return false; |
| } |
| bool source_file_paths_should_be_absolute = |
| source_file_directory_option_enabled || source_file_target_option_enabled; |
| |
| // Dispatch property setting. |
| switch (scope) { |
| case cmProperty::GLOBAL: |
| return HandleGlobalMode(status, names, propertyName, propertyValue, |
| appendAsString, appendMode, remove); |
| case cmProperty::DIRECTORY: |
| return HandleDirectoryMode(status, names, propertyName, propertyValue, |
| appendAsString, appendMode, remove); |
| case cmProperty::TARGET: |
| return HandleTargetMode(status, names, propertyName, propertyValue, |
| appendAsString, appendMode, remove); |
| case cmProperty::SOURCE_FILE: |
| return HandleSourceMode(status, names, propertyName, propertyValue, |
| appendAsString, appendMode, remove, |
| source_file_directory_makefiles, |
| source_file_paths_should_be_absolute); |
| case cmProperty::TEST: |
| return HandleTestMode(status, names, propertyName, propertyValue, |
| appendAsString, appendMode, remove); |
| case cmProperty::CACHE: |
| return HandleCacheMode(status, names, propertyName, propertyValue, |
| appendAsString, appendMode, remove); |
| case cmProperty::INSTALL: |
| return HandleInstallMode(status, names, propertyName, propertyValue, |
| appendAsString, appendMode, remove); |
| |
| case cmProperty::VARIABLE: |
| case cmProperty::CACHED_VARIABLE: |
| break; // should never happen |
| } |
| return true; |
| } |
| |
| namespace /* anonymous */ { |
| bool HandleGlobalMode(cmExecutionStatus& status, |
| const std::set<std::string>& names, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove) |
| { |
| if (!names.empty()) { |
| status.SetError("given names for GLOBAL scope."); |
| return false; |
| } |
| |
| // Set or append the property. |
| cmake* cm = status.GetMakefile().GetCMakeInstance(); |
| if (appendMode) { |
| cm->AppendProperty(propertyName, propertyValue, appendAsString); |
| } else { |
| if (remove) { |
| cm->SetProperty(propertyName, nullptr); |
| } else { |
| cm->SetProperty(propertyName, propertyValue); |
| } |
| } |
| |
| return true; |
| } |
| |
| bool HandleDirectoryMode(cmExecutionStatus& status, |
| const std::set<std::string>& names, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove) |
| { |
| if (names.size() > 1) { |
| status.SetError("allows at most one name for DIRECTORY scope."); |
| return false; |
| } |
| |
| // Default to the current directory. |
| cmMakefile* mf = &status.GetMakefile(); |
| |
| // Lookup the directory if given. |
| if (!names.empty()) { |
| // Construct the directory name. Interpret relative paths with |
| // respect to the current directory. |
| std::string dir = cmSystemTools::CollapseFullPath( |
| *names.begin(), status.GetMakefile().GetCurrentSourceDirectory()); |
| |
| mf = status.GetMakefile().GetGlobalGenerator()->FindMakefile(dir); |
| if (!mf) { |
| // Could not find the directory. |
| status.SetError( |
| "DIRECTORY scope provided but requested directory was not found. " |
| "This could be because the directory argument was invalid or, " |
| "it is valid but has not been processed yet."); |
| return false; |
| } |
| } |
| |
| // Set or append the property. |
| if (appendMode) { |
| mf->AppendProperty(propertyName, propertyValue, appendAsString); |
| } else { |
| if (remove) { |
| mf->SetProperty(propertyName, nullptr); |
| } else { |
| mf->SetProperty(propertyName, propertyValue); |
| } |
| } |
| |
| return true; |
| } |
| |
| bool HandleTargetMode(cmExecutionStatus& status, |
| const std::set<std::string>& names, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove) |
| { |
| for (std::string const& name : names) { |
| if (status.GetMakefile().IsAlias(name)) { |
| status.SetError("can not be used on an ALIAS target."); |
| return false; |
| } |
| if (cmTarget* target = status.GetMakefile().FindTargetToUse(name)) { |
| // Handle the current target. |
| if (!HandleTarget(target, status.GetMakefile(), propertyName, |
| propertyValue, appendAsString, appendMode, remove)) { |
| return false; |
| } |
| } else { |
| status.SetError(cmStrCat("could not find TARGET ", name, |
| ". Perhaps it has not yet been created.")); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool HandleTarget(cmTarget* target, cmMakefile& makefile, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove) |
| { |
| // Set or append the property. |
| if (appendMode) { |
| target->AppendProperty(propertyName, propertyValue, appendAsString); |
| } else { |
| if (remove) { |
| target->SetProperty(propertyName, nullptr); |
| } else { |
| target->SetProperty(propertyName, propertyValue); |
| } |
| } |
| |
| // Check the resulting value. |
| target->CheckProperty(propertyName, &makefile); |
| |
| return true; |
| } |
| |
| bool HandleSourceMode(cmExecutionStatus& status, |
| const std::set<std::string>& names, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove, |
| const std::vector<cmMakefile*>& directory_makefiles, |
| const bool source_file_paths_should_be_absolute) |
| { |
| std::vector<std::string> files_absolute; |
| std::vector<std::string> unique_files(names.begin(), names.end()); |
| SetPropertyCommand::MakeSourceFilePathsAbsoluteIfNeeded( |
| status, files_absolute, unique_files.begin(), unique_files.end(), |
| source_file_paths_should_be_absolute); |
| |
| for (auto* const mf : directory_makefiles) { |
| for (std::string const& name : files_absolute) { |
| // Get the source file. |
| if (cmSourceFile* sf = mf->GetOrCreateSource(name)) { |
| if (!HandleSource(sf, propertyName, propertyValue, appendAsString, |
| appendMode, remove)) { |
| return false; |
| } |
| } else { |
| status.SetError(cmStrCat( |
| "given SOURCE name that could not be found or created: ", name)); |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| bool HandleSource(cmSourceFile* sf, const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove) |
| { |
| // Special validation and handling of GENERATED flag? |
| if (propertyName == "GENERATED") { |
| SetPropertyCommand::PropertyOp op = (remove) |
| ? SetPropertyCommand::PropertyOp::Remove |
| : (appendAsString) |
| ? SetPropertyCommand::PropertyOp::AppendAsString |
| : (appendMode) ? SetPropertyCommand::PropertyOp::Append |
| : SetPropertyCommand::PropertyOp::Set; |
| return SetPropertyCommand::HandleAndValidateSourceFilePropertyGENERATED( |
| sf, propertyValue, op); |
| } |
| |
| // Set or append the property. |
| if (appendMode) { |
| sf->AppendProperty(propertyName, propertyValue, appendAsString); |
| } else { |
| if (remove) { |
| sf->SetProperty(propertyName, nullptr); |
| } else { |
| sf->SetProperty(propertyName, propertyValue); |
| } |
| } |
| return true; |
| } |
| |
| bool HandleTestMode(cmExecutionStatus& status, std::set<std::string>& names, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove) |
| { |
| // Look for tests with all names given. |
| std::set<std::string>::iterator next; |
| for (auto ni = names.begin(); ni != names.end(); ni = next) { |
| next = ni; |
| ++next; |
| if (cmTest* test = status.GetMakefile().GetTest(*ni)) { |
| if (HandleTest(test, propertyName, propertyValue, appendAsString, |
| appendMode, remove)) { |
| names.erase(ni); |
| } else { |
| return false; |
| } |
| } |
| } |
| |
| // Names that are still left were not found. |
| if (!names.empty()) { |
| std::ostringstream e; |
| e << "given TEST names that do not exist:\n"; |
| for (std::string const& name : names) { |
| e << " " << name << "\n"; |
| } |
| status.SetError(e.str()); |
| return false; |
| } |
| return true; |
| } |
| |
| bool HandleTest(cmTest* test, const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove) |
| { |
| // Set or append the property. |
| if (appendMode) { |
| test->AppendProperty(propertyName, propertyValue, appendAsString); |
| } else { |
| if (remove) { |
| test->SetProperty(propertyName, nullptr); |
| } else { |
| test->SetProperty(propertyName, propertyValue); |
| } |
| } |
| |
| return true; |
| } |
| |
| bool HandleCacheMode(cmExecutionStatus& status, |
| const std::set<std::string>& names, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove) |
| { |
| if (propertyName == "ADVANCED") { |
| if (!remove && !cmIsOn(propertyValue) && !cmIsOff(propertyValue)) { |
| status.SetError(cmStrCat("given non-boolean value \"", propertyValue, |
| R"(" for CACHE property "ADVANCED". )")); |
| return false; |
| } |
| } else if (propertyName == "TYPE") { |
| if (!cmState::IsCacheEntryType(propertyValue)) { |
| status.SetError( |
| cmStrCat("given invalid CACHE entry TYPE \"", propertyValue, "\"")); |
| return false; |
| } |
| } else if (propertyName != "HELPSTRING" && propertyName != "STRINGS" && |
| propertyName != "VALUE") { |
| status.SetError( |
| cmStrCat("given invalid CACHE property ", propertyName, |
| ". " |
| "Settable CACHE properties are: " |
| "ADVANCED, HELPSTRING, STRINGS, TYPE, and VALUE.")); |
| return false; |
| } |
| |
| for (std::string const& name : names) { |
| // Get the source file. |
| cmake* cm = status.GetMakefile().GetCMakeInstance(); |
| cmValue existingValue = cm->GetState()->GetCacheEntryValue(name); |
| if (existingValue) { |
| if (!HandleCacheEntry(name, status.GetMakefile(), propertyName, |
| propertyValue, appendAsString, appendMode, |
| remove)) { |
| return false; |
| } |
| } else { |
| status.SetError(cmStrCat("could not find CACHE variable ", name, |
| ". Perhaps it has not yet been created.")); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool HandleCacheEntry(std::string const& cacheKey, const cmMakefile& makefile, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove) |
| { |
| // Set or append the property. |
| cmState* state = makefile.GetState(); |
| if (remove) { |
| state->RemoveCacheEntryProperty(cacheKey, propertyName); |
| } |
| if (appendMode) { |
| state->AppendCacheEntryProperty(cacheKey, propertyName, propertyValue, |
| appendAsString); |
| } else { |
| state->SetCacheEntryProperty(cacheKey, propertyName, propertyValue); |
| } |
| |
| return true; |
| } |
| |
| bool HandleInstallMode(cmExecutionStatus& status, |
| const std::set<std::string>& names, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove) |
| { |
| cmake* cm = status.GetMakefile().GetCMakeInstance(); |
| |
| for (std::string const& name : names) { |
| if (cmInstalledFile* file = |
| cm->GetOrCreateInstalledFile(&status.GetMakefile(), name)) { |
| if (!HandleInstall(file, status.GetMakefile(), propertyName, |
| propertyValue, appendAsString, appendMode, remove)) { |
| return false; |
| } |
| } else { |
| status.SetError(cmStrCat( |
| "given INSTALL name that could not be found or created: ", name)); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool HandleInstall(cmInstalledFile* file, cmMakefile& makefile, |
| const std::string& propertyName, |
| const std::string& propertyValue, bool appendAsString, |
| bool appendMode, bool remove) |
| { |
| // Set or append the property. |
| if (remove) { |
| file->RemoveProperty(propertyName); |
| } else if (appendMode) { |
| file->AppendProperty(&makefile, propertyName, propertyValue, |
| appendAsString); |
| } else { |
| file->SetProperty(&makefile, propertyName, propertyValue); |
| } |
| return true; |
| } |
| } |