diff options
author | Brad King <brad.king@kitware.com> | 2008-01-17 22:19:13 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2008-01-17 22:19:13 (GMT) |
commit | 669db35aa445cc67eef1ff53aced9602e253249e (patch) | |
tree | 4d2d3eec6f0f04c78f9e5e5a2c3b93a2935824bb /Source | |
parent | 83901b30da3e42c43b06d1579a86b14be2acf50e (diff) | |
download | CMake-669db35aa445cc67eef1ff53aced9602e253249e.zip CMake-669db35aa445cc67eef1ff53aced9602e253249e.tar.gz CMake-669db35aa445cc67eef1ff53aced9602e253249e.tar.bz2 |
ENH: Changed signature of GET_PROPERTY command to be more powerful and extendible.
Diffstat (limited to 'Source')
-rw-r--r-- | Source/cmGetPropertyCommand.cxx | 429 | ||||
-rw-r--r-- | Source/cmGetPropertyCommand.h | 62 |
2 files changed, 329 insertions, 162 deletions
diff --git a/Source/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx index 273cfd6..2649cb6 100644 --- a/Source/cmGetPropertyCommand.cxx +++ b/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())); +} diff --git a/Source/cmGetPropertyCommand.h b/Source/cmGetPropertyCommand.h index f7155e1..f7c8ece 100644 --- a/Source/cmGetPropertyCommand.h +++ b/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 |