KWSys Nightly Date Stamp
[cmake.git] / Source / cmSourceFile.cxx
blobf41af976a08181d0194e9f3955662a2c98e47ac5
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmSourceFile.cxx,v $
5 Language: C++
6 Date: $Date: 2009-06-24 13:36:29 $
7 Version: $Revision: 1.57 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmSourceFile.h"
19 #include "cmGlobalGenerator.h"
20 #include "cmLocalGenerator.h"
21 #include "cmMakefile.h"
22 #include "cmSystemTools.h"
23 #include "cmake.h"
25 //----------------------------------------------------------------------------
26 cmSourceFile::cmSourceFile(cmMakefile* mf, const char* name):
27 Location(mf, name)
29 this->CustomCommand = 0;
30 this->Properties.SetCMakeInstance(mf->GetCMakeInstance());
31 this->FindFullPathFailed = false;
34 //----------------------------------------------------------------------------
35 cmSourceFile::~cmSourceFile()
37 this->SetCustomCommand(0);
40 //----------------------------------------------------------------------------
41 std::string const& cmSourceFile::GetExtension() const
43 return this->Extension;
46 //----------------------------------------------------------------------------
47 const char* cmSourceFile::GetLanguage()
49 // If the language was set explicitly by the user then use it.
50 if(const char* lang = this->GetProperty("LANGUAGE"))
52 return lang;
55 // Perform computation needed to get the language if necessary.
56 if(this->FullPath.empty() && this->Language.empty())
58 // If a known extension is given or a known full path is given
59 // then trust that the current extension is sufficient to
60 // determine the language. This will fail only if the user
61 // specifies a full path to the source but leaves off the
62 // extension, which is kind of weird.
63 if(this->Location.ExtensionIsAmbiguous() &&
64 this->Location.DirectoryIsAmbiguous())
66 // Finalize the file location to get the extension and set the
67 // language.
68 this->GetFullPath();
70 else
72 // Use the known extension to get the language if possible.
73 std::string ext =
74 cmSystemTools::GetFilenameLastExtension(this->Location.GetName());
75 this->CheckLanguage(ext);
79 // Now try to determine the language.
80 return static_cast<cmSourceFile const*>(this)->GetLanguage();
83 //----------------------------------------------------------------------------
84 const char* cmSourceFile::GetLanguage() const
86 // If the language was set explicitly by the user then use it.
87 if(const char* lang = this->GetProperty("LANGUAGE"))
89 return lang;
92 // If the language was determined from the source file extension use it.
93 if(!this->Language.empty())
95 return this->Language.c_str();
98 // The language is not known.
99 return 0;
102 //----------------------------------------------------------------------------
103 cmSourceFileLocation const& cmSourceFile::GetLocation() const
105 return this->Location;
108 //----------------------------------------------------------------------------
109 std::string const& cmSourceFile::GetFullPath()
111 if(this->FullPath.empty())
113 if(this->FindFullPath())
115 this->CheckExtension();
118 return this->FullPath;
121 //----------------------------------------------------------------------------
122 std::string const& cmSourceFile::GetFullPath() const
124 return this->FullPath;
127 //----------------------------------------------------------------------------
128 bool cmSourceFile::FindFullPath()
130 // If thie method has already failed once do not try again.
131 if(this->FindFullPathFailed)
133 return false;
136 // If the file is generated compute the location without checking on
137 // disk.
138 if(this->GetPropertyAsBool("GENERATED"))
140 // The file is either already a full path or is relative to the
141 // build directory for the target.
142 this->Location.DirectoryUseBinary();
143 this->FullPath = this->Location.GetDirectory();
144 this->FullPath += "/";
145 this->FullPath += this->Location.GetName();
146 return true;
149 // The file is not generated. It must exist on disk.
150 cmMakefile* mf = this->Location.GetMakefile();
151 const char* tryDirs[3] = {0, 0, 0};
152 if(this->Location.DirectoryIsAmbiguous())
154 tryDirs[0] = mf->GetCurrentDirectory();
155 tryDirs[1] = mf->GetCurrentOutputDirectory();
157 else
159 tryDirs[0] = "";
161 const std::vector<std::string>& srcExts = mf->GetSourceExtensions();
162 const std::vector<std::string>& hdrExts = mf->GetHeaderExtensions();
163 for(const char* const* di = tryDirs; *di; ++di)
165 std::string tryPath = this->Location.GetDirectory();
166 if(!tryPath.empty())
168 tryPath += "/";
170 tryPath += this->Location.GetName();
171 tryPath = cmSystemTools::CollapseFullPath(tryPath.c_str(), *di);
172 if(this->TryFullPath(tryPath.c_str(), 0))
174 return true;
176 for(std::vector<std::string>::const_iterator ei = srcExts.begin();
177 ei != srcExts.end(); ++ei)
179 if(this->TryFullPath(tryPath.c_str(), ei->c_str()))
181 return true;
184 for(std::vector<std::string>::const_iterator ei = hdrExts.begin();
185 ei != hdrExts.end(); ++ei)
187 if(this->TryFullPath(tryPath.c_str(), ei->c_str()))
189 return true;
194 cmOStringStream e;
195 e << "Cannot find source file \"" << this->Location.GetName() << "\"";
196 e << ". Tried extensions";
197 for(std::vector<std::string>::const_iterator ext = srcExts.begin();
198 ext != srcExts.end(); ++ext)
200 e << " ." << *ext;
202 for(std::vector<std::string>::const_iterator ext = hdrExts.begin();
203 ext != hdrExts.end(); ++ext)
205 e << " ." << *ext;
207 this->Location.GetMakefile()->IssueMessage(cmake::FATAL_ERROR, e.str());
208 this->FindFullPathFailed = true;
209 return false;
212 //----------------------------------------------------------------------------
213 bool cmSourceFile::TryFullPath(const char* tp, const char* ext)
215 std::string tryPath = tp;
216 if(ext && *ext)
218 tryPath += ".";
219 tryPath += ext;
221 if(cmSystemTools::FileExists(tryPath.c_str()))
223 this->FullPath = tryPath;
224 return true;
226 return false;
229 //----------------------------------------------------------------------------
230 void cmSourceFile::CheckExtension()
232 // Compute the extension.
233 std::string realExt =
234 cmSystemTools::GetFilenameLastExtension(this->FullPath);
235 if(!realExt.empty())
237 // Store the extension without the leading '.'.
238 this->Extension = realExt.substr(1);
241 // Look for object files.
242 if(this->Extension == "obj" ||
243 this->Extension == "o" ||
244 this->Extension == "lo")
246 this->SetProperty("EXTERNAL_OBJECT", "1");
249 // Try to identify the source file language from the extension.
250 if(this->Language.empty())
252 this->CheckLanguage(this->Extension);
256 //----------------------------------------------------------------------------
257 void cmSourceFile::CheckLanguage(std::string const& ext)
259 // Try to identify the source file language from the extension.
260 cmMakefile* mf = this->Location.GetMakefile();
261 cmGlobalGenerator* gg = mf->GetLocalGenerator()->GetGlobalGenerator();
262 if(const char* l = gg->GetLanguageFromExtension(ext.c_str()))
264 this->Language = l;
268 //----------------------------------------------------------------------------
269 bool cmSourceFile::Matches(cmSourceFileLocation const& loc)
271 return this->Location.Matches(loc);
274 //----------------------------------------------------------------------------
275 void cmSourceFile::SetProperty(const char* prop, const char* value)
277 if (!prop)
279 return;
282 this->Properties.SetProperty(prop, value, cmProperty::SOURCE_FILE);
285 //----------------------------------------------------------------------------
286 void cmSourceFile::AppendProperty(const char* prop, const char* value)
288 if (!prop)
290 return;
292 this->Properties.AppendProperty(prop, value, cmProperty::SOURCE_FILE);
295 //----------------------------------------------------------------------------
296 const char* cmSourceFile::GetPropertyForUser(const char *prop)
298 // This method is a consequence of design history and backwards
299 // compatibility. GetProperty is (and should be) a const method.
300 // Computed properties should not be stored back in the property map
301 // but instead reference information already known. If they need to
302 // cache information in a mutable ivar to provide the return string
303 // safely then so be it.
305 // The LOCATION property is particularly problematic. The CMake
306 // language has very loose restrictions on the names that will match
307 // a given source file (for historical reasons). Implementing
308 // lookups correctly with such loose naming requires the
309 // cmSourceFileLocation class to commit to a particular full path to
310 // the source file as late as possible. If the users requests the
311 // LOCATION property we must commit now.
312 if(strcmp(prop, "LOCATION") == 0)
314 // Commit to a location.
315 this->GetFullPath();
318 // Perform the normal property lookup.
319 return this->GetProperty(prop);
322 //----------------------------------------------------------------------------
323 const char* cmSourceFile::GetProperty(const char* prop) const
325 // Check for computed properties.
326 if(strcmp(prop, "LOCATION") == 0)
328 if(this->FullPath.empty())
330 return 0;
332 else
334 return this->FullPath.c_str();
338 bool chain = false;
339 const char *retVal =
340 this->Properties.GetPropertyValue(prop, cmProperty::SOURCE_FILE, chain);
341 if (chain)
343 cmMakefile* mf = this->Location.GetMakefile();
344 return mf->GetProperty(prop,cmProperty::SOURCE_FILE);
347 return retVal;
350 //----------------------------------------------------------------------------
351 bool cmSourceFile::GetPropertyAsBool(const char* prop) const
353 return cmSystemTools::IsOn(this->GetProperty(prop));
356 //----------------------------------------------------------------------------
357 cmCustomCommand* cmSourceFile::GetCustomCommand()
359 return this->CustomCommand;
362 //----------------------------------------------------------------------------
363 cmCustomCommand const* cmSourceFile::GetCustomCommand() const
365 return this->CustomCommand;
368 //----------------------------------------------------------------------------
369 void cmSourceFile::SetCustomCommand(cmCustomCommand* cc)
371 cmCustomCommand* old = this->CustomCommand;
372 this->CustomCommand = cc;
373 delete old;
376 //----------------------------------------------------------------------------
377 void cmSourceFile::DefineProperties(cmake *cm)
379 // define properties
380 cm->DefineProperty
381 ("ABSTRACT", cmProperty::SOURCE_FILE,
382 "Is this source file an abstract class.",
383 "A property on a source file that indicates if the source file "
384 "represents a class that is abstract. This only makes sense for "
385 "languages that have a notion of an abstract class and it is "
386 "only used by some tools that wrap classes into other languages.");
388 cm->DefineProperty
389 ("COMPILE_FLAGS", cmProperty::SOURCE_FILE,
390 "Additional flags to be added when compiling this source file.",
391 "These flags will be added to the list of compile flags when "
392 "this source file builds. Use COMPILE_DEFINITIONS to pass additional "
393 "preprocessor definitions.");
395 cm->DefineProperty
396 ("COMPILE_DEFINITIONS", cmProperty::SOURCE_FILE,
397 "Preprocessor definitions for compiling a source file.",
398 "The COMPILE_DEFINITIONS property may be set to a "
399 "semicolon-separated list of preprocessor "
400 "definitions using the syntax VAR or VAR=value. Function-style "
401 "definitions are not supported. CMake will automatically escape "
402 "the value correctly for the native build system (note that CMake "
403 "language syntax may require escapes to specify some values). "
404 "This property may be set on a per-configuration basis using the name "
405 "COMPILE_DEFINITIONS_<CONFIG> where <CONFIG> is an upper-case name "
406 "(ex. \"COMPILE_DEFINITIONS_DEBUG\").\n"
407 "CMake will automatically drop some definitions that "
408 "are not supported by the native build tool. "
409 "The VS6 IDE does not support definition values with spaces "
410 "(but NMake does). Xcode does not support per-configuration "
411 "definitions on source files.\n"
412 "Dislaimer: Most native build tools have poor support for escaping "
413 "certain values. CMake has work-arounds for many cases but some "
414 "values may just not be possible to pass correctly. If a value "
415 "does not seem to be escaped correctly, do not attempt to "
416 "work-around the problem by adding escape sequences to the value. "
417 "Your work-around may break in a future version of CMake that "
418 "has improved escape support. Instead consider defining the macro "
419 "in a (configured) header file. Then report the limitation.");
422 cm->DefineProperty
423 ("COMPILE_DEFINITIONS_<CONFIG>", cmProperty::SOURCE_FILE,
424 "Per-configuration preprocessor definitions on a source file.",
425 "This is the configuration-specific version of "
426 "COMPILE_DEFINITIONS. Note that Xcode does not support "
427 "per-configuration source file flags so this property will "
428 "be ignored by the Xcode generator.");
430 cm->DefineProperty
431 ("EXTERNAL_OBJECT", cmProperty::SOURCE_FILE,
432 "If set to true then this is an object file.",
433 "If this property is set to true then the source file "
434 "is really an object file and should not be compiled. "
435 "It will still be linked into the target though.");
437 cm->DefineProperty
438 ("GENERATED", cmProperty::SOURCE_FILE,
439 "Is this source file generated as part of the build process.",
440 "If a source file is generated by the build process CMake will "
441 "handle it differently in temrs of dependency checking etc. "
442 "Otherwise having a non-existent source file could create problems.");
444 cm->DefineProperty
445 ("HEADER_FILE_ONLY", cmProperty::SOURCE_FILE,
446 "Is this source file only a header file.",
447 "A property on a source file that indicates if the source file "
448 "is a header file with no associated implementation. This is "
449 "set automatically based on the file extension and is used by "
450 "CMake to determine is certain dependency information should be "
451 "computed.");
453 cm->DefineProperty
454 ("KEEP_EXTENSION", cmProperty::SOURCE_FILE,
455 "Make the output file have the same extension as the source file.",
456 "If this property is set then the file extension of the output "
457 "file will be the same as that of the source file. Normally "
458 "the output file extension is computed based on the language "
459 "of the source file, for example .cxx will go to a .o extension.");
461 cm->DefineProperty
462 ("LABELS", cmProperty::SOURCE_FILE,
463 "Specify a list of text labels associated with a source file.",
464 "This property has meaning only when the source file is listed in "
465 "a target whose LABELS property is also set. "
466 "No other semantics are currently specified.");
468 cm->DefineProperty
469 ("LANGUAGE", cmProperty::SOURCE_FILE,
470 "What programming language is the file.",
471 "A property that can be set to indicate what programming language "
472 "the source file is. If it is not set the language is determined "
473 "based on the file extension. Typical values are CXX C etc.");
475 cm->DefineProperty
476 ("LOCATION", cmProperty::SOURCE_FILE,
477 "The full path to a source file.",
478 "A read only property on a SOURCE FILE that contains the full path "
479 "to the source file.");
481 cm->DefineProperty
482 ("MACOSX_PACKAGE_LOCATION", cmProperty::SOURCE_FILE,
483 "Place a source file inside a Mac OS X bundle or framework.",
484 "Executable targets with the MACOSX_BUNDLE property set are built "
485 "as Mac OS X application bundles on Apple platforms. "
486 "Shared library targets with the FRAMEWORK property set are built "
487 "as Mac OS X frameworks on Apple platforms. "
488 "Source files listed in the target with this property set will "
489 "be copied to a directory inside the bundle or framework content "
490 "folder specified by the property value. "
491 "For bundles the content folder is \"<name>.app/Contents\". "
492 "For frameworks the content folder is "
493 "\"<name>.framework/Versions/<version>\". "
494 "See the PUBLIC_HEADER, PRIVATE_HEADER, and RESOURCE target "
495 "properties for specifying files meant for Headers, PrivateHeadres, "
496 "or Resources directories.");
498 cm->DefineProperty
499 ("OBJECT_DEPENDS", cmProperty::SOURCE_FILE,
500 "Additional files on which a compiled object file depends.",
501 "Specifies a semicolon-separated list of full-paths to files on which "
502 "any object files compiled from this source file depend. "
503 "An object file will be recompiled if any of the named files is newer "
504 "than it.\n"
505 "This property need not be used to specify the dependency of a "
506 "source file on a generated header file that it includes. "
507 "Although the property was originally introduced for this purpose, it "
508 "is no longer necessary. "
509 "If the generated header file is created by a custom command in the "
510 "same target as the source file, the automatic dependency scanning "
511 "process will recognize the dependency. "
512 "If the generated header file is created by another target, an "
513 "inter-target dependency should be created with the add_dependencies "
514 "command (if one does not already exist due to linking relationships).");
516 cm->DefineProperty
517 ("OBJECT_OUTPUTS", cmProperty::SOURCE_FILE,
518 "Additional outputs for a Makefile rule.",
519 "Additional outputs created by compilation of this source file. "
520 "If any of these outputs is missing the object will be recompiled. "
521 "This is supported only on Makefile generators and will be ignored "
522 "on other generators.");
524 cm->DefineProperty
525 ("SYMBOLIC", cmProperty::SOURCE_FILE,
526 "Is this just a name for a rule.",
527 "If SYMBOLIC (boolean) is set to true the build system will be "
528 "informed that the source file is not actually created on disk but "
529 "instead used as a symbolic name for a build rule.");
531 cm->DefineProperty
532 ("WRAP_EXCLUDE", cmProperty::SOURCE_FILE,
533 "Exclude this source file from any code wrapping techniques.",
534 "Some packages can wrap source files into alternate languages "
535 "to provide additional functionality. For example, C++ code "
536 "can be wrapped into Java or Python etc using SWIG etc. "
537 "If WRAP_EXCLUDE is set to true (1 etc) that indicates then "
538 "this source file should not be wrapped.");