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 "cmSourceFile.h"
14 #include "cmGlobalGenerator.h"
15 #include "cmLocalGenerator.h"
16 #include "cmMakefile.h"
17 #include "cmSystemTools.h"
19 #include "cmDocumentCompileDefinitions.h"
21 //----------------------------------------------------------------------------
22 cmSourceFile::cmSourceFile(cmMakefile* mf, const char* name):
25 this->CustomCommand = 0;
26 this->Properties.SetCMakeInstance(mf->GetCMakeInstance());
27 this->FindFullPathFailed = false;
30 //----------------------------------------------------------------------------
31 cmSourceFile::~cmSourceFile()
33 this->SetCustomCommand(0);
36 //----------------------------------------------------------------------------
37 std::string const& cmSourceFile::GetExtension() const
39 return this->Extension;
42 //----------------------------------------------------------------------------
43 const char* cmSourceFile::GetLanguage()
45 // If the language was set explicitly by the user then use it.
46 if(const char* lang = this->GetProperty("LANGUAGE"))
51 // Perform computation needed to get the language if necessary.
52 if(this->FullPath.empty() && this->Language.empty())
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())
62 // Finalize the file location to get the extension and set the
68 // Use the known extension to get the language if possible.
70 cmSystemTools::GetFilenameLastExtension(this->Location.GetName());
71 this->CheckLanguage(ext);
75 // Now try to determine the language.
76 return static_cast<cmSourceFile const*>(this)->GetLanguage();
79 //----------------------------------------------------------------------------
80 const char* cmSourceFile::GetLanguage() const
82 // If the language was set explicitly by the user then use it.
83 if(const char* lang = this->GetProperty("LANGUAGE"))
88 // If the language was determined from the source file extension use it.
89 if(!this->Language.empty())
91 return this->Language.c_str();
94 // The language is not known.
98 //----------------------------------------------------------------------------
99 cmSourceFileLocation const& cmSourceFile::GetLocation() const
101 return this->Location;
104 //----------------------------------------------------------------------------
105 std::string const& cmSourceFile::GetFullPath(std::string* error)
107 if(this->FullPath.empty())
109 if(this->FindFullPath(error))
111 this->CheckExtension();
114 return this->FullPath;
117 //----------------------------------------------------------------------------
118 std::string const& cmSourceFile::GetFullPath() const
120 return this->FullPath;
123 //----------------------------------------------------------------------------
124 bool cmSourceFile::FindFullPath(std::string* error)
126 // If thie method has already failed once do not try again.
127 if(this->FindFullPathFailed)
132 // If the file is generated compute the location without checking on
134 if(this->GetPropertyAsBool("GENERATED"))
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();
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())
150 tryDirs[0] = mf->GetCurrentDirectory();
151 tryDirs[1] = mf->GetCurrentOutputDirectory();
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)
161 std::string tryPath = this->Location.GetDirectory();
166 tryPath += this->Location.GetName();
167 tryPath = cmSystemTools::CollapseFullPath(tryPath.c_str(), *di);
168 if(this->TryFullPath(tryPath.c_str(), 0))
172 for(std::vector<std::string>::const_iterator ei = srcExts.begin();
173 ei != srcExts.end(); ++ei)
175 if(this->TryFullPath(tryPath.c_str(), ei->c_str()))
180 for(std::vector<std::string>::const_iterator ei = hdrExts.begin();
181 ei != hdrExts.end(); ++ei)
183 if(this->TryFullPath(tryPath.c_str(), ei->c_str()))
191 std::string missing = this->Location.GetDirectory();
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)
203 for(std::vector<std::string>::const_iterator ext = hdrExts.begin();
204 ext != hdrExts.end(); ++ext)
214 this->Location.GetMakefile()->IssueMessage(cmake::FATAL_ERROR, e.str());
216 this->FindFullPathFailed = true;
220 //----------------------------------------------------------------------------
221 bool cmSourceFile::TryFullPath(const char* tp, const char* ext)
223 std::string tryPath = tp;
229 if(cmSystemTools::FileExists(tryPath.c_str()))
231 this->FullPath = tryPath;
237 //----------------------------------------------------------------------------
238 void cmSourceFile::CheckExtension()
240 // Compute the extension.
241 std::string realExt =
242 cmSystemTools::GetFilenameLastExtension(this->FullPath);
245 // Store the extension without the leading '.'.
246 this->Extension = realExt.substr(1);
249 // Look for object files.
250 if(this->Extension == "obj" ||
251 this->Extension == "o" ||
252 this->Extension == "lo")
254 this->SetProperty("EXTERNAL_OBJECT", "1");
257 // Try to identify the source file language from the extension.
258 if(this->Language.empty())
260 this->CheckLanguage(this->Extension);
264 //----------------------------------------------------------------------------
265 void cmSourceFile::CheckLanguage(std::string const& ext)
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()))
276 //----------------------------------------------------------------------------
277 bool cmSourceFile::Matches(cmSourceFileLocation const& loc)
279 return this->Location.Matches(loc);
282 //----------------------------------------------------------------------------
283 void cmSourceFile::SetProperty(const char* prop, const char* value)
290 this->Properties.SetProperty(prop, value, cmProperty::SOURCE_FILE);
293 //----------------------------------------------------------------------------
294 void cmSourceFile::AppendProperty(const char* prop, const char* value,
301 this->Properties.AppendProperty(prop, value, cmProperty::SOURCE_FILE,
305 //----------------------------------------------------------------------------
306 const char* cmSourceFile::GetPropertyForUser(const char *prop)
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.
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)
324 // Commit to a location.
328 // Perform the normal property lookup.
329 return this->GetProperty(prop);
332 //----------------------------------------------------------------------------
333 const char* cmSourceFile::GetProperty(const char* prop) const
335 // Check for computed properties.
336 if(strcmp(prop, "LOCATION") == 0)
338 if(this->FullPath.empty())
344 return this->FullPath.c_str();
350 this->Properties.GetPropertyValue(prop, cmProperty::SOURCE_FILE, chain);
353 cmMakefile* mf = this->Location.GetMakefile();
354 return mf->GetProperty(prop,cmProperty::SOURCE_FILE);
360 //----------------------------------------------------------------------------
361 bool cmSourceFile::GetPropertyAsBool(const char* prop) const
363 return cmSystemTools::IsOn(this->GetProperty(prop));
366 //----------------------------------------------------------------------------
367 cmCustomCommand* cmSourceFile::GetCustomCommand()
369 return this->CustomCommand;
372 //----------------------------------------------------------------------------
373 cmCustomCommand const* cmSourceFile::GetCustomCommand() const
375 return this->CustomCommand;
378 //----------------------------------------------------------------------------
379 void cmSourceFile::SetCustomCommand(cmCustomCommand* cc)
381 cmCustomCommand* old = this->CustomCommand;
382 this->CustomCommand = cc;
386 //----------------------------------------------------------------------------
387 void cmSourceFile::DefineProperties(cmake *cm)
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.");
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.");
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);
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.");
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.");
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.");
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.");
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 "
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.");
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.");
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.");
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.");
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.");
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 "
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).");
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.");
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.");
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.");