Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/auriamg/macdylibbundler.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorauriamg <auria.mg@gmail.com>2021-03-19 01:06:22 +0300
committerGitHub <noreply@github.com>2021-03-19 01:06:22 +0300
commitd89023bfe7947c405ae5e5d031a06b376671243b (patch)
treee2869357afef042eef876961982894a27d982b59
parentd40a434840a341a9645d25a3e34fd226421e32a7 (diff)
parent853b212107db319b289895e8a7017826982d1da9 (diff)
Merge pull request #60 from SCG82/resolve_loader_path
Resolve @loader_path dependencies. Refine recursive search algorithm.
-rw-r--r--src/Dependency.cpp72
-rw-r--r--src/Dependency.h6
-rw-r--r--src/DylibBundler.cpp149
-rw-r--r--src/DylibBundler.h3
-rw-r--r--src/Settings.cpp14
-rw-r--r--src/Settings.h14
-rw-r--r--src/Utils.cpp16
-rw-r--r--src/Utils.h8
8 files changed, 154 insertions, 128 deletions
diff --git a/src/Dependency.cpp b/src/Dependency.cpp
index 46edc32..f67d06d 100644
--- a/src/Dependency.cpp
+++ b/src/Dependency.cpp
@@ -49,24 +49,21 @@ std::string& rtrim(std::string &s) {
return s;
}
-//the paths to search for dylibs, store it globally to parse the environment variables only once
-std::vector<std::string> paths;
-
//initialize the dylib search paths
void initSearchPaths(){
//Check the same paths the system would search for dylibs
std::string searchPaths;
char *dyldLibPath = std::getenv("DYLD_LIBRARY_PATH");
- if( dyldLibPath!=0 )
+ if (dyldLibPath != nullptr)
searchPaths = dyldLibPath;
dyldLibPath = std::getenv("DYLD_FALLBACK_FRAMEWORK_PATH");
- if (dyldLibPath != 0)
+ if (dyldLibPath != nullptr)
{
if (!searchPaths.empty() && searchPaths[ searchPaths.size()-1 ] != ':') searchPaths += ":";
searchPaths += dyldLibPath;
}
dyldLibPath = std::getenv("DYLD_FALLBACK_LIBRARY_PATH");
- if (dyldLibPath!=0 )
+ if (dyldLibPath != nullptr)
{
if (!searchPaths.empty() && searchPaths[ searchPaths.size()-1 ] != ':') searchPaths += ":";
searchPaths += dyldLibPath;
@@ -78,7 +75,7 @@ void initSearchPaths(){
while(std::getline(ss, item, ':'))
{
if (item[ item.size()-1 ] != '/') item += "/";
- paths.push_back(item);
+ Settings::addSearchPath(item);
}
}
}
@@ -87,52 +84,56 @@ void initSearchPaths(){
// more stuff will then be necessary to do
bool missing_prefixes = false;
-Dependency::Dependency(std::string path)
+Dependency::Dependency(std::string path, const std::string& dependent_file)
{
char original_file_buffer[PATH_MAX];
std::string original_file;
+ rtrim(path);
if (isRpath(path))
{
- original_file = searchFilenameInRpaths(path);
+ original_file = searchFilenameInRpaths(path, dependent_file);
}
- else if (not realpath(rtrim(path).c_str(), original_file_buffer))
+ else if (realpath(rtrim(path).c_str(), original_file_buffer))
{
- std::cerr << "\n/!\\ WARNING : Cannot resolve path '" << path.c_str() << "'" << std::endl;
- original_file = path;
+ original_file = original_file_buffer;
}
else
{
- original_file = original_file_buffer;
+ std::cerr << "\n/!\\ WARNING : Cannot resolve path '" << path.c_str() << "'" << std::endl;
+ original_file = path;
}
// check if given path is a symlink
- if (original_file != rtrim(path))
- {
- filename = stripPrefix(original_file);
- prefix = original_file.substr(0, original_file.rfind("/")+1);
- addSymlink(path);
- }
- else
- {
- filename = stripPrefix(path);
- prefix = path.substr(0, path.rfind("/")+1);
- }
+ if (original_file != path) addSymlink(path);
+
+ filename = stripPrefix(original_file);
+ prefix = original_file.substr(0, original_file.rfind("/")+1);
- //check if the lib is in a known location
if( !prefix.empty() && prefix[ prefix.size()-1 ] != '/' ) prefix += "/";
+
+ // check if this dependency is in /usr/lib, /System/Library, or in ignored list
+ if (!Settings::isPrefixBundled(prefix)) return;
+
+ // check if the lib is in a known location
if( prefix.empty() || !fileExists( prefix+filename ) )
{
//the paths contains at least /usr/lib so if it is empty we have not initialized it
- if( paths.empty() ) initSearchPaths();
+ int searchPathAmount = Settings::searchPathAmount();
+ if( searchPathAmount == 0 )
+ {
+ initSearchPaths();
+ searchPathAmount = Settings::searchPathAmount();
+ }
//check if file is contained in one of the paths
- for( size_t i=0; i<paths.size(); ++i)
+ for( int i=0; i<searchPathAmount; ++i)
{
- if (fileExists( paths[i]+filename ))
+ std::string search_path = Settings::searchPath(i);
+ if (fileExists( search_path+filename ))
{
- std::cout << "FOUND " << filename << " in " << paths[i] << std::endl;
- prefix = paths[i];
+ std::cout << "FOUND " << filename << " in " << search_path << std::endl;
+ prefix = search_path;
missing_prefixes = true; //the prefix was missing
break;
}
@@ -145,11 +146,10 @@ Dependency::Dependency(std::string path)
{
std::cerr << "\n/!\\ WARNING : Library " << filename << " has an incomplete name (location unknown)" << std::endl;
missing_prefixes = true;
-
- paths.push_back(getUserInputDirForFile(filename));
+
+ Settings::addSearchPath(getUserInputDirForFile(filename));
}
-
- //new_name = filename.substr(0, filename.find(".")) + ".dylib";
+
new_name = filename;
}
@@ -173,7 +173,7 @@ std::string Dependency::getInnerPath()
}
-void Dependency::addSymlink(std::string s)
+void Dependency::addSymlink(const std::string& s)
{
// calling std::find on this vector is not near as slow as an extra invocation of install_name_tool
if(std::find(symlinks.begin(), symlinks.end(), s) == symlinks.end()) symlinks.push_back(s);
@@ -207,7 +207,7 @@ void Dependency::copyYourself()
}
}
-void Dependency::fixFileThatDependsOnMe(std::string file_to_fix)
+void Dependency::fixFileThatDependsOnMe(const std::string& file_to_fix)
{
// for main lib file
changeInstallName(file_to_fix, getOriginalPath(), getInnerPath());
diff --git a/src/Dependency.h b/src/Dependency.h
index c3c4e0c..e883494 100644
--- a/src/Dependency.h
+++ b/src/Dependency.h
@@ -39,7 +39,7 @@ class Dependency
// installation
std::string new_name;
public:
- Dependency(std::string path);
+ Dependency(std::string path, const std::string& dependent_file);
void print();
@@ -48,14 +48,14 @@ public:
std::string getInstallPath();
std::string getInnerPath();
- void addSymlink(std::string s);
+ void addSymlink(const std::string& s);
int getSymlinkAmount() const{ return symlinks.size(); }
std::string getSymlink(const int i) const{ return symlinks[i]; }
std::string getPrefix() const{ return prefix; }
void copyYourself();
- void fixFileThatDependsOnMe(std::string file);
+ void fixFileThatDependsOnMe(const std::string& file);
// Compares the given dependency with this one. If both refer to the same file,
// it returns true and merges both entries into one.
diff --git a/src/DylibBundler.cpp b/src/DylibBundler.cpp
index 72fa5a3..cda5a81 100644
--- a/src/DylibBundler.cpp
+++ b/src/DylibBundler.cpp
@@ -28,6 +28,7 @@ THE SOFTWARE.
#include <cstdlib>
#include <set>
#include <map>
+#include <regex>
#include <sys/param.h>
#ifdef __linux
#include <linux/limits.h>
@@ -40,8 +41,8 @@ THE SOFTWARE.
std::vector<Dependency> deps;
std::map<std::string, std::vector<Dependency> > deps_per_file;
std::map<std::string, bool> deps_collected;
-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 changeLibPathsOnFile(std::string file_to_fix)
{
@@ -96,7 +97,6 @@ void collectRpaths(const std::string& filename)
}
start_pos += 5;
std::string rpath = line.substr(start_pos, end_pos - start_pos);
- rpaths.insert(rpath);
rpaths_per_file[filename].push_back(rpath);
read_rpath = false;
continue;
@@ -110,42 +110,87 @@ void collectRpaths(const std::string& filename)
}
}
-void collectRpathsForFilename(const std::string& filename)
-{
- if (rpaths_per_file.find(filename) == rpaths_per_file.end())
- {
- collectRpaths(filename);
- }
-}
-
-std::string searchFilenameInRpaths(const std::string& rpath_file)
+std::string searchFilenameInRpaths(const std::string& rpath_file, const std::string& dependent_file)
{
char buffer[PATH_MAX];
std::string fullpath;
- std::string suffix = rpath_file.substr(rpath_file.rfind("/")+1);
+ std::string suffix = rpath_file.substr(rpath_file.rfind('/')+1);
+
+ const auto check_path = [&](std::string path)
+ {
+ char buffer[PATH_MAX];
+ std::string file_prefix = dependent_file.substr(0, dependent_file.rfind('/')+1);
+ if (dependent_file != rpath_file)
+ {
+ std::string path_to_check;
+ if (path.find("@loader_path") != std::string::npos)
+ {
+ path_to_check = std::regex_replace(path, std::regex("@loader_path/"), file_prefix);
+ }
+ else if (path.find("@rpath") != std::string::npos)
+ {
+ path_to_check = std::regex_replace(path, std::regex("@rpath/"), file_prefix);
+ }
+ if (realpath(path_to_check.c_str(), buffer))
+ {
+ fullpath = buffer;
+ rpath_to_fullpath[rpath_file] = fullpath;
+ return true;
+ }
+ }
+ return false;
+ };
- for (std::set<std::string>::iterator it = rpaths.begin(); it != rpaths.end(); ++it)
+ // fullpath previously stored
+ if (rpath_to_fullpath.find(rpath_file) != rpath_to_fullpath.end())
+ {
+ fullpath = rpath_to_fullpath[rpath_file];
+ }
+ else if (!check_path(rpath_file))
{
- std::string path = *it + "/" + suffix;
- if (realpath(path.c_str(), buffer))
+ for (auto rpath : rpaths_per_file[dependent_file])
{
- fullpath = buffer;
- break;
+ if (rpath[rpath.size()-1] != '/') rpath += "/";
+ if (check_path(rpath+suffix)) break;
+ }
+ if (rpath_to_fullpath.find(rpath_file) != rpath_to_fullpath.end())
+ {
+ fullpath = rpath_to_fullpath[rpath_file];
}
}
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;
+ const int searchPathAmount = Settings::searchPathAmount();
+ for (int n=0; n<searchPathAmount; n++)
+ {
+ std::string search_path = Settings::searchPath(n);
+ if (fileExists(search_path+suffix))
+ {
+ fullpath = search_path + suffix;
+ 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;
}
+std::string searchFilenameInRpaths(const std::string& rpath_dep)
+{
+ return searchFilenameInRpaths(rpath_dep, rpath_dep);
+}
+
void fixRpathsOnFile(const std::string& original_file, const std::string& file_to_fix)
{
std::vector<std::string> rpaths_to_fix;
@@ -167,9 +212,9 @@ void fixRpathsOnFile(const std::string& original_file, const std::string& file_t
}
}
-void addDependency(std::string path, std::string filename)
+void addDependency(const std::string& path, const std::string& filename)
{
- Dependency dep(path);
+ Dependency dep(path, filename);
// we need to check if this library was already added to avoid duplicates
bool in_deps = false;
@@ -197,7 +242,7 @@ void addDependency(std::string path, std::string filename)
/*
* Fill vector 'lines' with dependencies of given 'filename'
*/
-void collectDependencies(std::string filename, std::vector<std::string>& lines)
+void collectDependencies(const std::string& filename, std::vector<std::string>& lines)
{
// execute "otool -l" on the given file and collect the command's output
std::string cmd = "otool -l \"" + filename + "\"";
@@ -237,30 +282,30 @@ void collectDependencies(std::string filename, std::vector<std::string>& lines)
}
-void collectDependencies(std::string filename)
+void collectDependencies(const std::string& filename)
{
+ if (deps_collected.find(filename) != deps_collected.end()) return;
+
+ collectRpaths(filename);
+
std::vector<std::string> lines;
collectDependencies(filename, lines);
std::cout << "."; fflush(stdout);
-
- const int line_amount = lines.size();
- for(int n=0; n<line_amount; n++)
+
+ for (const auto& line : lines)
{
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
+ if (line[0] != '\t') continue; // only lines beginning with a tab interest us
+ if (line.find(".framework") != std::string::npos) continue; //Ignore frameworks, we can not handle them
// trim useless info, keep only library name
- std::string dep_path = lines[n].substr(1, lines[n].rfind(" (") - 1);
+ std::string dep_path = line.substr(1, line.rfind(" (") - 1);
if (Settings::isSystemLibrary(dep_path)) continue;
- if (isRpath(dep_path))
- {
- collectRpathsForFilename(filename);
- }
addDependency(dep_path, filename);
}
+
deps_collected[filename] = true;
}
@@ -273,35 +318,14 @@ void collectSubDependencies()
while(true)
{
dep_amount = deps.size();
- for(int n=0; n<dep_amount; n++)
+ for (const auto& dep : deps)
{
std::cout << "."; fflush(stdout);
- std::vector<std::string> 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++)
- {
- 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 cannot handle them
-
- // trim useless info, keep only library name
- std::string dep_path = lines[n].substr(1, lines[n].rfind(" (") - 1);
- if (Settings::isSystemLibrary(dep_path)) continue;
- if (isRpath(dep_path))
- {
- collectRpathsForFilename(searchFilenameInRpaths(dep_path));
- }
-
- addDependency(dep_path, original_path);
- }//next
- }//next
+ std::string original_path = dep.getOriginalPath();
+ if (isRpath(original_path)) original_path = searchFilenameInRpaths(original_path);
+
+ collectDependencies(original_path);
+ }
if(deps.size() == dep_amount) break; // no more dependencies were added on this iteration, stop searching
}
@@ -376,6 +400,7 @@ void doneWithDeps_go()
const int fileToFixAmount = Settings::fileToFixAmount();
for(int n=0; n<fileToFixAmount; n++)
{
+ copyFile(Settings::fileToFix(n), Settings::fileToFix(n)); // to set write permission
changeLibPathsOnFile(Settings::fileToFix(n));
fixRpathsOnFile(Settings::fileToFix(n), Settings::fileToFix(n));
}
diff --git a/src/DylibBundler.h b/src/DylibBundler.h
index edf557b..5de3534 100644
--- a/src/DylibBundler.h
+++ b/src/DylibBundler.h
@@ -27,10 +27,11 @@ THE SOFTWARE.
#include <string>
-void collectDependencies(std::string filename);
+void collectDependencies(const std::string& filename);
void collectSubDependencies();
void doneWithDeps_go();
bool isRpath(const std::string& path);
+std::string searchFilenameInRpaths(const std::string& rpath_file, const std::string& dependent_file);
std::string searchFilenameInRpaths(const std::string& rpath_dep);
#endif
diff --git a/src/Settings.cpp b/src/Settings.cpp
index 50f5221..0ace811 100644
--- a/src/Settings.cpp
+++ b/src/Settings.cpp
@@ -48,7 +48,7 @@ void bundleLibs(bool on){ bundleLibs_bool = on; }
std::string dest_folder_str = "./libs/";
std::string destFolder(){ return dest_folder_str; }
-void destFolder(std::string path)
+void destFolder(const std::string& path)
{
dest_folder_str = path;
// fix path if needed so it ends with '/'
@@ -56,13 +56,13 @@ void destFolder(std::string path)
}
std::vector<std::string> files;
-void addFileToFix(std::string path){ files.push_back(path); }
+void addFileToFix(const std::string& path){ files.push_back(path); }
int fileToFixAmount(){ return files.size(); }
std::string fileToFix(const int n){ return files[n]; }
std::string inside_path_str = "@executable_path/../libs/";
std::string inside_lib_path(){ return inside_path_str; }
-void inside_lib_path(std::string p)
+void inside_lib_path(const std::string& p)
{
inside_path_str = p;
// fix path if needed so it ends with '/'
@@ -76,7 +76,7 @@ void ignore_prefix(std::string prefix)
prefixes_to_ignore.push_back(prefix);
}
-bool isSystemLibrary(std::string prefix)
+bool isSystemLibrary(const std::string& prefix)
{
if(prefix.find("/usr/lib/") == 0) return true;
if(prefix.find("/System/Library/") == 0) return true;
@@ -84,7 +84,7 @@ bool isSystemLibrary(std::string prefix)
return false;
}
-bool isPrefixIgnored(std::string prefix)
+bool isPrefixIgnored(const std::string& prefix)
{
const int prefix_amount = prefixes_to_ignore.size();
for(int n=0; n<prefix_amount; n++)
@@ -95,7 +95,7 @@ bool isPrefixIgnored(std::string prefix)
return false;
}
-bool isPrefixBundled(std::string prefix)
+bool isPrefixBundled(const std::string& prefix)
{
if(prefix.find(".framework") != std::string::npos) return false;
if(prefix.find("@executable_path") != std::string::npos) return false;
@@ -106,7 +106,7 @@ bool isPrefixBundled(std::string prefix)
}
std::vector<std::string> searchPaths;
-void addSearchPath(std::string path){ searchPaths.push_back(path); }
+void addSearchPath(const std::string& path){ searchPaths.push_back(path); }
int searchPathAmount(){ return searchPaths.size(); }
std::string searchPath(const int n){ return searchPaths[n]; }
diff --git a/src/Settings.h b/src/Settings.h
index 512a8f6..1b1cb27 100644
--- a/src/Settings.h
+++ b/src/Settings.h
@@ -30,9 +30,9 @@ THE SOFTWARE.
namespace Settings
{
-bool isSystemLibrary(std::string prefix);
-bool isPrefixBundled(std::string prefix);
-bool isPrefixIgnored(std::string prefix);
+bool isSystemLibrary(const std::string& prefix);
+bool isPrefixBundled(const std::string& prefix);
+bool isPrefixIgnored(const std::string& prefix);
void ignore_prefix(std::string prefix);
bool canOverwriteFiles();
@@ -48,16 +48,16 @@ bool bundleLibs();
void bundleLibs(bool on);
std::string destFolder();
-void destFolder(std::string path);
+void destFolder(const std::string& path);
-void addFileToFix(std::string path);
+void addFileToFix(const std::string& path);
int fileToFixAmount();
std::string fileToFix(const int n);
std::string inside_lib_path();
-void inside_lib_path(std::string p);
+void inside_lib_path(const std::string& p);
-void addSearchPath(std::string path);
+void addSearchPath(const std::string& path);
int searchPathAmount();
std::string searchPath(const int n);
diff --git a/src/Utils.cpp b/src/Utils.cpp
index 8651c5f..9903f20 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -69,7 +69,7 @@ void tokenize(const string& str, const char* delim, vector<string>* vectorarg)
-bool fileExists( std::string filename )
+bool fileExists(const std::string& filename)
{
if (access( filename.c_str(), F_OK ) != -1)
{
@@ -93,10 +93,10 @@ bool fileExists( std::string filename )
}
}
-void copyFile(string from, string to)
+void copyFile(const string& from, const string& to)
{
bool override = Settings::canOverwriteFiles();
- if(!override)
+ if( from != to && !override )
{
if(fileExists( to ))
{
@@ -124,7 +124,7 @@ void copyFile(string from, string to)
}
}
-std::string system_get_output(std::string cmd)
+std::string system_get_output(const std::string& cmd)
{
FILE * command_output;
char output[128];
@@ -161,7 +161,7 @@ std::string system_get_output(std::string cmd)
return full_output;
}
-int systemp(std::string& cmd)
+int systemp(const std::string& cmd)
{
std::cout << " " << cmd.c_str() << std::endl;
return system(cmd.c_str());
@@ -185,9 +185,8 @@ std::string getUserInputDirForFile(const std::string& filename)
auto searchPath = Settings::searchPath(n);
if( !searchPath.empty() && searchPath[ searchPath.size()-1 ] != '/' ) searchPath += "/";
- if( !fileExists( searchPath+filename ) ) {
- continue;
- } else {
+ if( fileExists( searchPath+filename ) )
+ {
std::cerr << (searchPath+filename) << " was found. /!\\ DYLIBBUNDLER MAY NOT CORRECTLY HANDLE THIS DEPENDENCY: Manually check the executable with 'otool -L'" << std::endl;
return searchPath;
}
@@ -213,6 +212,7 @@ std::string getUserInputDirForFile(const std::string& filename)
else
{
std::cerr << (prefix+filename) << " was found. /!\\ DYLIBBUNDLER MAY NOT CORRECTLY HANDLE THIS DEPENDENCY: Manually check the executable with 'otool -L'" << std::endl;
+ Settings::addSearchPath(prefix);
return prefix;
}
}
diff --git a/src/Utils.h b/src/Utils.h
index dc76431..fa1016f 100644
--- a/src/Utils.h
+++ b/src/Utils.h
@@ -32,15 +32,15 @@ THE SOFTWARE.
class Library;
void tokenize(const std::string& str, const char* delimiters, std::vector<std::string>*);
-bool fileExists( std::string filename );
+bool fileExists(const std::string& filename);
-void copyFile(std::string from, std::string to);
+void copyFile(const std::string& from, const std::string& to);
// executes a command in the native shell and returns output in string
-std::string system_get_output(std::string cmd);
+std::string system_get_output(const std::string& cmd);
// like 'system', runs a command on the system shell, but also prints the command to stdout.
-int systemp(std::string& cmd);
+int systemp(const std::string& cmd);
void changeInstallName(const std::string& binary_file, const std::string& old_name, const std::string& new_name);
std::string getUserInputDirForFile(const std::string& filename);