/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file LICENSE.rst or https://cmake.org/licensing for details. */ #include "cmGetPropertyCommand.h" #include "cmDirectoryPropertyHelper.h" #include "cmExecutionStatus.h" #include "cmFileSet.h" #include "cmInstalledFile.h" #include "cmMakefile.h" #include "cmProperty.h" #include "cmPropertyDefinition.h" #include "cmRule.h" #include "cmSetPropertyCommand.h" #include "cmSourceFilePropertyHelper.h" #include "cmState.h" #include "cmStringAlgorithms.h" #include "cmTarget.h" #include "cmTargetPropertyHelper.h" #include "cmTestPropertyHelper.h" #include "cmValue.h" #include "cmake.h" namespace { enum OutType { OutValue, OutDefined, OutBriefDoc, OutFullDoc, OutSet }; // Implementation of each property type. bool HandleGlobalMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName); bool HandleDirectoryMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName); bool HandleRuleMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName); bool HandleTargetMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName); bool HandleFileSetMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName, cmTarget* target); bool HandleSourceMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName, bool sourceFileDirectoryOptionEnabled, bool sourceFileTargetOptionEnabled, std::vector& sourceFileDirectories, std::vector& sourceFileTargetDirectories); bool HandleTestMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName, bool testDirectoryOptionEnabled, std::string& testDirectory); bool HandleVariableMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName); bool HandleCacheMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName); bool HandleInstallMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName); } bool cmGetPropertyCommand(std::vector const& args, cmExecutionStatus& status) { OutType infoType = OutValue; if (args.size() < 3) { status.SetError("called with incorrect number of arguments"); return false; } // The cmake variable in which to store the result. std::string const& variable = args[0]; std::string name; std::string propertyName; std::string file_set_target_name; bool file_set_target_option_enabled = false; std::vector source_file_directories; std::vector source_file_target_directories; bool source_file_directory_option_enabled = false; bool source_file_target_option_enabled = false; std::string test_directory; bool test_directory_option_enabled = false; // Get the scope from which to get the property. cmProperty::ScopeType scope; if (args[1] == "GLOBAL") { scope = cmProperty::GLOBAL; } else if (args[1] == "DIRECTORY") { scope = cmProperty::DIRECTORY; } else if (args[1] == "RULE") { scope = cmProperty::RULE; } else if (args[1] == "TARGET") { scope = cmProperty::TARGET; } else if (args[1] == "FILE_SET") { scope = cmProperty::FILE_SET; } else if (args[1] == "SOURCE") { scope = cmProperty::SOURCE_FILE; } else if (args[1] == "TEST") { scope = cmProperty::TEST; } else if (args[1] == "VARIABLE") { scope = cmProperty::VARIABLE; } else if (args[1] == "CACHE") { scope = cmProperty::CACHE; } else if (args[1] == "INSTALL") { scope = cmProperty::INSTALL; } else { status.SetError( cmStrCat("given invalid scope ", args[1], ". Valid scopes are GLOBAL, DIRECTORY, RULE, TARGET, " "FILE_SET, SOURCE, TEST, VARIABLE, CACHE, INSTALL.")); return false; } // Parse remaining arguments. enum Doing { DoingNone, DoingName, DoingProperty, DoingType, DoingFileSetTarget, DoingSourceDirectory, DoingSourceTargetDirectory, DoingTestDirectory, }; Doing doing = DoingName; for (unsigned int i = 2; i < args.size(); ++i) { if (args[i] == "PROPERTY") { doing = DoingProperty; } else if (args[i] == "BRIEF_DOCS") { doing = DoingNone; infoType = OutBriefDoc; } else if (args[i] == "FULL_DOCS") { doing = DoingNone; infoType = OutFullDoc; } else if (args[i] == "SET") { doing = DoingNone; infoType = OutSet; } else if (args[i] == "DEFINED") { doing = DoingNone; infoType = OutDefined; } else if (doing == DoingName) { doing = DoingNone; name = args[i]; } else if (doing == DoingNone && scope == cmProperty::FILE_SET && args[i] == "TARGET") { doing = DoingFileSetTarget; file_set_target_option_enabled = true; } else if (doing == DoingNone && scope == cmProperty::SOURCE_FILE && args[i] == "DIRECTORY") { doing = DoingSourceDirectory; source_file_directory_option_enabled = true; } else if (doing == DoingNone && scope == cmProperty::SOURCE_FILE && args[i] == "TARGET_DIRECTORY") { doing = DoingSourceTargetDirectory; source_file_target_option_enabled = true; } else if (doing == DoingNone && scope == cmProperty::TEST && args[i] == "DIRECTORY") { doing = DoingTestDirectory; test_directory_option_enabled = true; } else if (doing == DoingFileSetTarget) { file_set_target_name = args[i]; doing = DoingNone; } else if (doing == DoingSourceDirectory) { source_file_directories.push_back(args[i]); doing = DoingNone; } else if (doing == DoingSourceTargetDirectory) { source_file_target_directories.push_back(args[i]); doing = DoingNone; } else if (doing == DoingTestDirectory) { test_directory = args[i]; doing = DoingNone; } else if (doing == DoingProperty) { doing = DoingNone; propertyName = args[i]; } else { status.SetError(cmStrCat("given invalid argument \"", args[i], "\".")); return false; } } // Make sure a property name was found. if (propertyName.empty()) { status.SetError("not given a PROPERTY argument."); return false; } // Compute requested output. if (infoType == OutBriefDoc) { // Lookup brief documentation. std::string output; if (cmPropertyDefinition const* def = status.GetMakefile().GetState()->GetPropertyDefinition(propertyName, scope)) { output = def->GetShortDescription(); } if (output.empty()) { output = "NOTFOUND"; } status.GetMakefile().AddDefinition(variable, output); } else if (infoType == OutFullDoc) { // Lookup full documentation. std::string output; if (cmPropertyDefinition const* def = status.GetMakefile().GetState()->GetPropertyDefinition(propertyName, scope)) { output = def->GetFullDescription(); } if (output.empty()) { output = "NOTFOUND"; } status.GetMakefile().AddDefinition(variable, output); } else if (infoType == OutDefined) { // Lookup if the property is defined if (status.GetMakefile().GetState()->GetPropertyDefinition(propertyName, scope)) { status.GetMakefile().AddDefinition(variable, "1"); } else { status.GetMakefile().AddDefinition(variable, "0"); } } else { // Dispatch property getting. switch (scope) { case cmProperty::GLOBAL: return HandleGlobalMode(status, name, infoType, variable, propertyName); case cmProperty::DIRECTORY: return HandleDirectoryMode(status, name, infoType, variable, propertyName); case cmProperty::RULE: return HandleRuleMode(status, name, infoType, variable, propertyName); case cmProperty::TARGET: return HandleTargetMode(status, name, infoType, variable, propertyName); case cmProperty::FILE_SET: { cmTarget* file_set_target; if (!SetPropertyCommand::HandleAndValidateFileSetTargetScopes( status, file_set_target_option_enabled, file_set_target_name, file_set_target)) { return false; } return HandleFileSetMode(status, name, infoType, variable, propertyName, file_set_target); } case cmProperty::SOURCE_FILE: return HandleSourceMode(status, name, infoType, variable, propertyName, source_file_directory_option_enabled, source_file_target_option_enabled, source_file_directories, source_file_target_directories); case cmProperty::TEST: return HandleTestMode(status, name, infoType, variable, propertyName, test_directory_option_enabled, test_directory); case cmProperty::VARIABLE: return HandleVariableMode(status, name, infoType, variable, propertyName); case cmProperty::CACHE: return HandleCacheMode(status, name, infoType, variable, propertyName); case cmProperty::INSTALL: return HandleInstallMode(status, name, infoType, variable, propertyName); case cmProperty::CACHED_VARIABLE: break; // should never happen } } return true; } namespace { // Implementation of result storage. template bool StoreResult(OutType infoType, cmMakefile& makefile, std::string const& variable, ValueType value) { if (infoType == OutSet) { makefile.AddDefinition(variable, value ? "1" : "0"); } else // if(infoType == OutValue) { if (value) { makefile.AddDefinition(variable, value); } else { makefile.RemoveDefinition(variable); } } return true; } bool HandleGlobalMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName) { if (!name.empty()) { status.SetError("given name for GLOBAL scope."); return false; } // Get the property. cmake* cm = status.GetMakefile().GetCMakeInstance(); return StoreResult(infoType, status.GetMakefile(), variable, cm->GetState()->GetGlobalProperty(propertyName)); } bool HandleDirectoryMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName) { cmValue prop; if (!GetPropertyCommand::LookupDirectoryProperty(status, name, propertyName, prop)) { return false; } return StoreResult(infoType, status.GetMakefile(), variable, prop); } bool HandleRuleMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName) { if (name.empty()) { status.SetError("not given name for RULE scope."); return false; } if (cmRule* rule = status.GetMakefile().FindRuleToUse(name)) { cmValue prop = rule->GetProperty(propertyName); return StoreResult(infoType, status.GetMakefile(), variable, prop); } status.SetError(cmStrCat("could not find RULE ", name, ". Perhaps it has not yet been created.")); return false; } bool HandleTargetMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName) { cmValue prop; if (!GetPropertyCommand::LookupTargetProperty(status, name, propertyName, prop)) { return false; } return StoreResult(infoType, status.GetMakefile(), variable, prop); } bool HandleFileSetMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName, cmTarget* target) { if (name.empty()) { status.SetError("not given name for FILE_SET scope."); return false; } if (cmFileSet* fileSet = target->GetFileSet(name)) { cmValue prop = fileSet->GetProperty(propertyName); return StoreResult(infoType, status.GetMakefile(), variable, prop); } status.SetError(cmStrCat("could not find FILE_SET ", name, " for TARGET ", target->GetName(), ". Perhaps it has not yet been created.")); return false; } bool HandleSourceMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName, bool sourceFileDirectoryOptionEnabled, bool sourceFileTargetOptionEnabled, std::vector& sourceFileDirectories, std::vector& sourceFileTargetDirectories) { cmValue prop; if (!GetPropertyCommand::LookupSourceProperty( status, name, propertyName, sourceFileDirectoryOptionEnabled, sourceFileTargetOptionEnabled, sourceFileDirectories, sourceFileTargetDirectories, prop)) { return false; } return StoreResult(infoType, status.GetMakefile(), variable, prop); } bool HandleTestMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName, bool testDirectoryOptionEnabled, std::string& testDirectory) { cmValue prop; if (!GetPropertyCommand::LookupTestProperty(status, name, propertyName, testDirectoryOptionEnabled, testDirectory, prop)) { return false; } return StoreResult(infoType, status.GetMakefile(), variable, prop); } bool HandleVariableMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName) { if (!name.empty()) { status.SetError("given name for VARIABLE scope."); return false; } return StoreResult(infoType, status.GetMakefile(), variable, status.GetMakefile().GetDefinition(propertyName)); } bool HandleCacheMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName) { cmValue value; if (!GetPropertyCommand::LookupCacheProperty(status, name, propertyName, value)) { return false; } StoreResult(infoType, status.GetMakefile(), variable, value); return true; } bool HandleInstallMode(cmExecutionStatus& status, std::string const& name, OutType infoType, std::string const& variable, std::string const& propertyName) { if (name.empty()) { status.SetError("not given name for INSTALL scope."); return false; } // Get the installed file. cmake* cm = status.GetMakefile().GetCMakeInstance(); if (cmInstalledFile* file = cm->GetOrCreateInstalledFile(&status.GetMakefile(), name)) { std::string value; bool isSet = file->GetProperty(propertyName, value); return StoreResult(infoType, status.GetMakefile(), variable, isSet ? value.c_str() : nullptr); } status.SetError( cmStrCat("given INSTALL name that could not be found or created: ", name)); return false; } } namespace GetPropertyCommand { bool LookupTargetProperty(cmExecutionStatus& status, std::string const& name, std::string const& propertyName, cmValue& out) { if (name.empty()) { status.SetError("not given name for TARGET scope."); return false; } auto result = cmGetTargetProperty(name, propertyName, status.GetMakefile(), out); if (result == cmGetTargetPropertyResult::Success) { return true; } if (result == cmGetTargetPropertyResult::TargetNotFound) { status.SetError(cmStrCat("could not find TARGET ", name, ". Perhaps it has not yet been created.")); } return false; } bool LookupDirectoryProperty(cmExecutionStatus& status, std::string const& name, std::string const& propertyName, cmValue& out) { auto result = cmGetDirectoryProperty(name, propertyName, status.GetMakefile(), out); if (result == cmGetDirectoryPropertyResult::Success) { return true; } if (result == cmGetDirectoryPropertyResult::DirectoryNotFound) { 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; } bool LookupSourceProperty( cmExecutionStatus& status, std::string const& name, std::string const& propertyName, bool sourceFileDirectoryOptionEnabled, bool sourceFileTargetOptionEnabled, std::vector& sourceFileDirectories, std::vector& sourceFileTargetDirectories, cmValue& out) { if (name.empty()) { status.SetError("not given name for SOURCE scope."); return false; } auto result = cmGetSourceFileProperty( name, propertyName, status, sourceFileDirectoryOptionEnabled, sourceFileTargetOptionEnabled, sourceFileDirectories, sourceFileTargetDirectories, out, /*alwaysCreateSource=*/true); if (result == cmGetSourceFilePropertyResult::Success) { return true; } if (result == cmGetSourceFilePropertyResult::Error || result == cmGetSourceFilePropertyResult::SourceNotFound) { status.SetError(cmStrCat( "given SOURCE name that could not be found or created: ", name)); } return false; } bool LookupSourceProperty(cmExecutionStatus& status, std::string const& name, std::string const& propertyName, cmValue& out) { std::vector noDirectories; std::vector noTargetDirectories; return LookupSourceProperty(status, name, propertyName, /*sourceFileDirectoryOptionEnabled=*/false, /*sourceFileTargetOptionEnabled=*/false, noDirectories, noTargetDirectories, out); } bool LookupTestProperty(cmExecutionStatus& status, std::string const& name, std::string const& propertyName, bool testDirectoryOptionEnabled, std::string& testDirectory, cmValue& out) { if (name.empty()) { status.SetError("not given name for TEST scope."); return false; } auto result = cmGetTestProperty(name, propertyName, status, testDirectoryOptionEnabled, testDirectory, out); if (result == cmGetTestPropertyResult::Success) { return true; } if (result == cmGetTestPropertyResult::TestNotFound) { status.SetError(cmStrCat("given TEST name that does not exist: ", name)); } return false; } bool LookupTestProperty(cmExecutionStatus& status, std::string const& name, std::string const& propertyName, cmValue& out) { std::string noDirectory; return LookupTestProperty(status, name, propertyName, /*testDirectoryOptionEnabled=*/false, noDirectory, out); } bool LookupCacheProperty(cmExecutionStatus& status, std::string const& name, std::string const& propertyName, cmValue& out) { if (name.empty()) { status.SetError("not given name for CACHE scope."); return false; } out = nullptr; if (status.GetMakefile().GetState()->GetCacheEntryValue(name)) { out = status.GetMakefile().GetState()->GetCacheEntryProperty(name, propertyName); } return true; } }