1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
12 #include "cmSetPropertyCommand.h"
13 #include "cmSetTargetPropertiesCommand.h"
14 #include "cmSetTestsPropertiesCommand.h"
15 #include "cmSetSourceFilesPropertiesCommand.h"
17 #include "cmCacheManager.h"
19 //----------------------------------------------------------------------------
20 cmSetPropertyCommand::cmSetPropertyCommand()
22 this->AppendMode = false;
23 this->AppendAsString = false;
27 //----------------------------------------------------------------------------
28 bool cmSetPropertyCommand
29 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
33 this->SetError("called with incorrect number of arguments");
37 // Get the scope on which to set the property.
38 std::vector<std::string>::const_iterator arg = args.begin();
39 cmProperty::ScopeType scope;
42 scope = cmProperty::GLOBAL;
44 else if(*arg == "DIRECTORY")
46 scope = cmProperty::DIRECTORY;
48 else if(*arg == "TARGET")
50 scope = cmProperty::TARGET;
52 else if(*arg == "SOURCE")
54 scope = cmProperty::SOURCE_FILE;
56 else if(*arg == "TEST")
58 scope = cmProperty::TEST;
60 else if(*arg == "CACHE")
62 scope = cmProperty::CACHE;
67 e << "given invalid scope " << *arg << ". "
68 << "Valid scopes are GLOBAL, DIRECTORY, TARGET, SOURCE, TEST, CACHE.";
69 this->SetError(e.str().c_str());
73 // Parse the rest of the arguments up to the values.
74 enum Doing { DoingNone, DoingNames, DoingProperty, DoingValues };
75 Doing doing = DoingNames;
77 for(++arg; arg != args.end(); ++arg)
79 if(*arg == "PROPERTY")
81 doing = DoingProperty;
83 else if(*arg == "APPEND")
86 this->AppendMode = true;
87 this->AppendAsString = false;
89 else if(*arg == "APPEND_STRING")
92 this->AppendMode = true;
93 this->AppendAsString = true;
95 else if(doing == DoingNames)
97 this->Names.insert(*arg);
99 else if(doing == DoingProperty)
101 this->PropertyName = *arg;
104 else if(doing == DoingValues)
106 this->PropertyValue += sep;
108 this->PropertyValue += *arg;
109 this->Remove = false;
114 e << "given invalid argument \"" << *arg << "\".";
115 this->SetError(e.str().c_str());
120 // Make sure a property name was found.
121 if(this->PropertyName.empty())
123 this->SetError("not given a PROPERTY <name> argument.");
127 // Dispatch property setting.
130 case cmProperty::GLOBAL: return this->HandleGlobalMode();
131 case cmProperty::DIRECTORY: return this->HandleDirectoryMode();
132 case cmProperty::TARGET: return this->HandleTargetMode();
133 case cmProperty::SOURCE_FILE: return this->HandleSourceMode();
134 case cmProperty::TEST: return this->HandleTestMode();
135 case cmProperty::CACHE: return this->HandleCacheMode();
137 case cmProperty::VARIABLE:
138 case cmProperty::CACHED_VARIABLE:
139 break; // should never happen
144 //----------------------------------------------------------------------------
145 bool cmSetPropertyCommand::HandleGlobalMode()
147 if(!this->Names.empty())
149 this->SetError("given names for GLOBAL scope.");
153 // Set or append the property.
154 cmake* cm = this->Makefile->GetCMakeInstance();
155 const char* name = this->PropertyName.c_str();
156 const char *value = this->PropertyValue.c_str();
163 cm->AppendProperty(name, value, this->AppendAsString);
167 cm->SetProperty(name, value);
173 //----------------------------------------------------------------------------
174 bool cmSetPropertyCommand::HandleDirectoryMode()
176 if(this->Names.size() > 1)
178 this->SetError("allows at most one name for DIRECTORY scope.");
182 // Default to the current directory.
183 cmMakefile* mf = this->Makefile;
185 // Lookup the directory if given.
186 if(!this->Names.empty())
188 // Construct the directory name. Interpret relative paths with
189 // respect to the current directory.
190 std::string dir = *this->Names.begin();
191 if(!cmSystemTools::FileIsFullPath(dir.c_str()))
193 dir = this->Makefile->GetCurrentDirectory();
195 dir += *this->Names.begin();
198 // The local generators are associated with collapsed paths.
199 dir = cmSystemTools::CollapseFullPath(dir.c_str());
201 // Lookup the generator.
202 if(cmLocalGenerator* lg =
203 (this->Makefile->GetLocalGenerator()
204 ->GetGlobalGenerator()->FindLocalGenerator(dir.c_str())))
206 // Use the makefile for the directory found.
207 mf = lg->GetMakefile();
211 // Could not find the directory.
213 ("DIRECTORY scope provided but requested directory was not found. "
214 "This could be because the directory argument was invalid or, "
215 "it is valid but has not been processed yet.");
220 // Set or append the property.
221 const char* name = this->PropertyName.c_str();
222 const char *value = this->PropertyValue.c_str();
229 mf->AppendProperty(name, value, this->AppendAsString);
233 mf->SetProperty(name, value);
239 //----------------------------------------------------------------------------
240 bool cmSetPropertyCommand::HandleTargetMode()
242 for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
243 ni != this->Names.end(); ++ni)
245 if(cmTarget* target = this->Makefile->FindTargetToUse(ni->c_str()))
247 // Handle the current target.
248 if(!this->HandleTarget(target))
256 e << "could not find TARGET " << *ni
257 << ". Perhaps it has not yet been created.";
258 this->SetError(e.str().c_str());
265 //----------------------------------------------------------------------------
266 bool cmSetPropertyCommand::HandleTarget(cmTarget* target)
268 // Set or append the property.
269 const char* name = this->PropertyName.c_str();
270 const char *value = this->PropertyValue.c_str();
277 target->AppendProperty(name, value, this->AppendAsString);
281 target->SetProperty(name, value);
284 // Check the resulting value.
285 target->CheckProperty(name, this->Makefile);
290 //----------------------------------------------------------------------------
291 bool cmSetPropertyCommand::HandleSourceMode()
293 for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
294 ni != this->Names.end(); ++ni)
296 // Get the source file.
297 if(cmSourceFile* sf = this->Makefile->GetOrCreateSource(ni->c_str()))
299 if(!this->HandleSource(sf))
307 e << "given SOURCE name that could not be found or created: " << *ni;
308 this->SetError(e.str().c_str());
315 //----------------------------------------------------------------------------
316 bool cmSetPropertyCommand::HandleSource(cmSourceFile* sf)
318 // Set or append the property.
319 const char* name = this->PropertyName.c_str();
320 const char *value = this->PropertyValue.c_str();
328 sf->AppendProperty(name, value, this->AppendAsString);
332 sf->SetProperty(name, value);
337 //----------------------------------------------------------------------------
338 bool cmSetPropertyCommand::HandleTestMode()
340 // Look for tests with all names given.
341 std::set<cmStdString>::iterator next;
342 for(std::set<cmStdString>::iterator ni = this->Names.begin();
343 ni != this->Names.end(); ni = next)
347 if(cmTest* test = this->Makefile->GetTest(ni->c_str()))
349 if(this->HandleTest(test))
351 this->Names.erase(ni);
360 // Names that are still left were not found.
361 if(!this->Names.empty())
364 e << "given TEST names that do not exist:\n";
365 for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
366 ni != this->Names.end(); ++ni)
368 e << " " << *ni << "\n";
370 this->SetError(e.str().c_str());
376 //----------------------------------------------------------------------------
377 bool cmSetPropertyCommand::HandleTest(cmTest* test)
379 // Set or append the property.
380 const char* name = this->PropertyName.c_str();
381 const char *value = this->PropertyValue.c_str();
388 test->AppendProperty(name, value, this->AppendAsString);
392 test->SetProperty(name, value);
398 //----------------------------------------------------------------------------
399 bool cmSetPropertyCommand::HandleCacheMode()
401 if(this->PropertyName == "ADVANCED")
404 !cmSystemTools::IsOn(this->PropertyValue.c_str()) &&
405 !cmSystemTools::IsOff(this->PropertyValue.c_str()))
408 e << "given non-boolean value \"" << this->PropertyValue
409 << "\" for CACHE property \"ADVANCED\". ";
410 this->SetError(e.str().c_str());
414 else if(this->PropertyName == "TYPE")
416 if(!cmCacheManager::IsType(this->PropertyValue.c_str()))
419 e << "given invalid CACHE entry TYPE \"" << this->PropertyValue << "\"";
420 this->SetError(e.str().c_str());
424 else if(this->PropertyName != "HELPSTRING" &&
425 this->PropertyName != "STRINGS" &&
426 this->PropertyName != "VALUE")
429 e << "given invalid CACHE property " << this->PropertyName << ". "
430 << "Settable CACHE properties are: "
431 << "ADVANCED, HELPSTRING, STRINGS, TYPE, and VALUE.";
432 this->SetError(e.str().c_str());
436 for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
437 ni != this->Names.end(); ++ni)
439 // Get the source file.
440 cmMakefile* mf = this->GetMakefile();
441 cmake* cm = mf->GetCMakeInstance();
442 cmCacheManager::CacheIterator it =
443 cm->GetCacheManager()->GetCacheIterator(ni->c_str());
446 if(!this->HandleCacheEntry(it))
454 e << "could not find CACHE variable " << *ni
455 << ". Perhaps it has not yet been created.";
456 this->SetError(e.str().c_str());
463 //----------------------------------------------------------------------------
464 bool cmSetPropertyCommand::HandleCacheEntry(cmCacheManager::CacheIterator& it)
466 // Set or append the property.
467 const char* name = this->PropertyName.c_str();
468 const char* value = this->PropertyValue.c_str();
475 it.AppendProperty(name, value, this->AppendAsString);
479 it.SetProperty(name, value);