diff options
-rw-r--r-- | Modules/CPackDeb.cmake | 4 | ||||
-rw-r--r-- | Modules/FeatureSummary.cmake | 8 | ||||
-rw-r--r-- | Modules/FindPythonLibs.cmake | 3 | ||||
-rw-r--r-- | Source/cmGetPropertyCommand.cxx | 429 | ||||
-rw-r--r-- | Source/cmGetPropertyCommand.h | 62 | ||||
-rw-r--r-- | Tests/Properties/CMakeLists.txt | 22 |
6 files changed, 349 insertions, 179 deletions
diff --git a/Modules/CPackDeb.cmake b/Modules/CPackDeb.cmake index 22940a2..dcce5c6 100644 --- a/Modules/CPackDeb.cmake +++ b/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.") diff --git a/Modules/FeatureSummary.cmake b/Modules/FeatureSummary.cmake index 2452d7c..788ad02 100644 --- a/Modules/FeatureSummary.cmake +++ b/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) diff --git a/Modules/FindPythonLibs.cmake b/Modules/FindPythonLibs.cmake index 8e60c0d..698b674 100644 --- a/Modules/FindPythonLibs.cmake +++ b/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) 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 diff --git a/Tests/Properties/CMakeLists.txt b/Tests/Properties/CMakeLists.txt index 15b5e14..9766b46 100644 --- a/Tests/Properties/CMakeLists.txt +++ b/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) |