Add rpath support

This commit is contained in:
Pablo Marcos Oltra 2018-04-12 08:35:29 +02:00
parent 4f5f54ac3a
commit f5efd92f6e
5 changed files with 148 additions and 36 deletions

View File

@ -33,6 +33,7 @@ THE SOFTWARE.
#include <sys/param.h>
#include "Utils.h"
#include "Settings.h"
#include "DylibBundler.h"
#include <stdlib.h>
#include <sstream>
@ -91,7 +92,11 @@ Dependency::Dependency(std::string path)
char original_file_buffer[PATH_MAX];
std::string original_file;
if (not realpath(rtrim(path).c_str(), original_file_buffer))
if (isRpath(path))
{
original_file = searchFilenameInRpaths(path);
}
else if (not realpath(rtrim(path).c_str(), original_file_buffer))
{
std::cerr << "\n/!\\ WARNING : Cannot resolve path '" << path.c_str() << "'" << std::endl;
original_file = path;
@ -141,31 +146,7 @@ Dependency::Dependency(std::string path)
std::cerr << "\n/!\\ WARNING : Library " << filename << " has an incomplete name (location unknown)" << std::endl;
missing_prefixes = true;
while (true)
{
std::cout << "Please specify now where this library can be found (or write 'quit' to abort): "; fflush(stdout);
char buffer[128];
std::cin >> buffer;
prefix = buffer;
std::cout << std::endl;
if(prefix.compare("quit")==0) exit(1);
if( !prefix.empty() && prefix[ prefix.size()-1 ] != '/' ) prefix += "/";
if( !fileExists( prefix+filename ) )
{
std::cerr << (prefix+filename) << " does not exist. Try again" << std::endl;
continue;
}
else
{
pathes.push_back( prefix );
std::cerr << (prefix+filename) << " was found. /!\\MANUALLY CHECK THE EXECUTABLE WITH 'otool -L', DYLIBBUNDLDER MAY NOT HANDLE CORRECTLY THIS UNSTANDARD/ILL-FORMED DEPENDENCY" << std::endl;
break;
}
}
paths.push_back(getUserInputDirForFile(filename));
}
//new_name = filename.substr(0, filename.find(".")) + ".dylib";

View File

@ -26,12 +26,15 @@ THE SOFTWARE.
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <set>
#include "Utils.h"
#include "Settings.h"
#include "Dependency.h"
std::vector<Dependency> deps;
std::set<std::string> rpaths;
std::set<std::string> filenames_rpaths_already_collected;
void changeLibPathsOnFile(std::string file_to_fix)
{
@ -44,6 +47,88 @@ void changeLibPathsOnFile(std::string file_to_fix)
}
}
void collectRpaths(const std::string& filename)
{
if (!fileExists(filename))
{
std::cerr << "\n/!\\ WARNING : can't collect rpaths for inexistent file '" << filename << "'\n";
return;
}
std::string cmd = "otool -l " + filename;
std::string output = system_get_output(cmd);
std::vector<std::string> lc_lines;
tokenize(output, "\n", &lc_lines);
size_t pos = 0;
bool read_rpath = false;
while (pos < lc_lines.size())
{
std::string line = lc_lines[pos];
pos++;
if (read_rpath)
{
size_t start_pos = line.find("path ");
size_t end_pos = line.find(" (");
if (start_pos == std::string::npos || end_pos == std::string::npos)
{
std::cerr << "\n/!\\ WARNING: Unexpected LC_RPATH format\n";
continue;
}
start_pos += 5;
std::string rpath = line.substr(start_pos, end_pos - start_pos);
rpaths.insert(rpath);
read_rpath = false;
continue;
}
if (line.find("LC_RPATH") != std::string::npos)
{
read_rpath = true;
pos++;
}
}
}
void collectRpathsForFilename(const std::string& filename)
{
if (filenames_rpaths_already_collected.find(filename) == filenames_rpaths_already_collected.end())
{
collectRpaths(filename);
filenames_rpaths_already_collected.insert(filename);
}
}
std::string searchFilenameInRpaths(const std::string& rpath_file)
{
char buffer[PATH_MAX];
std::string fullpath;
std::string suffix = rpath_file.substr(7, rpath_file.size()-6);
for (std::set<std::string>::iterator it = rpaths.begin(); it != rpaths.end(); ++it)
{
std::string path = *it + "/" + suffix;
if (realpath(path.c_str(), buffer))
{
fullpath = buffer;
break;
}
}
if (fullpath.empty())
{
std::cerr << "\n/!\\ WARNING : can't get path for '" << rpath_file << "'\n";
fullpath = getUserInputDirForFile(suffix) + suffix;
if (realpath(fullpath.c_str(), buffer)) {
fullpath = buffer;
}
}
return fullpath;
}
void addDependency(std::string path)
{
Dependency dep(path);
@ -93,10 +178,15 @@ void collectDependencies(std::string filename)
std::cout << "."; fflush(stdout);
if(lines[n][0] != '\t') continue; // only lines beginning with a tab interest us
if( lines[n].find(".framework") != std::string::npos ) continue; //Ignore frameworks, we can not handle them
addDependency( // trim useless info, keep only library name
lines[n].substr(1, lines[n].rfind(" (") - 1)
);
// trim useless info, keep only library name
std::string dep_path = lines[n].substr(1, lines[n].rfind(" (") - 1);
if (isRpath(dep_path))
{
collectRpathsForFilename(filename);
}
addDependency(dep_path);
}
}
void collectSubDependencies()
@ -112,7 +202,13 @@ void collectSubDependencies()
{
std::cout << "."; fflush(stdout);
std::vector<std::string> lines;
collectDependencies(deps[n].getOriginalPath(), lines);
std::string original_path = deps[n].getOriginalPath();
if (isRpath(original_path))
{
original_path = searchFilenameInRpaths(original_path);
}
collectRpathsForFilename(original_path);
collectDependencies(original_path, lines);
const int line_amount = lines.size();
for(int n=0; n<line_amount; n++)
@ -120,9 +216,14 @@ void collectSubDependencies()
if(lines[n][0] != '\t') continue; // only lines beginning with a tab interest us
if( lines[n].find(".framework") != std::string::npos ) continue; //Ignore frameworks, we can not handle them
addDependency( // trim useless info, keep only library name
lines[n].substr(1, lines[n].rfind(" (") - 1)
);
// trim useless info, keep only library name
std::string dep_path = lines[n].substr(1, lines[n].rfind(" (") - 1);
if (isRpath(dep_path))
{
collectRpathsForFilename(searchFilenameInRpaths(dep_path));
}
addDependency(dep_path);
}//next
}//next

View File

@ -30,5 +30,7 @@ THE SOFTWARE.
void collectDependencies(std::string filename);
void collectSubDependencies();
void doneWithDeps_go();
bool isRpath(const std::string& path);
std::string searchFilenameInRpaths(const std::string& rpath_dep);
#endif
#endif

View File

@ -177,3 +177,30 @@ int systemp(std::string& cmd)
std::cout << " " << cmd.c_str() << std::endl;
return system(cmd.c_str());
}
std::string getUserInputDirForFile(const std::string& filename)
{
while (true)
{
std::cout << "Please specify now the directory where this library can be found (or write 'quit' to abort): "; fflush(stdout);
std::string prefix;
std::cin >> prefix;
std::cout << std::endl;
if(prefix.compare("quit")==0) exit(1);
if( !prefix.empty() && prefix[ prefix.size()-1 ] != '/' ) prefix += "/";
if( !fileExists( prefix+filename ) )
{
std::cerr << (prefix+filename) << " does not exist. Try again" << std::endl;
continue;
}
else
{
std::cerr << (prefix+filename) << " was found. /!\\MANUALLY CHECK THE EXECUTABLE WITH 'otool -L', DYLIBBUNDLDER MAY NOT HANDLE CORRECTLY THIS UNSTANDARD/ILL-FORMED DEPENDENCY" << std::endl;
return prefix;
}
}
}

View File

@ -41,5 +41,6 @@ std::string system_get_output(std::string cmd);
// like 'system', runs a command on the system shell, but also prints the command to stdout.
int systemp(std::string& cmd);
std::string getUserInputDirForFile(const std::string& filename);
#endif
#endif