Explorar o código

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.
Brad King %!s(int64=16) %!d(string=hai) anos
pai
achega
e5e91d6179

+ 12 - 0
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());

+ 1 - 0
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*); 

+ 26 - 1
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;
+}

+ 3 - 0
Source/cmGetPropertyCommand.h

@@ -66,6 +66,7 @@ public:
         "                TARGET    <target> |\n"
         "                SOURCE    <source> |\n"
         "                TEST      <test>   |\n"
+        "                CACHE     <entry>  |\n"
         "                VARIABLE>\n"
         "               PROPERTY <name>\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

+ 94 - 1
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<cmStdString>::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;
+}

+ 5 - 1
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 <name> [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&);
 };
 
 

+ 26 - 0
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()