summaryrefslogtreecommitdiff
path: root/Source/cmSourceFile.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmSourceFile.cxx')
-rw-r--r--Source/cmSourceFile.cxx557
1 files changed, 557 insertions, 0 deletions
diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx
new file mode 100644
index 000000000..cd94753cb
--- /dev/null
+++ b/Source/cmSourceFile.cxx
@@ -0,0 +1,557 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSourceFile.h"
+
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+#include "cmDocumentCompileDefinitions.h"
+
+//----------------------------------------------------------------------------
+cmSourceFile::cmSourceFile(cmMakefile* mf, const char* name):
+ Location(mf, name)
+{
+ this->CustomCommand = 0;
+ this->Properties.SetCMakeInstance(mf->GetCMakeInstance());
+ this->FindFullPathFailed = false;
+}
+
+//----------------------------------------------------------------------------
+cmSourceFile::~cmSourceFile()
+{
+ this->SetCustomCommand(0);
+}
+
+//----------------------------------------------------------------------------
+std::string const& cmSourceFile::GetExtension() const
+{
+ return this->Extension;
+}
+
+//----------------------------------------------------------------------------
+const char* cmSourceFile::GetLanguage()
+{
+ // If the language was set explicitly by the user then use it.
+ if(const char* lang = this->GetProperty("LANGUAGE"))
+ {
+ return lang;
+ }
+
+ // Perform computation needed to get the language if necessary.
+ if(this->FullPath.empty() && this->Language.empty())
+ {
+ // If a known extension is given or a known full path is given
+ // then trust that the current extension is sufficient to
+ // determine the language. This will fail only if the user
+ // specifies a full path to the source but leaves off the
+ // extension, which is kind of weird.
+ if(this->Location.ExtensionIsAmbiguous() &&
+ this->Location.DirectoryIsAmbiguous())
+ {
+ // Finalize the file location to get the extension and set the
+ // language.
+ this->GetFullPath();
+ }
+ else
+ {
+ // Use the known extension to get the language if possible.
+ std::string ext =
+ cmSystemTools::GetFilenameLastExtension(this->Location.GetName());
+ this->CheckLanguage(ext);
+ }
+ }
+
+ // Now try to determine the language.
+ return static_cast<cmSourceFile const*>(this)->GetLanguage();
+}
+
+//----------------------------------------------------------------------------
+const char* cmSourceFile::GetLanguage() const
+{
+ // If the language was set explicitly by the user then use it.
+ if(const char* lang = this->GetProperty("LANGUAGE"))
+ {
+ return lang;
+ }
+
+ // If the language was determined from the source file extension use it.
+ if(!this->Language.empty())
+ {
+ return this->Language.c_str();
+ }
+
+ // The language is not known.
+ return 0;
+}
+
+//----------------------------------------------------------------------------
+cmSourceFileLocation const& cmSourceFile::GetLocation() const
+{
+ return this->Location;
+}
+
+//----------------------------------------------------------------------------
+std::string const& cmSourceFile::GetFullPath(std::string* error)
+{
+ if(this->FullPath.empty())
+ {
+ if(this->FindFullPath(error))
+ {
+ this->CheckExtension();
+ }
+ }
+ return this->FullPath;
+}
+
+//----------------------------------------------------------------------------
+std::string const& cmSourceFile::GetFullPath() const
+{
+ return this->FullPath;
+}
+
+//----------------------------------------------------------------------------
+bool cmSourceFile::FindFullPath(std::string* error)
+{
+ // If thie method has already failed once do not try again.
+ if(this->FindFullPathFailed)
+ {
+ return false;
+ }
+
+ // If the file is generated compute the location without checking on
+ // disk.
+ if(this->GetPropertyAsBool("GENERATED"))
+ {
+ // The file is either already a full path or is relative to the
+ // build directory for the target.
+ this->Location.DirectoryUseBinary();
+ this->FullPath = this->Location.GetDirectory();
+ this->FullPath += "/";
+ this->FullPath += this->Location.GetName();
+ return true;
+ }
+
+ // The file is not generated. It must exist on disk.
+ cmMakefile* mf = this->Location.GetMakefile();
+ const char* tryDirs[3] = {0, 0, 0};
+ if(this->Location.DirectoryIsAmbiguous())
+ {
+ tryDirs[0] = mf->GetCurrentDirectory();
+ tryDirs[1] = mf->GetCurrentOutputDirectory();
+ }
+ else
+ {
+ tryDirs[0] = "";
+ }
+ const std::vector<std::string>& srcExts = mf->GetSourceExtensions();
+ const std::vector<std::string>& hdrExts = mf->GetHeaderExtensions();
+ for(const char* const* di = tryDirs; *di; ++di)
+ {
+ std::string tryPath = this->Location.GetDirectory();
+ if(!tryPath.empty())
+ {
+ tryPath += "/";
+ }
+ tryPath += this->Location.GetName();
+ tryPath = cmSystemTools::CollapseFullPath(tryPath.c_str(), *di);
+ if(this->TryFullPath(tryPath.c_str(), 0))
+ {
+ return true;
+ }
+ for(std::vector<std::string>::const_iterator ei = srcExts.begin();
+ ei != srcExts.end(); ++ei)
+ {
+ if(this->TryFullPath(tryPath.c_str(), ei->c_str()))
+ {
+ return true;
+ }
+ }
+ for(std::vector<std::string>::const_iterator ei = hdrExts.begin();
+ ei != hdrExts.end(); ++ei)
+ {
+ if(this->TryFullPath(tryPath.c_str(), ei->c_str()))
+ {
+ return true;
+ }
+ }
+ }
+
+ cmOStringStream e;
+ std::string missing = this->Location.GetDirectory();
+ if(!missing.empty())
+ {
+ missing += "/";
+ }
+ missing += this->Location.GetName();
+ e << "Cannot find source file:\n " << missing << "\nTried extensions";
+ for(std::vector<std::string>::const_iterator ext = srcExts.begin();
+ ext != srcExts.end(); ++ext)
+ {
+ e << " ." << *ext;
+ }
+ for(std::vector<std::string>::const_iterator ext = hdrExts.begin();
+ ext != hdrExts.end(); ++ext)
+ {
+ e << " ." << *ext;
+ }
+ if(error)
+ {
+ *error = e.str();
+ }
+ else
+ {
+ this->Location.GetMakefile()->IssueMessage(cmake::FATAL_ERROR, e.str());
+ }
+ this->FindFullPathFailed = true;
+ return false;
+}
+
+//----------------------------------------------------------------------------
+bool cmSourceFile::TryFullPath(const char* tp, const char* ext)
+{
+ std::string tryPath = tp;
+ if(ext && *ext)
+ {
+ tryPath += ".";
+ tryPath += ext;
+ }
+ if(cmSystemTools::FileExists(tryPath.c_str()))
+ {
+ this->FullPath = tryPath;
+ return true;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------------
+void cmSourceFile::CheckExtension()
+{
+ // Compute the extension.
+ std::string realExt =
+ cmSystemTools::GetFilenameLastExtension(this->FullPath);
+ if(!realExt.empty())
+ {
+ // Store the extension without the leading '.'.
+ this->Extension = realExt.substr(1);
+ }
+
+ // Look for object files.
+ if(this->Extension == "obj" ||
+ this->Extension == "o" ||
+ this->Extension == "lo")
+ {
+ this->SetProperty("EXTERNAL_OBJECT", "1");
+ }
+
+ // Try to identify the source file language from the extension.
+ if(this->Language.empty())
+ {
+ this->CheckLanguage(this->Extension);
+ }
+}
+
+//----------------------------------------------------------------------------
+void cmSourceFile::CheckLanguage(std::string const& ext)
+{
+ // Try to identify the source file language from the extension.
+ cmMakefile* mf = this->Location.GetMakefile();
+ cmGlobalGenerator* gg = mf->GetLocalGenerator()->GetGlobalGenerator();
+ if(const char* l = gg->GetLanguageFromExtension(ext.c_str()))
+ {
+ this->Language = l;
+ }
+}
+
+//----------------------------------------------------------------------------
+bool cmSourceFile::Matches(cmSourceFileLocation const& loc)
+{
+ return this->Location.Matches(loc);
+}
+
+//----------------------------------------------------------------------------
+void cmSourceFile::SetProperty(const char* prop, const char* value)
+{
+ if (!prop)
+ {
+ return;
+ }
+
+ this->Properties.SetProperty(prop, value, cmProperty::SOURCE_FILE);
+}
+
+//----------------------------------------------------------------------------
+void cmSourceFile::AppendProperty(const char* prop, const char* value,
+ bool asString)
+{
+ if (!prop)
+ {
+ return;
+ }
+ this->Properties.AppendProperty(prop, value, cmProperty::SOURCE_FILE,
+ asString);
+}
+
+//----------------------------------------------------------------------------
+const char* cmSourceFile::GetPropertyForUser(const char *prop)
+{
+ // This method is a consequence of design history and backwards
+ // compatibility. GetProperty is (and should be) a const method.
+ // Computed properties should not be stored back in the property map
+ // but instead reference information already known. If they need to
+ // cache information in a mutable ivar to provide the return string
+ // safely then so be it.
+ //
+ // The LOCATION property is particularly problematic. The CMake
+ // language has very loose restrictions on the names that will match
+ // a given source file (for historical reasons). Implementing
+ // lookups correctly with such loose naming requires the
+ // cmSourceFileLocation class to commit to a particular full path to
+ // the source file as late as possible. If the users requests the
+ // LOCATION property we must commit now.
+ if(strcmp(prop, "LOCATION") == 0)
+ {
+ // Commit to a location.
+ this->GetFullPath();
+ }
+
+ // Perform the normal property lookup.
+ return this->GetProperty(prop);
+}
+
+//----------------------------------------------------------------------------
+const char* cmSourceFile::GetProperty(const char* prop) const
+{
+ // Check for computed properties.
+ if(strcmp(prop, "LOCATION") == 0)
+ {
+ if(this->FullPath.empty())
+ {
+ return 0;
+ }
+ else
+ {
+ return this->FullPath.c_str();
+ }
+ }
+
+ bool chain = false;
+ const char *retVal =
+ this->Properties.GetPropertyValue(prop, cmProperty::SOURCE_FILE, chain);
+ if (chain)
+ {
+ cmMakefile* mf = this->Location.GetMakefile();
+ return mf->GetProperty(prop,cmProperty::SOURCE_FILE);
+ }
+
+ return retVal;
+}
+
+//----------------------------------------------------------------------------
+bool cmSourceFile::GetPropertyAsBool(const char* prop) const
+{
+ return cmSystemTools::IsOn(this->GetProperty(prop));
+}
+
+//----------------------------------------------------------------------------
+cmCustomCommand* cmSourceFile::GetCustomCommand()
+{
+ return this->CustomCommand;
+}
+
+//----------------------------------------------------------------------------
+cmCustomCommand const* cmSourceFile::GetCustomCommand() const
+{
+ return this->CustomCommand;
+}
+
+//----------------------------------------------------------------------------
+void cmSourceFile::SetCustomCommand(cmCustomCommand* cc)
+{
+ cmCustomCommand* old = this->CustomCommand;
+ this->CustomCommand = cc;
+ delete old;
+}
+
+//----------------------------------------------------------------------------
+void cmSourceFile::DefineProperties(cmake *cm)
+{
+ // define properties
+ cm->DefineProperty
+ ("ABSTRACT", cmProperty::SOURCE_FILE,
+ "Is this source file an abstract class.",
+ "A property on a source file that indicates if the source file "
+ "represents a class that is abstract. This only makes sense for "
+ "languages that have a notion of an abstract class and it is "
+ "only used by some tools that wrap classes into other languages.");
+
+ cm->DefineProperty
+ ("COMPILE_FLAGS", cmProperty::SOURCE_FILE,
+ "Additional flags to be added when compiling this source file.",
+ "These flags will be added to the list of compile flags when "
+ "this source file builds. Use COMPILE_DEFINITIONS to pass additional "
+ "preprocessor definitions.");
+
+ cm->DefineProperty
+ ("COMPILE_DEFINITIONS", cmProperty::SOURCE_FILE,
+ "Preprocessor definitions for compiling a source file.",
+ "The COMPILE_DEFINITIONS property may be set to a "
+ "semicolon-separated list of preprocessor "
+ "definitions using the syntax VAR or VAR=value. Function-style "
+ "definitions are not supported. CMake will automatically escape "
+ "the value correctly for the native build system (note that CMake "
+ "language syntax may require escapes to specify some values). "
+ "This property may be set on a per-configuration basis using the name "
+ "COMPILE_DEFINITIONS_<CONFIG> where <CONFIG> is an upper-case name "
+ "(ex. \"COMPILE_DEFINITIONS_DEBUG\").\n"
+ "CMake will automatically drop some definitions that "
+ "are not supported by the native build tool. "
+ "The VS6 IDE does not support definition values with spaces "
+ "(but NMake does). Xcode does not support per-configuration "
+ "definitions on source files.\n"
+ CM_DOCUMENT_COMPILE_DEFINITIONS_DISCLAIMER);
+
+ cm->DefineProperty
+ ("COMPILE_DEFINITIONS_<CONFIG>", cmProperty::SOURCE_FILE,
+ "Per-configuration preprocessor definitions on a source file.",
+ "This is the configuration-specific version of "
+ "COMPILE_DEFINITIONS. Note that Xcode does not support "
+ "per-configuration source file flags so this property will "
+ "be ignored by the Xcode generator.");
+
+ cm->DefineProperty
+ ("EXTERNAL_OBJECT", cmProperty::SOURCE_FILE,
+ "If set to true then this is an object file.",
+ "If this property is set to true then the source file "
+ "is really an object file and should not be compiled. "
+ "It will still be linked into the target though.");
+
+ cm->DefineProperty
+ ("Fortran_FORMAT", cmProperty::SOURCE_FILE,
+ "Set to FIXED or FREE to indicate the Fortran source layout.",
+ "This property tells CMake whether a given Fortran source file "
+ "uses fixed-format or free-format. "
+ "CMake will pass the corresponding format flag to the compiler. "
+ "Consider using the target-wide Fortran_FORMAT property if all "
+ "source files in a target share the same format.");
+
+ cm->DefineProperty
+ ("GENERATED", cmProperty::SOURCE_FILE,
+ "Is this source file generated as part of the build process.",
+ "If a source file is generated by the build process CMake will "
+ "handle it differently in terms of dependency checking etc. "
+ "Otherwise having a non-existent source file could create problems.");
+
+ cm->DefineProperty
+ ("HEADER_FILE_ONLY", cmProperty::SOURCE_FILE,
+ "Is this source file only a header file.",
+ "A property on a source file that indicates if the source file "
+ "is a header file with no associated implementation. This is "
+ "set automatically based on the file extension and is used by "
+ "CMake to determine is certain dependency information should be "
+ "computed.");
+
+ cm->DefineProperty
+ ("KEEP_EXTENSION", cmProperty::SOURCE_FILE,
+ "Make the output file have the same extension as the source file.",
+ "If this property is set then the file extension of the output "
+ "file will be the same as that of the source file. Normally "
+ "the output file extension is computed based on the language "
+ "of the source file, for example .cxx will go to a .o extension.");
+
+ cm->DefineProperty
+ ("LABELS", cmProperty::SOURCE_FILE,
+ "Specify a list of text labels associated with a source file.",
+ "This property has meaning only when the source file is listed in "
+ "a target whose LABELS property is also set. "
+ "No other semantics are currently specified.");
+
+ cm->DefineProperty
+ ("LANGUAGE", cmProperty::SOURCE_FILE,
+ "What programming language is the file.",
+ "A property that can be set to indicate what programming language "
+ "the source file is. If it is not set the language is determined "
+ "based on the file extension. Typical values are CXX C etc. Setting "
+ "this property for a file means this file will be compiled. "
+ "Do not set this for header or files that should not be compiled.");
+
+ cm->DefineProperty
+ ("LOCATION", cmProperty::SOURCE_FILE,
+ "The full path to a source file.",
+ "A read only property on a SOURCE FILE that contains the full path "
+ "to the source file.");
+
+ cm->DefineProperty
+ ("MACOSX_PACKAGE_LOCATION", cmProperty::SOURCE_FILE,
+ "Place a source file inside a Mac OS X bundle, CFBundle, or framework.",
+ "Executable targets with the MACOSX_BUNDLE property set are built "
+ "as Mac OS X application bundles on Apple platforms. "
+ "Shared library targets with the FRAMEWORK property set are built "
+ "as Mac OS X frameworks on Apple platforms. "
+ "Module library targets with the BUNDLE property set are built "
+ "as Mac OS X CFBundle bundles on Apple platforms. "
+ "Source files listed in the target with this property set will "
+ "be copied to a directory inside the bundle or framework content "
+ "folder specified by the property value. "
+ "For bundles the content folder is \"<name>.app/Contents\". "
+ "For frameworks the content folder is "
+ "\"<name>.framework/Versions/<version>\". "
+ "For cfbundles the content folder is "
+ "\"<name>.bundle/Contents\" (unless the extension is changed). "
+ "See the PUBLIC_HEADER, PRIVATE_HEADER, and RESOURCE target "
+ "properties for specifying files meant for Headers, PrivateHeaders, "
+ "or Resources directories.");
+
+ cm->DefineProperty
+ ("OBJECT_DEPENDS", cmProperty::SOURCE_FILE,
+ "Additional files on which a compiled object file depends.",
+ "Specifies a semicolon-separated list of full-paths to files on which "
+ "any object files compiled from this source file depend. "
+ "An object file will be recompiled if any of the named files is newer "
+ "than it.\n"
+ "This property need not be used to specify the dependency of a "
+ "source file on a generated header file that it includes. "
+ "Although the property was originally introduced for this purpose, it "
+ "is no longer necessary. "
+ "If the generated header file is created by a custom command in the "
+ "same target as the source file, the automatic dependency scanning "
+ "process will recognize the dependency. "
+ "If the generated header file is created by another target, an "
+ "inter-target dependency should be created with the add_dependencies "
+ "command (if one does not already exist due to linking relationships).");
+
+ cm->DefineProperty
+ ("OBJECT_OUTPUTS", cmProperty::SOURCE_FILE,
+ "Additional outputs for a Makefile rule.",
+ "Additional outputs created by compilation of this source file. "
+ "If any of these outputs is missing the object will be recompiled. "
+ "This is supported only on Makefile generators and will be ignored "
+ "on other generators.");
+
+ cm->DefineProperty
+ ("SYMBOLIC", cmProperty::SOURCE_FILE,
+ "Is this just a name for a rule.",
+ "If SYMBOLIC (boolean) is set to true the build system will be "
+ "informed that the source file is not actually created on disk but "
+ "instead used as a symbolic name for a build rule.");
+
+ cm->DefineProperty
+ ("WRAP_EXCLUDE", cmProperty::SOURCE_FILE,
+ "Exclude this source file from any code wrapping techniques.",
+ "Some packages can wrap source files into alternate languages "
+ "to provide additional functionality. For example, C++ code "
+ "can be wrapped into Java or Python etc using SWIG etc. "
+ "If WRAP_EXCLUDE is set to true (1 etc) that indicates then "
+ "this source file should not be wrapped.");
+}
+