Commit a577d3c0 authored by Brad King's avatar Brad King Committed by Kitware Robot
Browse files

Merge topic 'relative-paths'

8526756b cmOutputConverter: Adopt relative path conversion helpers
013ec595 cmLocalGenerator: De-duplicate StateSnapshot member
24bfdbcf cmLocalGenerator: Remove unused MaybeRelativeToCurSrcDir method
d6fe1bdb cmLocalGenerator: Localize logic mapping source path to object file name
4cb6a53b cmListFileCache: Simplify relative path conversion in backtraces
5b3a71a8 cmSystemTools: Adopt RelativeIfUnder helper
ea9b1d36 cmStateDirectory: Clarify relative path top selection logic
2d9109df

 cmStateDirectory: Remove network path logic from relative path top selection
...
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Merge-request: !6128
parents 62b0eba2 8526756b
......@@ -57,15 +57,7 @@ using TargetIndexMapType =
std::string RelativeIfUnder(std::string const& top, std::string const& in)
{
std::string out;
if (in == top) {
out = ".";
} else if (cmSystemTools::IsSubDirectory(in, top)) {
out = in.substr(top.size() + 1);
} else {
out = in;
}
return out;
return cmSystemTools::RelativeIfUnder(top, in);
}
class JBTIndex
......
......@@ -2434,10 +2434,10 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile(
cmStateSnapshot snapshot = this->GetCMakeInstance()->GetCurrentSnapshot();
snapshot.GetDirectory().SetCurrentSource(dir_cur_src);
snapshot.GetDirectory().SetCurrentBinary(dir_cur_bld);
snapshot.GetDirectory().SetRelativePathTopSource(dir_top_src.c_str());
snapshot.GetDirectory().SetRelativePathTopBinary(dir_top_bld.c_str());
auto mfd = cm::make_unique<cmMakefile>(this, snapshot);
auto lgd = this->CreateLocalGenerator(mfd.get());
lgd->SetRelativePathTopSource(dir_top_src);
lgd->SetRelativePathTopBinary(dir_top_bld);
this->Makefiles.push_back(std::move(mfd));
this->LocalGenerators.push_back(std::move(lgd));
}
......
......@@ -22,7 +22,6 @@
#include "cmOutputConverter.h"
#include "cmProperty.h"
#include "cmState.h"
#include "cmStateDirectory.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
......@@ -552,21 +551,6 @@ cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
bool fast, int jobs, bool verbose,
std::vector<std::string> const& makeOptions)
{
std::unique_ptr<cmMakefile> mfu;
cmMakefile* mf;
if (!this->Makefiles.empty()) {
mf = this->Makefiles[0].get();
} else {
cmStateSnapshot snapshot = this->CMakeInstance->GetCurrentSnapshot();
snapshot.GetDirectory().SetCurrentSource(
this->CMakeInstance->GetHomeDirectory());
snapshot.GetDirectory().SetCurrentBinary(
this->CMakeInstance->GetHomeOutputDirectory());
snapshot.SetDefaultDefinitions();
mfu = cm::make_unique<cmMakefile>(this, snapshot);
mf = mfu.get();
}
GeneratedMakeCommand makeCommand;
// Make it possible to set verbosity also from command line
......@@ -597,9 +581,6 @@ cmGlobalUnixMakefileGenerator3::GenerateBuildCommand(
if (fast) {
tname += "/fast";
}
tname =
mf->GetStateSnapshot().GetDirectory().ConvertToRelPathIfContained(
mf->GetState()->GetBinaryDirectory(), tname);
cmSystemTools::ConvertToOutputSlashes(tname);
makeCommand.Add(std::move(tname));
}
......
......@@ -11,10 +11,8 @@
#include "cmGeneratorTarget.h"
#include "cmListFileCache.h"
#include "cmOutputConverter.h"
#include "cmStateDirectory.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
cmLinkLineComputer::cmLinkLineComputer(cmOutputConverter* outputConverter,
cmStateDirectory const& stateDir)
......@@ -52,13 +50,7 @@ void cmLinkLineComputer::SetRelink(bool relink)
std::string cmLinkLineComputer::ConvertToLinkReference(
std::string const& lib) const
{
std::string relLib = lib;
if (this->StateDir.ContainsBoth(this->StateDir.GetCurrentBinary(), lib)) {
relLib = cmSystemTools::ForceToRelativePath(
this->StateDir.GetCurrentBinary(), lib);
}
return relLib;
return this->OutputConverter->MaybeRelativeToCurBinDir(lib);
}
std::string cmLinkLineComputer::ComputeLinkLibs(cmComputeLinkInformation& cli)
......
......@@ -15,7 +15,6 @@
#include "cmMessageType.h"
#include "cmMessenger.h"
#include "cmState.h"
#include "cmStateDirectory.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
......@@ -550,7 +549,7 @@ void cmListFileBacktrace::PrintTitle(std::ostream& out) const
cmListFileContext lfc = this->TopEntry->Context;
cmStateSnapshot bottom = this->GetBottom();
if (!bottom.GetState()->GetIsInTryCompile()) {
lfc.FilePath = bottom.GetDirectory().ConvertToRelPathIfContained(
lfc.FilePath = cmSystemTools::RelativeIfUnder(
bottom.GetState()->GetSourceDirectory(), lfc.FilePath);
}
out << (lfc.Line ? " at " : " in ") << lfc;
......@@ -581,7 +580,7 @@ void cmListFileBacktrace::PrintCallStack(std::ostream& out) const
}
cmListFileContext lfc = cur->Context;
if (!bottom.GetState()->GetIsInTryCompile()) {
lfc.FilePath = bottom.GetDirectory().ConvertToRelPathIfContained(
lfc.FilePath = cmSystemTools::RelativeIfUnder(
bottom.GetState()->GetSourceDirectory(), lfc.FilePath);
}
out << " " << lfc << "\n";
......
......@@ -88,7 +88,6 @@ static auto ruleReplaceVars = { "CMAKE_${LANG}_COMPILER",
cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile)
: cmOutputConverter(makefile->GetStateSnapshot())
, StateSnapshot(makefile->GetStateSnapshot())
, DirectoryBacktrace(makefile->GetBacktrace())
{
this->GlobalGenerator = gg;
......@@ -3532,6 +3531,21 @@ bool cmLocalGenerator::IsNinjaMulti() const
return this->GetState()->UseNinjaMulti();
}
namespace {
std::string relativeIfUnder(std::string const& top, std::string const& cur,
std::string const& path)
{
// Use a path relative to 'cur' if it can be expressed without
// a `../` sequence that leaves 'top'.
if (cmSystemTools::IsSubDirectory(path, cur) ||
(cmSystemTools::IsSubDirectory(cur, top) &&
cmSystemTools::IsSubDirectory(path, top))) {
return cmSystemTools::ForceToRelativePath(cur, path);
}
return path;
}
}
std::string cmLocalGenerator::GetObjectFileNameWithoutTarget(
const cmSourceFile& source, std::string const& dir_max,
bool* hasSourceExtension, char const* customOutputExtension)
......@@ -3541,13 +3555,15 @@ std::string cmLocalGenerator::GetObjectFileNameWithoutTarget(
std::string const& fullPath = source.GetFullPath();
// Try referencing the source relative to the source tree.
std::string relFromSource = this->MaybeRelativeToCurSrcDir(fullPath);
std::string relFromSource = relativeIfUnder(
this->GetSourceDirectory(), this->GetCurrentSourceDirectory(), fullPath);
assert(!relFromSource.empty());
bool relSource = !cmSystemTools::FileIsFullPath(relFromSource);
bool subSource = relSource && relFromSource[0] != '.';
// Try referencing the source relative to the binary tree.
std::string relFromBinary = this->MaybeRelativeToCurBinDir(fullPath);
std::string relFromBinary = relativeIfUnder(
this->GetBinaryDirectory(), this->GetCurrentBinaryDirectory(), fullPath);
assert(!relFromBinary.empty());
bool relBinary = !cmSystemTools::FileIsFullPath(relFromBinary);
bool subBinary = relBinary && relFromBinary[0] != '.';
......@@ -3662,31 +3678,6 @@ std::string const& cmLocalGenerator::GetCurrentSourceDirectory() const
return this->StateSnapshot.GetDirectory().GetCurrentSource();
}
std::string cmLocalGenerator::MaybeRelativeTo(
std::string const& local_path, std::string const& remote_path) const
{
return this->StateSnapshot.GetDirectory().ConvertToRelPathIfContained(
local_path, remote_path);
}
std::string cmLocalGenerator::MaybeRelativeToTopBinDir(
std::string const& path) const
{
return this->MaybeRelativeTo(this->GetBinaryDirectory(), path);
}
std::string cmLocalGenerator::MaybeRelativeToCurBinDir(
std::string const& path) const
{
return this->MaybeRelativeTo(this->GetCurrentBinaryDirectory(), path);
}
std::string cmLocalGenerator::MaybeRelativeToCurSrcDir(
std::string const& path) const
{
return this->MaybeRelativeTo(this->GetCurrentSourceDirectory(), path);
}
std::string cmLocalGenerator::GetTargetDirectory(
const cmGeneratorTarget* /*unused*/) const
{
......
......@@ -462,17 +462,6 @@ public:
std::string const& GetCurrentBinaryDirectory() const;
std::string const& GetCurrentSourceDirectory() const;
/**
* Convert the given remote path to a relative path with respect to
* one of our common work directories. The path must use forward
* slashes and not already be escaped or quoted.
* The conversion is skipped if the paths are not both in the source
* or both in the binary tree.
*/
std::string MaybeRelativeToTopBinDir(std::string const& path) const;
std::string MaybeRelativeToCurBinDir(std::string const& path) const;
std::string MaybeRelativeToCurSrcDir(std::string const& path) const;
/**
* Generate a macOS application bundle Info.plist file.
*/
......@@ -559,9 +548,6 @@ public:
cmProp GetRuleLauncher(cmGeneratorTarget* target, const std::string& prop);
protected:
std::string MaybeRelativeTo(std::string const& local_path,
std::string const& remote_path) const;
// The default implementation ignores the IncludePathStyle and always
// uses absolute paths. A generator may override this to use relative
// paths in some cases.
......@@ -595,7 +581,6 @@ protected:
virtual bool CheckDefinition(std::string const& define) const;
cmMakefile* Makefile;
cmStateSnapshot StateSnapshot;
cmListFileBacktrace DirectoryBacktrace;
cmGlobalGenerator* GlobalGenerator;
std::map<std::string, std::string> UniqueObjectNamesMap;
......
......@@ -38,7 +38,6 @@
#include "cmRulePlaceholderExpander.h"
#include "cmSourceFile.h"
#include "cmState.h"
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
......@@ -474,11 +473,9 @@ void cmLocalUnixMakefileGenerator3::WriteDirectoryInformationFile()
infoFileStream
<< "# Relative path conversion top directories.\n"
<< "set(CMAKE_RELATIVE_PATH_TOP_SOURCE \""
<< this->StateSnapshot.GetDirectory().GetRelativePathTopSource()
<< "\")\n"
<< this->GetRelativePathTopSource() << "\")\n"
<< "set(CMAKE_RELATIVE_PATH_TOP_BINARY \""
<< this->StateSnapshot.GetDirectory().GetRelativePathTopBinary()
<< "\")\n"
<< this->GetRelativePathTopBinary() << "\")\n"
<< "\n";
/* clang-format on */
......@@ -1513,13 +1510,11 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies(
// Setup relative path top directories.
if (cmProp relativePathTopSource =
mf->GetDefinition("CMAKE_RELATIVE_PATH_TOP_SOURCE")) {
this->StateSnapshot.GetDirectory().SetRelativePathTopSource(
relativePathTopSource->c_str());
this->SetRelativePathTopSource(*relativePathTopSource);
}
if (cmProp relativePathTopBinary =
mf->GetDefinition("CMAKE_RELATIVE_PATH_TOP_BINARY")) {
this->StateSnapshot.GetDirectory().SetRelativePathTopBinary(
relativePathTopBinary->c_str());
this->SetRelativePathTopBinary(*relativePathTopBinary);
}
} else {
cmSystemTools::Error("Directory Information file not found");
......
......@@ -1749,7 +1749,8 @@ public:
{
// Construct the name of the next object.
this->NextObject = this->OutputConverter->ConvertToOutputFormat(
this->MaybeRelativeToCurBinDir(obj), cmOutputConverter::RESPONSE);
this->OutputConverter->MaybeRelativeToCurBinDir(obj),
cmOutputConverter::RESPONSE);
// Roll over to next string if the limit will be exceeded.
if (this->LengthLimit != std::string::npos &&
......@@ -1770,15 +1771,6 @@ public:
void Done() { this->Strings.push_back(this->CurrentString); }
private:
std::string MaybeRelativeToCurBinDir(std::string const& path)
{
std::string const& base = this->StateDir.GetCurrentBinary();
if (!this->StateDir.ContainsBoth(base, path)) {
return path;
}
return cmSystemTools::ForceToRelativePath(base, path);
}
std::vector<std::string>& Strings;
cmOutputConverter* OutputConverter;
cmStateDirectory StateDir;
......
......@@ -9,14 +9,108 @@
#include <vector>
#include "cmState.h"
#include "cmStateDirectory.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
namespace {
bool PathEqOrSubDir(std::string const& a, std::string const& b)
{
return (cmSystemTools::ComparePath(a, b) ||
cmSystemTools::IsSubDirectory(a, b));
};
}
cmOutputConverter::cmOutputConverter(cmStateSnapshot const& snapshot)
: StateSnapshot(snapshot)
, LinkScriptShell(false)
{
assert(this->StateSnapshot.IsValid());
this->ComputeRelativePathTopSource();
this->ComputeRelativePathTopBinary();
}
void cmOutputConverter::ComputeRelativePathTopSource()
{
// Walk up the buildsystem directory tree to find the highest source
// directory that contains the current source directory.
cmStateSnapshot snapshot = this->StateSnapshot;
for (cmStateSnapshot parent = snapshot.GetBuildsystemDirectoryParent();
parent.IsValid(); parent = parent.GetBuildsystemDirectoryParent()) {
if (cmSystemTools::IsSubDirectory(
snapshot.GetDirectory().GetCurrentSource(),
parent.GetDirectory().GetCurrentSource())) {
snapshot = parent;
}
}
this->RelativePathTopSource = snapshot.GetDirectory().GetCurrentSource();
}
void cmOutputConverter::ComputeRelativePathTopBinary()
{
// Walk up the buildsystem directory tree to find the highest binary
// directory that contains the current binary directory.
cmStateSnapshot snapshot = this->StateSnapshot;
for (cmStateSnapshot parent = snapshot.GetBuildsystemDirectoryParent();
parent.IsValid(); parent = parent.GetBuildsystemDirectoryParent()) {
if (cmSystemTools::IsSubDirectory(
snapshot.GetDirectory().GetCurrentBinary(),
parent.GetDirectory().GetCurrentBinary())) {
snapshot = parent;
}
}
this->RelativePathTopBinary = snapshot.GetDirectory().GetCurrentBinary();
}
std::string const& cmOutputConverter::GetRelativePathTopSource() const
{
return this->RelativePathTopSource;
}
std::string const& cmOutputConverter::GetRelativePathTopBinary() const
{
return this->RelativePathTopBinary;
}
void cmOutputConverter::SetRelativePathTopSource(std::string const& top)
{
this->RelativePathTopSource = top;
}
void cmOutputConverter::SetRelativePathTopBinary(std::string const& top)
{
this->RelativePathTopBinary = top;
}
std::string cmOutputConverter::MaybeRelativeTo(
std::string const& local_path, std::string const& remote_path) const
{
bool bothInBinary =
PathEqOrSubDir(local_path, this->RelativePathTopBinary) &&
PathEqOrSubDir(remote_path, this->RelativePathTopBinary);
bool bothInSource =
PathEqOrSubDir(local_path, this->RelativePathTopSource) &&
PathEqOrSubDir(remote_path, this->RelativePathTopSource);
if (bothInBinary || bothInSource) {
return cmSystemTools::ForceToRelativePath(local_path, remote_path);
}
return remote_path;
}
std::string cmOutputConverter::MaybeRelativeToTopBinDir(
std::string const& path) const
{
return this->MaybeRelativeTo(this->GetState()->GetBinaryDirectory(), path);
}
std::string cmOutputConverter::MaybeRelativeToCurBinDir(
std::string const& path) const
{
return this->MaybeRelativeTo(
this->StateSnapshot.GetDirectory().GetCurrentBinary(), path);
}
std::string cmOutputConverter::ConvertToOutputForExisting(
......
......@@ -17,6 +17,21 @@ class cmOutputConverter
public:
cmOutputConverter(cmStateSnapshot const& snapshot);
/**
* Convert the given remote path to a relative path with respect to
* one of our common work directories. The path must use forward
* slashes and not already be escaped or quoted.
* The conversion is skipped if the paths are not both in the source
* or both in the binary tree.
*/
std::string MaybeRelativeToTopBinDir(std::string const& path) const;
std::string MaybeRelativeToCurBinDir(std::string const& path) const;
std::string const& GetRelativePathTopSource() const;
std::string const& GetRelativePathTopBinary() const;
void SetRelativePathTopSource(std::string const& top);
void SetRelativePathTopBinary(std::string const& top);
enum OutputFormat
{
SHELL,
......@@ -102,6 +117,9 @@ public:
};
static FortranPreprocess GetFortranPreprocess(cm::string_view value);
protected:
cmStateSnapshot StateSnapshot;
private:
cmState* GetState() const;
......@@ -111,7 +129,17 @@ private:
static bool Shell_ArgumentNeedsQuotes(cm::string_view in, int flags);
static std::string Shell_GetArgument(cm::string_view in, int flags);
cmStateSnapshot StateSnapshot;
bool LinkScriptShell;
// The top-most directories for relative path conversion. Both the
// source and destination location of a relative path conversion
// must be underneath one of these directories (both under source or
// both under binary) in order for the relative path to be evaluated
// safely by the build tools.
std::string RelativePathTopSource;
std::string RelativePathTopBinary;
void ComputeRelativePathTopSource();
void ComputeRelativePathTopBinary();
std::string MaybeRelativeTo(std::string const& local_path,
std::string const& remote_path) const;
};
......@@ -24,74 +24,6 @@ static std::string const kBUILDSYSTEM_TARGETS = "BUILDSYSTEM_TARGETS";
static std::string const kSOURCE_DIR = "SOURCE_DIR";
static std::string const kSUBDIRECTORIES = "SUBDIRECTORIES";
void cmStateDirectory::ComputeRelativePathTopSource()
{
// Relative path conversion inside the source tree is not used to
// construct relative paths passed to build tools so it is safe to use
// even when the source is a network path.
cmStateSnapshot snapshot = this->Snapshot_;
std::vector<cmStateSnapshot> snapshots;
snapshots.push_back(snapshot);
while (true) {
snapshot = snapshot.GetBuildsystemDirectoryParent();
if (snapshot.IsValid()) {
snapshots.push_back(snapshot);
} else {
break;
}
}
std::string result = snapshots.front().GetDirectory().GetCurrentSource();
// Walk up the buildsystem directory tree to find the highest source
// directory that contains the current source directory and the
// intermediate ancestors.
for (cmStateSnapshot const& snp : cmMakeRange(snapshots).advance(1)) {
std::string currentSource = snp.GetDirectory().GetCurrentSource();
if (cmSystemTools::IsSubDirectory(result, currentSource)) {
result = currentSource;
}
}
this->DirectoryState->RelativePathTopSource = result;
}
void cmStateDirectory::ComputeRelativePathTopBinary()
{
cmStateSnapshot snapshot = this->Snapshot_;
std::vector<cmStateSnapshot> snapshots;
snapshots.push_back(snapshot);
while (true) {
snapshot = snapshot.GetBuildsystemDirectoryParent();
if (snapshot.IsValid()) {
snapshots.push_back(snapshot);
} else {
break;
}
}
std::string result = snapshots.front().GetDirectory().GetCurrentBinary();
// Walk up the buildsystem directory tree to find the highest binary
// directory that contains the current binary directory and the
// intermediate ancestors.
for (cmStateSnapshot const& snp : cmMakeRange(snapshots).advance(1)) {
std::string currentBinary = snp.GetDirectory().GetCurrentBinary();
if (cmSystemTools::IsSubDirectory(result, currentBinary)) {
result = currentBinary;
}
}
// The current working directory on Windows cannot be a network
// path. Therefore relative paths cannot work when the binary tree
// is a network path.
if (result.size() < 2 || result.substr(0, 2) != "//") {
this->DirectoryState->RelativePathTopBinary = result;
} else {
this->DirectoryState->RelativePathTopBinary.clear();
}
}
std::string const& cmStateDirectory::GetCurrentSource() const
{
return this->DirectoryState->Location;
......@@ -103,9 +35,6 @@ void cmStateDirectory::SetCurrentSource(std::string const& dir)
loc = dir;
cmSystemTools::ConvertToUnixSlashes(loc);
loc = cmSystemTools::CollapseFullPath(loc);
this->ComputeRelativePathTopSource();
this->Snapshot_.SetDefinition("CMAKE_CURRENT_SOURCE_DIR", loc);
}
......@@ -120,60 +49,9 @@ void cmStateDirectory::SetCurrentBinary(std::string const& dir)
loc = dir;
cmSystemTools::ConvertToUnixSlashes(loc);
loc = cmSystemTools::CollapseFullPath(loc);
this->ComputeRelativePathTopBinary();
this->Snapshot_.SetDefinition("CMAKE_CURRENT_BINARY_DIR", loc);
}
std::string const& cmStateDirectory::GetRelativePathTopSource() const
{
return this->DirectoryState->RelativePathTopSource;
}
std::string const& cmStateDirectory::GetRelativePathTopBinary() const
{
return this->DirectoryState->RelativePathTopBinary;
}
void cmStateDirectory::SetRelativePathTopSource(const char* dir)
{
this->DirectoryState->RelativePathTopSource = dir;
}
void cmStateDirectory::SetRelativePathTopBinary(const char* dir)
{
this->DirectoryState->RelativePathTopBinary = dir;
}
bool cmStateDirectory::ContainsBoth(std::string const& local_path,
std::string const& remote_path) const
{
auto PathEqOrSubDir = [](std::string const& a, std::string const& b) {
return (cmSystemTools::ComparePath(a, b) ||
cmSystemTools::IsSubDirectory(a, b));
};
bool bothInBinary =
PathEqOrSubDir(local_path, this->GetRelativePathTopBinary()) &&
PathEqOrSubDir(remote_path, this->GetRelativePathTopBinary());
bool bothInSource =
PathEqOrSubDir(local_path, this->GetRelativePathTopSource()) &&
PathEqOrSubDir(remote_path, this->GetRelativePathTopSource());
return bothInBinary || bothInSource;
}
std::string cmStateDirectory::ConvertToRelPathIfContained(
std::string const& local_path, std::string const& remote_path) const
{
if (!this->ContainsBoth(local_path, remote_path)) {
return remote_path;
}
return cmSystemTools::ForceToRelativePath(local_path, remote_path);
}