Imported Upstream version 2.8.12.2
[platform/upstream/cmake.git] / Source / cmSourceFile.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 "cmSourceFile.h"
13
14 #include "cmGlobalGenerator.h"
15 #include "cmLocalGenerator.h"
16 #include "cmMakefile.h"
17 #include "cmSystemTools.h"
18 #include "cmake.h"
19 #include "cmDocumentCompileDefinitions.h"
20
21 //----------------------------------------------------------------------------
22 cmSourceFile::cmSourceFile(cmMakefile* mf, const char* name):
23   Location(mf, name)
24 {
25   this->CustomCommand = 0;
26   this->Properties.SetCMakeInstance(mf->GetCMakeInstance());
27   this->FindFullPathFailed = false;
28 }
29
30 //----------------------------------------------------------------------------
31 cmSourceFile::~cmSourceFile()
32 {
33   this->SetCustomCommand(0);
34 }
35
36 //----------------------------------------------------------------------------
37 std::string const& cmSourceFile::GetExtension() const
38 {
39   return this->Extension;
40 }
41
42 //----------------------------------------------------------------------------
43 const char* cmSourceFile::GetLanguage()
44 {
45   // If the language was set explicitly by the user then use it.
46   if(const char* lang = this->GetProperty("LANGUAGE"))
47     {
48     return lang;
49     }
50
51   // Perform computation needed to get the language if necessary.
52   if(this->FullPath.empty() && this->Language.empty())
53     {
54     // If a known extension is given or a known full path is given
55     // then trust that the current extension is sufficient to
56     // determine the language.  This will fail only if the user
57     // specifies a full path to the source but leaves off the
58     // extension, which is kind of weird.
59     if(this->Location.ExtensionIsAmbiguous() &&
60        this->Location.DirectoryIsAmbiguous())
61       {
62       // Finalize the file location to get the extension and set the
63       // language.
64       this->GetFullPath();
65       }
66     else
67       {
68       // Use the known extension to get the language if possible.
69       std::string ext =
70         cmSystemTools::GetFilenameLastExtension(this->Location.GetName());
71       this->CheckLanguage(ext);
72       }
73     }
74
75   // Now try to determine the language.
76   return static_cast<cmSourceFile const*>(this)->GetLanguage();
77 }
78
79 //----------------------------------------------------------------------------
80 const char* cmSourceFile::GetLanguage() const
81 {
82   // If the language was set explicitly by the user then use it.
83   if(const char* lang = this->GetProperty("LANGUAGE"))
84     {
85     return lang;
86     }
87
88   // If the language was determined from the source file extension use it.
89   if(!this->Language.empty())
90     {
91     return this->Language.c_str();
92     }
93
94   // The language is not known.
95   return 0;
96 }
97
98 //----------------------------------------------------------------------------
99 cmSourceFileLocation const& cmSourceFile::GetLocation() const
100 {
101     return this->Location;
102 }
103
104 //----------------------------------------------------------------------------
105 std::string const& cmSourceFile::GetFullPath(std::string* error)
106 {
107   if(this->FullPath.empty())
108     {
109     if(this->FindFullPath(error))
110       {
111       this->CheckExtension();
112       }
113     }
114   return this->FullPath;
115 }
116
117 //----------------------------------------------------------------------------
118 std::string const& cmSourceFile::GetFullPath() const
119 {
120   return this->FullPath;
121 }
122
123 //----------------------------------------------------------------------------
124 bool cmSourceFile::FindFullPath(std::string* error)
125 {
126   // If thie method has already failed once do not try again.
127   if(this->FindFullPathFailed)
128     {
129     return false;
130     }
131
132   // If the file is generated compute the location without checking on
133   // disk.
134   if(this->GetPropertyAsBool("GENERATED"))
135     {
136     // The file is either already a full path or is relative to the
137     // build directory for the target.
138     this->Location.DirectoryUseBinary();
139     this->FullPath = this->Location.GetDirectory();
140     this->FullPath += "/";
141     this->FullPath += this->Location.GetName();
142     return true;
143     }
144
145   // The file is not generated.  It must exist on disk.
146   cmMakefile* mf = this->Location.GetMakefile();
147   const char* tryDirs[3] = {0, 0, 0};
148   if(this->Location.DirectoryIsAmbiguous())
149     {
150     tryDirs[0] = mf->GetCurrentDirectory();
151     tryDirs[1] = mf->GetCurrentOutputDirectory();
152     }
153   else
154     {
155     tryDirs[0] = "";
156     }
157   const std::vector<std::string>& srcExts = mf->GetSourceExtensions();
158   const std::vector<std::string>& hdrExts = mf->GetHeaderExtensions();
159   for(const char* const* di = tryDirs; *di; ++di)
160     {
161     std::string tryPath = this->Location.GetDirectory();
162     if(!tryPath.empty())
163       {
164       tryPath += "/";
165       }
166     tryPath += this->Location.GetName();
167     tryPath = cmSystemTools::CollapseFullPath(tryPath.c_str(), *di);
168     if(this->TryFullPath(tryPath.c_str(), 0))
169       {
170       return true;
171       }
172     for(std::vector<std::string>::const_iterator ei = srcExts.begin();
173         ei != srcExts.end(); ++ei)
174       {
175       if(this->TryFullPath(tryPath.c_str(), ei->c_str()))
176         {
177         return true;
178         }
179       }
180     for(std::vector<std::string>::const_iterator ei = hdrExts.begin();
181         ei != hdrExts.end(); ++ei)
182       {
183       if(this->TryFullPath(tryPath.c_str(), ei->c_str()))
184         {
185         return true;
186         }
187       }
188     }
189
190   cmOStringStream e;
191   std::string missing = this->Location.GetDirectory();
192   if(!missing.empty())
193     {
194     missing += "/";
195     }
196   missing += this->Location.GetName();
197   e << "Cannot find source file:\n  " << missing << "\nTried extensions";
198   for(std::vector<std::string>::const_iterator ext = srcExts.begin();
199       ext != srcExts.end(); ++ext)
200     {
201     e << " ." << *ext;
202     }
203   for(std::vector<std::string>::const_iterator ext = hdrExts.begin();
204       ext != hdrExts.end(); ++ext)
205     {
206     e << " ." << *ext;
207     }
208   if(error)
209     {
210     *error = e.str();
211     }
212   else
213     {
214     this->Location.GetMakefile()->IssueMessage(cmake::FATAL_ERROR, e.str());
215     }
216   this->FindFullPathFailed = true;
217   return false;
218 }
219
220 //----------------------------------------------------------------------------
221 bool cmSourceFile::TryFullPath(const char* tp, const char* ext)
222 {
223   std::string tryPath = tp;
224   if(ext && *ext)
225     {
226     tryPath += ".";
227     tryPath += ext;
228     }
229   if(cmSystemTools::FileExists(tryPath.c_str()))
230     {
231     this->FullPath = tryPath;
232     return true;
233     }
234   return false;
235 }
236
237 //----------------------------------------------------------------------------
238 void cmSourceFile::CheckExtension()
239 {
240   // Compute the extension.
241   std::string realExt =
242     cmSystemTools::GetFilenameLastExtension(this->FullPath);
243   if(!realExt.empty())
244     {
245     // Store the extension without the leading '.'.
246     this->Extension = realExt.substr(1);
247     }
248
249   // Look for object files.
250   if(this->Extension == "obj" ||
251      this->Extension == "o" ||
252      this->Extension == "lo")
253     {
254     this->SetProperty("EXTERNAL_OBJECT", "1");
255     }
256
257   // Try to identify the source file language from the extension.
258   if(this->Language.empty())
259     {
260     this->CheckLanguage(this->Extension);
261     }
262 }
263
264 //----------------------------------------------------------------------------
265 void cmSourceFile::CheckLanguage(std::string const& ext)
266 {
267   // Try to identify the source file language from the extension.
268   cmMakefile* mf = this->Location.GetMakefile();
269   cmGlobalGenerator* gg = mf->GetLocalGenerator()->GetGlobalGenerator();
270   if(const char* l = gg->GetLanguageFromExtension(ext.c_str()))
271     {
272     this->Language = l;
273     }
274 }
275
276 //----------------------------------------------------------------------------
277 bool cmSourceFile::Matches(cmSourceFileLocation const& loc)
278 {
279   return this->Location.Matches(loc);
280 }
281
282 //----------------------------------------------------------------------------
283 void cmSourceFile::SetProperty(const char* prop, const char* value)
284 {
285   if (!prop)
286     {
287     return;
288     }
289
290   this->Properties.SetProperty(prop, value, cmProperty::SOURCE_FILE);
291 }
292
293 //----------------------------------------------------------------------------
294 void cmSourceFile::AppendProperty(const char* prop, const char* value,
295                                   bool asString)
296 {
297   if (!prop)
298     {
299     return;
300     }
301   this->Properties.AppendProperty(prop, value, cmProperty::SOURCE_FILE,
302                                   asString);
303 }
304
305 //----------------------------------------------------------------------------
306 const char* cmSourceFile::GetPropertyForUser(const char *prop)
307 {
308   // This method is a consequence of design history and backwards
309   // compatibility.  GetProperty is (and should be) a const method.
310   // Computed properties should not be stored back in the property map
311   // but instead reference information already known.  If they need to
312   // cache information in a mutable ivar to provide the return string
313   // safely then so be it.
314   //
315   // The LOCATION property is particularly problematic.  The CMake
316   // language has very loose restrictions on the names that will match
317   // a given source file (for historical reasons).  Implementing
318   // lookups correctly with such loose naming requires the
319   // cmSourceFileLocation class to commit to a particular full path to
320   // the source file as late as possible.  If the users requests the
321   // LOCATION property we must commit now.
322   if(strcmp(prop, "LOCATION") == 0)
323     {
324     // Commit to a location.
325     this->GetFullPath();
326     }
327
328   // Perform the normal property lookup.
329   return this->GetProperty(prop);
330 }
331
332 //----------------------------------------------------------------------------
333 const char* cmSourceFile::GetProperty(const char* prop) const
334 {
335   // Check for computed properties.
336   if(strcmp(prop, "LOCATION") == 0)
337     {
338     if(this->FullPath.empty())
339       {
340       return 0;
341       }
342     else
343       {
344       return this->FullPath.c_str();
345       }
346     }
347
348   bool chain = false;
349   const char *retVal =
350     this->Properties.GetPropertyValue(prop, cmProperty::SOURCE_FILE, chain);
351   if (chain)
352     {
353     cmMakefile* mf = this->Location.GetMakefile();
354     return mf->GetProperty(prop,cmProperty::SOURCE_FILE);
355     }
356
357   return retVal;
358 }
359
360 //----------------------------------------------------------------------------
361 bool cmSourceFile::GetPropertyAsBool(const char* prop) const
362 {
363   return cmSystemTools::IsOn(this->GetProperty(prop));
364 }
365
366 //----------------------------------------------------------------------------
367 cmCustomCommand* cmSourceFile::GetCustomCommand()
368 {
369   return this->CustomCommand;
370 }
371
372 //----------------------------------------------------------------------------
373 cmCustomCommand const* cmSourceFile::GetCustomCommand() const
374 {
375   return this->CustomCommand;
376 }
377
378 //----------------------------------------------------------------------------
379 void cmSourceFile::SetCustomCommand(cmCustomCommand* cc)
380 {
381   cmCustomCommand* old = this->CustomCommand;
382   this->CustomCommand = cc;
383   delete old;
384 }
385
386 //----------------------------------------------------------------------------
387 void cmSourceFile::DefineProperties(cmake *cm)
388 {
389   // define properties
390   cm->DefineProperty
391     ("ABSTRACT", cmProperty::SOURCE_FILE,
392      "Is this source file an abstract class.",
393      "A property on a source file that indicates if the source file "
394      "represents a class that is abstract. This only makes sense for "
395      "languages that have a notion of an abstract class and it is "
396      "only used by some tools that wrap classes into other languages.");
397
398   cm->DefineProperty
399     ("COMPILE_FLAGS", cmProperty::SOURCE_FILE,
400      "Additional flags to be added when compiling this source file.",
401      "These flags will be added to the list of compile flags when "
402      "this source file builds.  Use COMPILE_DEFINITIONS to pass additional "
403      "preprocessor definitions.");
404
405   cm->DefineProperty
406     ("COMPILE_DEFINITIONS", cmProperty::SOURCE_FILE,
407      "Preprocessor definitions for compiling a source file.",
408      "The COMPILE_DEFINITIONS property may be set to a "
409      "semicolon-separated list of preprocessor "
410      "definitions using the syntax VAR or VAR=value.  Function-style "
411      "definitions are not supported.  CMake will automatically escape "
412      "the value correctly for the native build system (note that CMake "
413      "language syntax may require escapes to specify some values).  "
414      "This property may be set on a per-configuration basis using the name "
415      "COMPILE_DEFINITIONS_<CONFIG> where <CONFIG> is an upper-case name "
416      "(ex. \"COMPILE_DEFINITIONS_DEBUG\").\n"
417      "CMake will automatically drop some definitions that "
418      "are not supported by the native build tool.  "
419      "The VS6 IDE does not support definition values with spaces "
420      "(but NMake does).  Xcode does not support per-configuration "
421      "definitions on source files.\n"
422      CM_DOCUMENT_COMPILE_DEFINITIONS_DISCLAIMER);
423
424   cm->DefineProperty
425     ("COMPILE_DEFINITIONS_<CONFIG>", cmProperty::SOURCE_FILE,
426      "Per-configuration preprocessor definitions on a source file.",
427      "This is the configuration-specific version of "
428      "COMPILE_DEFINITIONS.  Note that Xcode does not support "
429      "per-configuration source file flags so this property will "
430      "be ignored by the Xcode generator.");
431
432   cm->DefineProperty
433     ("EXTERNAL_OBJECT", cmProperty::SOURCE_FILE,
434      "If set to true then this is an object file.",
435      "If this property is set to true then the source file "
436      "is really an object file and should not be compiled.  "
437      "It will still be linked into the target though.");
438
439   cm->DefineProperty
440     ("Fortran_FORMAT", cmProperty::SOURCE_FILE,
441      "Set to FIXED or FREE to indicate the Fortran source layout.",
442      "This property tells CMake whether a given Fortran source file "
443      "uses fixed-format or free-format.  "
444      "CMake will pass the corresponding format flag to the compiler.  "
445      "Consider using the target-wide Fortran_FORMAT property if all "
446      "source files in a target share the same format.");
447
448   cm->DefineProperty
449     ("GENERATED", cmProperty::SOURCE_FILE,
450      "Is this source file generated as part of the build process.",
451      "If a source file is generated by the build process CMake will "
452      "handle it differently in terms of dependency checking etc. "
453      "Otherwise having a non-existent source file could create problems.");
454
455   cm->DefineProperty
456     ("HEADER_FILE_ONLY", cmProperty::SOURCE_FILE,
457      "Is this source file only a header file.",
458      "A property on a source file that indicates if the source file "
459      "is a header file with no associated implementation. This is "
460      "set automatically based on the file extension and is used by "
461      "CMake to determine if certain dependency information should be "
462      "computed.");
463
464   cm->DefineProperty
465     ("KEEP_EXTENSION", cmProperty::SOURCE_FILE,
466      "Make the output file have the same extension as the source file.",
467      "If this property is set then the file extension of the output "
468      "file will be the same as that of the source file. Normally "
469      "the output file extension is computed based on the language "
470      "of the source file, for example .cxx will go to a .o extension.");
471
472   cm->DefineProperty
473     ("LABELS", cmProperty::SOURCE_FILE,
474      "Specify a list of text labels associated with a source file.",
475      "This property has meaning only when the source file is listed in "
476      "a target whose LABELS property is also set.  "
477      "No other semantics are currently specified.");
478
479   cm->DefineProperty
480     ("LANGUAGE", cmProperty::SOURCE_FILE,
481      "What programming language is the file.",
482      "A property that can be set to indicate what programming language "
483      "the source file is. If it is not set the language is determined "
484      "based on the file extension. Typical values are CXX C etc. Setting "
485      "this property for a file means this file will be compiled. "
486      "Do not set this for headers or files that should not be compiled.");
487
488   cm->DefineProperty
489     ("LOCATION", cmProperty::SOURCE_FILE,
490      "The full path to a source file.",
491      "A read only property on a SOURCE FILE that contains the full path "
492      "to the source file.");
493
494   cm->DefineProperty
495     ("MACOSX_PACKAGE_LOCATION", cmProperty::SOURCE_FILE,
496      "Place a source file inside a Mac OS X bundle, CFBundle, or framework.",
497      "Executable targets with the MACOSX_BUNDLE property set are built "
498      "as Mac OS X application bundles on Apple platforms.  "
499      "Shared library targets with the FRAMEWORK property set are built "
500      "as Mac OS X frameworks on Apple platforms.  "
501      "Module library targets with the BUNDLE property set are built "
502      "as Mac OS X CFBundle bundles on Apple platforms.  "
503      "Source files listed in the target with this property set will "
504      "be copied to a directory inside the bundle or framework content "
505      "folder specified by the property value.  "
506      "For bundles the content folder is \"<name>.app/Contents\".  "
507      "For frameworks the content folder is "
508      "\"<name>.framework/Versions/<version>\".  "
509      "For cfbundles the content folder is "
510      "\"<name>.bundle/Contents\" (unless the extension is changed).  "
511      "See the PUBLIC_HEADER, PRIVATE_HEADER, and RESOURCE target "
512      "properties for specifying files meant for Headers, PrivateHeaders, "
513      "or Resources directories.");
514
515   cm->DefineProperty
516     ("OBJECT_DEPENDS", cmProperty::SOURCE_FILE,
517      "Additional files on which a compiled object file depends.",
518      "Specifies a semicolon-separated list of full-paths to files on which "
519      "any object files compiled from this source file depend.  "
520      "An object file will be recompiled if any of the named files is newer "
521      "than it.\n"
522      "This property need not be used to specify the dependency of a "
523      "source file on a generated header file that it includes.  "
524      "Although the property was originally introduced for this purpose, it "
525      "is no longer necessary.  "
526      "If the generated header file is created by a custom command in the "
527      "same target as the source file, the automatic dependency scanning "
528      "process will recognize the dependency.  "
529      "If the generated header file is created by another target, an "
530      "inter-target dependency should be created with the add_dependencies "
531      "command (if one does not already exist due to linking relationships).");
532
533   cm->DefineProperty
534     ("OBJECT_OUTPUTS", cmProperty::SOURCE_FILE,
535      "Additional outputs for a Makefile rule.",
536      "Additional outputs created by compilation of this source file. "
537      "If any of these outputs is missing the object will be recompiled. "
538      "This is supported only on Makefile generators and will be ignored "
539      "on other generators.");
540
541   cm->DefineProperty
542     ("SYMBOLIC", cmProperty::SOURCE_FILE,
543      "Is this just a name for a rule.",
544      "If SYMBOLIC (boolean) is set to true the build system will be "
545      "informed that the source file is not actually created on disk but "
546      "instead used as a symbolic name for a build rule.");
547
548   cm->DefineProperty
549     ("WRAP_EXCLUDE", cmProperty::SOURCE_FILE,
550      "Exclude this source file from any code wrapping techniques.",
551      "Some packages can wrap source files into alternate languages "
552      "to provide additional functionality. For example, C++ code "
553      "can be wrapped into Java or Python etc using SWIG etc. "
554      "If WRAP_EXCLUDE is set to true (1 etc) that indicates that "
555      "this source file should not be wrapped.");
556 }
557