code cleanup

This commit is contained in:
SCG82 2019-12-29 10:54:38 -08:00
parent a5d434d8ae
commit 47253001ec
6 changed files with 118 additions and 94 deletions

View File

@ -33,9 +33,14 @@ Here is a list of flags you can pass to dylibbundler:
Displays a summary of options
</blockquote>
`-a`, `--app` (path to app bundle)
<blockquote>
Application bundle to make self-contained. Fixes the main executable of the app bundle. Add additional binary files to fix up with the `-x` flag.
</blockquote>
`-x`, `--fix-file` (executable or plug-in filepath)
<blockquote>
Fixes given executable or plug-in file (a .dylib can work too. anything on which `otool -L` works is accepted by `-x`). dylibbundler will walk through the dependencies of the specified file to build a dependency list. It will also fix the said files' dependencies so that it expects to find the libraries relative to itself (e.g. in the app bundle) instead of at an absolute path (e.g. /usr/local/lib). To pass multiple files to fix, simply specify multiple `-x` flags.
Fixes given executable or plug-in file (ex: .dylib, .so) anything on which `otool -L` works is accepted by `-x`. dylibbundler will walk through the dependencies of the specified file to build a dependency list. It will also fix the said files' dependencies so that it expects to find the libraries relative to itself (e.g. in the app bundle) instead of at an absolute path (e.g. /usr/local/lib). To pass multiple files to fix, simply specify multiple `-x` flags.
</blockquote>
`-b`, `--bundle-deps`
@ -47,7 +52,7 @@ fixes dependencies where bundled libraries depend on each other. If this option
`-f`, `--bundle-frameworks`
<blockquote>
Copies frameworks to a local directory, fixes their internal name so that they are aware of their new location,
fixes dependencies where bundled libraries depend on each other. If this option is not passed, no frameworks will be prepared for distribution.
fixes dependencies where bundled libraries depend on each other. If this option is not passed, dependencies contained in frameworks will be ignored. dylibbundler will also copy any needed Qt plugins and create qt.conf in the `Resources` directory (no need to run macdeployqt).
</blockquote>
`-i`, `--ignore` (path)

View File

@ -177,10 +177,11 @@ bool Dependency::mergeIfSameAs(Dependency& dep2)
void Dependency::print()
{
std::cout << "\n * " << filename << " from " << prefix << "\n";
std::cout << "\n* " << filename << " from " << prefix << "\n";
for (size_t n=0; n<symlinks.size(); ++n)
std::cout << " symlink --> " << symlinks[n] << "\n";;
for (size_t n=0; n<symlinks.size(); ++n) {
std::cout << " symlink --> " << symlinks[n] << "\n";
}
}
void Dependency::copyYourself()
@ -217,6 +218,8 @@ void Dependency::copyYourself()
deleteFile(headers_path, true);
deleteFile(headers_realpath, true);
deleteFile(dest_path + "/*.prl");
}
// fix the lib's inner name
@ -228,15 +231,17 @@ void Dependency::fixFileThatDependsOnMe(std::string file_to_fix)
// for main lib file
changeInstallName(file_to_fix, getOriginalPath(), getInnerPath());
// for symlinks
for (size_t n=0; n<symlinks.size(); ++n)
for (size_t n=0; n<symlinks.size(); ++n) {
changeInstallName(file_to_fix, symlinks[n], getInnerPath());
}
// FIXME - hackish
// TODO: revise
if (missing_prefixes) {
// for main lib file
changeInstallName(file_to_fix, filename, getInnerPath());
// for symlinks
for (size_t n=0; n<symlinks.size(); ++n)
for (size_t n=0; n<symlinks.size(); ++n) {
changeInstallName(file_to_fix, symlinks[n], getInnerPath());
}
}
}

View File

@ -52,23 +52,21 @@ void collectRpaths(const std::string& filename)
std::cerr << "\n/!\\ WARNING: Can't collect rpaths for nonexistent file '" << filename << "'\n";
return;
}
std::string cmd = "otool -l " + filename;
std::string output = systemOutput(cmd);
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;
size_t pos = 0;
bool read_rpath = false;
std::string cmd = "otool -l " + filename;
std::string output = systemOutput(cmd);
std::vector<std::string> lc_lines;
tokenize(output, "\n", &lc_lines);
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(" (");
@ -78,15 +76,13 @@ void collectRpaths(const std::string& filename)
}
start_pos += 5; // to exclude "path "
std::string rpath = line.substr(start_pos, end_pos - start_pos);
if (Settings::verboseOutput()) {
std::cout << " rpath: " << rpath << std::endl;
}
rpaths.insert(rpath);
rpaths_per_file[filename].push_back(rpath);
read_rpath = false;
if (Settings::verboseOutput())
std::cout << " rpath: " << rpath << std::endl;
continue;
}
if (line.find("LC_RPATH") != std::string::npos) {
read_rpath = true;
pos++;
@ -102,24 +98,28 @@ void collectRpathsForFilename(const std::string& filename)
std::string searchFilenameInRpaths(const std::string& rpath_file, const std::string& dependent_file)
{
if (Settings::verboseOutput()) {
if (dependent_file != rpath_file)
std::cout << " dependent file: " << dependent_file << std::endl;
std::cout << " dependency: " << rpath_file << std::endl;
}
std::string fullpath;
std::string suffix = rpath_file.substr(rpath_file.rfind("/")+1);
char fullpath_buffer[PATH_MAX];
if (dependent_file != rpath_file)
std::cout << " dependent file: " << dependent_file << 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());
if (dependent_file != rpath_file)
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 (Settings::verboseOutput())
std::cout << " path to search: " << path << std::endl;
if (realpath(path.c_str(), buffer)) {
fullpath = buffer;
rpath_to_fullpath[rpath_file] = fullpath;
@ -129,14 +129,16 @@ std::string searchFilenameInRpaths(const std::string& rpath_file, const std::str
else if (path.find("@rpath") != std::string::npos) {
std::string pathE = std::regex_replace(path, std::regex("@rpath/"), Settings::executableFolder());
std::string pathL = std::regex_replace(path, std::regex("@rpath/"), file_prefix);
std::cout << " path to search: " << pathE << std::endl;
if (Settings::verboseOutput())
std::cout << " path to search: " << pathE << std::endl;
if (realpath(pathE.c_str(), buffer)) {
fullpath = buffer;
rpath_to_fullpath[rpath_file] = fullpath;
return true;
}
if (dependent_file != rpath_file) {
std::cout << " path to search: " << pathL << std::endl;
if (Settings::verboseOutput())
std::cout << " path to search: " << pathL << std::endl;
if (realpath(pathL.c_str(), buffer)) {
fullpath = buffer;
rpath_to_fullpath[rpath_file] = fullpath;
@ -147,6 +149,7 @@ std::string searchFilenameInRpaths(const std::string& rpath_file, const std::str
return false;
};
// fullpath previously stored
if (rpath_to_fullpath.find(rpath_file) != rpath_to_fullpath.end()) {
fullpath = rpath_to_fullpath[rpath_file];
}
@ -157,21 +160,21 @@ std::string searchFilenameInRpaths(const std::string& rpath_file, const std::str
if (rpath[rpath.size()-1] != '/')
rpath += "/";
std::string path = rpath + suffix;
std::cout << " trying rpath: " << path << std::endl;
if (check_path(path)) {
if (Settings::verboseOutput())
std::cout << " trying rpath: " << path << std::endl;
if (check_path(path))
break;
}
}
}
}
if (Settings::verboseOutput()) {
// std::cout << "rpath file: " << rpath_file << std::endl;
// std::cout << "suffix: " << suffix << std::endl;
if (!fullpath.empty())
if (!fullpath.empty()) {
std::cout << " ** rpath fullpath: " << fullpath << std::endl;
else
}
else {
std::cout << " ** rpath fullpath: not found" << std::endl;
}
}
if (fullpath.empty()) {
@ -218,9 +221,10 @@ void addDependency(std::string path, std::string dependent_file)
// check if this library was already added to |deps| to avoid duplicates
bool in_deps = false;
for (size_t n=0; n<deps.size(); ++n)
for (size_t n=0; n<deps.size(); ++n) {
if (dep.mergeIfSameAs(deps[n]))
in_deps = true;
}
// check if this library was already added to |deps_per_file[dependent_file]| to avoid duplicates
bool in_deps_per_file = false;
@ -262,7 +266,7 @@ void collectDependencies(std::string dependent_file, std::vector<std::string>& l
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;
std::cerr << "\n\n/!\\ ERROR: Failed to find name before next cmd" << std::endl;
exit(1);
}
searching = true;
@ -283,9 +287,10 @@ void collectDependencies(std::string dependent_file)
collectDependencies(dependent_file, lines);
for (size_t n=0; n<lines.size(); n++) {
if (!Settings::bundleFrameworks())
if (!Settings::bundleFrameworks()) {
if (lines[n].find(".framework") != std::string::npos)
continue;
}
// lines containing path begin with a tab
if (lines[n][0] != '\t')
continue;
@ -299,12 +304,15 @@ void collectDependencies(std::string dependent_file)
deps_collected[dependent_file] = true;
}
// recursively collect each dependency's dependencies
void collectSubDependencies()
{
if (Settings::verboseOutput()) {
std::cout << "(pre sub) # OF FILES: " << Settings::filesToFixCount() << std::endl;
std::cout << "(pre sub) # OF DEPS: " << deps.size() << std::endl;
}
size_t deps_size = deps.size();
std::cout << "(pre sub) # OF FILES: " << Settings::filesToFixCount() << std::endl;
std::cout << "(pre sub) # OF DEPS: " << deps.size() << std::endl;
// recursively collect each dependency's dependencies
while (true) {
deps_size = deps.size();
@ -321,9 +329,10 @@ void collectSubDependencies()
collectDependencies(original_path, lines);
for (size_t n=0; n<lines.size(); ++n) {
if (!Settings::bundleFrameworks())
if (!Settings::bundleFrameworks()) {
if (lines[n].find(".framework") != std::string::npos)
continue;
}
// lines containing path begin with a tab
if (lines[n][0] != '\t')
continue;
@ -334,17 +343,49 @@ void collectSubDependencies()
full_path = searchFilenameInRpaths(dep_path, original_path);
collectRpathsForFilename(full_path);
}
// addDependency(dep_path, full_path);
addDependency(dep_path, original_path);
}
}
// if no more dependencies were added on this iteration, stop searching
if (deps.size() == deps_size)
if (deps.size() == deps_size) {
break;
}
}
if (Settings::verboseOutput()) {
std::cout << "(post sub) # OF FILES: " << Settings::filesToFixCount() << std::endl;
std::cout << "(post sub) # OF DEPS: " << deps.size() << std::endl;
}
}
void doneWithDeps_go()
{
if (Settings::verboseOutput()) {
for (std::set<std::string>::iterator it = rpaths.begin(); it != rpaths.end(); ++it) {
std::cout << "rpaths: " << *it << std::endl;
}
}
const size_t deps_size = deps.size();
for (size_t n=0; n<deps_size; ++n)
deps[n].print();
std::cout << "\n";
// copy files if requested by user
if (Settings::bundleLibs()) {
createDestDir();
for (size_t i=0; i<deps_size; ++i) {
deps[i].copyYourself();
changeLibPathsOnFile(deps[i].getInstallPath());
fixRpathsOnFile(deps[i].getOriginalPath(), deps[i].getInstallPath());
}
}
const size_t filesToFixSize = Settings::filesToFix().size();
for (size_t n=0; n<filesToFixSize; ++n) {
changeLibPathsOnFile(Settings::fileToFix(n));
fixRpathsOnFile(Settings::fileToFix(n), Settings::fileToFix(n));
}
std::cout << "(post sub) # OF FILES: " << Settings::filesToFixCount() << std::endl;
std::cout << "(post sub) # OF DEPS: " << deps.size() << std::endl;
}
void createQtConf(std::string directory)
@ -402,10 +443,6 @@ void copyQtPlugins()
createQtConf(Settings::resourcesFolder());
std::string framework_root = getFrameworkRoot(original_file);
std::string prefix = filePrefix(framework_root);
std::string qt_prefix = filePrefix(prefix.substr(0, prefix.size()-1));
std::string qt_plugins_prefix = qt_prefix + "plugins/";
std::string dest = Settings::pluginsFolder();
auto fixupPlugin = [original_file,dest](std::string plugin) {
@ -423,6 +460,11 @@ void copyQtPlugins()
}
};
std::string framework_root = getFrameworkRoot(original_file);
std::string prefix = filePrefix(framework_root);
std::string qt_prefix = filePrefix(prefix.substr(0, prefix.size()-1));
std::string qt_plugins_prefix = qt_prefix + "plugins/";
mkdir(dest + "platforms");
copyFile(qt_plugins_prefix + "platforms/libqcocoa.dylib", dest + "platforms");
Settings::addFileToFix(dest + "platforms/libqcocoa.dylib");
@ -452,42 +494,16 @@ void copyQtPlugins()
if (qtLocationFound)
fixupPlugin("geoservices");
std::cout << "(post qt) # OF FILES: " << Settings::filesToFixCount() << std::endl;
std::cout << "(post qt) # OF DEPS: " << deps.size() << std::endl;
if (Settings::verboseOutput()) {
std::cout << "(post qt) # OF FILES: " << Settings::filesToFixCount() << std::endl;
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;
}
void doneWithDeps_go()
{
for (std::set<std::string>::iterator it = rpaths.begin(); it != rpaths.end(); ++it) {
std::cout << "rpaths: " << *it << std::endl;
}
const size_t deps_size = deps.size();
std::cout << "\n";
for (size_t n=0; n<deps_size; ++n)
deps[n].print();
std::cout << "\n";
// copy files if requested by user
if (Settings::bundleLibs()) {
createDestDir();
for (size_t i=0; i<deps_size; ++i) {
deps[i].copyYourself();
changeLibPathsOnFile(deps[i].getInstallPath());
fixRpathsOnFile(deps[i].getOriginalPath(), deps[i].getInstallPath());
}
}
const size_t filesToFixSize = Settings::filesToFix().size();
for (size_t n=0; n<filesToFixSize; ++n) {
changeLibPathsOnFile(Settings::fileToFix(n));
fixRpathsOnFile(Settings::fileToFix(n), Settings::fileToFix(n));
if (Settings::verboseOutput()) {
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

@ -13,13 +13,13 @@ std::string searchFilenameInRpaths(const std::string& rpath_dep, const std::stri
std::string searchFilenameInRpaths(const std::string& rpath_file);
void fixRpathsOnFile(const std::string& original_file, const std::string& file_to_fix);
void createQtConf(std::string directory);
void copyQtPlugins();
void addDependency(std::string path, std::string dependent_file);
void collectDependencies(std::string dependent_file);
void collectSubDependencies();
void doneWithDeps_go();
void createQtConf(std::string directory);
void copyQtPlugins();
#endif

View File

@ -214,7 +214,8 @@ bool mkdir(std::string path)
void createDestDir()
{
std::string dest_folder = Settings::destFolder();
std::cout << "* Checking output directory " << dest_folder << "\n";
if (Settings::verboseOutput())
std::cout << "* Checking output directory " << dest_folder << "\n";
bool dest_exists = fileExists(dest_folder);
@ -272,7 +273,7 @@ std::string getUserInputDirForFile(const std::string& filename)
std::cin >> prefix;
std::cout << std::endl;
if (prefix.compare("quit") == 0)
if (prefix.compare("quit") == 0 || prefix.compare("exit") == 0 || prefix.compare("abort") == 0)
exit(1);
if (!prefix.empty() && prefix[prefix.size()-1] != '/')

View File

@ -126,9 +126,6 @@ int main (int argc, char * const argv[])
exit(0);
}
// if (!Settings::appBundle().empty())
// initRpaths();
std::cout << "* Collecting dependencies...\n";
const size_t count = Settings::filesToFixCount();