cmake/Source/cmSourceFile.cxx

410 lines
12 KiB
C++
Raw Normal View History

2016-10-30 18:24:19 +01:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmSourceFile.h"
2019-11-11 23:01:05 +01:00
#include <array>
#include <utility>
2017-04-14 19:02:05 +02:00
#include "cmGlobalGenerator.h"
2020-02-01 23:06:01 +01:00
#include "cmListFileCache.h"
#include "cmMakefile.h"
2019-11-11 23:01:05 +01:00
#include "cmMessageType.h"
2016-10-30 18:24:19 +01:00
#include "cmProperty.h"
#include "cmState.h"
2020-02-01 23:06:01 +01:00
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmake.h"
2018-04-23 21:13:27 +02:00
cmSourceFile::cmSourceFile(cmMakefile* mf, const std::string& name,
cmSourceFileLocationKind kind)
: Location(mf, name, kind)
{
}
std::string const& cmSourceFile::GetExtension() const
{
return this->Extension;
}
2015-04-27 22:25:09 +02:00
const std::string cmSourceFile::propLANGUAGE = "LANGUAGE";
2019-11-11 23:01:05 +01:00
const std::string cmSourceFile::propLOCATION = "LOCATION";
const std::string cmSourceFile::propGENERATED = "GENERATED";
2020-02-01 23:06:01 +01:00
const std::string cmSourceFile::propCOMPILE_DEFINITIONS =
"COMPILE_DEFINITIONS";
const std::string cmSourceFile::propCOMPILE_OPTIONS = "COMPILE_OPTIONS";
const std::string cmSourceFile::propINCLUDE_DIRECTORIES =
"INCLUDE_DIRECTORIES";
2015-04-27 22:25:09 +02:00
void cmSourceFile::SetObjectLibrary(std::string const& objlib)
{
this->ObjectLibrary = objlib;
}
std::string cmSourceFile::GetObjectLibrary() const
{
return this->ObjectLibrary;
}
2020-02-01 23:06:01 +01:00
std::string const& cmSourceFile::GetOrDetermineLanguage()
{
// If the language was set explicitly by the user then use it.
2020-08-30 11:54:41 +02:00
if (cmProp lang = this->GetProperty(propLANGUAGE)) {
2020-02-01 23:06:01 +01:00
// Assign to member in order to return a reference.
2020-08-30 11:54:41 +02:00
this->Language = *lang;
2020-02-01 23:06:01 +01:00
return this->Language;
2016-07-09 11:21:54 +02:00
}
// Perform computation needed to get the language if necessary.
2016-07-09 11:21:54 +02:00
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.
2016-07-09 11:21:54 +02:00
if (this->Location.ExtensionIsAmbiguous() &&
this->Location.DirectoryIsAmbiguous()) {
// Finalize the file location to get the extension and set the
// language.
2020-02-01 23:06:01 +01:00
this->ResolveFullPath();
2016-07-09 11:21:54 +02:00
} else {
// Use the known extension to get the language if possible.
std::string ext =
cmSystemTools::GetFilenameLastExtension(this->Location.GetName());
this->CheckLanguage(ext);
}
2016-07-09 11:21:54 +02:00
}
2020-02-01 23:06:01 +01:00
// Use the language determined from the file extension.
return this->Language;
}
2015-04-27 22:25:09 +02:00
std::string cmSourceFile::GetLanguage() const
{
// If the language was set explicitly by the user then use it.
2020-08-30 11:54:41 +02:00
if (cmProp lang = this->GetProperty(propLANGUAGE)) {
return *lang;
2016-07-09 11:21:54 +02:00
}
2020-02-01 23:06:01 +01:00
// Use the language determined from the file extension.
return this->Language;
}
cmSourceFileLocation const& cmSourceFile::GetLocation() const
{
2016-07-09 11:21:54 +02:00
return this->Location;
}
2020-02-01 23:06:01 +01:00
std::string const& cmSourceFile::ResolveFullPath(std::string* error)
{
2016-07-09 11:21:54 +02:00
if (this->FullPath.empty()) {
if (this->FindFullPath(error)) {
this->CheckExtension();
}
2016-07-09 11:21:54 +02:00
}
return this->FullPath;
}
std::string const& cmSourceFile::GetFullPath() const
{
return this->FullPath;
}
2010-11-13 01:00:53 +02:00
bool cmSourceFile::FindFullPath(std::string* error)
{
2019-11-11 23:01:05 +01:00
// If the file is generated compute the location without checking on disk.
if (this->GetIsGenerated()) {
// The file is either already a full path or is relative to the
// build directory for the target.
this->Location.DirectoryUseBinary();
2019-11-11 23:01:05 +01:00
this->FullPath = this->Location.GetFullPath();
return true;
2016-07-09 11:21:54 +02:00
}
2019-11-11 23:01:05 +01:00
// If this method has already failed once do not try again.
if (this->FindFullPathFailed) {
return false;
2016-07-09 11:21:54 +02:00
}
2018-01-26 17:06:56 +01:00
2019-11-11 23:01:05 +01:00
// The file is not generated. It must exist on disk.
cmMakefile const* makefile = this->Location.GetMakefile();
// Location path
2020-08-30 11:54:41 +02:00
std::string const& lPath = this->Location.GetFullPath();
2019-11-11 23:01:05 +01:00
// List of extension lists
std::array<std::vector<std::string> const*, 2> const extsLists = {
{ &makefile->GetCMakeInstance()->GetSourceExtensions(),
&makefile->GetCMakeInstance()->GetHeaderExtensions() }
};
// Tries to find the file in a given directory
auto findInDir = [this, &extsLists, &lPath](std::string const& dir) -> bool {
// Compute full path
std::string const fullPath = cmSystemTools::CollapseFullPath(lPath, dir);
// Try full path
if (cmSystemTools::FileExists(fullPath)) {
this->FullPath = fullPath;
return true;
2016-07-09 11:21:54 +02:00
}
2019-11-11 23:01:05 +01:00
// Try full path with extension
2020-08-30 11:54:41 +02:00
for (auto& exts : extsLists) {
2019-11-11 23:01:05 +01:00
for (std::string const& ext : *exts) {
if (!ext.empty()) {
2020-02-01 23:06:01 +01:00
std::string extPath = cmStrCat(fullPath, '.', ext);
2019-11-11 23:01:05 +01:00
if (cmSystemTools::FileExists(extPath)) {
this->FullPath = extPath;
return true;
}
}
}
2016-07-09 11:21:54 +02:00
}
2019-11-11 23:01:05 +01:00
// File not found
return false;
};
// Try to find the file in various directories
if (this->Location.DirectoryIsAmbiguous()) {
if (findInDir(makefile->GetCurrentSourceDirectory()) ||
findInDir(makefile->GetCurrentBinaryDirectory())) {
return true;
}
} else {
if (findInDir({})) {
return true;
}
2016-07-09 11:21:54 +02:00
}
2019-11-11 23:01:05 +01:00
// Compose error
2020-02-01 23:06:01 +01:00
std::string err =
cmStrCat("Cannot find source file:\n ", lPath, "\nTried extensions");
2019-11-11 23:01:05 +01:00
for (auto exts : extsLists) {
for (std::string const& ext : *exts) {
err += " .";
err += ext;
}
2016-07-09 11:21:54 +02:00
}
2019-11-11 23:01:05 +01:00
if (error != nullptr) {
*error = std::move(err);
2016-07-09 11:21:54 +02:00
} else {
2019-11-11 23:01:05 +01:00
makefile->IssueMessage(MessageType::FATAL_ERROR, err);
2016-07-09 11:21:54 +02:00
}
this->FindFullPathFailed = true;
2019-11-11 23:01:05 +01:00
// File not found
return false;
}
void cmSourceFile::CheckExtension()
{
// Compute the extension.
std::string realExt =
cmSystemTools::GetFilenameLastExtension(this->FullPath);
2016-07-09 11:21:54 +02:00
if (!realExt.empty()) {
// Store the extension without the leading '.'.
this->Extension = realExt.substr(1);
2016-07-09 11:21:54 +02:00
}
// Look for object files.
2016-07-09 11:21:54 +02:00
if (this->Extension == "obj" || this->Extension == "o" ||
this->Extension == "lo") {
this->SetProperty("EXTERNAL_OBJECT", "1");
2016-07-09 11:21:54 +02:00
}
// Try to identify the source file language from the extension.
2016-07-09 11:21:54 +02:00
if (this->Language.empty()) {
this->CheckLanguage(this->Extension);
2016-07-09 11:21:54 +02:00
}
}
void cmSourceFile::CheckLanguage(std::string const& ext)
{
// Try to identify the source file language from the extension.
2014-08-03 19:52:23 +02:00
cmMakefile const* mf = this->Location.GetMakefile();
2015-08-17 11:37:30 +02:00
cmGlobalGenerator* gg = mf->GetGlobalGenerator();
2015-04-27 22:25:09 +02:00
std::string l = gg->GetLanguageFromExtension(ext.c_str());
2016-07-09 11:21:54 +02:00
if (!l.empty()) {
this->Language = l;
2016-07-09 11:21:54 +02:00
}
}
bool cmSourceFile::Matches(cmSourceFileLocation const& loc)
{
return this->Location.Matches(loc);
}
2015-04-27 22:25:09 +02:00
void cmSourceFile::SetProperty(const std::string& prop, const char* value)
{
2020-02-01 23:06:01 +01:00
if (prop == propINCLUDE_DIRECTORIES) {
this->IncludeDirectories.clear();
if (value) {
cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
this->IncludeDirectories.emplace_back(value, lfbt);
}
} else if (prop == propCOMPILE_OPTIONS) {
this->CompileOptions.clear();
if (value) {
cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
this->CompileOptions.emplace_back(value, lfbt);
}
} else if (prop == propCOMPILE_DEFINITIONS) {
this->CompileDefinitions.clear();
if (value) {
cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
this->CompileDefinitions.emplace_back(value, lfbt);
}
} else {
this->Properties.SetProperty(prop, value);
}
2019-11-11 23:01:05 +01:00
// Update IsGenerated flag
if (prop == propGENERATED) {
2020-02-01 23:06:01 +01:00
this->IsGenerated = cmIsOn(value);
2019-11-11 23:01:05 +01:00
}
}
2020-08-30 11:54:41 +02:00
void cmSourceFile::AppendProperty(const std::string& prop,
const std::string& value, bool asString)
{
2020-02-01 23:06:01 +01:00
if (prop == propINCLUDE_DIRECTORIES) {
2020-08-30 11:54:41 +02:00
if (!value.empty()) {
2020-02-01 23:06:01 +01:00
cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
this->IncludeDirectories.emplace_back(value, lfbt);
}
} else if (prop == propCOMPILE_OPTIONS) {
2020-08-30 11:54:41 +02:00
if (!value.empty()) {
2020-02-01 23:06:01 +01:00
cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
this->CompileOptions.emplace_back(value, lfbt);
}
} else if (prop == propCOMPILE_DEFINITIONS) {
2020-08-30 11:54:41 +02:00
if (!value.empty()) {
2020-02-01 23:06:01 +01:00
cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
this->CompileDefinitions.emplace_back(value, lfbt);
}
} else {
this->Properties.AppendProperty(prop, value, asString);
}
2019-11-11 23:01:05 +01:00
// Update IsGenerated flag
if (prop == propGENERATED) {
this->IsGenerated = this->GetPropertyAsBool(propGENERATED);
}
}
2015-04-27 22:25:09 +02:00
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.
2019-11-11 23:01:05 +01:00
if (prop == propLOCATION) {
// Commit to a location.
2020-02-01 23:06:01 +01:00
this->ResolveFullPath();
}
// Similarly, LANGUAGE can be determined by the file extension
// if it is requested by the user.
if (prop == propLANGUAGE) {
// The c_str pointer is valid until `this->Language` is modified.
return this->GetOrDetermineLanguage().c_str();
2016-07-09 11:21:54 +02:00
}
// Perform the normal property lookup.
2020-08-30 11:54:41 +02:00
cmProp p = this->GetProperty(prop);
return p ? p->c_str() : nullptr;
}
2020-08-30 11:54:41 +02:00
cmProp cmSourceFile::GetProperty(const std::string& prop) const
{
// Check for computed properties.
2019-11-11 23:01:05 +01:00
if (prop == propLOCATION) {
2016-07-09 11:21:54 +02:00
if (this->FullPath.empty()) {
2018-01-26 17:06:56 +01:00
return nullptr;
}
2020-08-30 11:54:41 +02:00
return &this->FullPath;
2016-07-09 11:21:54 +02:00
}
2020-02-01 23:06:01 +01:00
// Check for the properties with backtraces.
if (prop == propINCLUDE_DIRECTORIES) {
if (this->IncludeDirectories.empty()) {
return nullptr;
}
static std::string output;
output = cmJoin(this->IncludeDirectories, ";");
2020-08-30 11:54:41 +02:00
return &output;
2020-02-01 23:06:01 +01:00
}
if (prop == propCOMPILE_OPTIONS) {
if (this->CompileOptions.empty()) {
return nullptr;
}
static std::string output;
output = cmJoin(this->CompileOptions, ";");
2020-08-30 11:54:41 +02:00
return &output;
2020-02-01 23:06:01 +01:00
}
if (prop == propCOMPILE_DEFINITIONS) {
if (this->CompileDefinitions.empty()) {
return nullptr;
}
static std::string output;
output = cmJoin(this->CompileDefinitions, ";");
2020-08-30 11:54:41 +02:00
return &output;
2020-02-01 23:06:01 +01:00
}
2020-08-30 11:54:41 +02:00
cmProp retVal = this->Properties.GetPropertyValue(prop);
2016-07-09 11:21:54 +02:00
if (!retVal) {
2014-08-03 19:52:23 +02:00
cmMakefile const* mf = this->Location.GetMakefile();
2016-07-09 11:21:54 +02:00
const bool chain =
mf->GetState()->IsPropertyChained(prop, cmProperty::SOURCE_FILE);
if (chain) {
2015-11-17 17:22:37 +01:00
return mf->GetProperty(prop, chain);
}
2020-08-30 11:54:41 +02:00
return nullptr;
2016-07-09 11:21:54 +02:00
}
2013-03-16 19:13:01 +02:00
return retVal;
}
2018-10-28 12:09:07 +01:00
const char* cmSourceFile::GetSafeProperty(const std::string& prop) const
{
2020-08-30 11:54:41 +02:00
cmProp ret = this->GetProperty(prop);
2018-10-28 12:09:07 +01:00
if (!ret) {
return "";
}
2020-08-30 11:54:41 +02:00
return ret->c_str();
2018-10-28 12:09:07 +01:00
}
2015-04-27 22:25:09 +02:00
bool cmSourceFile::GetPropertyAsBool(const std::string& prop) const
{
2020-08-30 11:54:41 +02:00
cmProp p = this->GetProperty(prop);
return p && cmIsOn(*p);
}
2020-02-01 23:06:01 +01:00
void cmSourceFile::SetProperties(cmPropertyMap properties)
{
2020-02-01 23:06:01 +01:00
this->Properties = std::move(properties);
this->IsGenerated = this->GetPropertyAsBool(propGENERATED);
}
2020-02-01 23:06:01 +01:00
cmCustomCommand* cmSourceFile::GetCustomCommand() const
{
2020-02-01 23:06:01 +01:00
return this->CustomCommand.get();
}
2020-02-01 23:06:01 +01:00
void cmSourceFile::SetCustomCommand(std::unique_ptr<cmCustomCommand> cc)
{
2020-02-01 23:06:01 +01:00
this->CustomCommand = std::move(cc);
}