STYLE: Fix typo in GetFilenameLastExtension docs
[cmake.git] / Source / cmSourceFile.cxx
blobe69f378eff1fcce7ddfe32ddaee831ba19e89bcb
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmSourceFile.cxx,v $
5 Language: C++
6 Date: $Date: 2008-09-22 13:42:27 $
7 Version: $Revision: 1.53 $
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 // Look for header files.
250 cmMakefile* mf = this->Location.GetMakefile();
251 const std::vector<std::string>& hdrExts = mf->GetHeaderExtensions();
252 if(std::find(hdrExts.begin(), hdrExts.end(), this->Extension) ==
253 hdrExts.end())
255 // This is not a known header file extension. Mark it as not a
256 // header unless the user has already explicitly set the property.
257 if(!this->GetProperty("HEADER_FILE_ONLY"))
259 this->SetProperty("HEADER_FILE_ONLY", "0");
262 else
264 // This is a known header file extension. The source cannot be compiled.
265 this->SetProperty("HEADER_FILE_ONLY", "1");
268 // Try to identify the source file language from the extension.
269 if(this->Language.empty())
271 this->CheckLanguage(this->Extension);
275 //----------------------------------------------------------------------------
276 void cmSourceFile::CheckLanguage(std::string const& ext)
278 // Try to identify the source file language from the extension.
279 cmMakefile* mf = this->Location.GetMakefile();
280 cmGlobalGenerator* gg = mf->GetLocalGenerator()->GetGlobalGenerator();
281 if(const char* l = gg->GetLanguageFromExtension(ext.c_str()))
283 this->Language = l;
287 //----------------------------------------------------------------------------
288 bool cmSourceFile::Matches(cmSourceFileLocation const& loc)
290 return this->Location.Matches(loc);
293 //----------------------------------------------------------------------------
294 void cmSourceFile::SetProperty(const char* prop, const char* value)
296 if (!prop)
298 return;
301 this->Properties.SetProperty(prop, value, cmProperty::SOURCE_FILE);
304 //----------------------------------------------------------------------------
305 void cmSourceFile::AppendProperty(const char* prop, const char* value)
307 if (!prop)
309 return;
311 this->Properties.AppendProperty(prop, value, cmProperty::SOURCE_FILE);
314 //----------------------------------------------------------------------------
315 const char* cmSourceFile::GetPropertyForUser(const char *prop)
317 // This method is a consequence of design history and backwards
318 // compatibility. GetProperty is (and should be) a const method.
319 // Computed properties should not be stored back in the property map
320 // but instead reference information already known. If they need to
321 // cache information in a mutable ivar to provide the return string
322 // safely then so be it.
324 // The LOCATION property is particularly problematic. The CMake
325 // language has very loose restrictions on the names that will match
326 // a given source file (for historical reasons). Implementing
327 // lookups correctly with such loose naming requires the
328 // cmSourceFileLocation class to commit to a particular full path to
329 // the source file as late as possible. If the users requests the
330 // LOCATION property we must commit now.
331 if(strcmp(prop, "LOCATION") == 0)
333 // Commit to a location.
334 this->GetFullPath();
337 // Perform the normal property lookup.
338 return this->GetProperty(prop);
341 //----------------------------------------------------------------------------
342 const char* cmSourceFile::GetProperty(const char* prop) const
344 // Check for computed properties.
345 if(strcmp(prop, "LOCATION") == 0)
347 if(this->FullPath.empty())
349 return 0;
351 else
353 return this->FullPath.c_str();
357 bool chain = false;
358 const char *retVal =
359 this->Properties.GetPropertyValue(prop, cmProperty::SOURCE_FILE, chain);
360 if (chain)
362 cmMakefile* mf = this->Location.GetMakefile();
363 return mf->GetProperty(prop,cmProperty::SOURCE_FILE);
366 return retVal;
369 //----------------------------------------------------------------------------
370 bool cmSourceFile::GetPropertyAsBool(const char* prop) const
372 return cmSystemTools::IsOn(this->GetProperty(prop));
375 //----------------------------------------------------------------------------
376 cmCustomCommand* cmSourceFile::GetCustomCommand()
378 return this->CustomCommand;
381 //----------------------------------------------------------------------------
382 cmCustomCommand const* cmSourceFile::GetCustomCommand() const
384 return this->CustomCommand;
387 //----------------------------------------------------------------------------
388 void cmSourceFile::SetCustomCommand(cmCustomCommand* cc)
390 cmCustomCommand* old = this->CustomCommand;
391 this->CustomCommand = cc;
392 delete old;
395 //----------------------------------------------------------------------------
396 void cmSourceFile::DefineProperties(cmake *cm)
398 // define properties
399 cm->DefineProperty
400 ("ABSTRACT", cmProperty::SOURCE_FILE,
401 "Is this source file an abstract class.",
402 "A property on a source file that indicates if the source file "
403 "represents a class that is abstract. This only makes sense for "
404 "languages that have a notion of an abstract class and it is "
405 "only used by some tools that wrap classes into other languages.");
407 cm->DefineProperty
408 ("COMPILE_FLAGS", cmProperty::SOURCE_FILE,
409 "Additional flags to be added when compiling this source file.",
410 "These flags will be added to the list of compile flags when "
411 "this source file builds. Use COMPILE_DEFINITIONS to pass additional "
412 "preprocessor definitions.");
414 cm->DefineProperty
415 ("COMPILE_DEFINITIONS", cmProperty::SOURCE_FILE,
416 "Preprocessor definitions for compiling a source file.",
417 "The COMPILE_DEFINITIONS property may be set to a list of preprocessor "
418 "definitions using the syntax VAR or VAR=value. Function-style "
419 "definitions are not supported. CMake will automatically escape "
420 "the value correctly for the native build system (note that CMake "
421 "language syntax may require escapes to specify some values). "
422 "This property may be set on a per-configuration basis using the name "
423 "COMPILE_DEFINITIONS_<CONFIG> where <CONFIG> is an upper-case name "
424 "(ex. \"COMPILE_DEFINITIONS_DEBUG\").\n"
425 "CMake will automatically drop some definitions that "
426 "are not supported by the native build tool. "
427 "The VS6 IDE does not support definitions with values "
428 "(but NMake does). Xcode does not support per-configuration "
429 "definitions on source files.\n"
430 "Dislaimer: Most native build tools have poor support for escaping "
431 "certain values. CMake has work-arounds for many cases but some "
432 "values may just not be possible to pass correctly. If a value "
433 "does not seem to be escaped correctly, do not attempt to "
434 "work-around the problem by adding escape sequences to the value. "
435 "Your work-around may break in a future version of CMake that "
436 "has improved escape support. Instead consider defining the macro "
437 "in a (configured) header file. Then report the limitation.");
440 cm->DefineProperty
441 ("COMPILE_DEFINITIONS_<CONFIG>", cmProperty::SOURCE_FILE,
442 "Per-configuration preprocessor definitions on a source file.",
443 "This is the configuration-specific version of "
444 "COMPILE_DEFINITIONS. Note that Xcode does not support "
445 "per-configuration source file flags so this property will "
446 "be ignored by the Xcode generator.");
448 cm->DefineProperty
449 ("EXTERNAL_OBJECT", cmProperty::SOURCE_FILE,
450 "If set to true then this is an object file.",
451 "If this property is set to true then the source file "
452 "is really an object file and should not be compiled. "
453 "It will still be linked into the target though.");
455 cm->DefineProperty
456 ("GENERATED", cmProperty::SOURCE_FILE,
457 "Is this source file generated as part of the build process.",
458 "If a source file is generated by the build process CMake will "
459 "handle it differently in temrs of dependency checking etc. "
460 "Otherwise having a non-existent source file could create problems.");
462 cm->DefineProperty
463 ("HEADER_FILE_ONLY", cmProperty::SOURCE_FILE,
464 "Is this source file only a header file.",
465 "A property on a source file that indicates if the source file "
466 "is a header file with no associated implementation. This is "
467 "set automatically based on the file extension and is used by "
468 "CMake to determine is certain dependency information should be "
469 "computed.");
471 cm->DefineProperty
472 ("KEEP_EXTENSION", cmProperty::SOURCE_FILE,
473 "Make the output file have the same extension as the source file.",
474 "If this property is set then the file extension of the output "
475 "file will be the same as that of the source file. Normally "
476 "the output file extension is computed based on the language "
477 "of the source file, for example .cxx will go to a .o extension.");
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.");
486 cm->DefineProperty
487 ("LOCATION", cmProperty::SOURCE_FILE,
488 "The full path to a source file.",
489 "A read only property on a SOURCE FILE that contains the full path "
490 "to the source file.");
492 cm->DefineProperty
493 ("MACOSX_PACKAGE_LOCATION", cmProperty::SOURCE_FILE,
494 "Place a source file inside a Mac OS X bundle or framework.",
495 "Executable targets with the MACOSX_BUNDLE property set are built "
496 "as Mac OS X application bundles on Apple platforms. "
497 "Shared library targets with the FRAMEWORK property set are built "
498 "as Mac OS X frameworks on Apple platforms. "
499 "Source files listed in the target with this property set will "
500 "be copied to a directory inside the bundle or framework content "
501 "folder specified by the property value. "
502 "For bundles the content folder is \"<name>.app/Contents\". "
503 "For frameworks the content folder is "
504 "\"<name>.framework/Versions/<version>\". "
505 "See the PUBLIC_HEADER, PRIVATE_HEADER, and RESOURCE target "
506 "properties for specifying files meant for Headers, PrivateHeadres, "
507 "or Resources directories.");
509 cm->DefineProperty
510 ("OBJECT_DEPENDS", cmProperty::SOURCE_FILE,
511 "Additional files on which a compiled object file depends.",
512 "Specifies a semicolon-separated list of full-paths to files on which "
513 "any object files compiled from this source file depend. "
514 "An object file will be recompiled if any of the named files is newer "
515 "than it.\n"
516 "This property need not be used to specify the dependency of a "
517 "source file on a generated header file that it includes. "
518 "Although the property was originally introduced for this purpose, it "
519 "is no longer necessary. "
520 "If the generated header file is created by a custom command in the "
521 "same target as the source file, the automatic dependency scanning "
522 "process will recognize the dependency. "
523 "If the generated header file is created by another target, an "
524 "inter-target dependency should be created with the add_dependencies "
525 "command (if one does not already exist due to linking relationships).");
527 cm->DefineProperty
528 ("OBJECT_OUTPUTS", cmProperty::SOURCE_FILE,
529 "Additional outputs for a Makefile rule.",
530 "Additional outputs created by compilation of this source file. "
531 "If any of these outputs is missing the object will be recompiled. "
532 "This is supported only on Makefile generators and will be ignored "
533 "on other generators.");
535 cm->DefineProperty
536 ("SYMBOLIC", cmProperty::SOURCE_FILE,
537 "Is this just a name for a rule.",
538 "If SYMBOLIC (boolean) is set to true the build system will be "
539 "informed that the source file is not actually created on disk but "
540 "instead used as a symbolic name for a build rule.");
542 cm->DefineProperty
543 ("WRAP_EXCLUDE", cmProperty::SOURCE_FILE,
544 "Exclude this source file from any code wrapping techniques.",
545 "Some packages can wrap source files into alternate languages "
546 "to provide additional functionality. For example, C++ code "
547 "can be wrapped into Java or Python etc using SWIG etc. "
548 "If WRAP_EXCLUDE is set to true (1 etc) that indicates then "
549 "this source file should not be wrapped.");