Pārlūkot izejas kodu

ENH: Changed signature of GET_PROPERTY command to be more powerful and extendible.

Brad King 18 gadi atpakaļ
vecāks
revīzija
669db35aa4

+ 2 - 2
Modules/CPackDeb.cmake

@@ -39,8 +39,8 @@ IF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
   SET(CPACK_DEBIAN_PACKAGE_ARCHITECTURE i386)
 ENDIF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
 
-# have a look at GET_PROPERTY(result GLOBAL ENABLED_FEATURES), this returns 
-# the successful FIND_PACKAGE() calls, maybe this can help
+# have a look at GET_PROPERTY(result GLOBAL PROPERTY ENABLED_FEATURES),
+# this returns the successful FIND_PACKAGE() calls, maybe this can help
 # Depends:
 IF(NOT CPACK_DEBIAN_PACKAGE_DEPENDS)
   MESSAGE(STATUS "CPACK_DEBIAN_PACKAGE_DEPENDS not set, the package will have no dependencies.")

+ 4 - 4
Modules/FeatureSummary.cmake

@@ -33,18 +33,18 @@ ENDMACRO(SET_FEATURE_INFO)
 
 MACRO(_PRINT_FEATURES _property _text)
   SET(_currentFeatureText "${_text}")
-  GET_PROPERTY(_EnabledFeatures  GLOBAL  ${_property})
+  GET_PROPERTY(_EnabledFeatures  GLOBAL PROPERTY ${_property})
   FOREACH(_currentFeature ${_EnabledFeatures})
     SET(_currentFeatureText "${_currentFeatureText}\n${_currentFeature}")
-    GET_PROPERTY(_info  GLOBAL  ${_currentFeature}_DESCRIPTION)
+    GET_PROPERTY(_info  GLOBAL PROPERTY ${_currentFeature}_DESCRIPTION)
     IF(_info)
       SET(_currentFeatureText "${_currentFeatureText} , ${_info}")
     ENDIF(_info)
-    GET_PROPERTY(_info  GLOBAL  ${_currentFeature}_URL)
+    GET_PROPERTY(_info  GLOBAL PROPERTY ${_currentFeature}_URL)
     IF(_info)
       SET(_currentFeatureText "${_currentFeatureText} , <${_info}>")
     ENDIF(_info)
-    GET_PROPERTY(_info  GLOBAL  ${_currentFeature}_COMMENT)
+    GET_PROPERTY(_info  GLOBAL PROPERTY ${_currentFeature}_COMMENT)
     IF(_info)
       SET(_currentFeatureText "${_currentFeatureText} , ${_info}")
     ENDIF(_info)

+ 2 - 1
Modules/FindPythonLibs.cmake

@@ -93,7 +93,8 @@ IF(NOT _FIND_PYTHONLIBS_ALREADY_INCLUDED)
   SET(PY_MODULES_LIST        "" CACHE STRING "Collect a list of all added python modules" FORCE)
 ENDIF(NOT _FIND_PYTHONLIBS_ALREADY_INCLUDED)
 
-GET_PROPERTY(_TARGET_SUPPORTS_SHARED_LIBS GLOBAL TARGET_SUPPORTS_SHARED_LIBS)
+GET_PROPERTY(_TARGET_SUPPORTS_SHARED_LIBS
+  GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS)
 
 MACRO(PYTHON_ADD_MODULE _NAME )
   OPTION(PYTHON_ENABLE_MODULE_${_NAME} "Add module ${_NAME}" TRUE)

+ 280 - 149
Source/cmGetPropertyCommand.cxx

@@ -20,9 +20,14 @@
 #include "cmTest.h"
 #include "cmPropertyDefinition.h"
 
-// cmGetPropertyCommand
-bool cmGetPropertyCommand::InitialPass(
-  std::vector<std::string> const& args)
+//----------------------------------------------------------------------------
+cmGetPropertyCommand::cmGetPropertyCommand()
+{
+  this->InfoType = OutValue;
+}
+
+//----------------------------------------------------------------------------
+bool cmGetPropertyCommand::InitialPass(std::vector<std::string> const& args)
 {
   if(args.size() < 3 )
     {
@@ -30,182 +35,308 @@ bool cmGetPropertyCommand::InitialPass(
     return false;
     }
 
-  // the last argument in the property to get
-  const char *property = args[args.size()-1].c_str();
-  bool get_brief = false;
-  if (!strcmp(property,"BRIEF_DOCS"))
-    {
-    get_brief = true;
-    property = args[args.size()-2].c_str();
-    }
-  bool get_full = false;
-  if (!strcmp(property,"FULL_DOCS"))
-    {
-    get_full = true;
-    property = args[args.size()-2].c_str();
-    }
-
-  std::string output = "NOTFOUND";
+  // The cmake variable in which to store the result.
+  this->Variable = args[0];
 
+  // Get the scope from which to get the property.
   cmProperty::ScopeType scope;
-  const char *scopeName = 0;
-  if (args[1] == "GLOBAL")
+  if(args[1] == "GLOBAL")
     {
     scope = cmProperty::GLOBAL;
     }
-  else if (args[1] == "VARIABLE")
-    {
-    scope = cmProperty::VARIABLE;
-    }
-  else if (args[1] == "DIRECTORY" && args.size() >= 3)
+  else if(args[1] == "DIRECTORY")
     {
     scope = cmProperty::DIRECTORY;
-    if ((args.size() == 4 && !get_brief && !get_full) ||
-        (args.size() == 5 && (get_brief || get_full)))
-      {
-      scopeName = args[2].c_str();
-      }
     }
-  else if (args[1] == "TARGET" && args.size() >= 4)
+  else if(args[1] == "TARGET")
     {
     scope = cmProperty::TARGET;
-    scopeName = args[2].c_str();
     }
-  else if (args[1] == "TEST" && args.size() >= 4)
+  else if(args[1] == "SOURCE")
+    {
+    scope = cmProperty::SOURCE_FILE;
+    }
+  else if(args[1] == "TEST")
     {
     scope = cmProperty::TEST;
-    scopeName = args[2].c_str();
     }
-  else if (args[1] == "SOURCE_FILE" && args.size() >= 4)
+  else if(args[1] == "VARIABLE")
     {
-    scope = cmProperty::SOURCE_FILE;
-    scopeName = args[2].c_str();
+    scope = cmProperty::VARIABLE;
     }
   else
     {
-    this->SetError("called with illegal arguments.");
+    cmOStringStream e;
+    e << "given invalid scope " << args[1] << ".  "
+      << "Valid scopes are "
+      << "GLOBAL, DIRECTORY, TARGET, SOURCE, TEST, VARIABLE.";
+    this->SetError(e.str().c_str());
     return false;
     }
-  
-  if (get_brief)
+
+  // Parse remaining arguments.
+  enum Doing { DoingNone, DoingName, DoingProperty, DoingType };
+  Doing doing = DoingName;
+  for(unsigned int i=2; i < args.size(); ++i)
     {
-    cmPropertyDefinition *def = 
-      this->Makefile->GetCMakeInstance()->
-      GetPropertyDefinition(property,scope);
-    if (def)
+    if(args[i] == "PROPERTY")
+      {
+      doing = DoingProperty;
+      }
+    else if(args[i] == "BRIEF_DOCS")
+      {
+      doing = DoingNone;
+      this->InfoType = OutBriefDoc;
+      }
+    else if(args[i] == "FULL_DOCS")
+      {
+      doing = DoingNone;
+      this->InfoType = OutFullDoc;
+      }
+    else if(args[i] == "DEFINED")
+      {
+      doing = DoingNone;
+      this->InfoType = OutDefined;
+      }
+    else if(doing == DoingName)
+      {
+      doing = DoingNone;
+      this->Name = args[i];
+      }
+    else if(doing == DoingProperty)
+      {
+      doing = DoingNone;
+      this->PropertyName = args[i];
+      }
+    else
+      {
+      cmOStringStream e;
+      e << "given invalid argument \"" << args[i] << "\".";
+      this->SetError(e.str().c_str());
+      return false;
+      }
+    }
+
+  // Make sure a property name was found.
+  if(this->PropertyName.empty())
+    {
+    this->SetError("not given a PROPERTY <name> argument.");
+    return false;
+    }
+
+  // Compute requested output.
+  if(this->InfoType == OutBriefDoc)
+    {
+    // Lookup brief documentation.
+    std::string output;
+    if(cmPropertyDefinition* def =
+       this->Makefile->GetCMakeInstance()->
+       GetPropertyDefinition(this->PropertyName.c_str(), scope))
       {
       output = def->GetShortDescription();
       }
+    else
+      {
+      output = "NOTFOUND";
+      }
+    this->Makefile->AddDefinition(this->Variable.c_str(), output.c_str());
     }
-  else if (get_full)
+  else if(this->InfoType == OutFullDoc)
     {
-    cmPropertyDefinition *def = 
-      this->Makefile->GetCMakeInstance()->
-      GetPropertyDefinition(property,scope);
-    if (def)
+    // Lookup full documentation.
+    std::string output;
+    if(cmPropertyDefinition* def =
+       this->Makefile->GetCMakeInstance()->
+       GetPropertyDefinition(this->PropertyName.c_str(), scope))
       {
       output = def->GetFullDescription();
       }
+    else
+      {
+      output = "NOTFOUND";
+      }
+    this->Makefile->AddDefinition(this->Variable.c_str(), output.c_str());
     }
-  
-  else switch (scope) 
-    {
-    case cmProperty::VARIABLE:
-      {
-      if (this->Makefile->GetDefinition(property))
-        {
-        output = this->Makefile->GetDefinition(property);
-        }
-      }
-      break;
-    case cmProperty::TARGET:
-      {
-      cmTarget *tgt = this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
-        ->FindTarget(0, scopeName, true);
-      if (tgt)
-        {
-        cmTarget& target = *tgt;
-        const char *prop = target.GetProperty(property);
-        if (prop)
-          {
-          output = prop;
-          }
-        }
-      }
-      break;
-    case cmProperty::DIRECTORY:
-      {
-      cmLocalGenerator *lg = this->Makefile->GetLocalGenerator();
-      if (args.size() >= 4)
-        {
-        std::string sd = scopeName;
-        // make sure the start dir is a full path
-        if (!cmSystemTools::FileIsFullPath(sd.c_str()))
-          {
-          sd = this->Makefile->GetStartDirectory();
-          sd += "/";
-          sd += scopeName;
-          }
-        
-        // The local generators are associated with collapsed paths.
-        sd = cmSystemTools::CollapseFullPath(sd.c_str());
-        
-        // lookup the makefile from the directory name
-        lg = 
-          this->Makefile->GetLocalGenerator()->GetGlobalGenerator()->
-          FindLocalGenerator(sd.c_str());
-        }
-      if (!lg)
-        {
-        this->SetError
-          ("DIRECTORY argument provided but requested directory not found. "
-           "This could be because the directory argument was invalid or, "
-           "it is valid but has not been processed yet.");
-        return false;
-        }
-      const char *prop = lg->GetMakefile()->GetProperty(property);
-      if (prop)
-        {
-        output = prop;
-        }      
-      }
-      break;
-    case cmProperty::GLOBAL:
-      {
-      const char *prop = 
-        this->Makefile->GetCMakeInstance()->GetProperty(property);
-      if (prop)
-        {
-        output = prop;
-        }      
-      }
-      break;
-    case cmProperty::TEST:
-      {
-      cmTest *test = this->Makefile->GetTest(scopeName);
-      const char *prop = test->GetProperty(property);
-      if (prop)
-        {
-        output = prop;
-        }
-      }
-      break;
-    case cmProperty::SOURCE_FILE:
-      {
-      cmSourceFile* sf = this->Makefile->GetSource(scopeName);
-      const char *prop = sf->GetProperty(property);
-      if (prop)
-        {
-        output = prop;
-        }
-      }
-      break;
-    case cmProperty::CACHED_VARIABLE:
-      // not handled by GetProperty
-      break;
-    }
-
-  this->Makefile->AddDefinition(args[0].c_str(), output.c_str());
+  else
+    {
+    // Dispatch property getting.
+    switch(scope)
+      {
+      case cmProperty::GLOBAL:      return this->HandleGlobalMode();
+      case cmProperty::DIRECTORY:   return this->HandleDirectoryMode();
+      case cmProperty::TARGET:      return this->HandleTargetMode();
+      case cmProperty::SOURCE_FILE: return this->HandleSourceMode();
+      case cmProperty::TEST:        return this->HandleTestMode();
+      case cmProperty::VARIABLE:    return this->HandleVariableMode();
+
+      case cmProperty::CACHED_VARIABLE:
+        break; // should never happen
+      }
+    }
+
   return true;
 }
 
+//----------------------------------------------------------------------------
+bool cmGetPropertyCommand::StoreResult(const char* value)
+{
+  if(this->InfoType == OutDefined)
+    {
+    this->Makefile->AddDefinition(this->Variable.c_str(), value? "1":"0");
+    }
+  else // if(this->InfoType == OutValue)
+    {
+    this->Makefile->AddDefinition(this->Variable.c_str(), value);
+    }
+  return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmGetPropertyCommand::HandleGlobalMode()
+{
+  if(!this->Name.empty())
+    {
+    this->SetError("given name for GLOBAL scope.");
+    return false;
+    }
+
+  // Get the property.
+  cmake* cm = this->Makefile->GetCMakeInstance();
+  return this->StoreResult(cm->GetProperty(this->PropertyName.c_str()));
+}
+
+//----------------------------------------------------------------------------
+bool cmGetPropertyCommand::HandleDirectoryMode()
+{
+  // Default to the current directory.
+  cmMakefile* mf = this->Makefile;
+
+  // Lookup the directory if given.
+  if(!this->Name.empty())
+    {
+    // Construct the directory name.  Interpret relative paths with
+    // respect to the current directory.
+    std::string dir = this->Name;
+    if(!cmSystemTools::FileIsFullPath(dir.c_str()))
+      {
+      dir = this->Makefile->GetCurrentDirectory();
+      dir += "/";
+      dir += this->Name;
+      }
+
+    // The local generators are associated with collapsed paths.
+    dir = cmSystemTools::CollapseFullPath(dir.c_str());
+
+    // Lookup the generator.
+    if(cmLocalGenerator* lg =
+       (this->Makefile->GetLocalGenerator()
+        ->GetGlobalGenerator()->FindLocalGenerator(dir.c_str())))
+      {
+      // Use the makefile for the directory found.
+      mf = lg->GetMakefile();
+      }
+    else
+      {
+      // Could not find the directory.
+      this->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;
+      }
+    }
+
+  // Get the property.
+  return this->StoreResult(mf->GetProperty(this->PropertyName.c_str()));
+}
+
+//----------------------------------------------------------------------------
+bool cmGetPropertyCommand::HandleTargetMode()
+{
+  if(this->Name.empty())
+    {
+    this->SetError("not given name for TARGET scope.");
+    return false;
+    }
+
+  if(cmTarget* target =
+     this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
+     ->FindTarget(0, this->Name.c_str(), true))
+    {
+    return this->StoreResult(target->GetProperty(this->PropertyName.c_str()));
+    }
+  else
+    {
+    cmOStringStream e;
+    e << "could not find TARGET " << this->Name
+      << ".  Perhaps it has not yet been created.";
+    this->SetError(e.str().c_str());
+    return false;
+    }
+}
+
+//----------------------------------------------------------------------------
+bool cmGetPropertyCommand::HandleSourceMode()
+{
+  if(this->Name.empty())
+    {
+    this->SetError("not given name for SOURCE scope.");
+    return false;
+    }
+
+  // Get the source file.
+  if(cmSourceFile* sf =
+     this->Makefile->GetOrCreateSource(this->Name.c_str()))
+    {
+    return this->StoreResult(sf->GetProperty(this->PropertyName.c_str()));
+    }
+  else
+    {
+    cmOStringStream e;
+    e << "given SOURCE name that could not be found or created: "
+      << this->Name;
+    this->SetError(e.str().c_str());
+    return false;
+    }
+}
+
+//----------------------------------------------------------------------------
+bool cmGetPropertyCommand::HandleTestMode()
+{
+  if(this->Name.empty())
+    {
+    this->SetError("not given name for TEST scope.");
+    return false;
+    }
+
+  // Loop over all tests looking for matching names.
+  std::vector<cmTest*> const& tests = *this->Makefile->GetTests();
+  for(std::vector<cmTest*>::const_iterator ti = tests.begin();
+      ti != tests.end(); ++ti)
+    {
+    cmTest* test = *ti;
+    if(test->GetName() == this->Name)
+      {
+      return this->StoreResult(test->GetProperty(this->PropertyName.c_str()));
+      }
+    }
+
+  // If not found it is an error.
+  cmOStringStream e;
+  e << "given TEST name that does not exist: " << this->Name;
+  this->SetError(e.str().c_str());
+  return false;
+}
+
+//----------------------------------------------------------------------------
+bool cmGetPropertyCommand::HandleVariableMode()
+{
+  if(!this->Name.empty())
+    {
+    this->SetError("given name for VARIABLE scope.");
+    return false;
+    }
+
+  return this->StoreResult
+    (this->Makefile->GetDefinition(this->PropertyName.c_str()));
+}

+ 49 - 13
Source/cmGetPropertyCommand.h

@@ -22,6 +22,8 @@
 class cmGetPropertyCommand : public cmCommand
 {
 public:
+  cmGetPropertyCommand();
+
   virtual cmCommand* Clone() 
     {
       return new cmGetPropertyCommand;
@@ -57,23 +59,57 @@ public:
   virtual const char* GetFullDocumentation()
     {
       return
-        "  get_property(VAR scope_value property)\n"
-        "  get_property(VAR scope_value property \n"
-        "               BRIEF_DOCS)\n"
-        "  get_property(VAR scope_value property \n"
-        "               FULL_DOCS)\n"
-        "Get a property from cmake.  The scope_value is either GLOBAL, "
-        "DIRECTORY dir_name, TARGET tgt_name, SOURCE_FILE src_name, "
-        "TEST test_name or VARIABLE var_name. The resulting value is "
-        "stored in the variable VAR. If the property is not found, "
-        "CMake will report an error. The second and third signatures "
-        "return the documentation for a property or variable instead of "
-        "its value.";
+        "  get_property(<variable>\n"
+        "               <GLOBAL             |\n"
+        "                DIRECTORY [dir]    |\n"
+        "                TARGET    <target> |\n"
+        "                SOURCE    <source> |\n"
+        "                TEST      <test>   |\n"
+        "                VARIABLE>\n"
+        "               PROPERTY <name>\n"
+        "               [DEFINED | BRIEF_DOCS | FULL_DOCS])\n"
+        "Get one property from one object in a scope.  "
+        "The first argument specifies the variable in which to store the "
+        "result.  "
+        "The second argument determines the scope from which to get the "
+        "property.  It must be one of the following:\n"
+        "GLOBAL scope is unique and does not accept a name.\n"
+        "DIRECTORY scope defaults to the current directory but another "
+        "directory (already processed by CMake) may be named by full or "
+        "relative path.\n"
+        "TARGET scope must name one existing target.\n"
+        "SOURCE scope must name one source file.\n"
+        "TEST scope must name one existing test.\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.  "
+        "If the property is not set an empty value is returned.  "
+        "If the DEFINED option is given the variable is set to a boolean "
+        "value indicating whether the property has been set.  "
+        "If BRIEF_DOCS or FULL_DOCS is given then the variable is set to "
+        "a string containing documentation for the requested property.  "
+        "If documentation is requested for a property that has not been "
+        "defined NOTFOUND is returned.";
     }
   
   cmTypeMacro(cmGetPropertyCommand, cmCommand);
-};
+private:
+  enum OutType { OutValue, OutDefined, OutBriefDoc, OutFullDoc };
+  std::string Variable;
+  std::string Name;
+  std::string PropertyName;
+  OutType InfoType;
 
+  // Implementation of result storage.
+  bool StoreResult(const char* value);
 
+  // Implementation of each property type.
+  bool HandleGlobalMode();
+  bool HandleDirectoryMode();
+  bool HandleTargetMode();
+  bool HandleSourceMode();
+  bool HandleTestMode();
+  bool HandleVariableMode();
+};
 
 #endif

+ 12 - 10
Tests/Properties/CMakeLists.txt

@@ -27,32 +27,34 @@ define_property(GLOBALTEST GLOBAL "A test property"
 set_property(GLOBAL PROPERTY GLOBALTEST 1)
 set_property(DIRECTORY PROPERTY DIRECTORYTEST 1)
 set_property(SOURCE SubDir/properties3.cxx PROPERTY SOURCETEST 1)
-get_property(GLOBALRESULT GLOBAL GLOBALTEST)
-get_property(DIRECTORYRESULT DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 
-  DIRECTORYTEST)
-get_property(SOURCE_FILERESULT SOURCE_FILE SubDir/properties3.cxx SOURCETEST)
+get_property(GLOBALRESULT GLOBAL PROPERTY GLOBALTEST)
+get_property(DIRECTORYRESULT DIRECTORY PROPERTY DIRECTORYTEST)
+get_property(SOURCERESULT
+  SOURCE SubDir/properties3.cxx
+  PROPERTY SOURCETEST
+  )
 
 if (RESULT1 AND RESULT2 AND RESULT3 AND GLOBALRESULT AND 
-    DIRECTORYRESULT AND SOURCE_FILERESULT)
+    DIRECTORYRESULT AND SOURCERESULT)
   add_executable (Properties SubDir/properties3.cxx properties)
 else (RESULT1 AND RESULT2 AND RESULT3 AND GLOBALRESULT AND 
-    DIRECTORYRESULT AND SOURCE_FILERESULT)
+    DIRECTORYRESULT AND SOURCERESULT)
   message("Error: test results are RESULT1=${RESULT1} RESULT2=${RESULT2} "
     "RESULT3=${RESULT3} GLOBALRESULT=${GLOBALRESULT} "
     "DIRECTORYRESULT=${DIRECTORYRESULT} "
-    "SOURCE_FILERESULT=${SOURCE_FILERESULT}")
+    "SOURCERESULT=${SOURCERESULT}")
 endif (RESULT1 AND RESULT2 AND RESULT3 AND GLOBALRESULT AND 
-  DIRECTORYRESULT AND SOURCE_FILERESULT)
+  DIRECTORYRESULT AND SOURCERESULT)
 
 # test the target property
 set_property(TARGET Properties PROPERTY TARGETTEST 1)
-get_property(TARGETRESULT TARGET Properties TARGETTEST)
+get_property(TARGETRESULT TARGET Properties PROPERTY TARGETTEST)
 if (NOT TARGETRESULT)
     message("Error: target result is TARGETRESULT=${TARGETRESULT}")
 endif (NOT TARGETRESULT)
 
 # test the target SOURCES property
-get_property(Properties_SOURCES TARGET Properties SOURCES)
+get_property(Properties_SOURCES TARGET Properties PROPERTY SOURCES)
 set_source_files_properties(${Properties_SOURCES} PROPERTIES TEST4 1)
 get_source_file_property(RESULT4 properties.h TEST4)
 if(NOT RESULT4)