summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Modules/CMakeGenericSystem.cmake2
-rw-r--r--Modules/FeatureSummary.cmake6
-rw-r--r--Modules/Platform/BlueGeneL.cmake2
-rw-r--r--Modules/Platform/Catamount.cmake2
-rw-r--r--Modules/Platform/Generic.cmake3
-rw-r--r--Modules/Platform/Linux.cmake2
-rw-r--r--Modules/Platform/UnixPaths.cmake2
-rw-r--r--Modules/Platform/eCos.cmake2
-rw-r--r--Source/cmBootstrapCommands.cxx4
-rw-r--r--Source/cmSetPropertiesCommand.cxx210
-rw-r--r--Source/cmSetPropertiesCommand.h74
-rw-r--r--Source/cmSetPropertyCommand.cxx408
-rw-r--r--Source/cmSetPropertyCommand.h112
-rw-r--r--Tests/DocTest/CMakeLists.txt2
-rw-r--r--Tests/Properties/CMakeLists.txt9
15 files changed, 537 insertions, 303 deletions
diff --git a/Modules/CMakeGenericSystem.cmake b/Modules/CMakeGenericSystem.cmake
index baecc52..d66e809 100644
--- a/Modules/CMakeGenericSystem.cmake
+++ b/Modules/CMakeGenericSystem.cmake
@@ -21,7 +21,7 @@ SET(CMAKE_FIND_LIBRARY_PREFIXES "lib")
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a")
# basically all general purpose OSs support shared libs
-SET_PROPERTIES(GLOBAL PROPERTIES TARGET_SUPPORTS_SHARED_LIBS TRUE)
+SET_PROPERTY(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
SET (CMAKE_SKIP_RPATH "NO" CACHE BOOL
"If set, runtime paths are not added when using shared libraries.")
diff --git a/Modules/FeatureSummary.cmake b/Modules/FeatureSummary.cmake
index 40d6d7f..2452d7c 100644
--- a/Modules/FeatureSummary.cmake
+++ b/Modules/FeatureSummary.cmake
@@ -21,12 +21,12 @@
MACRO(SET_FEATURE_INFO _name _desc)
SET(_url "${ARGV2}")
SET(_comment "${ARGV3}")
- SET_PROPERTIES(GLOBAL PROPERTIES ${_name}_DESCRIPTION "${_desc}" )
+ SET_PROPERTY(GLOBAL PROPERTY ${_name}_DESCRIPTION "${_desc}" )
IF(_url MATCHES ".+")
- SET_PROPERTIES(GLOBAL PROPERTIES ${_name}_URL "${_url}" )
+ SET_PROPERTY(GLOBAL PROPERTY ${_name}_URL "${_url}" )
ENDIF(_url MATCHES ".+")
IF(_comment MATCHES ".+")
- SET_PROPERTIES(GLOBAL PROPERTIES ${_name}_COMMENT "${_comment}" )
+ SET_PROPERTY(GLOBAL PROPERTY ${_name}_COMMENT "${_comment}" )
ENDIF(_comment MATCHES ".+")
ENDMACRO(SET_FEATURE_INFO)
diff --git a/Modules/Platform/BlueGeneL.cmake b/Modules/Platform/BlueGeneL.cmake
index dc334cc..7794a26 100644
--- a/Modules/Platform/BlueGeneL.cmake
+++ b/Modules/Platform/BlueGeneL.cmake
@@ -1,5 +1,5 @@
#the compute nodes on BlueGene/L don't support shared libs
-SET_PROPERTIES(GLOBAL PROPERTIES TARGET_SUPPORTS_SHARED_LIBS FALSE)
+SET_PROPERTY(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
SET(CMAKE_SHARED_LIBRARY_C_FLAGS "") # -pic
SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "") # -shared
diff --git a/Modules/Platform/Catamount.cmake b/Modules/Platform/Catamount.cmake
index cd619df..01493fc 100644
--- a/Modules/Platform/Catamount.cmake
+++ b/Modules/Platform/Catamount.cmake
@@ -1,5 +1,5 @@
#Catamount, which runs on the compute nodes of Cray machines, e.g. RedStorm, doesn't support shared libs
-SET_PROPERTIES(GLOBAL PROPERTIES TARGET_SUPPORTS_SHARED_LIBS FALSE)
+SET_PROPERTY(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
SET(CMAKE_SHARED_LIBRARY_C_FLAGS "") # -pic
SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "") # -shared
diff --git a/Modules/Platform/Generic.cmake b/Modules/Platform/Generic.cmake
index b6629e2..00508b2 100644
--- a/Modules/Platform/Generic.cmake
+++ b/Modules/Platform/Generic.cmake
@@ -8,5 +8,4 @@
# and/or ${CMAKE_SYSTEM_NAME}-<compiler_basename>-${CMAKE_SYSTEM_PROCESSOR}.cmake
# (embedded) targets without operating system usually don't support shared libraries
-SET_PROPERTIES(GLOBAL PROPERTIES TARGET_SUPPORTS_SHARED_LIBS FALSE)
-
+SET_PROPERTY(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
diff --git a/Modules/Platform/Linux.cmake b/Modules/Platform/Linux.cmake
index 4de71d0..85178ce 100644
--- a/Modules/Platform/Linux.cmake
+++ b/Modules/Platform/Linux.cmake
@@ -52,5 +52,5 @@ INCLUDE(Platform/UnixPaths)
# Debian has lib64 paths only for compatibility so they should not be
# searched.
IF(EXISTS "/etc/debian_version")
- SET_PROPERTIES(GLOBAL PROPERTIES FIND_LIBRARY_USE_LIB64_PATHS FALSE)
+ SET_PROPERTY(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS FALSE)
ENDIF(EXISTS "/etc/debian_version")
diff --git a/Modules/Platform/UnixPaths.cmake b/Modules/Platform/UnixPaths.cmake
index b7f060d..7ed85c0 100644
--- a/Modules/Platform/UnixPaths.cmake
+++ b/Modules/Platform/UnixPaths.cmake
@@ -54,4 +54,4 @@ LIST(APPEND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES
)
# Enable use of lib64 search path variants by default.
-SET_PROPERTIES(GLOBAL PROPERTIES FIND_LIBRARY_USE_LIB64_PATHS TRUE)
+SET_PROPERTY(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS TRUE)
diff --git a/Modules/Platform/eCos.cmake b/Modules/Platform/eCos.cmake
index 9805965..e7709cc 100644
--- a/Modules/Platform/eCos.cmake
+++ b/Modules/Platform/eCos.cmake
@@ -47,7 +47,7 @@ SET(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLA
SET(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -nostdlib -nostartfiles -L${ECOS_LIBTARGET_DIRECTORY} -Ttarget.ld <LINK_LIBRARIES>")
# eCos doesn't support shared libs
-SET_PROPERTIES(GLOBAL PROPERTIES TARGET_SUPPORTS_SHARED_LIBS FALSE)
+SET_PROPERTY(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE)
SET(CMAKE_CXX_LINK_SHARED_LIBRARY )
SET(CMAKE_CXX_LINK_MODULE_LIBRARY )
diff --git a/Source/cmBootstrapCommands.cxx b/Source/cmBootstrapCommands.cxx
index 77adce5..31533f0 100644
--- a/Source/cmBootstrapCommands.cxx
+++ b/Source/cmBootstrapCommands.cxx
@@ -72,7 +72,7 @@
#include "cmProjectCommand.cxx"
#include "cmRaiseScopeCommand.cxx"
#include "cmSetCommand.cxx"
-#include "cmSetPropertiesCommand.cxx"
+#include "cmSetPropertyCommand.cxx"
#include "cmSetSourceFilesPropertiesCommand.cxx"
#include "cmSetTargetPropertiesCommand.cxx"
#include "cmSetTestsPropertiesCommand.cxx"
@@ -132,7 +132,7 @@ void GetBootstrapCommands(std::list<cmCommand*>& commands)
commands.push_back(new cmProjectCommand);
commands.push_back(new cmRaiseScopeCommand);
commands.push_back(new cmSetCommand);
- commands.push_back(new cmSetPropertiesCommand);
+ commands.push_back(new cmSetPropertyCommand);
commands.push_back(new cmSetSourceFilesPropertiesCommand);
commands.push_back(new cmSetTargetPropertiesCommand);
commands.push_back(new cmSetTestsPropertiesCommand);
diff --git a/Source/cmSetPropertiesCommand.cxx b/Source/cmSetPropertiesCommand.cxx
deleted file mode 100644
index 117d0df..0000000
--- a/Source/cmSetPropertiesCommand.cxx
+++ /dev/null
@@ -1,210 +0,0 @@
-/*=========================================================================
-
- Program: CMake - Cross-Platform Makefile Generator
- Module: $RCSfile$
- Language: C++
- Date: $Date$
- Version: $Revision$
-
- Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
- See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even
- the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- PURPOSE. See the above copyright notices for more information.
-
-=========================================================================*/
-#include "cmSetPropertiesCommand.h"
-#include "cmSetTargetPropertiesCommand.h"
-#include "cmSetTestsPropertiesCommand.h"
-#include "cmSetSourceFilesPropertiesCommand.h"
-
-// cmSetPropertiesCommand
-bool cmSetPropertiesCommand::InitialPass(
- std::vector<std::string> const& args)
-{
- if(args.size() < 2 )
- {
- this->SetError("called with incorrect number of arguments");
- return false;
- }
-
- // first collect up the list of files
- std::vector<std::string> propertyPairs;
- bool doingFiles = true;
- int numFiles = 0;
- std::vector<std::string>::const_iterator j;
- for(j= args.begin(); j != args.end();++j)
- {
- if(*j == "PROPERTIES")
- {
- doingFiles = false;
- // now loop through the rest of the arguments, new style
- ++j;
- while (j != args.end())
- {
- propertyPairs.push_back(*j);
- ++j;
- if(j == args.end())
- {
- this->SetError("called with incorrect number of arguments.");
- return false;
- }
- propertyPairs.push_back(*j);
- ++j;
- }
- // break out of the loop because j is already == end
- break;
- }
- else if (doingFiles)
- {
- numFiles++;
- }
- else
- {
- this->SetError("called with illegal arguments, maybe missing "
- "a PROPERTIES specifier?");
- return false;
- }
- }
- if(propertyPairs.size() == 0)
- {
- this->SetError("called with illegal arguments, maybe missing "
- "a PROPERTIES specifier?");
- return false;
- }
-
- cmProperty::ScopeType scope;
- const char *scopeName = 0;
- if (args[0] == "GLOBAL" && numFiles == 1)
- {
- scope = cmProperty::GLOBAL;
- }
- else if (args[0] == "DIRECTORY" && numFiles >= 1)
- {
- scope = cmProperty::DIRECTORY;
- if (numFiles == 2)
- {
- scopeName = args[1].c_str();
- }
- }
- else if (args[0] == "TARGET" && numFiles == 2)
- {
- scope = cmProperty::TARGET;
- scopeName = args[1].c_str();
- }
- else if (args[0] == "TEST" && numFiles == 2)
- {
- scope = cmProperty::TEST;
- scopeName = args[1].c_str();
- }
- else if (args[0] == "SOURCE_FILE" && numFiles == 2)
- {
- scope = cmProperty::SOURCE_FILE;
- scopeName = args[1].c_str();
- }
- else
- {
- this->SetError("called with illegal arguments.");
- return false;
- }
-
- switch (scope)
- {
- case cmProperty::TARGET:
- {
- bool ret = cmSetTargetPropertiesCommand::
- SetOneTarget(scopeName,propertyPairs, this->Makefile);
- if (!ret)
- {
- std::string message = "Can not find target to add properties to: ";
- message += scopeName;
- this->SetError(message.c_str());
- return ret;
- }
- }
- break;
- case cmProperty::DIRECTORY:
- {
- // lookup the makefile from the directory name
- cmLocalGenerator *lg = this->Makefile->GetLocalGenerator();
- if (numFiles == 2)
- {
- 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());
-
- 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;
- }
-
- for(j= propertyPairs.begin(); j != propertyPairs.end(); ++j)
- {
- const char *pn = j->c_str();
- ++j;
- lg->GetMakefile()->SetProperty(pn,j->c_str());
- }
- }
- break;
- case cmProperty::GLOBAL:
- {
- for(j= propertyPairs.begin(); j != propertyPairs.end(); ++j)
- {
- const char *pn = j->c_str();
- ++j;
- this->Makefile->GetCMakeInstance()->SetProperty(pn, j->c_str());
- }
- }
- break;
- case cmProperty::TEST:
- {
- std::string errors;
- bool ret = cmSetTestsPropertiesCommand::
- SetOneTest(scopeName,propertyPairs, this->Makefile, errors);
- if (!ret)
- {
- this->SetError(errors.c_str());
- return ret;
- }
- }
- break;
- case cmProperty::SOURCE_FILE:
- {
- std::string errors;
- bool ret = cmSetSourceFilesPropertiesCommand::
- RunCommand(this->Makefile,
- args.begin()+1, args.begin()+2,
- args.begin() + 2, args.end(),
- errors);
- if (!ret)
- {
- this->SetError(errors.c_str());
- return ret;
- }
- }
- break;
- case cmProperty::VARIABLE:
- case cmProperty::CACHED_VARIABLE:
- // not handled by SetProperty
- break;
- }
-
- return true;
-}
-
diff --git a/Source/cmSetPropertiesCommand.h b/Source/cmSetPropertiesCommand.h
deleted file mode 100644
index ce85cbd..0000000
--- a/Source/cmSetPropertiesCommand.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*=========================================================================
-
- Program: CMake - Cross-Platform Makefile Generator
- Module: $RCSfile$
- Language: C++
- Date: $Date$
- Version: $Revision$
-
- Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
- See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even
- the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- PURPOSE. See the above copyright notices for more information.
-
-=========================================================================*/
-#ifndef cmSetsPropertiesCommand_h
-#define cmSetsPropertiesCommand_h
-
-#include "cmCommand.h"
-
-class cmSetPropertiesCommand : public cmCommand
-{
-public:
- virtual cmCommand* Clone()
- {
- return new cmSetPropertiesCommand;
- }
-
- /**
- * This is called when the command is first encountered in
- * the input file.
- */
- virtual bool InitialPass(std::vector<std::string> const& args);
-
- /**
- * The name of the command as specified in CMakeList.txt.
- */
- virtual const char* GetName() { return "set_properties";}
-
- /**
- * Succinct documentation.
- */
- virtual const char* GetTerseDocumentation()
- {
- return "Set properties used by CMake.";
- }
-
- /**
- * Longer documentation.
- */
- virtual const char* GetFullDocumentation()
- {
- return
- " set_properties(scope_value\n"
- " PROPERTIES prop1 value1\n"
- " prop2 value2 ...)\n"
- "Set properties on something. The scope_value is either GLOBAL, "
- "DIRECTORY dir_name, TARGET tgt_name, SOURCE_FILE src_name, "
- "or TEST test_name."
- ;
- }
-
- /**
- * This determines if the command is invoked when in script mode.
- */
- virtual bool IsScriptable() { return true; }
-
- cmTypeMacro(cmSetPropertiesCommand, cmCommand);
-};
-
-
-
-#endif
diff --git a/Source/cmSetPropertyCommand.cxx b/Source/cmSetPropertyCommand.cxx
new file mode 100644
index 0000000..a0455aa
--- /dev/null
+++ b/Source/cmSetPropertyCommand.cxx
@@ -0,0 +1,408 @@
+/*=========================================================================
+
+ Program: CMake - Cross-Platform Makefile Generator
+ Module: $RCSfile$
+ Language: C++
+ Date: $Date$
+ Version: $Revision$
+
+ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
+ See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notices for more information.
+
+=========================================================================*/
+#include "cmSetPropertyCommand.h"
+#include "cmSetTargetPropertiesCommand.h"
+#include "cmSetTestsPropertiesCommand.h"
+#include "cmSetSourceFilesPropertiesCommand.h"
+
+//----------------------------------------------------------------------------
+cmSetPropertyCommand::cmSetPropertyCommand()
+{
+ this->AppendMode = false;
+}
+
+//----------------------------------------------------------------------------
+bool cmSetPropertyCommand::InitialPass(std::vector<std::string> const& args)
+{
+ if(args.size() < 2 )
+ {
+ this->SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // Get the scope on which to set the property.
+ std::vector<std::string>::const_iterator arg = args.begin();
+ cmProperty::ScopeType scope;
+ if(*arg == "GLOBAL")
+ {
+ scope = cmProperty::GLOBAL;
+ }
+ else if(*arg == "DIRECTORY")
+ {
+ scope = cmProperty::DIRECTORY;
+ }
+ else if(*arg == "TARGET")
+ {
+ scope = cmProperty::TARGET;
+ }
+ else if(*arg == "SOURCE")
+ {
+ scope = cmProperty::SOURCE_FILE;
+ }
+ else if(*arg == "TEST")
+ {
+ scope = cmProperty::TEST;
+ }
+ else
+ {
+ cmOStringStream e;
+ e << "given invalid scope " << *arg << ". "
+ << "Valid scopes are GLOBAL, DIRECTORY, TARGET, SOURCE, TEST.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+
+ // Parse the rest of the arguments up to the values.
+ enum Doing { DoingNone, DoingNames, DoingProperty, DoingValues };
+ Doing doing = DoingNames;
+ const char* sep = "";
+ for(++arg; arg != args.end(); ++arg)
+ {
+ if(*arg == "PROPERTY")
+ {
+ doing = DoingProperty;
+ }
+ else if(*arg == "APPEND")
+ {
+ doing = DoingNone;
+ this->AppendMode = true;
+ }
+ else if(doing == DoingNames)
+ {
+ this->Names.insert(*arg);
+ }
+ else if(doing == DoingProperty)
+ {
+ this->PropertyName = *arg;
+ doing = DoingValues;
+ }
+ else if(doing == DoingValues)
+ {
+ this->PropertyValue += sep;
+ sep = ";";
+ this->PropertyValue += *arg;
+ }
+ else
+ {
+ cmOStringStream e;
+ e << "given invalid argument \"" << *arg << "\".";
+ 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;
+ }
+
+ // Dispatch property setting.
+ 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:
+ case cmProperty::CACHED_VARIABLE:
+ break; // should never happen
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmSetPropertyCommand::ConstructValue(std::string& value,
+ const char* old)
+{
+ if(this->AppendMode)
+ {
+ // This is an append. Start with the original value.
+ if(old)
+ {
+ value = old;
+ }
+ }
+ else if(this->PropertyValue.empty())
+ {
+ // This is a set to no values. Remove the property.
+ return false;
+ }
+
+ // Add the new value.
+ if(!this->PropertyValue.empty())
+ {
+ if(!value.empty())
+ {
+ value += ";";
+ }
+ value += this->PropertyValue;
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmSetPropertyCommand::HandleGlobalMode()
+{
+ if(!this->Names.empty())
+ {
+ this->SetError("given names for GLOBAL scope.");
+ return false;
+ }
+
+ // Set or append the property.
+ cmake* cm = this->Makefile->GetCMakeInstance();
+ const char* name = this->PropertyName.c_str();
+ std::string value;
+ if(this->ConstructValue(value, cm->GetProperty(name)))
+ {
+ // Set the new property.
+ cm->SetProperty(name, value.c_str());
+ }
+ else
+ {
+ // Remove the property.
+ cm->SetProperty(name, 0);
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmSetPropertyCommand::HandleDirectoryMode()
+{
+ if(this->Names.size() > 1)
+ {
+ this->SetError("allows at most one name for DIRECTORY scope.");
+ return false;
+ }
+
+ // Default to the current directory.
+ cmMakefile* mf = this->Makefile;
+
+ // Lookup the directory if given.
+ if(!this->Names.empty())
+ {
+ // Construct the directory name. Interpret relative paths with
+ // respect to the current directory.
+ std::string dir = *this->Names.begin();
+ if(!cmSystemTools::FileIsFullPath(dir.c_str()))
+ {
+ dir = this->Makefile->GetCurrentDirectory();
+ dir += "/";
+ dir += *this->Names.begin();
+ }
+
+ // 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;
+ }
+ }
+
+ // Set or append the property.
+ const char* name = this->PropertyName.c_str();
+ std::string value;
+ if(this->ConstructValue(value, mf->GetProperty(name)))
+ {
+ // Set the new property.
+ mf->SetProperty(name, value.c_str());
+ }
+ else
+ {
+ // Remove the property.
+ mf->SetProperty(name, 0);
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmSetPropertyCommand::HandleTargetMode()
+{
+ for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni)
+ {
+ if(cmTarget* target =
+ this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
+ ->FindTarget(0, ni->c_str(), true))
+ {
+ // Handle the current target.
+ if(!this->HandleTarget(target))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ cmOStringStream e;
+ e << "could not find TARGET " << *ni
+ << ". Perhaps it has not yet been created.";
+ this->SetError(e.str().c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmSetPropertyCommand::HandleTarget(cmTarget* target)
+{
+ // Set or append the property.
+ const char* name = this->PropertyName.c_str();
+ std::string value;
+ if(this->ConstructValue(value, target->GetProperty(name)))
+ {
+ // Set the new property.
+ target->SetProperty(name, value.c_str());
+ }
+ else
+ {
+ // Remove the property.
+ target->SetProperty(name, 0);
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmSetPropertyCommand::HandleSourceMode()
+{
+ for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni)
+ {
+ // Get the source file.
+ if(cmSourceFile* sf = this->Makefile->GetOrCreateSource(ni->c_str()))
+ {
+ if(!this->HandleSource(sf))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ cmOStringStream e;
+ e << "given SOURCE name that could not be found or created: " << *ni;
+ this->SetError(e.str().c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmSetPropertyCommand::HandleSource(cmSourceFile* sf)
+{
+ // Set or append the property.
+ const char* name = this->PropertyName.c_str();
+ std::string value;
+ if(this->ConstructValue(value, sf->GetProperty(name)))
+ {
+ // Set the new property.
+ sf->SetProperty(name, value.c_str());
+ }
+ else
+ {
+ // Remove the property.
+ sf->SetProperty(name, 0);
+ }
+
+ // TODO: MACOSX_PACKAGE_LOCATION special case in
+ // cmSetSourceFilesPropertiesCommand
+ // The logic should be moved to cmSourceFile.
+
+ return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmSetPropertyCommand::HandleTestMode()
+{
+ // 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;
+ std::set<cmStdString>::const_iterator ni =
+ this->Names.find(test->GetName());
+ if(ni != this->Names.end())
+ {
+ if(this->HandleTest(test))
+ {
+ this->Names.erase(ni);
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ // Names that are still left were not found.
+ if(!this->Names.empty())
+ {
+ cmOStringStream e;
+ e << "given TEST names that do not exist:\n";
+ for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
+ ni != this->Names.end(); ++ni)
+ {
+ e << " " << *ni << "\n";
+ }
+ this->SetError(e.str().c_str());
+ return false;
+ }
+ return true;
+}
+
+//----------------------------------------------------------------------------
+bool cmSetPropertyCommand::HandleTest(cmTest* test)
+{
+ // Set or append the property.
+ const char* name = this->PropertyName.c_str();
+ std::string value;
+ if(this->ConstructValue(value, test->GetProperty(name)))
+ {
+ // Set the new property.
+ test->SetProperty(name, value.c_str());
+ }
+ else
+ {
+ // Remove the property.
+ test->SetProperty(name, 0);
+ }
+
+ return true;
+}
diff --git a/Source/cmSetPropertyCommand.h b/Source/cmSetPropertyCommand.h
new file mode 100644
index 0000000..c5de8e5
--- /dev/null
+++ b/Source/cmSetPropertyCommand.h
@@ -0,0 +1,112 @@
+/*=========================================================================
+
+ Program: CMake - Cross-Platform Makefile Generator
+ Module: $RCSfile$
+ Language: C++
+ Date: $Date$
+ Version: $Revision$
+
+ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
+ See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef cmSetsPropertiesCommand_h
+#define cmSetsPropertiesCommand_h
+
+#include "cmCommand.h"
+
+class cmSetPropertyCommand : public cmCommand
+{
+public:
+ cmSetPropertyCommand();
+
+ virtual cmCommand* Clone()
+ {
+ return new cmSetPropertyCommand;
+ }
+
+ /**
+ * This is called when the command is first encountered in
+ * the input file.
+ */
+ virtual bool InitialPass(std::vector<std::string> const& args);
+
+ /**
+ * The name of the command as specified in CMakeList.txt.
+ */
+ virtual const char* GetName() { return "set_property";}
+
+ /**
+ * Succinct documentation.
+ */
+ virtual const char* GetTerseDocumentation()
+ {
+ return "Set a named property in a given scope.";
+ }
+
+ /**
+ * Longer documentation.
+ */
+ virtual const char* GetFullDocumentation()
+ {
+ return
+ " set_property(<GLOBAL |\n"
+ " DIRECTORY [dir] |\n"
+ " TARGET [target1 [target2 ...]] |\n"
+ " SOURCE [src1 [src2 ...]] |\n"
+ " TEST [test1 [test2 ...]]>\n"
+ " [APPEND]\n"
+ " PROPERTY <name> [value1 [value2 ...]])\n"
+ "Set one property on zero or more objects of a scope. "
+ "The first argument determines the scope in which the property "
+ "is set. 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 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"
+ "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 "
+ "list. "
+ "If the APPEND option is given the list is appended to any "
+ "existing property value."
+ ;
+ }
+
+ /**
+ * This determines if the command is invoked when in script mode.
+ */
+ virtual bool IsScriptable() { return true; }
+
+ cmTypeMacro(cmSetPropertyCommand, cmCommand);
+
+private:
+ std::set<cmStdString> Names;
+ std::string PropertyName;
+ std::string PropertyValue;
+ bool AppendMode;
+
+ // Implementation of value construction.
+ bool ConstructValue(std::string& value, const char* old);
+
+ // Implementation of each property type.
+ bool HandleGlobalMode();
+ bool HandleDirectoryMode();
+ bool HandleTargetMode();
+ bool HandleTarget(cmTarget* target);
+ bool HandleSourceMode();
+ bool HandleSource(cmSourceFile* sf);
+ bool HandleTestMode();
+ bool HandleTest(cmTest* test);
+};
+
+
+
+#endif
diff --git a/Tests/DocTest/CMakeLists.txt b/Tests/DocTest/CMakeLists.txt
index 1789746..bd78992 100644
--- a/Tests/DocTest/CMakeLists.txt
+++ b/Tests/DocTest/CMakeLists.txt
@@ -2,5 +2,5 @@ project (DocTest)
add_executable (DocTest DocTest.cxx)
-set_properties(GLOBAL PROPERTIES REPORT_UNDEFINED_PROPERTIES
+set_property(GLOBAL PROPERTY REPORT_UNDEFINED_PROPERTIES
"${CMAKE_CURRENT_BINARY_DIR}/UndefinedProperties.txt")
diff --git a/Tests/Properties/CMakeLists.txt b/Tests/Properties/CMakeLists.txt
index 7b7bd2d..15b5e14 100644
--- a/Tests/Properties/CMakeLists.txt
+++ b/Tests/Properties/CMakeLists.txt
@@ -24,10 +24,9 @@ include_directories("${Properties_SOURCE_DIR}" "${Properties_BINARY_DIR}")
# test generic property interfaces
define_property(GLOBALTEST GLOBAL "A test property"
"A long description of this test property" 0)
-set_properties(GLOBAL PROPERTIES GLOBALTEST 1)
-set_properties(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
- PROPERTIES DIRECTORYTEST 1)
-set_properties(SOURCE_FILE SubDir/properties3.cxx PROPERTIES SOURCETEST 1)
+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)
@@ -46,7 +45,7 @@ endif (RESULT1 AND RESULT2 AND RESULT3 AND GLOBALRESULT AND
DIRECTORYRESULT AND SOURCE_FILERESULT)
# test the target property
-set_properties(TARGET Properties PROPERTIES TARGETTEST 1)
+set_property(TARGET Properties PROPERTY TARGETTEST 1)
get_property(TARGETRESULT TARGET Properties TARGETTEST)
if (NOT TARGETRESULT)
message("Error: target result is TARGETRESULT=${TARGETRESULT}")