ENH: Moved ConvertToRelativePath from cmGlobalGenerator to cmLocalGenerator. This is in preparation for setting up each local generator to have its own RelativePathTopSource and RelativePathTopBinary based on its ancestor directories.

This commit is contained in:
Brad King 2007-03-07 15:15:46 -05:00
parent 3bd9d67488
commit fc19882e8f
4 changed files with 191 additions and 193 deletions

View File

@ -42,9 +42,6 @@ cmGlobalGenerator::cmGlobalGenerator()
// By default do not use link scripts.
this->UseLinkScript = false;
// Relative paths are not configured in the constructor.
this->RelativePathsConfigured = false;
// Whether an install target is needed.
this->InstallTargetEnabled = false;
@ -1107,163 +1104,6 @@ cmTarget* cmGlobalGenerator::FindTarget(const char* project,
return 0;
}
//----------------------------------------------------------------------------
void cmGlobalGenerator::ConfigureRelativePaths()
{
// The current working directory on Windows cannot be a network
// path. Therefore relative paths cannot work when the build tree
// is a network path.
std::string source = this->CMakeInstance->GetHomeDirectory();
std::string binary = this->CMakeInstance->GetHomeOutputDirectory();
if(binary.size() < 2 || binary.substr(0, 2) != "//")
{
this->RelativePathTopSource = source;
this->RelativePathTopBinary = binary;
}
else
{
this->RelativePathTopSource = "";
this->RelativePathTopBinary = "";
}
}
//----------------------------------------------------------------------------
std::string cmGlobalGenerator
::ConvertToRelativePath(const std::vector<std::string>& local,
const char* in_remote)
{
// The path should never be quoted.
assert(in_remote[0] != '\"');
// The local path should never have a trailing slash.
assert(local.size() > 0 && !(local[local.size()-1] == ""));
// If the path is already relative then just return the path.
if(!cmSystemTools::FileIsFullPath(in_remote))
{
return in_remote;
}
// Make sure relative path conversion is configured.
if(!this->RelativePathsConfigured)
{
this->ConfigureRelativePaths();
this->RelativePathsConfigured = true;
}
std::string original = in_remote;
// Skip conversion if the path and local are not both in the source or both
// in the binary tree
std::string local_path = cmSystemTools::JoinPath(local);
bool should_convert = false;
// is the root in the binary tree?
if (local_path.size() >= this->RelativePathTopBinary.size() &&
cmSystemTools::ComparePath
(local_path.substr(0, this->RelativePathTopBinary.size()).c_str(),
this->RelativePathTopBinary.c_str()))
{
// is the source also in the binary tree?
if (original.size() >= this->RelativePathTopBinary.size() &&
cmSystemTools::ComparePath
(original.substr(0, this->RelativePathTopBinary.size()).c_str(),
this->RelativePathTopBinary.c_str()))
{
should_convert = true;
}
}
if (local_path.size() >= this->RelativePathTopSource.size() &&
cmSystemTools::ComparePath
(local_path.substr(0, this->RelativePathTopSource.size()).c_str(),
this->RelativePathTopSource.c_str()))
{
// is the source also in the binary tree?
if (original.size() >= this->RelativePathTopSource.size() &&
cmSystemTools::ComparePath
(original.substr(0, this->RelativePathTopSource.size()).c_str(),
this->RelativePathTopSource.c_str()))
{
should_convert = true;
}
}
if (!should_convert)
{
return in_remote;
}
// Identify the longest shared path component between the remote
// path and the local path.
std::vector<std::string> remote;
cmSystemTools::SplitPath(in_remote, remote);
unsigned int common=0;
while(common < remote.size() &&
common < local.size() &&
cmSystemTools::ComparePath(remote[common].c_str(),
local[common].c_str()))
{
++common;
}
// If no part of the path is in common then return the full path.
if(common == 0)
{
return in_remote;
}
// If the entire path is in common then just return a ".".
if(common == remote.size() &&
common == local.size())
{
return ".";
}
// If the entire path is in common except for a trailing slash then
// just return a "./".
if(common+1 == remote.size() &&
remote[common].size() == 0 &&
common == local.size())
{
return "./";
}
// Construct the relative path.
std::string relative;
// First add enough ../ to get up to the level of the shared portion
// of the path. Leave off the trailing slash. Note that the last
// component of local will never be empty because local should never
// have a trailing slash.
for(unsigned int i=common; i < local.size(); ++i)
{
relative += "..";
if(i < local.size()-1)
{
relative += "/";
}
}
// Now add the portion of the destination path that is not included
// in the shared portion of the path. Add a slash the first time
// only if there was already something in the path. If there was a
// trailing slash in the input then the last iteration of the loop
// will add a slash followed by an empty string which will preserve
// the trailing slash in the output.
for(unsigned int i=common; i < remote.size(); ++i)
{
if(relative.size() > 0)
{
relative += "/";
}
relative += remote[i];
}
// Finally return the path.
return relative;
}
inline std::string removeQuotes(const std::string& s)
{
if(s[0] == '\"' && s[s.size()-1] == '\"')

View File

@ -144,16 +144,6 @@ public:
///! What is the configurations directory variable called?
virtual const char* GetCMakeCFGInitDirectory() { return "."; }
/**
* Convert the given remote path to a relative path with respect to
* the given local path. The local path must be given in component
* form (see SystemTools::SplitPath) without a trailing slash. The
* remote path must use forward slashes and not already be escaped
* or quoted.
*/
std::string ConvertToRelativePath(const std::vector<std::string>& local,
const char* remote);
/** Get whether the generator should use a script for link commands. */
bool GetUseLinkScript() { return this->UseLinkScript; }
@ -209,9 +199,6 @@ protected:
void FillProjectMap();
bool IsExcluded(cmLocalGenerator* root, cmLocalGenerator* gen);
void ConfigureRelativePaths();
bool RelativePathsConfigured;
void CreateDefaultGlobalTargets(cmTargets* targets);
cmTarget CreateGlobalTarget(const char* name, const char* message,
const cmCustomCommandLines* commandLines,
@ -246,14 +233,6 @@ private:
std::map<cmStdString, cmStdString> ExtensionToLanguage;
std::map<cmStdString, cmStdString> LanguageToLinkerPreference;
// The paths to the tops of the source and binary trees used for
// relative path computation. A path must be either in the source
// tree or the build tree to be converted to a relative path. The
// ConfigureRelativePaths method may set these to be empty when
// using relative paths is unsafe.
std::string RelativePathTopSource;
std::string RelativePathTopBinary;
// this is used to improve performance
std::map<cmStdString,cmTarget *> TotalTargets;
};

View File

@ -45,6 +45,7 @@ cmLocalGenerator::cmLocalGenerator()
this->UseRelativePaths = false;
this->Configured = false;
this->EmitUniversalBinaryFlags = true;
this->RelativePathsConfigured = false;
}
cmLocalGenerator::~cmLocalGenerator()
@ -2020,27 +2021,25 @@ std::string cmLocalGenerator::Convert(const char* source,
{
case HOME:
//result = cmSystemTools::CollapseFullPath(result.c_str());
result = this->GlobalGenerator->
ConvertToRelativePath(this->HomeDirectoryComponents,
result.c_str());
result = this->ConvertToRelativePath(this->HomeDirectoryComponents,
result.c_str());
break;
case START:
//result = cmSystemTools::CollapseFullPath(result.c_str());
result = this->GlobalGenerator->
ConvertToRelativePath(this->StartDirectoryComponents,
result.c_str());
result = this->ConvertToRelativePath(this->StartDirectoryComponents,
result.c_str());
break;
case HOME_OUTPUT:
//result = cmSystemTools::CollapseFullPath(result.c_str());
result = this->GlobalGenerator->
ConvertToRelativePath(this->HomeOutputDirectoryComponents,
result.c_str());
result =
this->ConvertToRelativePath(this->HomeOutputDirectoryComponents,
result.c_str());
break;
case START_OUTPUT:
//result = cmSystemTools::CollapseFullPath(result.c_str());
result = this->GlobalGenerator->
ConvertToRelativePath(this->StartOutputDirectoryComponents,
result.c_str());
result =
this->ConvertToRelativePath(this->StartOutputDirectoryComponents,
result.c_str());
break;
case FULL:
result = cmSystemTools::CollapseFullPath(result.c_str());
@ -2082,6 +2081,165 @@ std::string cmLocalGenerator::Convert(const char* source,
return result;
}
//----------------------------------------------------------------------------
void cmLocalGenerator::ConfigureRelativePaths()
{
// The current working directory on Windows cannot be a network
// path. Therefore relative paths cannot work when the build tree
// is a network path.
std::string source = this->Makefile->GetHomeDirectory();
std::string binary = this->Makefile->GetHomeOutputDirectory();
if(binary.size() < 2 || binary.substr(0, 2) != "//")
{
this->RelativePathTopSource = source;
this->RelativePathTopBinary = binary;
}
else
{
this->RelativePathTopSource = "";
this->RelativePathTopBinary = "";
}
}
//----------------------------------------------------------------------------
std::string
cmLocalGenerator
::ConvertToRelativePath(const std::vector<std::string>& local,
const char* in_remote)
{
// The path should never be quoted.
assert(in_remote[0] != '\"');
// The local path should never have a trailing slash.
assert(local.size() > 0 && !(local[local.size()-1] == ""));
// If the path is already relative then just return the path.
if(!cmSystemTools::FileIsFullPath(in_remote))
{
return in_remote;
}
// Make sure relative path conversion is configured.
if(!this->RelativePathsConfigured)
{
this->ConfigureRelativePaths();
this->RelativePathsConfigured = true;
}
std::string original = in_remote;
// Skip conversion if the path and local are not both in the source or both
// in the binary tree
std::string local_path = cmSystemTools::JoinPath(local);
bool should_convert = false;
// A relative path is safe if both the local and remote locations
// are underneath the current relative path top in the binary tree.
if (local_path.size() >= this->RelativePathTopBinary.size() &&
cmSystemTools::ComparePath
(local_path.substr(0, this->RelativePathTopBinary.size()).c_str(),
this->RelativePathTopBinary.c_str()))
{
if (original.size() >= this->RelativePathTopBinary.size() &&
cmSystemTools::ComparePath
(original.substr(0, this->RelativePathTopBinary.size()).c_str(),
this->RelativePathTopBinary.c_str()))
{
should_convert = true;
}
}
// A relative path is safe if both the local and remote locations
// are underneath the current relative path top in the source tree.
if (local_path.size() >= this->RelativePathTopSource.size() &&
cmSystemTools::ComparePath
(local_path.substr(0, this->RelativePathTopSource.size()).c_str(),
this->RelativePathTopSource.c_str()))
{
if (original.size() >= this->RelativePathTopSource.size() &&
cmSystemTools::ComparePath
(original.substr(0, this->RelativePathTopSource.size()).c_str(),
this->RelativePathTopSource.c_str()))
{
should_convert = true;
}
}
// Do not convert if it is not safe.
if(!should_convert)
{
return in_remote;
}
// Identify the longest shared path component between the remote
// path and the local path.
std::vector<std::string> remote;
cmSystemTools::SplitPath(in_remote, remote);
unsigned int common=0;
while(common < remote.size() &&
common < local.size() &&
cmSystemTools::ComparePath(remote[common].c_str(),
local[common].c_str()))
{
++common;
}
// If no part of the path is in common then return the full path.
if(common == 0)
{
return in_remote;
}
// If the entire path is in common then just return a ".".
if(common == remote.size() &&
common == local.size())
{
return ".";
}
// If the entire path is in common except for a trailing slash then
// just return a "./".
if(common+1 == remote.size() &&
remote[common].size() == 0 &&
common == local.size())
{
return "./";
}
// Construct the relative path.
std::string relative;
// First add enough ../ to get up to the level of the shared portion
// of the path. Leave off the trailing slash. Note that the last
// component of local will never be empty because local should never
// have a trailing slash.
for(unsigned int i=common; i < local.size(); ++i)
{
relative += "..";
if(i < local.size()-1)
{
relative += "/";
}
}
// Now add the portion of the destination path that is not included
// in the shared portion of the path. Add a slash the first time
// only if there was already something in the path. If there was a
// trailing slash in the input then the last iteration of the loop
// will add a slash followed by an empty string which will preserve
// the trailing slash in the output.
for(unsigned int i=common; i < remote.size(); ++i)
{
if(relative.size() > 0)
{
relative += "/";
}
relative += remote[i];
}
// Finally return the path.
return relative;
}
//----------------------------------------------------------------------------
void

View File

@ -266,6 +266,18 @@ protected:
std::string GetObjectFileNameWithoutTarget(const cmSourceFile& source);
std::string& CreateSafeUniqueObjectFileName(const char* sin);
void ConfigureRelativePaths();
/**
* Convert the given remote path to a relative path with respect to
* the given local path. The local path must be given in component
* form (see SystemTools::SplitPath) without a trailing slash. The
* remote path must use forward slashes and not already be escaped
* or quoted.
*/
std::string ConvertToRelativePath(const std::vector<std::string>& local,
const char* remote);
cmMakefile *Makefile;
cmGlobalGenerator *GlobalGenerator;
// members used for relative path function ConvertToMakefilePath
@ -291,6 +303,15 @@ protected:
// Hack for ExpandRuleVariable until object-oriented version is
// committed.
std::string TargetImplib;
// 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;
bool RelativePathsConfigured;
};
#endif