mirror of
https://github.com/reactos/CMake.git
synced 2024-12-04 17:56:26 +00:00
b0716fbcc5
The ambiguous extension logic is an old behavior that ends up taking lots of extra compute cycles to execute. This is triggered by various CMake codepaths which pass extension-less paths down when CMake actually knows that they are not ambiguous. These codepaths will be indicated in upcoming changes. Various APIs have gained a cmSourceFileLocationKind parameter, but they are all optional and default to the existing behavior.
230 lines
7.7 KiB
C++
230 lines
7.7 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
|
#include "cmSourceFileLocation.h"
|
|
|
|
#include "cmAlgorithms.h"
|
|
#include "cmGlobalGenerator.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmSystemTools.h"
|
|
#include "cmake.h"
|
|
|
|
#include <assert.h>
|
|
|
|
cmSourceFileLocation::cmSourceFileLocation()
|
|
: Makefile(nullptr)
|
|
, AmbiguousDirectory(true)
|
|
, AmbiguousExtension(true)
|
|
{
|
|
}
|
|
|
|
cmSourceFileLocation::cmSourceFileLocation(const cmSourceFileLocation& loc)
|
|
: Makefile(loc.Makefile)
|
|
{
|
|
this->AmbiguousDirectory = loc.AmbiguousDirectory;
|
|
this->AmbiguousExtension = loc.AmbiguousExtension;
|
|
this->Directory = loc.Directory;
|
|
this->Name = loc.Name;
|
|
}
|
|
|
|
cmSourceFileLocation::cmSourceFileLocation(cmMakefile const* mf,
|
|
const std::string& name,
|
|
cmSourceFileLocationKind kind)
|
|
: Makefile(mf)
|
|
{
|
|
this->AmbiguousDirectory = !cmSystemTools::FileIsFullPath(name.c_str());
|
|
this->AmbiguousExtension = true;
|
|
this->Directory = cmSystemTools::GetFilenamePath(name);
|
|
if (cmSystemTools::FileIsFullPath(this->Directory.c_str())) {
|
|
this->Directory = cmSystemTools::CollapseFullPath(this->Directory);
|
|
}
|
|
this->Name = cmSystemTools::GetFilenameName(name);
|
|
if (kind == cmSourceFileLocationKind::Known) {
|
|
this->DirectoryUseSource();
|
|
this->AmbiguousExtension = false;
|
|
} else {
|
|
this->UpdateExtension(name);
|
|
}
|
|
}
|
|
|
|
void cmSourceFileLocation::Update(cmSourceFileLocation const& loc)
|
|
{
|
|
if (this->AmbiguousDirectory && !loc.AmbiguousDirectory) {
|
|
this->Directory = loc.Directory;
|
|
this->AmbiguousDirectory = false;
|
|
}
|
|
if (this->AmbiguousExtension && !loc.AmbiguousExtension) {
|
|
this->Name = loc.Name;
|
|
this->AmbiguousExtension = false;
|
|
}
|
|
}
|
|
|
|
void cmSourceFileLocation::DirectoryUseSource()
|
|
{
|
|
assert(this->Makefile);
|
|
if (this->AmbiguousDirectory) {
|
|
this->Directory = cmSystemTools::CollapseFullPath(
|
|
this->Directory, this->Makefile->GetCurrentSourceDirectory());
|
|
this->AmbiguousDirectory = false;
|
|
}
|
|
}
|
|
|
|
void cmSourceFileLocation::DirectoryUseBinary()
|
|
{
|
|
assert(this->Makefile);
|
|
if (this->AmbiguousDirectory) {
|
|
this->Directory = cmSystemTools::CollapseFullPath(
|
|
this->Directory, this->Makefile->GetCurrentBinaryDirectory());
|
|
this->AmbiguousDirectory = false;
|
|
}
|
|
}
|
|
|
|
void cmSourceFileLocation::UpdateExtension(const std::string& name)
|
|
{
|
|
assert(this->Makefile);
|
|
// Check the extension.
|
|
std::string ext = cmSystemTools::GetFilenameLastExtension(name);
|
|
if (!ext.empty()) {
|
|
ext = ext.substr(1);
|
|
}
|
|
|
|
// The global generator checks extensions of enabled languages.
|
|
cmGlobalGenerator* gg = this->Makefile->GetGlobalGenerator();
|
|
cmMakefile const* mf = this->Makefile;
|
|
auto cm = mf->GetCMakeInstance();
|
|
if (!gg->GetLanguageFromExtension(ext.c_str()).empty() ||
|
|
cm->IsSourceExtension(ext) || cm->IsHeaderExtension(ext)) {
|
|
// This is a known extension. Use the given filename with extension.
|
|
this->Name = cmSystemTools::GetFilenameName(name);
|
|
this->AmbiguousExtension = false;
|
|
} else {
|
|
// This is not a known extension. See if the file exists on disk as
|
|
// named.
|
|
std::string tryPath;
|
|
if (this->AmbiguousDirectory) {
|
|
// Check the source tree only because a file in the build tree should
|
|
// be specified by full path at least once. We do not want this
|
|
// detection to depend on whether the project has already been built.
|
|
tryPath = this->Makefile->GetCurrentSourceDirectory();
|
|
tryPath += "/";
|
|
}
|
|
if (!this->Directory.empty()) {
|
|
tryPath += this->Directory;
|
|
tryPath += "/";
|
|
}
|
|
tryPath += this->Name;
|
|
if (cmSystemTools::FileExists(tryPath.c_str(), true)) {
|
|
// We found a source file named by the user on disk. Trust it's
|
|
// extension.
|
|
this->Name = cmSystemTools::GetFilenameName(name);
|
|
this->AmbiguousExtension = false;
|
|
|
|
// If the directory was ambiguous, it isn't anymore.
|
|
if (this->AmbiguousDirectory) {
|
|
this->DirectoryUseSource();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool cmSourceFileLocation::MatchesAmbiguousExtension(
|
|
cmSourceFileLocation const& loc) const
|
|
{
|
|
assert(this->Makefile);
|
|
// This location's extension is not ambiguous but loc's extension
|
|
// is. See if the names match as-is.
|
|
if (this->Name == loc.Name) {
|
|
return true;
|
|
}
|
|
|
|
// Check if loc's name could possibly be extended to our name by
|
|
// adding an extension.
|
|
if (!(this->Name.size() > loc.Name.size() &&
|
|
this->Name[loc.Name.size()] == '.' &&
|
|
cmHasLiteralPrefixImpl(this->Name.c_str(), loc.Name.c_str(),
|
|
loc.Name.size()))) {
|
|
return false;
|
|
}
|
|
|
|
// Only a fixed set of extensions will be tried to match a file on
|
|
// disk. One of these must match if loc refers to this source file.
|
|
std::string const& ext = this->Name.substr(loc.Name.size() + 1);
|
|
cmMakefile const* mf = this->Makefile;
|
|
auto cm = mf->GetCMakeInstance();
|
|
return cm->IsSourceExtension(ext) || cm->IsHeaderExtension(ext);
|
|
}
|
|
|
|
bool cmSourceFileLocation::Matches(cmSourceFileLocation const& loc)
|
|
{
|
|
assert(this->Makefile);
|
|
if (this->AmbiguousExtension == loc.AmbiguousExtension) {
|
|
// Both extensions are similarly ambiguous. Since only the old fixed set
|
|
// of extensions will be tried, the names must match at this point to be
|
|
// the same file.
|
|
if (this->Name.size() != loc.Name.size() ||
|
|
!cmSystemTools::ComparePath(this->Name, loc.Name)) {
|
|
return false;
|
|
}
|
|
} else {
|
|
const cmSourceFileLocation* loc1;
|
|
const cmSourceFileLocation* loc2;
|
|
if (this->AmbiguousExtension) {
|
|
// Only "this" extension is ambiguous.
|
|
loc1 = &loc;
|
|
loc2 = this;
|
|
} else {
|
|
// Only "loc" extension is ambiguous.
|
|
loc1 = this;
|
|
loc2 = &loc;
|
|
}
|
|
if (!loc1->MatchesAmbiguousExtension(*loc2)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!this->AmbiguousDirectory && !loc.AmbiguousDirectory) {
|
|
// Both sides have absolute directories.
|
|
if (this->Directory != loc.Directory) {
|
|
return false;
|
|
}
|
|
} else if (this->AmbiguousDirectory && loc.AmbiguousDirectory) {
|
|
if (this->Makefile == loc.Makefile) {
|
|
// Both sides have directories relative to the same location.
|
|
if (this->Directory != loc.Directory) {
|
|
return false;
|
|
}
|
|
} else {
|
|
// Each side has a directory relative to a different location.
|
|
// This can occur when referencing a source file from a different
|
|
// directory. This is not yet allowed.
|
|
this->Makefile->IssueMessage(
|
|
cmake::INTERNAL_ERROR,
|
|
"Matches error: Each side has a directory relative to a different "
|
|
"location. This can occur when referencing a source file from a "
|
|
"different directory. This is not yet allowed.");
|
|
return false;
|
|
}
|
|
} else if (this->AmbiguousDirectory) {
|
|
// Compare possible directory combinations.
|
|
std::string const& srcDir = cmSystemTools::CollapseFullPath(
|
|
this->Directory, this->Makefile->GetCurrentSourceDirectory());
|
|
std::string const& binDir = cmSystemTools::CollapseFullPath(
|
|
this->Directory, this->Makefile->GetCurrentBinaryDirectory());
|
|
if (srcDir != loc.Directory && binDir != loc.Directory) {
|
|
return false;
|
|
}
|
|
} else if (loc.AmbiguousDirectory) {
|
|
// Compare possible directory combinations.
|
|
std::string const& srcDir = cmSystemTools::CollapseFullPath(
|
|
loc.Directory, loc.Makefile->GetCurrentSourceDirectory());
|
|
std::string const& binDir = cmSystemTools::CollapseFullPath(
|
|
loc.Directory, loc.Makefile->GetCurrentBinaryDirectory());
|
|
if (srcDir != this->Directory && binDir != this->Directory) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// File locations match.
|
|
this->Update(loc);
|
|
return true;
|
|
}
|