ENH: Improve RPATH behavior during installation.
- If new RPATH is empty then remove the entry completely - Preserve file modification time so installation is not repeated - If installed file already exists remove it if its RPATH does not match that expected
This commit is contained in:
parent
b9a5dccc8d
commit
fdc3bfff7c
|
@ -112,9 +112,17 @@ bool cmFileCommand
|
||||||
{
|
{
|
||||||
return this->HandleInstallCommand(args);
|
return this->HandleInstallCommand(args);
|
||||||
}
|
}
|
||||||
else if ( subCommand == "CHRPATH" )
|
else if ( subCommand == "RPATH_CHANGE" || subCommand == "CHRPATH" )
|
||||||
{
|
{
|
||||||
return this->HandleChrpathCommand(args);
|
return this->HandleRPathChangeCommand(args);
|
||||||
|
}
|
||||||
|
else if ( subCommand == "RPATH_CHECK" )
|
||||||
|
{
|
||||||
|
return this->HandleRPathCheckCommand(args);
|
||||||
|
}
|
||||||
|
else if ( subCommand == "RPATH_REMOVE" )
|
||||||
|
{
|
||||||
|
return this->HandleRPathRemoveCommand(args);
|
||||||
}
|
}
|
||||||
else if ( subCommand == "RELATIVE_PATH" )
|
else if ( subCommand == "RELATIVE_PATH" )
|
||||||
{
|
{
|
||||||
|
@ -1332,7 +1340,8 @@ bool cmFileCommand::HandleInstallDestination(cmFileInstaller& installer,
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
bool cmFileCommand::HandleChrpathCommand(std::vector<std::string> const& args)
|
bool
|
||||||
|
cmFileCommand::HandleRPathChangeCommand(std::vector<std::string> const& args)
|
||||||
{
|
{
|
||||||
// Evaluate arguments.
|
// Evaluate arguments.
|
||||||
const char* file = 0;
|
const char* file = 0;
|
||||||
|
@ -1372,49 +1381,174 @@ bool cmFileCommand::HandleChrpathCommand(std::vector<std::string> const& args)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmOStringStream e;
|
cmOStringStream e;
|
||||||
e << "CHRPATH given unknown argument " << args[i];
|
e << "RPATH_CHANGE given unknown argument " << args[i];
|
||||||
this->SetError(e.str().c_str());
|
this->SetError(e.str().c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!file)
|
if(!file)
|
||||||
{
|
{
|
||||||
this->SetError("CHRPATH not given FILE option.");
|
this->SetError("RPATH_CHANGE not given FILE option.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(!oldRPath)
|
if(!oldRPath)
|
||||||
{
|
{
|
||||||
this->SetError("CHRPATH not given OLD_RPATH option.");
|
this->SetError("RPATH_CHANGE not given OLD_RPATH option.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(!newRPath)
|
if(!newRPath)
|
||||||
{
|
{
|
||||||
this->SetError("CHRPATH not given NEW_RPATH option.");
|
this->SetError("RPATH_CHANGE not given NEW_RPATH option.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(!cmSystemTools::FileExists(file, true))
|
if(!cmSystemTools::FileExists(file, true))
|
||||||
{
|
{
|
||||||
cmOStringStream e;
|
cmOStringStream e;
|
||||||
e << "CHRPATH given FILE \"" << file << "\" that does not exist.";
|
e << "RPATH_CHANGE given FILE \"" << file << "\" that does not exist.";
|
||||||
this->SetError(e.str().c_str());
|
this->SetError(e.str().c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
bool success = true;
|
||||||
|
cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
|
||||||
|
bool have_ft = cmSystemTools::FileTimeGet(file, ft);
|
||||||
std::string emsg;
|
std::string emsg;
|
||||||
if(cmSystemTools::ChangeRPath(file, oldRPath, newRPath, &emsg))
|
if(!cmSystemTools::ChangeRPath(file, oldRPath, newRPath, &emsg))
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
cmOStringStream e;
|
cmOStringStream e;
|
||||||
e << "CHRPATH could not write new RPATH:\n"
|
e << "RPATH_CHANGE could not write new RPATH:\n"
|
||||||
<< " " << newRPath << "\n"
|
<< " " << newRPath << "\n"
|
||||||
<< "to the file:\n"
|
<< "to the file:\n"
|
||||||
<< " " << file << "\n"
|
<< " " << file << "\n"
|
||||||
<< emsg;
|
<< emsg;
|
||||||
this->SetError(e.str().c_str());
|
this->SetError(e.str().c_str());
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
if(success && have_ft)
|
||||||
|
{
|
||||||
|
cmSystemTools::FileTimeSet(file, ft);
|
||||||
|
}
|
||||||
|
cmSystemTools::FileTimeDelete(ft);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool
|
||||||
|
cmFileCommand::HandleRPathRemoveCommand(std::vector<std::string> const& args)
|
||||||
|
{
|
||||||
|
// Evaluate arguments.
|
||||||
|
const char* file = 0;
|
||||||
|
enum Doing { DoingNone, DoingFile };
|
||||||
|
Doing doing = DoingNone;
|
||||||
|
for(unsigned int i=1; i < args.size(); ++i)
|
||||||
|
{
|
||||||
|
if(args[i] == "FILE")
|
||||||
|
{
|
||||||
|
doing = DoingFile;
|
||||||
|
}
|
||||||
|
else if(doing == DoingFile)
|
||||||
|
{
|
||||||
|
file = args[i].c_str();
|
||||||
|
doing = DoingNone;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmOStringStream e;
|
||||||
|
e << "RPATH_REMOVE given unknown argument " << args[i];
|
||||||
|
this->SetError(e.str().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!file)
|
||||||
|
{
|
||||||
|
this->SetError("RPATH_REMOVE not given FILE option.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if(!cmSystemTools::FileExists(file, true))
|
||||||
|
{
|
||||||
|
cmOStringStream e;
|
||||||
|
e << "RPATH_REMOVE given FILE \"" << file << "\" that does not exist.";
|
||||||
|
this->SetError(e.str().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool success = true;
|
||||||
|
cmSystemToolsFileTime* ft = cmSystemTools::FileTimeNew();
|
||||||
|
bool have_ft = cmSystemTools::FileTimeGet(file, ft);
|
||||||
|
std::string emsg;
|
||||||
|
if(!cmSystemTools::RemoveRPath(file, &emsg))
|
||||||
|
{
|
||||||
|
cmOStringStream e;
|
||||||
|
e << "RPATH_REMOVE could not remove RPATH from file:\n"
|
||||||
|
<< " " << file << "\n"
|
||||||
|
<< emsg;
|
||||||
|
this->SetError(e.str().c_str());
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
if(success && have_ft)
|
||||||
|
{
|
||||||
|
cmSystemTools::FileTimeSet(file, ft);
|
||||||
|
}
|
||||||
|
cmSystemTools::FileTimeDelete(ft);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool
|
||||||
|
cmFileCommand::HandleRPathCheckCommand(std::vector<std::string> const& args)
|
||||||
|
{
|
||||||
|
// Evaluate arguments.
|
||||||
|
const char* file = 0;
|
||||||
|
const char* rpath = 0;
|
||||||
|
enum Doing { DoingNone, DoingFile, DoingRPath };
|
||||||
|
Doing doing = DoingNone;
|
||||||
|
for(unsigned int i=1; i < args.size(); ++i)
|
||||||
|
{
|
||||||
|
if(args[i] == "RPATH")
|
||||||
|
{
|
||||||
|
doing = DoingRPath;
|
||||||
|
}
|
||||||
|
else if(args[i] == "FILE")
|
||||||
|
{
|
||||||
|
doing = DoingFile;
|
||||||
|
}
|
||||||
|
else if(doing == DoingFile)
|
||||||
|
{
|
||||||
|
file = args[i].c_str();
|
||||||
|
doing = DoingNone;
|
||||||
|
}
|
||||||
|
else if(doing == DoingRPath)
|
||||||
|
{
|
||||||
|
rpath = args[i].c_str();
|
||||||
|
doing = DoingNone;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cmOStringStream e;
|
||||||
|
e << "RPATH_CHECK given unknown argument " << args[i];
|
||||||
|
this->SetError(e.str().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!file)
|
||||||
|
{
|
||||||
|
this->SetError("RPATH_CHECK not given FILE option.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!rpath)
|
||||||
|
{
|
||||||
|
this->SetError("RPATH_CHECK not given RPATH option.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the file exists but does not have the desired RPath then
|
||||||
|
// delete it. This is used during installation to re-install a file
|
||||||
|
// if its RPath will change.
|
||||||
|
if(cmSystemTools::FileExists(file, true) &&
|
||||||
|
!cmSystemTools::CheckRPath(file, rpath))
|
||||||
|
{
|
||||||
|
cmSystemTools::RemoveFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
|
@ -171,7 +171,9 @@ protected:
|
||||||
bool HandleRelativePathCommand(std::vector<std::string> const& args);
|
bool HandleRelativePathCommand(std::vector<std::string> const& args);
|
||||||
bool HandleCMakePathCommand(std::vector<std::string> const& args,
|
bool HandleCMakePathCommand(std::vector<std::string> const& args,
|
||||||
bool nativePath);
|
bool nativePath);
|
||||||
bool HandleChrpathCommand(std::vector<std::string> const& args);
|
bool HandleRPathChangeCommand(std::vector<std::string> const& args);
|
||||||
|
bool HandleRPathCheckCommand(std::vector<std::string> const& args);
|
||||||
|
bool HandleRPathRemoveCommand(std::vector<std::string> const& args);
|
||||||
|
|
||||||
// file(INSTALL ...) related functions
|
// file(INSTALL ...) related functions
|
||||||
bool HandleInstallCommand(std::vector<std::string> const& args);
|
bool HandleInstallCommand(std::vector<std::string> const& args);
|
||||||
|
|
|
@ -333,6 +333,32 @@ cmInstallTargetGenerator
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Construct the path of the file on disk after installation on
|
||||||
|
// which tweaks may be performed.
|
||||||
|
std::string toDestDirPath = "$ENV{DESTDIR}";
|
||||||
|
if(toInstallPath[0] != '/' && toInstallPath[0] != '$')
|
||||||
|
{
|
||||||
|
toDestDirPath += "/";
|
||||||
|
}
|
||||||
|
toDestDirPath += toInstallPath;
|
||||||
|
|
||||||
|
// Add pre-installation tweaks.
|
||||||
|
if(tweakInstalledFile)
|
||||||
|
{
|
||||||
|
// Collect tweaking rules.
|
||||||
|
cmOStringStream tw;
|
||||||
|
this->AddRPathCheckRule(tw, indent.Next(), config, toDestDirPath);
|
||||||
|
std::string tws = tw.str();
|
||||||
|
|
||||||
|
// Add the rules, if any.
|
||||||
|
if(!tws.empty())
|
||||||
|
{
|
||||||
|
os << indent << "IF(EXISTS \"" << toDestDirPath << "\")\n";
|
||||||
|
os << tws;
|
||||||
|
os << indent << "ENDIF(EXISTS \"" << toDestDirPath << "\")\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Write code to install the target file.
|
// Write code to install the target file.
|
||||||
const char* no_dir_permissions = 0;
|
const char* no_dir_permissions = 0;
|
||||||
const char* no_rename = 0;
|
const char* no_rename = 0;
|
||||||
|
@ -344,25 +370,24 @@ cmInstallTargetGenerator
|
||||||
no_rename, literal_args.c_str(),
|
no_rename, literal_args.c_str(),
|
||||||
indent);
|
indent);
|
||||||
|
|
||||||
// Construct the path of the file on disk after installation on
|
// Add post-installation tweaks.
|
||||||
// which tweaks may be performed.
|
|
||||||
std::string toDestDirPath = "$ENV{DESTDIR}";
|
|
||||||
if(toInstallPath[0] != '/' && toInstallPath[0] != '$')
|
|
||||||
{
|
|
||||||
toDestDirPath += "/";
|
|
||||||
}
|
|
||||||
toDestDirPath += toInstallPath;
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// - Skip IF(EXISTS) checks if nothing is done with the installed file
|
|
||||||
if(tweakInstalledFile)
|
if(tweakInstalledFile)
|
||||||
{
|
{
|
||||||
os << indent << "IF(EXISTS \"" << toDestDirPath << "\")\n";
|
// Collect tweaking rules.
|
||||||
this->AddInstallNamePatchRule(os, indent.Next(), config, toDestDirPath);
|
cmOStringStream tw;
|
||||||
this->AddChrpathPatchRule(os, indent.Next(), config, toDestDirPath);
|
this->AddInstallNamePatchRule(tw, indent.Next(), config, toDestDirPath);
|
||||||
this->AddRanlibRule(os, indent.Next(), type, toDestDirPath);
|
this->AddChrpathPatchRule(tw, indent.Next(), config, toDestDirPath);
|
||||||
this->AddStripRule(os, indent.Next(), type, toDestDirPath);
|
this->AddRanlibRule(tw, indent.Next(), type, toDestDirPath);
|
||||||
os << indent << "ENDIF(EXISTS \"" << toDestDirPath << "\")\n";
|
this->AddStripRule(tw, indent.Next(), type, toDestDirPath);
|
||||||
|
std::string tws = tw.str();
|
||||||
|
|
||||||
|
// Add the rules, if any.
|
||||||
|
if(!tws.empty())
|
||||||
|
{
|
||||||
|
os << indent << "IF(EXISTS \"" << toDestDirPath << "\")\n";
|
||||||
|
os << tws;
|
||||||
|
os << indent << "ENDIF(EXISTS \"" << toDestDirPath << "\")\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,6 +572,37 @@ cmInstallTargetGenerator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void
|
||||||
|
cmInstallTargetGenerator
|
||||||
|
::AddRPathCheckRule(std::ostream& os, Indent const& indent,
|
||||||
|
const char* config, std::string const& toDestDirPath)
|
||||||
|
{
|
||||||
|
// Skip the chrpath if the target does not need it.
|
||||||
|
if(this->ImportLibrary || !this->Target->IsChrpathUsed())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the link information for this target.
|
||||||
|
// It can provide the RPATH.
|
||||||
|
cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config);
|
||||||
|
if(!cli)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the install RPATH from the link information.
|
||||||
|
std::string newRpath = cli->GetChrpathString();
|
||||||
|
|
||||||
|
// Write a rule to remove the installed file if its rpath is not the
|
||||||
|
// new rpath. This is needed for existing build/install trees when
|
||||||
|
// the installed rpath changes but the file is not rebuilt.
|
||||||
|
os << indent << "FILE(RPATH_CHECK\n"
|
||||||
|
<< indent << " FILE \"" << toDestDirPath << "\"\n"
|
||||||
|
<< indent << " RPATH \"" << newRpath << "\")\n";
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void
|
void
|
||||||
cmInstallTargetGenerator
|
cmInstallTargetGenerator
|
||||||
|
@ -580,9 +636,18 @@ cmInstallTargetGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write a rule to run chrpath to set the install-tree RPATH
|
// Write a rule to run chrpath to set the install-tree RPATH
|
||||||
os << indent << "FILE(CHRPATH FILE \"" << toDestDirPath << "\"\n"
|
if(newRpath.empty())
|
||||||
<< indent << " OLD_RPATH \"" << oldRpath << "\"\n"
|
{
|
||||||
<< indent << " NEW_RPATH \"" << newRpath << "\")\n";
|
os << indent << "FILE(RPATH_REMOVE\n"
|
||||||
|
<< indent << " FILE \"" << toDestDirPath << "\")\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
os << indent << "FILE(RPATH_CHANGE\n"
|
||||||
|
<< indent << " FILE \"" << toDestDirPath << "\"\n"
|
||||||
|
<< indent << " OLD_RPATH \"" << oldRpath << "\"\n"
|
||||||
|
<< indent << " NEW_RPATH \"" << newRpath << "\")\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
|
@ -80,6 +80,9 @@ protected:
|
||||||
void AddChrpathPatchRule(std::ostream& os, Indent const& indent,
|
void AddChrpathPatchRule(std::ostream& os, Indent const& indent,
|
||||||
const char* config,
|
const char* config,
|
||||||
std::string const& toDestDirPath);
|
std::string const& toDestDirPath);
|
||||||
|
void AddRPathCheckRule(std::ostream& os, Indent const& indent,
|
||||||
|
const char* config,
|
||||||
|
std::string const& toDestDirPath);
|
||||||
|
|
||||||
void AddStripRule(std::ostream& os, Indent const& indent,
|
void AddStripRule(std::ostream& os, Indent const& indent,
|
||||||
cmTarget::TargetType type,
|
cmTarget::TargetType type,
|
||||||
|
|
Loading…
Reference in New Issue