Imported Upstream version 2.8.12.2
[platform/upstream/cmake.git] / Source / cmSetPropertyCommand.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
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"
16
17 #include "cmCacheManager.h"
18
19 //----------------------------------------------------------------------------
20 cmSetPropertyCommand::cmSetPropertyCommand()
21 {
22   this->AppendMode = false;
23   this->AppendAsString = false;
24   this->Remove = true;
25 }
26
27 //----------------------------------------------------------------------------
28 bool cmSetPropertyCommand
29 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
30 {
31   if(args.size() < 2 )
32     {
33     this->SetError("called with incorrect number of arguments");
34     return false;
35     }
36
37   // Get the scope on which to set the property.
38   std::vector<std::string>::const_iterator arg = args.begin();
39   cmProperty::ScopeType scope;
40   if(*arg == "GLOBAL")
41     {
42     scope = cmProperty::GLOBAL;
43     }
44   else if(*arg == "DIRECTORY")
45     {
46     scope = cmProperty::DIRECTORY;
47     }
48   else if(*arg == "TARGET")
49     {
50     scope = cmProperty::TARGET;
51     }
52   else if(*arg == "SOURCE")
53     {
54     scope = cmProperty::SOURCE_FILE;
55     }
56   else if(*arg == "TEST")
57     {
58     scope = cmProperty::TEST;
59     }
60   else if(*arg == "CACHE")
61     {
62     scope = cmProperty::CACHE;
63     }
64   else
65     {
66     cmOStringStream e;
67     e << "given invalid scope " << *arg << ".  "
68       << "Valid scopes are GLOBAL, DIRECTORY, TARGET, SOURCE, TEST, CACHE.";
69     this->SetError(e.str().c_str());
70     return false;
71     }
72
73   // Parse the rest of the arguments up to the values.
74   enum Doing { DoingNone, DoingNames, DoingProperty, DoingValues };
75   Doing doing = DoingNames;
76   const char* sep = "";
77   for(++arg; arg != args.end(); ++arg)
78     {
79     if(*arg == "PROPERTY")
80       {
81       doing = DoingProperty;
82       }
83     else if(*arg == "APPEND")
84       {
85       doing = DoingNone;
86       this->AppendMode = true;
87       this->Remove = false;
88       this->AppendAsString = false;
89       }
90     else if(*arg == "APPEND_STRING")
91       {
92       doing = DoingNone;
93       this->AppendMode = true;
94       this->Remove = false;
95       this->AppendAsString = true;
96       }
97     else if(doing == DoingNames)
98       {
99       this->Names.insert(*arg);
100       }
101     else if(doing == DoingProperty)
102       {
103       this->PropertyName = *arg;
104       doing = DoingValues;
105       }
106     else if(doing == DoingValues)
107       {
108       this->PropertyValue += sep;
109       sep = ";";
110       this->PropertyValue += *arg;
111       this->Remove = false;
112       }
113     else
114       {
115       cmOStringStream e;
116       e << "given invalid argument \"" << *arg << "\".";
117       this->SetError(e.str().c_str());
118       return false;
119       }
120     }
121
122   // Make sure a property name was found.
123   if(this->PropertyName.empty())
124     {
125     this->SetError("not given a PROPERTY <name> argument.");
126     return false;
127     }
128
129   // Dispatch property setting.
130   switch(scope)
131     {
132     case cmProperty::GLOBAL:      return this->HandleGlobalMode();
133     case cmProperty::DIRECTORY:   return this->HandleDirectoryMode();
134     case cmProperty::TARGET:      return this->HandleTargetMode();
135     case cmProperty::SOURCE_FILE: return this->HandleSourceMode();
136     case cmProperty::TEST:        return this->HandleTestMode();
137     case cmProperty::CACHE:       return this->HandleCacheMode();
138
139     case cmProperty::VARIABLE:
140     case cmProperty::CACHED_VARIABLE:
141       break; // should never happen
142     }
143   return true;
144 }
145
146 //----------------------------------------------------------------------------
147 bool cmSetPropertyCommand::HandleGlobalMode()
148 {
149   if(!this->Names.empty())
150     {
151     this->SetError("given names for GLOBAL scope.");
152     return false;
153     }
154
155   // Set or append the property.
156   cmake* cm = this->Makefile->GetCMakeInstance();
157   const char* name = this->PropertyName.c_str();
158   const char *value = this->PropertyValue.c_str();
159   if (this->Remove)
160     {
161     value = 0;
162     }
163   if(this->AppendMode)
164     {
165     cm->AppendProperty(name, value ? value : "", this->AppendAsString);
166     }
167   else
168     {
169     cm->SetProperty(name, value);
170     }
171
172   return true;
173 }
174
175 //----------------------------------------------------------------------------
176 bool cmSetPropertyCommand::HandleDirectoryMode()
177 {
178   if(this->Names.size() > 1)
179     {
180     this->SetError("allows at most one name for DIRECTORY scope.");
181     return false;
182     }
183
184   // Default to the current directory.
185   cmMakefile* mf = this->Makefile;
186
187   // Lookup the directory if given.
188   if(!this->Names.empty())
189     {
190     // Construct the directory name.  Interpret relative paths with
191     // respect to the current directory.
192     std::string dir = *this->Names.begin();
193     if(!cmSystemTools::FileIsFullPath(dir.c_str()))
194       {
195       dir = this->Makefile->GetCurrentDirectory();
196       dir += "/";
197       dir += *this->Names.begin();
198       }
199
200     // The local generators are associated with collapsed paths.
201     dir = cmSystemTools::CollapseFullPath(dir.c_str());
202
203     // Lookup the generator.
204     if(cmLocalGenerator* lg =
205        (this->Makefile->GetLocalGenerator()
206         ->GetGlobalGenerator()->FindLocalGenerator(dir.c_str())))
207       {
208       // Use the makefile for the directory found.
209       mf = lg->GetMakefile();
210       }
211     else
212       {
213       // Could not find the directory.
214       this->SetError
215         ("DIRECTORY scope provided but requested directory was not found. "
216          "This could be because the directory argument was invalid or, "
217          "it is valid but has not been processed yet.");
218       return false;
219       }
220     }
221
222   // Set or append the property.
223   const char* name = this->PropertyName.c_str();
224   const char *value = this->PropertyValue.c_str();
225   if (this->Remove)
226     {
227     value = 0;
228     }
229   if(this->AppendMode)
230     {
231     mf->AppendProperty(name, value ? value : "", this->AppendAsString);
232     }
233   else
234     {
235     mf->SetProperty(name, value);
236     }
237
238   return true;
239 }
240
241 //----------------------------------------------------------------------------
242 bool cmSetPropertyCommand::HandleTargetMode()
243 {
244   for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
245       ni != this->Names.end(); ++ni)
246     {
247     if (this->Makefile->IsAlias(ni->c_str()))
248       {
249       this->SetError("can not be used on an ALIAS target.");
250       return false;
251       }
252     if(cmTarget* target = this->Makefile->FindTargetToUse(ni->c_str()))
253       {
254       // Handle the current target.
255       if(!this->HandleTarget(target))
256         {
257         return false;
258         }
259       }
260     else
261       {
262       cmOStringStream e;
263       e << "could not find TARGET " << *ni
264         << ".  Perhaps it has not yet been created.";
265       this->SetError(e.str().c_str());
266       return false;
267       }
268     }
269   return true;
270 }
271
272 //----------------------------------------------------------------------------
273 bool cmSetPropertyCommand::HandleTarget(cmTarget* target)
274 {
275   // Set or append the property.
276   const char* name = this->PropertyName.c_str();
277   const char *value = this->PropertyValue.c_str();
278   if (this->Remove)
279     {
280     value = 0;
281     }
282   if(this->AppendMode)
283     {
284     target->AppendProperty(name, value, this->AppendAsString);
285     }
286   else
287     {
288     target->SetProperty(name, value);
289     }
290
291   // Check the resulting value.
292   target->CheckProperty(name, this->Makefile);
293
294   return true;
295 }
296
297 //----------------------------------------------------------------------------
298 bool cmSetPropertyCommand::HandleSourceMode()
299 {
300   for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
301       ni != this->Names.end(); ++ni)
302     {
303     // Get the source file.
304     if(cmSourceFile* sf = this->Makefile->GetOrCreateSource(ni->c_str()))
305       {
306       if(!this->HandleSource(sf))
307         {
308         return false;
309         }
310       }
311     else
312       {
313       cmOStringStream e;
314       e << "given SOURCE name that could not be found or created: " << *ni;
315       this->SetError(e.str().c_str());
316       return false;
317       }
318     }
319   return true;
320 }
321
322 //----------------------------------------------------------------------------
323 bool cmSetPropertyCommand::HandleSource(cmSourceFile* sf)
324 {
325   // Set or append the property.
326   const char* name = this->PropertyName.c_str();
327   const char *value = this->PropertyValue.c_str();
328   if (this->Remove)
329     {
330     value = 0;
331     }
332
333   if(this->AppendMode)
334     {
335     sf->AppendProperty(name, value, this->AppendAsString);
336     }
337   else
338     {
339     sf->SetProperty(name, value);
340     }
341   return true;
342 }
343
344 //----------------------------------------------------------------------------
345 bool cmSetPropertyCommand::HandleTestMode()
346 {
347   // Look for tests with all names given.
348   std::set<cmStdString>::iterator next;
349   for(std::set<cmStdString>::iterator ni = this->Names.begin();
350       ni != this->Names.end(); ni = next)
351     {
352     next = ni;
353     ++next;
354     if(cmTest* test = this->Makefile->GetTest(ni->c_str()))
355       {
356       if(this->HandleTest(test))
357         {
358         this->Names.erase(ni);
359         }
360       else
361         {
362         return false;
363         }
364       }
365     }
366
367   // Names that are still left were not found.
368   if(!this->Names.empty())
369     {
370     cmOStringStream e;
371     e << "given TEST names that do not exist:\n";
372     for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
373         ni != this->Names.end(); ++ni)
374       {
375       e << "  " << *ni << "\n";
376       }
377     this->SetError(e.str().c_str());
378     return false;
379     }
380   return true;
381 }
382
383 //----------------------------------------------------------------------------
384 bool cmSetPropertyCommand::HandleTest(cmTest* test)
385 {
386   // Set or append the property.
387   const char* name = this->PropertyName.c_str();
388   const char *value = this->PropertyValue.c_str();
389   if (this->Remove)
390     {
391     value = 0;
392     }
393   if(this->AppendMode)
394     {
395     test->AppendProperty(name, value, this->AppendAsString);
396     }
397   else
398     {
399     test->SetProperty(name, value);
400     }
401
402   return true;
403 }
404
405 //----------------------------------------------------------------------------
406 bool cmSetPropertyCommand::HandleCacheMode()
407 {
408   if(this->PropertyName == "ADVANCED")
409     {
410     if(!this->Remove &&
411        !cmSystemTools::IsOn(this->PropertyValue.c_str()) &&
412        !cmSystemTools::IsOff(this->PropertyValue.c_str()))
413       {
414       cmOStringStream e;
415       e << "given non-boolean value \"" << this->PropertyValue
416         << "\" for CACHE property \"ADVANCED\".  ";
417       this->SetError(e.str().c_str());
418       return false;
419       }
420     }
421   else if(this->PropertyName == "TYPE")
422     {
423     if(!cmCacheManager::IsType(this->PropertyValue.c_str()))
424       {
425       cmOStringStream e;
426       e << "given invalid CACHE entry TYPE \"" << this->PropertyValue << "\"";
427       this->SetError(e.str().c_str());
428       return false;
429       }
430     }
431   else if(this->PropertyName != "HELPSTRING" &&
432           this->PropertyName != "STRINGS" &&
433           this->PropertyName != "VALUE")
434     {
435     cmOStringStream e;
436     e << "given invalid CACHE property " << this->PropertyName << ".  "
437       << "Settable CACHE properties are: "
438       << "ADVANCED, HELPSTRING, STRINGS, TYPE, and VALUE.";
439     this->SetError(e.str().c_str());
440     return false;
441     }
442
443   for(std::set<cmStdString>::const_iterator ni = this->Names.begin();
444       ni != this->Names.end(); ++ni)
445     {
446     // Get the source file.
447     cmMakefile* mf = this->GetMakefile();
448     cmake* cm = mf->GetCMakeInstance();
449     cmCacheManager::CacheIterator it =
450       cm->GetCacheManager()->GetCacheIterator(ni->c_str());
451     if(!it.IsAtEnd())
452       {
453       if(!this->HandleCacheEntry(it))
454         {
455         return false;
456         }
457       }
458     else
459       {
460       cmOStringStream e;
461       e << "could not find CACHE variable " << *ni
462         << ".  Perhaps it has not yet been created.";
463       this->SetError(e.str().c_str());
464       return false;
465       }
466     }
467   return true;
468 }
469
470 //----------------------------------------------------------------------------
471 bool cmSetPropertyCommand::HandleCacheEntry(cmCacheManager::CacheIterator& it)
472 {
473   // Set or append the property.
474   const char* name = this->PropertyName.c_str();
475   const char* value = this->PropertyValue.c_str();
476   if (this->Remove)
477     {
478     value = 0;
479     }
480   if(this->AppendMode)
481     {
482     it.AppendProperty(name, value, this->AppendAsString);
483     }
484   else
485     {
486     it.SetProperty(name, value);
487     }
488
489   return true;
490 }