337 строки
9.5 KiB
C++
337 строки
9.5 KiB
C++
|
/*============================================================================
|
||
|
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 "cmMakefile.h"
|
||
|
#include "cmSystemTools.h"
|
||
|
#include "cmake.h"
|
||
|
|
||
|
cmSourceFile::cmSourceFile(cmMakefile* mf, const std::string& name)
|
||
|
: Location(mf, name)
|
||
|
{
|
||
|
this->CustomCommand = 0;
|
||
|
this->FindFullPathFailed = false;
|
||
|
this->IsUiFile = (".ui" == cmSystemTools::GetFilenameLastExtension(
|
||
|
this->Location.GetName()));
|
||
|
}
|
||
|
|
||
|
cmSourceFile::~cmSourceFile()
|
||
|
{
|
||
|
this->SetCustomCommand(0);
|
||
|
}
|
||
|
|
||
|
std::string const& cmSourceFile::GetExtension() const
|
||
|
{
|
||
|
return this->Extension;
|
||
|
}
|
||
|
|
||
|
const std::string cmSourceFile::propLANGUAGE = "LANGUAGE";
|
||
|
|
||
|
void cmSourceFile::SetObjectLibrary(std::string const& objlib)
|
||
|
{
|
||
|
this->ObjectLibrary = objlib;
|
||
|
}
|
||
|
|
||
|
std::string cmSourceFile::GetObjectLibrary() const
|
||
|
{
|
||
|
return this->ObjectLibrary;
|
||
|
}
|
||
|
|
||
|
std::string cmSourceFile::GetLanguage()
|
||
|
{
|
||
|
// If the language was set explicitly by the user then use it.
|
||
|
if (const char* lang = this->GetProperty(propLANGUAGE)) {
|
||
|
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();
|
||
|
}
|
||
|
|
||
|
std::string cmSourceFile::GetLanguage() const
|
||
|
{
|
||
|
// If the language was set explicitly by the user then use it.
|
||
|
if (const char* lang = this->GetProperty(propLANGUAGE)) {
|
||
|
return lang;
|
||
|
}
|
||
|
|
||
|
// If the language was determined from the source file extension use it.
|
||
|
if (!this->Language.empty()) {
|
||
|
return this->Language;
|
||
|
}
|
||
|
|
||
|
// The language is not known.
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
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 const* mf = this->Location.GetMakefile();
|
||
|
const char* tryDirs[3] = { 0, 0, 0 };
|
||
|
if (this->Location.DirectoryIsAmbiguous()) {
|
||
|
tryDirs[0] = mf->GetCurrentSourceDirectory();
|
||
|
tryDirs[1] = mf->GetCurrentBinaryDirectory();
|
||
|
} else {
|
||
|
tryDirs[0] = "";
|
||
|
}
|
||
|
const std::vector<std::string>& srcExts =
|
||
|
mf->GetCMakeInstance()->GetSourceExtensions();
|
||
|
std::vector<std::string> hdrExts =
|
||
|
mf->GetCMakeInstance()->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, *di);
|
||
|
if (this->TryFullPath(tryPath, "")) {
|
||
|
return true;
|
||
|
}
|
||
|
for (std::vector<std::string>::const_iterator ei = srcExts.begin();
|
||
|
ei != srcExts.end(); ++ei) {
|
||
|
if (this->TryFullPath(tryPath, *ei)) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
for (std::vector<std::string>::const_iterator ei = hdrExts.begin();
|
||
|
ei != hdrExts.end(); ++ei) {
|
||
|
if (this->TryFullPath(tryPath, *ei)) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
std::ostringstream 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 std::string& path, const std::string& ext)
|
||
|
{
|
||
|
std::string tryPath = path;
|
||
|
if (!ext.empty()) {
|
||
|
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 const* mf = this->Location.GetMakefile();
|
||
|
cmGlobalGenerator* gg = mf->GetGlobalGenerator();
|
||
|
std::string l = gg->GetLanguageFromExtension(ext.c_str());
|
||
|
if (!l.empty()) {
|
||
|
this->Language = l;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool cmSourceFile::Matches(cmSourceFileLocation const& loc)
|
||
|
{
|
||
|
return this->Location.Matches(loc);
|
||
|
}
|
||
|
|
||
|
void cmSourceFile::SetProperty(const std::string& prop, const char* value)
|
||
|
{
|
||
|
this->Properties.SetProperty(prop, value);
|
||
|
|
||
|
if (this->IsUiFile) {
|
||
|
cmMakefile const* mf = this->Location.GetMakefile();
|
||
|
if (prop == "AUTOUIC_OPTIONS") {
|
||
|
const_cast<cmMakefile*>(mf)->AddQtUiFileWithOptions(this);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void cmSourceFile::AppendProperty(const std::string& prop, const char* value,
|
||
|
bool asString)
|
||
|
{
|
||
|
this->Properties.AppendProperty(prop, value, asString);
|
||
|
}
|
||
|
|
||
|
const char* cmSourceFile::GetPropertyForUser(const std::string& 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 (prop == "LOCATION") {
|
||
|
// Commit to a location.
|
||
|
this->GetFullPath();
|
||
|
}
|
||
|
|
||
|
// Perform the normal property lookup.
|
||
|
return this->GetProperty(prop);
|
||
|
}
|
||
|
|
||
|
const char* cmSourceFile::GetProperty(const std::string& prop) const
|
||
|
{
|
||
|
// Check for computed properties.
|
||
|
if (prop == "LOCATION") {
|
||
|
if (this->FullPath.empty()) {
|
||
|
return 0;
|
||
|
} else {
|
||
|
return this->FullPath.c_str();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const char* retVal = this->Properties.GetPropertyValue(prop);
|
||
|
if (!retVal) {
|
||
|
cmMakefile const* mf = this->Location.GetMakefile();
|
||
|
const bool chain =
|
||
|
mf->GetState()->IsPropertyChained(prop, cmProperty::SOURCE_FILE);
|
||
|
if (chain) {
|
||
|
return mf->GetProperty(prop, chain);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return retVal;
|
||
|
}
|
||
|
|
||
|
bool cmSourceFile::GetPropertyAsBool(const std::string& 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;
|
||
|
}
|