Commit 669db35a authored by Brad King's avatar Brad King
Browse files

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

parent 83901b30
...@@ -39,8 +39,8 @@ IF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE) ...@@ -39,8 +39,8 @@ IF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
SET(CPACK_DEBIAN_PACKAGE_ARCHITECTURE i386) SET(CPACK_DEBIAN_PACKAGE_ARCHITECTURE i386)
ENDIF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE) ENDIF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
# have a look at GET_PROPERTY(result GLOBAL ENABLED_FEATURES), this returns # have a look at GET_PROPERTY(result GLOBAL PROPERTY ENABLED_FEATURES),
# the successful FIND_PACKAGE() calls, maybe this can help # this returns the successful FIND_PACKAGE() calls, maybe this can help
# Depends: # Depends:
IF(NOT CPACK_DEBIAN_PACKAGE_DEPENDS) IF(NOT CPACK_DEBIAN_PACKAGE_DEPENDS)
MESSAGE(STATUS "CPACK_DEBIAN_PACKAGE_DEPENDS not set, the package will have no dependencies.") MESSAGE(STATUS "CPACK_DEBIAN_PACKAGE_DEPENDS not set, the package will have no dependencies.")
......
...@@ -33,18 +33,18 @@ ENDMACRO(SET_FEATURE_INFO) ...@@ -33,18 +33,18 @@ ENDMACRO(SET_FEATURE_INFO)
MACRO(_PRINT_FEATURES _property _text) MACRO(_PRINT_FEATURES _property _text)
SET(_currentFeatureText "${_text}") SET(_currentFeatureText "${_text}")
GET_PROPERTY(_EnabledFeatures GLOBAL ${_property}) GET_PROPERTY(_EnabledFeatures GLOBAL PROPERTY ${_property})
FOREACH(_currentFeature ${_EnabledFeatures}) FOREACH(_currentFeature ${_EnabledFeatures})
SET(_currentFeatureText "${_currentFeatureText}\n${_currentFeature}") SET(_currentFeatureText "${_currentFeatureText}\n${_currentFeature}")
GET_PROPERTY(_info GLOBAL ${_currentFeature}_DESCRIPTION) GET_PROPERTY(_info GLOBAL PROPERTY ${_currentFeature}_DESCRIPTION)
IF(_info) IF(_info)
SET(_currentFeatureText "${_currentFeatureText} , ${_info}") SET(_currentFeatureText "${_currentFeatureText} , ${_info}")
ENDIF(_info) ENDIF(_info)
GET_PROPERTY(_info GLOBAL ${_currentFeature}_URL) GET_PROPERTY(_info GLOBAL PROPERTY ${_currentFeature}_URL)
IF(_info) IF(_info)
SET(_currentFeatureText "${_currentFeatureText} , <${_info}>") SET(_currentFeatureText "${_currentFeatureText} , <${_info}>")
ENDIF(_info) ENDIF(_info)
GET_PROPERTY(_info GLOBAL ${_currentFeature}_COMMENT) GET_PROPERTY(_info GLOBAL PROPERTY ${_currentFeature}_COMMENT)
IF(_info) IF(_info)
SET(_currentFeatureText "${_currentFeatureText} , ${_info}") SET(_currentFeatureText "${_currentFeatureText} , ${_info}")
ENDIF(_info) ENDIF(_info)
......
...@@ -93,7 +93,8 @@ IF(NOT _FIND_PYTHONLIBS_ALREADY_INCLUDED) ...@@ -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) SET(PY_MODULES_LIST "" CACHE STRING "Collect a list of all added python modules" FORCE)
ENDIF(NOT _FIND_PYTHONLIBS_ALREADY_INCLUDED) 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 ) MACRO(PYTHON_ADD_MODULE _NAME )
OPTION(PYTHON_ENABLE_MODULE_${_NAME} "Add module ${_NAME}" TRUE) OPTION(PYTHON_ENABLE_MODULE_${_NAME} "Add module ${_NAME}" TRUE)
......
...@@ -20,9 +20,14 @@ ...@@ -20,9 +20,14 @@
#include "cmTest.h" #include "cmTest.h"
#include "cmPropertyDefinition.h" #include "cmPropertyDefinition.h"
// cmGetPropertyCommand //----------------------------------------------------------------------------
bool cmGetPropertyCommand::InitialPass( cmGetPropertyCommand::cmGetPropertyCommand()
std::vector<std::string> const& args) {
this->InfoType = OutValue;
}
//----------------------------------------------------------------------------
bool cmGetPropertyCommand::InitialPass(std::vector<std::string> const& args)
{ {
if(args.size() < 3 ) if(args.size() < 3 )
{ {
...@@ -30,182 +35,308 @@ bool cmGetPropertyCommand::InitialPass( ...@@ -30,182 +35,308 @@ bool cmGetPropertyCommand::InitialPass(
return false; return false;
} }
// the last argument in the property to get // The cmake variable in which to store the result.
const char *property = args[args.size()-1].c_str(); this->Variable = args[0];
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";
// Get the scope from which to get the property.
cmProperty::ScopeType scope; cmProperty::ScopeType scope;
const char *scopeName = 0; if(args[1] == "GLOBAL")
if (args[1] == "GLOBAL")
{ {
scope = cmProperty::GLOBAL; scope = cmProperty::GLOBAL;
} }
else if (args[1] == "VARIABLE") else if(args[1] == "DIRECTORY")
{
scope = cmProperty::VARIABLE;
}
else if (args[1] == "DIRECTORY" && args.size() >= 3)
{ {
scope = cmProperty::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; 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; 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; scope = cmProperty::VARIABLE;
scopeName = args[2].c_str();
} }
else 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; 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 = if(args[i] == "PROPERTY")
this->Makefile->GetCMakeInstance()-> {
GetPropertyDefinition(property,scope); doing = DoingProperty;
if (def) }
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(); 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 = // Lookup full documentation.
this->Makefile->GetCMakeInstance()-> std::string output;
GetPropertyDefinition(property,scope); if(cmPropertyDefinition* def =
if (def) this->Makefile->GetCMakeInstance()->
GetPropertyDefinition(this->PropertyName.c_str(), scope))
{ {
output = def->GetFullDescription(); output = def->GetFullDescription();
} }
else
{
output = "NOTFOUND";
}
this->Makefile->AddDefinition(this->Variable.c_str(), output.c_str());
} }
else
else switch (scope) {
{ // Dispatch property getting.
case cmProperty::VARIABLE: switch(scope)
{ {
if (this->Makefile->GetDefinition(property)) case cmProperty::GLOBAL: return this->HandleGlobalMode();
{ case cmProperty::DIRECTORY: return this->HandleDirectoryMode();
output = this->Makefile->GetDefinition(property); case cmProperty::TARGET: return this->HandleTargetMode();
} case cmProperty::SOURCE_FILE: return this->HandleSourceMode();
} case cmProperty::TEST: return this->HandleTestMode();
break; case cmProperty::VARIABLE: return this->HandleVariableMode();
case cmProperty::TARGET:
{ case cmProperty::CACHED_VARIABLE:
cmTarget *tgt = this->Makefile->GetLocalGenerator()->GetGlobalGenerator() break; // should never happen
->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());
return true; 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()));
}
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
class cmGetPropertyCommand : public cmCommand class cmGetPropertyCommand : public cmCommand
{ {
public: public:
cmGetPropertyCommand();
virtual cmCommand* Clone() virtual cmCommand* Clone()
{ {
return new cmGetPropertyCommand; return new cmGetPropertyCommand;
...@@ -57,23 +59,57 @@ public: ...@@ -57,23 +59,57 @@ public:
virtual const char* GetFullDocumentation() virtual const char* GetFullDocumentation()
{ {
return return
" get_property(VAR scope_value property)\n" " get_property(<variable>\n"
" get_property(VAR scope_value property \n" " <GLOBAL |\n"
" BRIEF_DOCS)\n" " DIRECTORY [dir] |\n"
" get_property(VAR scope_value property \n" " TARGET <target> |\n"
" FULL_DOCS)\n" " SOURCE <source> |\n"
"Get a property from cmake. The scope_value is either GLOBAL, " " TEST <test> |\n"
"DIRECTORY dir_name, TARGET tgt_name, SOURCE_FILE src_name, " " VARIABLE>\n"
"TEST test_name or VARIABLE var_name. The resulting value is " " PROPERTY <name>\n"
"stored in the variable VAR. If the property is not found, " " [DEFINED | BRIEF_DOCS | FULL_DOCS])\n"
"CMake will report an error. The second and third signatures " "Get one property from one object in a scope. "
"return the documentation for a property or variable instead of " "The first argument specifies the variable in which to store the "
"its value."; "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"