From e5e91d617940cab2ea4e8630c6c20cd09794b3a9 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 10 Mar 2009 11:10:59 -0400 Subject: ENH: Teach set/get_property about CACHE properties This adds the CACHE option to set_property and get_property commands. This allows full control over cache entry information, so advanced users can tweak their project cache as desired. The set_property command allows only pre-defined CACHE properties to be set since others would not persist anyway. --- Source/cmCacheManager.cxx | 12 ++++++ Source/cmCacheManager.h | 1 + Source/cmGetPropertyCommand.cxx | 27 +++++++++++- Source/cmGetPropertyCommand.h | 3 ++ Source/cmSetPropertyCommand.cxx | 95 ++++++++++++++++++++++++++++++++++++++++- Source/cmSetPropertyCommand.h | 6 ++- Tests/Properties/CMakeLists.txt | 26 +++++++++++ 7 files changed, 167 insertions(+), 3 deletions(-) diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx index f53ed49..365d052 100644 --- a/Source/cmCacheManager.cxx +++ b/Source/cmCacheManager.cxx @@ -71,6 +71,18 @@ cmCacheManager::CacheEntryType cmCacheManager::StringToType(const char* s) return STRING; } +bool cmCacheManager::IsType(const char* s) +{ + for(int i=0; cmCacheManagerTypes[i]; ++i) + { + if(strcmp(s, cmCacheManagerTypes[i]) == 0) + { + return true; + } + } + return false; +} + bool cmCacheManager::LoadCache(cmMakefile* mf) { return this->LoadCache(mf->GetHomeOutputDirectory()); diff --git a/Source/cmCacheManager.h b/Source/cmCacheManager.h index e57042b..abd14bd 100644 --- a/Source/cmCacheManager.h +++ b/Source/cmCacheManager.h @@ -105,6 +105,7 @@ public: */ static CacheEntryType StringToType(const char*); static const char* TypeToString(CacheEntryType); + static bool IsType(const char*); ///! Load a cache for given makefile. Loads from ouput home. bool LoadCache(cmMakefile*); diff --git a/Source/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx index 88a3e7c..3446fb2 100644 --- a/Source/cmGetPropertyCommand.cxx +++ b/Source/cmGetPropertyCommand.cxx @@ -65,12 +65,16 @@ bool cmGetPropertyCommand { scope = cmProperty::VARIABLE; } + else if(args[1] == "CACHE") + { + scope = cmProperty::CACHE; + } else { cmOStringStream e; e << "given invalid scope " << args[1] << ". " << "Valid scopes are " - << "GLOBAL, DIRECTORY, TARGET, SOURCE, TEST, VARIABLE."; + << "GLOBAL, DIRECTORY, TARGET, SOURCE, TEST, VARIABLE, CACHE."; this->SetError(e.str().c_str()); return false; } @@ -187,6 +191,7 @@ bool cmGetPropertyCommand case cmProperty::SOURCE_FILE: return this->HandleSourceMode(); case cmProperty::TEST: return this->HandleTestMode(); case cmProperty::VARIABLE: return this->HandleVariableMode(); + case cmProperty::CACHE: return this->HandleCacheMode(); case cmProperty::CACHED_VARIABLE: break; // should never happen @@ -359,3 +364,23 @@ bool cmGetPropertyCommand::HandleVariableMode() return this->StoreResult (this->Makefile->GetDefinition(this->PropertyName.c_str())); } + +//---------------------------------------------------------------------------- +bool cmGetPropertyCommand::HandleCacheMode() +{ + if(this->Name.empty()) + { + this->SetError("not given name for CACHE scope."); + return false; + } + + const char* value = 0; + cmCacheManager::CacheIterator it = + this->Makefile->GetCacheManager()->GetCacheIterator(this->Name.c_str()); + if(!it.IsAtEnd()) + { + value = it.GetProperty(this->PropertyName.c_str()); + } + this->StoreResult(value); + return true; +} diff --git a/Source/cmGetPropertyCommand.h b/Source/cmGetPropertyCommand.h index a8976c5..b4ec3cc 100644 --- a/Source/cmGetPropertyCommand.h +++ b/Source/cmGetPropertyCommand.h @@ -66,6 +66,7 @@ public: " TARGET |\n" " SOURCE |\n" " TEST |\n" + " CACHE |\n" " VARIABLE>\n" " PROPERTY \n" " [SET | DEFINED | BRIEF_DOCS | FULL_DOCS])\n" @@ -81,6 +82,7 @@ public: "TARGET scope must name one existing target.\n" "SOURCE scope must name one source file.\n" "TEST scope must name one existing test.\n" + "CACHE scope must name one cache entry.\n" "VARIABLE scope is unique and does not accept a name.\n" "The required PROPERTY option is immediately followed by the name " "of the property to get. " @@ -114,6 +116,7 @@ private: bool HandleSourceMode(); bool HandleTestMode(); bool HandleVariableMode(); + bool HandleCacheMode(); }; #endif diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx index b683fe7..fbe877b 100644 --- a/Source/cmSetPropertyCommand.cxx +++ b/Source/cmSetPropertyCommand.cxx @@ -19,6 +19,8 @@ #include "cmSetTestsPropertiesCommand.h" #include "cmSetSourceFilesPropertiesCommand.h" +#include "cmCacheManager.h" + //---------------------------------------------------------------------------- cmSetPropertyCommand::cmSetPropertyCommand() { @@ -59,11 +61,15 @@ bool cmSetPropertyCommand { scope = cmProperty::TEST; } + else if(*arg == "CACHE") + { + scope = cmProperty::CACHE; + } else { cmOStringStream e; e << "given invalid scope " << *arg << ". " - << "Valid scopes are GLOBAL, DIRECTORY, TARGET, SOURCE, TEST."; + << "Valid scopes are GLOBAL, DIRECTORY, TARGET, SOURCE, TEST, CACHE."; this->SetError(e.str().c_str()); return false; } @@ -123,6 +129,7 @@ bool cmSetPropertyCommand case cmProperty::TARGET: return this->HandleTargetMode(); case cmProperty::SOURCE_FILE: return this->HandleSourceMode(); case cmProperty::TEST: return this->HandleTestMode(); + case cmProperty::CACHE: return this->HandleCacheMode(); case cmProperty::VARIABLE: case cmProperty::CACHED_VARIABLE: @@ -384,3 +391,89 @@ bool cmSetPropertyCommand::HandleTest(cmTest* test) return true; } + +//---------------------------------------------------------------------------- +bool cmSetPropertyCommand::HandleCacheMode() +{ + if(this->PropertyName == "ADVANCED") + { + if(!this->Remove && + !cmSystemTools::IsOn(this->PropertyValue.c_str()) && + !cmSystemTools::IsOff(this->PropertyValue.c_str())) + { + cmOStringStream e; + e << "given non-boolean value \"" << this->PropertyValue + << "\" for CACHE property \"ADVANCED\". "; + this->SetError(e.str().c_str()); + return false; + } + } + else if(this->PropertyName == "TYPE") + { + if(!cmCacheManager::IsType(this->PropertyValue.c_str())) + { + cmOStringStream e; + e << "given invalid CACHE entry TYPE \"" << this->PropertyValue << "\""; + this->SetError(e.str().c_str()); + return false; + } + } + else if(this->PropertyName != "HELPSTRING" && + this->PropertyName != "VALUE") + { + cmOStringStream e; + e << "given invalid CACHE property " << this->PropertyName << ". " + << "Settable CACHE properties are: " + << "ADVANCED, HELPSTRING, TYPE, and VALUE."; + this->SetError(e.str().c_str()); + return false; + } + + for(std::set::const_iterator ni = this->Names.begin(); + ni != this->Names.end(); ++ni) + { + // Get the source file. + cmMakefile* mf = this->GetMakefile(); + cmake* cm = mf->GetCMakeInstance(); + cmCacheManager::CacheIterator it = + cm->GetCacheManager()->GetCacheIterator(ni->c_str()); + if(!it.IsAtEnd()) + { + if(!this->HandleCacheEntry(it)) + { + return false; + } + } + else + { + cmOStringStream e; + e << "could not find CACHE variable " << *ni + << ". Perhaps it has not yet been created."; + this->SetError(e.str().c_str()); + return false; + } + } + return true; +} + +//---------------------------------------------------------------------------- +bool cmSetPropertyCommand::HandleCacheEntry(cmCacheManager::CacheIterator& it) +{ + // Set or append the property. + const char* name = this->PropertyName.c_str(); + const char* value = this->PropertyValue.c_str(); + if (this->Remove) + { + value = 0; + } + if(this->AppendMode) + { + it.AppendProperty(name, value); + } + else + { + it.SetProperty(name, value); + } + + return true; +} diff --git a/Source/cmSetPropertyCommand.h b/Source/cmSetPropertyCommand.h index 8ef0b7c..4d7decf 100644 --- a/Source/cmSetPropertyCommand.h +++ b/Source/cmSetPropertyCommand.h @@ -59,7 +59,8 @@ public: " DIRECTORY [dir] |\n" " TARGET [target1 [target2 ...]] |\n" " SOURCE [src1 [src2 ...]] |\n" - " TEST [test1 [test2 ...]]>\n" + " TEST [test1 [test2 ...]] |\n" + " CACHE [entry1 [entry2 ...]]>\n" " [APPEND]\n" " PROPERTY [value1 [value2 ...]])\n" "Set one property on zero or more objects of a scope. " @@ -72,6 +73,7 @@ public: "TARGET scope may name zero or more existing targets.\n" "SOURCE scope may name zero or more source files.\n" "TEST scope may name zero or more existing tests.\n" + "CACHE scope must name zero or more cache existing entries.\n" "The required PROPERTY option is immediately followed by the name " "of the property to set. Remaining arguments are used to " "compose the property value in the form of a semicolon-separated " @@ -104,6 +106,8 @@ private: bool HandleSource(cmSourceFile* sf); bool HandleTestMode(); bool HandleTest(cmTest* test); + bool HandleCacheMode(); + bool HandleCacheEntry(cmCacheManager::CacheIterator&); }; diff --git a/Tests/Properties/CMakeLists.txt b/Tests/Properties/CMakeLists.txt index 8cdd61b..6f3b539 100644 --- a/Tests/Properties/CMakeLists.txt +++ b/Tests/Properties/CMakeLists.txt @@ -97,3 +97,29 @@ if(NOT RESULT4) " RESULT4=${RESULT4}" " Properties_SOURCES=[${Properties_SOURCES}]") endif(NOT RESULT4) + +# test CACHE properties +macro(check_cache_props) + foreach(prop VALUE TYPE HELPSTRING ADVANCED) + get_property(result CACHE SOME_ENTRY PROPERTY ${prop}) + if(NOT "x${result}" STREQUAL "x${expect_${prop}}") + message(SEND_ERROR "CACHE property ${prop} is [${result}], not [${expect_${prop}}]") + endif() + endforeach(prop) +endmacro(check_cache_props) +set(expect_VALUE "ON") +set(expect_TYPE "BOOL") +set(expect_HELPSTRING "sample cache entry") +set(expect_ADVANCED 0) +set(SOME_ENTRY "${expect_VALUE}" CACHE ${expect_TYPE} "${expect_HELPSTRING}" FORCE) +mark_as_advanced(CLEAR SOME_ENTRY) +check_cache_props() +set(expect_VALUE "Some string") +set(expect_TYPE "STRING") +set(expect_HELPSTRING "sample cache entry help") +set(expect_ADVANCED 1) +set_property(CACHE SOME_ENTRY PROPERTY TYPE "${expect_TYPE}") +set_property(CACHE SOME_ENTRY PROPERTY HELPSTRING "${expect_HELPSTRING}") +set_property(CACHE SOME_ENTRY PROPERTY VALUE "${expect_VALUE}") +set_property(CACHE SOME_ENTRY PROPERTY ADVANCED "${expect_ADVANCED}") +check_cache_props() -- cgit v0.12