use rpaths to locate dependencies

This commit is contained in:
SCG82 2019-12-29 09:07:35 -08:00
parent fcbedd3431
commit 9ae91a71ce
4 changed files with 101 additions and 46 deletions

View File

@ -64,11 +64,22 @@ Dependency::Dependency(std::string path, std::string dependent_file) : is_framew
std::string original_file;
std::string warning_msg;
rtrim_in_place(path);
if (Settings::verboseOutput()) {
std::cout<< "** Dependency ctor **" << std::endl;
if (path != dependent_file)
std::cout << " dependent file: " << dependent_file << std::endl;
std::cout << " dependency path: " << path << std::endl;
}
if (isRpath(path)) {
original_file = searchFilenameInRpaths(path, dependent_file);
}
else if (realpath(rtrim(path).c_str(), original_file_buffer)) {
else if (realpath(path.c_str(), original_file_buffer)) {
original_file = original_file_buffer;
if (Settings::verboseOutput())
std::cout << " original_file: " << original_file << std::endl;
}
else {
warning_msg = "\n/!\\ WARNING: Cannot resolve path '" + path + "'\n";
@ -76,21 +87,17 @@ Dependency::Dependency(std::string path, std::string dependent_file) : is_framew
}
// check if given path is a symlink
if (original_file != rtrim(path)) {
filename = stripPrefix(original_file);
prefix = filePrefix(original_file);
if (original_file != path)
addSymlink(path);
}
else {
filename = stripPrefix(path);
prefix = filePrefix(path);
}
prefix = filePrefix(original_file);
filename = stripPrefix(original_file);
// check if this dependency is in /usr/lib, /System/Library, or in ignored list
if (!Settings::isPrefixBundled(prefix))
return;
if (getOriginalPath().find(".framework") != std::string::npos) {
if (original_file.find(".framework") != std::string::npos) {
is_framework = true;
std::string framework_root = getFrameworkRoot(original_file);
std::string framework_path = getFrameworkPath(original_file);
@ -130,11 +137,9 @@ Dependency::Dependency(std::string path, std::string dependent_file) : is_framew
// if the location is still unknown, ask the user for search path
if (!Settings::isPrefixIgnored(prefix) && (prefix.empty() || !fileExists(prefix+filename))) {
if (!Settings::quietOutput())
std::cerr << "\n/!\\ WARNING: Library " << filename << " has an incomplete name (location unknown)\n";
if (Settings::verboseOutput()) {
std::cout << "path: " << (prefix+filename) << std::endl;
std::cout << "prefix: " << prefix << std::endl;
}
std::cerr << "\n/!\\ WARNING: Dependency " << filename << " of " << dependent_file << " not found\n";
if (Settings::verboseOutput())
std::cout << " path: " << (prefix+filename) << std::endl;
missing_prefixes = true;
paths.push_back(getUserInputDirForFile(filename));
}

View File

@ -22,8 +22,8 @@ public:
std::string getSymlink(int i) const { return symlinks[i]; }
std::string getPrefix() const { return prefix; }
// Compares the given dependency with this one. If both refer to the same file,
// it returns true and merges both entries into one.
// Compare the given dependency with this one. If both refer to the same file,
// merge both entries into one and return true.
bool mergeIfSameAs(Dependency& dep2);
void print();
@ -33,10 +33,12 @@ public:
private:
bool is_framework;
// origin
std::string filename;
std::string prefix;
std::vector<std::string> symlinks;
// installation
std::string new_name;
};

View File

@ -22,6 +22,7 @@ std::map<std::string, bool> deps_collected;
std::set<std::string> frameworks;
std::set<std::string> rpaths;
std::map<std::string, std::vector<std::string>> rpaths_per_file;
std::map<std::string, std::string> rpath_to_fullpath;
void initRpaths()
{
@ -57,6 +58,7 @@ void collectRpaths(const std::string& filename)
std::vector<std::string> lc_lines;
tokenize(output, "\n", &lc_lines);
bool rpath_found = false;
if (Settings::verboseOutput())
std::cout << "collecting rpaths for: " << filename << std::endl;
@ -100,28 +102,28 @@ void collectRpathsForFilename(const std::string& filename)
std::string searchFilenameInRpaths(const std::string& rpath_file, const std::string& dependent_file)
{
char buffer[PATH_MAX];
std::string fullpath;
std::string file_prefix = filePrefix(dependent_file);
std::string suffix = rpath_file.substr(rpath_file.rfind("/")+1);
char fullpath_buffer[PATH_MAX];
for (std::set<std::string>::iterator it = rpaths.begin(); it != rpaths.end(); ++it) {
std::string rpath = *it;
if (rpath[rpath.size()-1] != '/')
rpath += "/";
std::string path = rpath + suffix;
if (dependent_file != rpath_file)
std::cout << " dependent file: " << dependent_file << std::endl;
std::cout << " dependency: " << rpath_file << std::endl;
std::cout << " rpath: " << path << std::endl;
std::cout << " dependency: " << rpath_file << std::endl;
auto check_path = [&](std::string path) {
char buffer[PATH_MAX];
std::string file_prefix = filePrefix(dependent_file);
if (path.find("@executable_path") != std::string::npos || path.find("@loader_path") != std::string::npos) {
if (path.find("@executable_path") != std::string::npos)
path = std::regex_replace(path, std::regex("@executable_path/"), Settings::executableFolder());
else if (path.find("@loader_path") != std::string::npos)
path = std::regex_replace(path, std::regex("@loader_path/"), file_prefix);
if (dependent_file != rpath_file)
if (path.find("@loader_path") != std::string::npos)
path = std::regex_replace(path, std::regex("@loader_path/"), file_prefix);
std::cout << " path to search: " << path << std::endl;
if (realpath(path.c_str(), buffer)) {
fullpath = buffer;
break;
rpath_to_fullpath[rpath_file] = fullpath;
return true;
}
}
else if (path.find("@rpath") != std::string::npos) {
@ -130,12 +132,35 @@ std::string searchFilenameInRpaths(const std::string& rpath_file, const std::str
std::cout << " path to search: " << pathE << std::endl;
if (realpath(pathE.c_str(), buffer)) {
fullpath = buffer;
break;
rpath_to_fullpath[rpath_file] = fullpath;
return true;
}
std::cout << " path to search: " << pathL << std::endl;
if (realpath(pathL.c_str(), buffer)) {
fullpath = buffer;
break;
if (dependent_file != rpath_file) {
std::cout << " path to search: " << pathL << std::endl;
if (realpath(pathL.c_str(), buffer)) {
fullpath = buffer;
rpath_to_fullpath[rpath_file] = fullpath;
return true;
}
}
}
return false;
};
if (rpath_to_fullpath.find(rpath_file) != rpath_to_fullpath.end()) {
fullpath = rpath_to_fullpath[rpath_file];
}
else {
if (!check_path(rpath_file)) {
for (auto it = rpaths_per_file[dependent_file].begin(); it != rpaths_per_file[dependent_file].end(); ++it) {
std::string rpath = *it;
if (rpath[rpath.size()-1] != '/')
rpath += "/";
std::string path = rpath + suffix;
std::cout << " trying rpath: " << path << std::endl;
if (check_path(path)) {
break;
}
}
}
}
@ -143,7 +168,10 @@ std::string searchFilenameInRpaths(const std::string& rpath_file, const std::str
if (Settings::verboseOutput()) {
// std::cout << "rpath file: " << rpath_file << std::endl;
// std::cout << "suffix: " << suffix << std::endl;
std::cout << "rpath fullpath: " << fullpath << std::endl;
if (!fullpath.empty())
std::cout << " ** rpath fullpath: " << fullpath << std::endl;
else
std::cout << " ** rpath fullpath: not found" << std::endl;
}
if (fullpath.empty()) {
@ -152,8 +180,8 @@ std::string searchFilenameInRpaths(const std::string& rpath_file, const std::str
fullpath = getUserInputDirForFile(suffix) + suffix;
if (Settings::quietOutput() && fullpath.empty())
std::cerr << "\n/!\\ WARNING: Can't get path for '" << rpath_file << "'\n";
if (realpath(fullpath.c_str(), buffer))
fullpath = buffer;
if (realpath(fullpath.c_str(), fullpath_buffer))
fullpath = fullpath_buffer;
}
return fullpath;
@ -217,7 +245,7 @@ void addDependency(std::string path, std::string dependent_file)
// Fill |lines| with dependencies of given |filename|
void collectDependencies(std::string dependent_file, std::vector<std::string>& lines)
{
std::string cmd = "otool -L " + dependent_file;
std::string cmd = "otool -l " + dependent_file;
std::string output = systemOutput(cmd);
if (output.find("can't open file") != std::string::npos
@ -226,8 +254,27 @@ void collectDependencies(std::string dependent_file, std::vector<std::string>& l
std::cerr << "\n\n/!\\ ERROR: Cannot find file " << dependent_file << " to read its dependencies\n";
exit(1);
}
// split output
tokenize(output, "\n", &lines);
std::vector<std::string> raw_lines;
tokenize(output, "\n", &raw_lines);
bool searching = false;
for (const auto& line : raw_lines) {
if (line.find("cmd LC_LOAD_DYLIB") != std::string::npos) {
if (searching) {
std::cerr << "Failed to find name before next cmd" << std::endl;
exit(1);
}
searching = true;
}
else if (searching) {
size_t found = line.find("name ");
if (found != std::string::npos) {
lines.push_back('\t' + line.substr(found+5, std::string::npos));
searching = false;
}
}
}
}
void collectDependencies(std::string dependent_file)
@ -264,7 +311,7 @@ void collectSubDependencies()
for (size_t n=0; n<deps_size; n++) {
std::string original_path = deps[n].getOriginalPath();
if (Settings::verboseOutput())
std::cout << "original path: " << original_path << std::endl;
std::cout << "(collect sub deps) original path: " << original_path << std::endl;
if (isRpath(original_path))
original_path = searchFilenameInRpaths(original_path);
@ -284,11 +331,12 @@ void collectSubDependencies()
std::string dep_path = lines[n].substr(1, lines[n].rfind(" (") - 1);
std::string full_path = dep_path;
if (isRpath(dep_path)) {
full_path = searchFilenameInRpaths(dep_path);
full_path = searchFilenameInRpaths(dep_path, original_path);
collectRpathsForFilename(full_path);
}
addDependency(dep_path, full_path);
// addDependency(dep_path, full_path);
addDependency(dep_path, original_path);
}
}
// if no more dependencies were added on this iteration, stop searching
@ -408,7 +456,7 @@ void copyQtPlugins()
std::cout << "(post qt) # OF DEPS: " << deps.size() << std::endl;
// TODO: evaluate deps of Qt plugins to see if this can be skipped
collectSubDependencies();
// collectSubDependencies();
std::cout << "(post qt, post sub) # OF FILES: " << Settings::filesToFixCount() << std::endl;
std::cout << "(post qt, post sub) # OF DEPS: " << deps.size() << std::endl;

View File

@ -264,8 +264,8 @@ std::string getUserInputDirForFile(const std::string& filename)
while (true) {
if (Settings::quietOutput())
std::cerr << "\n/!\\ WARNING: Library " << filename << " has an incomplete name (location unknown)\n";
std::cout << "\nPlease specify the directory where this library is located (or enter 'quit' to abort): ";
std::cerr << "\n/!\\ WARNING: Dependency " << filename << " has an incomplete name (location unknown)\n";
std::cout << "\nPlease specify the directory where this file is located (or enter 'quit' to abort): ";
fflush(stdout);
std::string prefix;