add namespace macDylibBundler

This commit is contained in:
SCG82 2020-01-11 03:40:14 -08:00
parent a459e157b4
commit 4fb9a74882
9 changed files with 290 additions and 279 deletions

View File

@ -13,7 +13,9 @@
#include "DylibBundler.h" #include "DylibBundler.h"
#include "Utils.h" #include "Utils.h"
Dependency::Dependency(std::string path, const std::string& dependent_file, DylibBundler* db) namespace macDylibBundler {
Dependency::Dependency(std::string path, const std::string &dependent_file, DylibBundler *db)
: is_framework(false), db(db) : is_framework(false), db(db)
{ {
char buffer[PATH_MAX]; char buffer[PATH_MAX];
@ -23,17 +25,15 @@ Dependency::Dependency(std::string path, const std::string& dependent_file, Dyli
if (isRpath(path)) { if (isRpath(path)) {
original_file = db->searchFilenameInRpaths(path, dependent_file); original_file = db->searchFilenameInRpaths(path, dependent_file);
} } else if (realpath(path.c_str(), buffer)) {
else if (realpath(path.c_str(), buffer)) {
original_file = buffer; original_file = buffer;
} } else {
else {
warning_msg = "\n/!\\ WARNING: Cannot resolve path '" + path + "'\n"; warning_msg = "\n/!\\ WARNING: Cannot resolve path '" + path + "'\n";
original_file = path; original_file = path;
} }
if (db->verboseOutput()) { if (db->verboseOutput()) {
std::cout<< "** Dependency ctor **" << std::endl; std::cout << "** Dependency ctor **" << std::endl;
if (path != dependent_file) if (path != dependent_file)
std::cout << " dependent file: " << dependent_file << std::endl; std::cout << " dependent file: " << dependent_file << std::endl;
std::cout << " dependency path: " << path << std::endl; std::cout << " dependency path: " << path << std::endl;
@ -47,7 +47,7 @@ Dependency::Dependency(std::string path, const std::string& dependent_file, Dyli
prefix = filePrefix(original_file); prefix = filePrefix(original_file);
filename = stripPrefix(original_file); filename = stripPrefix(original_file);
if (!prefix.empty() && prefix[prefix.size()-1] != '/') if (!prefix.empty() && prefix[prefix.size() - 1] != '/')
prefix += "/"; prefix += "/";
// check if this dependency is in /usr/lib, /System/Library, or in ignored list // check if this dependency is in /usr/lib, /System/Library, or in ignored list
@ -69,13 +69,13 @@ Dependency::Dependency(std::string path, const std::string& dependent_file, Dyli
} }
// check if the lib is in a known location // check if the lib is in a known location
if (prefix.empty() || !fileExists(prefix+filename)) { if (prefix.empty() || !fileExists(prefix + filename)) {
std::vector<std::string> search_paths = db->searchPaths(); std::vector<std::string> search_paths = db->searchPaths();
if (search_paths.empty()) if (search_paths.empty())
db->initSearchPaths(); db->initSearchPaths();
// check if file is contained in one of the paths // check if file is contained in one of the paths
for (const auto& search_path : search_paths) { for (const auto &search_path : search_paths) {
if (fileExists(search_path+filename)) { if (fileExists(search_path + filename)) {
warning_msg += "FOUND " + filename + " in " + search_path + "\n"; warning_msg += "FOUND " + filename + " in " + search_path + "\n";
prefix = search_path; prefix = search_path;
db->missingPrefixes(true); db->missingPrefixes(true);
@ -92,7 +92,7 @@ Dependency::Dependency(std::string path, const std::string& dependent_file, Dyli
if (!db->quietOutput()) if (!db->quietOutput())
std::cerr << "\n/!\\ WARNING: Dependency " << filename << " of " << dependent_file << " not found\n"; std::cerr << "\n/!\\ WARNING: Dependency " << filename << " of " << dependent_file << " not found\n";
if (db->verboseOutput()) if (db->verboseOutput())
std::cout << " path: " << (prefix+filename) << std::endl; std::cout << " path: " << (prefix + filename) << std::endl;
db->missingPrefixes(true); db->missingPrefixes(true);
db->addSearchPath(db->getUserInputDirForFile(filename, dependent_file)); db->addSearchPath(db->getUserInputDirForFile(filename, dependent_file));
} }
@ -110,16 +110,16 @@ std::string Dependency::InstallPath() const
return db->destFolder() + new_name; return db->destFolder() + new_name;
} }
void Dependency::AddSymlink(const std::string& path) void Dependency::AddSymlink(const std::string &path)
{ {
if (std::find(symlinks.begin(), symlinks.end(), path) == symlinks.end()) if (std::find(symlinks.begin(), symlinks.end(), path) == symlinks.end())
symlinks.push_back(path); symlinks.push_back(path);
} }
bool Dependency::MergeIfIdentical(Dependency* dependency) bool Dependency::MergeIfIdentical(Dependency *dependency)
{ {
if (dependency->OriginalFilename() == filename) { if (dependency->OriginalFilename() == filename) {
for (const auto& symlink : symlinks) for (const auto &symlink : symlinks)
dependency->AddSymlink(symlink); dependency->AddSymlink(symlink);
return true; return true;
} }
@ -129,7 +129,7 @@ bool Dependency::MergeIfIdentical(Dependency* dependency)
void Dependency::Print() const void Dependency::Print() const
{ {
std::cout << "\n* " << filename << " from " << prefix << std::endl; std::cout << "\n* " << filename << " from " << prefix << std::endl;
for (const auto& symlink : symlinks) for (const auto &symlink : symlinks)
std::cout << " symlink --> " << symlink << std::endl; std::cout << " symlink --> " << symlink << std::endl;
} }
@ -165,15 +165,17 @@ void Dependency::CopyToBundle() const
db->changeId(InstallPath(), "@rpath/" + new_name); db->changeId(InstallPath(), "@rpath/" + new_name);
} }
void Dependency::FixDependentFile(const std::string& dependent_file) const void Dependency::FixDependentFile(const std::string &dependent_file) const
{ {
db->changeInstallName(dependent_file, OriginalPath(), InnerPath()); db->changeInstallName(dependent_file, OriginalPath(), InnerPath());
for (const auto& symlink : symlinks) for (const auto &symlink : symlinks)
db->changeInstallName(dependent_file, symlink, InnerPath()); db->changeInstallName(dependent_file, symlink, InnerPath());
if (!db->missingPrefixes()) return; if (!db->missingPrefixes()) return;
db->changeInstallName(dependent_file, filename, InnerPath()); db->changeInstallName(dependent_file, filename, InnerPath());
for (const auto& symlink : symlinks) for (const auto &symlink : symlinks)
db->changeInstallName(dependent_file, symlink, InnerPath()); db->changeInstallName(dependent_file, symlink, InnerPath());
} }
} //namespace macDylibBundler

View File

@ -1,33 +1,34 @@
#pragma once #pragma once
#ifndef DYLIBBUNDLER_DEPENDENCY_H #ifndef MACDYLIBBUNDLER_DEPENDENCY_H
#define DYLIBBUNDLER_DEPENDENCY_H #define MACDYLIBBUNDLER_DEPENDENCY_H
#include <string> #include <string>
#include <vector> #include <vector>
namespace macDylibBundler {
class DylibBundler; class DylibBundler;
class Dependency { class Dependency {
public: public:
Dependency(std::string path, const std::string& dependent_file, DylibBundler* db); Dependency(std::string path, const std::string &dependent_file, DylibBundler *db);
[[nodiscard]] bool IsFramework() const { return is_framework; } [[nodiscard]] bool IsFramework() const { return is_framework; }
[[nodiscard]] std::string Prefix() const { return prefix; } [[nodiscard]] std::string Prefix() const { return prefix; }
[[nodiscard]] std::string OriginalFilename() const { return filename; } [[nodiscard]] std::string OriginalFilename() const { return filename; }
[[nodiscard]] std::string OriginalPath() const { return prefix + filename; } [[nodiscard]] std::string OriginalPath() const { return prefix + filename; }
[[nodiscard]] std::string InnerPath() const; [[nodiscard]] std::string InnerPath() const;
[[nodiscard]] std::string InstallPath() const; [[nodiscard]] std::string InstallPath() const;
void AddSymlink(const std::string &path);
void AddSymlink(const std::string& path);
// Compare the |dependency| with |this|. Merge entries if both refer to the same file. // Compare the |dependency| with |this|. Merge entries if both refer to the same file.
bool MergeIfIdentical(Dependency* dependency); bool MergeIfIdentical(Dependency *dependency);
void Print() const; void Print() const;
void CopyToBundle() const; void CopyToBundle() const;
void FixDependentFile(const std::string& dependent_file) const;
void FixDependentFile(const std::string &dependent_file) const;
private: private:
bool is_framework; bool is_framework;
@ -40,7 +41,9 @@ private:
// installation // installation
std::string new_name; std::string new_name;
DylibBundler* db; DylibBundler *db;
}; };
#endif #endif
} // namespace macDylibBundler

View File

@ -2,7 +2,6 @@
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
#include <map>
#include <numeric> #include <numeric>
#include <regex> #include <regex>
#include <sstream> #include <sstream>
@ -15,23 +14,26 @@
#include "Dependency.h" #include "Dependency.h"
#include "Utils.h" #include "Utils.h"
namespace macDylibBundler {
DylibBundler::DylibBundler() : qt_plugins_called(false) {} DylibBundler::DylibBundler() : qt_plugins_called(false) {}
DylibBundler::~DylibBundler() = default; DylibBundler::~DylibBundler() = default;
void DylibBundler::addDependency(const std::string& path, const std::string& dependent_file) void DylibBundler::addDependency(const std::string &path, const std::string &dependent_file)
{ {
Dependency* dependency = new Dependency(path, dependent_file, this); Dependency *dependency = new Dependency(path, dependent_file, this);
// check if this library was already added to |deps| to avoid duplicates // check if this library was already added to |deps| to avoid duplicates
bool in_deps = false; bool in_deps = false;
for (auto& dep : deps) { for (auto &dep : deps) {
if (dependency->MergeIfIdentical(dep)) if (dependency->MergeIfIdentical(dep))
in_deps = true; in_deps = true;
} }
// check if this library was already added to |deps_per_file[dependent_file]| to avoid duplicates // check if this library was already added to |deps_per_file[dependent_file]| to avoid duplicates
bool in_deps_per_file = false; bool in_deps_per_file = false;
for (auto& dep : deps_per_file[dependent_file]) { for (auto &dep : deps_per_file[dependent_file]) {
if (dependency->MergeIfIdentical(dep)) if (dependency->MergeIfIdentical(dep))
in_deps_per_file = true; in_deps_per_file = true;
} }
@ -48,7 +50,7 @@ void DylibBundler::addDependency(const std::string& path, const std::string& dep
deps_per_file[dependent_file].push_back(dependency); deps_per_file[dependent_file].push_back(dependency);
} }
void DylibBundler::collectDependenciesRpaths(const std::string& dependent_file) void DylibBundler::collectDependenciesRpaths(const std::string &dependent_file)
{ {
if (deps_collected.find(dependent_file) != deps_collected.end() && fileHasRpath(dependent_file)) if (deps_collected.find(dependent_file) != deps_collected.end() && fileHasRpath(dependent_file))
return; return;
@ -64,7 +66,7 @@ void DylibBundler::collectDependenciesRpaths(const std::string& dependent_file)
if (rpaths_collected.find(dependent_file) == rpaths_collected.end()) { if (rpaths_collected.find(dependent_file) == rpaths_collected.end()) {
auto rpath_results = cmds_results[rpath]; auto rpath_results = cmds_results[rpath];
for (const auto& rpath_result : rpath_results) { for (const auto &rpath_result : rpath_results) {
rpaths.insert(rpath_result); rpaths.insert(rpath_result);
addRpathForFile(dependent_file, rpath_result); addRpathForFile(dependent_file, rpath_result);
if (verboseOutput()) if (verboseOutput())
@ -75,7 +77,7 @@ void DylibBundler::collectDependenciesRpaths(const std::string& dependent_file)
if (deps_collected.find(dependent_file) == deps_collected.end()) { if (deps_collected.find(dependent_file) == deps_collected.end()) {
auto dylib_results = cmds_results[dylib]; auto dylib_results = cmds_results[dylib];
for (const auto& dylib_result : dylib_results) { for (const auto &dylib_result : dylib_results) {
// skip system/ignored prefixes // skip system/ignored prefixes
if (isPrefixBundled(dylib_result)) if (isPrefixBundled(dylib_result))
addDependency(dylib_result, dependent_file); addDependency(dylib_result, dependent_file);
@ -86,21 +88,22 @@ void DylibBundler::collectDependenciesRpaths(const std::string& dependent_file)
void DylibBundler::collectSubDependencies() void DylibBundler::collectSubDependencies()
{ {
if (verboseOutput()) { std::vector<std::string> files_to_fix = filesToFix();
std::cout << "(pre sub) # OF FILES: " << filesToFixCount() << std::endl;
std::cout << "(pre sub) # OF DEPS: " << deps.size() << std::endl;
}
size_t dep_counter = deps.size(); size_t dep_counter = deps.size();
size_t deps_size = deps.size(); size_t deps_size = deps.size();
if (verboseOutput()) {
std::cout << "(pre sub) # OF FILES: " << files_to_fix.size() << std::endl;
std::cout << "(pre sub) # OF DEPS: " << deps.size() << std::endl;
}
while (true) { while (true) {
deps_size = deps.size(); deps_size = deps.size();
for (size_t n=0; n<deps_size; ++n) { for (size_t n = 0; n < deps_size; ++n) {
std::string original_path = deps[n]->OriginalPath(); std::string original_path = deps[n]->OriginalPath();
if (verboseOutput()) if (verboseOutput())
std::cout << " (collect sub deps) original path: " << original_path << std::endl; std::cout << " (collect sub deps) original path: " << original_path << std::endl;
if (isRpath(original_path)) if (isRpath(original_path))
original_path = searchFilenameInRpaths(original_path); original_path = searchFilenameInRpaths(original_path);
collectDependenciesRpaths(original_path); collectDependenciesRpaths(original_path);
} }
// if no more dependencies were added on this iteration, stop searching // if no more dependencies were added on this iteration, stop searching
@ -109,7 +112,8 @@ void DylibBundler::collectSubDependencies()
} }
if (verboseOutput()) { if (verboseOutput()) {
std::cout << "(post sub) # OF FILES: " << filesToFixCount() << std::endl; files_to_fix = filesToFix();
std::cout << "(post sub) # OF FILES: " << files_to_fix.size() << std::endl;
std::cout << "(post sub) # OF DEPS: " << deps.size() << std::endl; std::cout << "(post sub) # OF DEPS: " << deps.size() << std::endl;
} }
if (bundleLibs() && bundleFrameworks()) { if (bundleLibs() && bundleFrameworks()) {
@ -118,18 +122,20 @@ void DylibBundler::collectSubDependencies()
} }
} }
void DylibBundler::changeLibPathsOnFile(const std::string& file_to_fix) void DylibBundler::changeLibPathsOnFile(const std::string &file_to_fix)
{ {
if (deps_collected.find(file_to_fix) == deps_collected.end() || rpaths_collected.find(file_to_fix) == rpaths_collected.end()) if (deps_collected.find(file_to_fix) == deps_collected.end()
|| rpaths_collected.find(file_to_fix) == rpaths_collected.end()) {
collectDependenciesRpaths(file_to_fix); collectDependenciesRpaths(file_to_fix);
}
std::cout << "* Fixing dependencies on " << file_to_fix << "\n"; std::cout << "* Fixing dependencies on " << file_to_fix << "\n";
std::vector<Dependency*> dependencies = deps_per_file[file_to_fix]; std::vector<Dependency *> dependencies = deps_per_file[file_to_fix];
for (auto& dependency : dependencies) for (auto& dependency : dependencies)
dependency->FixDependentFile(file_to_fix); dependency->FixDependentFile(file_to_fix);
} }
void DylibBundler::fixRpathsOnFile(const std::string& original_file, const std::string& file_to_fix) void DylibBundler::fixRpathsOnFile(const std::string &original_file, const std::string &file_to_fix)
{ {
std::vector<std::string> rpaths_to_fix; std::vector<std::string> rpaths_to_fix;
if (!fileHasRpath(original_file)) if (!fileHasRpath(original_file))
@ -137,10 +143,11 @@ void DylibBundler::fixRpathsOnFile(const std::string& original_file, const std::
rpaths_to_fix = getRpathsForFile(original_file); rpaths_to_fix = getRpathsForFile(original_file);
for (const auto& rpath_to_fix : rpaths_to_fix) { for (const auto& rpath_to_fix : rpaths_to_fix) {
std::string command = std::string("/usr/bin/install_name_tool -rpath ").append(rpath_to_fix); std::string command = std::string("/usr/bin/install_name_tool -rpath ");
command += std::string(" ").append(insideLibPath()).append(" ").append(file_to_fix); command += rpath_to_fix + " " + insideLibPath() + " " + file_to_fix;
if (systemp(command) != 0) { if (systemp(command) != 0) {
std::cerr << "\n\n/!\\ ERROR: An error occured while trying to fix rpath " << rpath_to_fix << " of " << file_to_fix << std::endl; std::cerr << "\n\n/!\\ ERROR: An error occured while trying to fix rpath " << rpath_to_fix << " of "
<< file_to_fix << std::endl;
exit(1); exit(1);
} }
} }
@ -148,19 +155,19 @@ void DylibBundler::fixRpathsOnFile(const std::string& original_file, const std::
void DylibBundler::bundleDependencies() void DylibBundler::bundleDependencies()
{ {
for (const auto& dep : deps) for (const auto &dep : deps)
dep->Print(); dep->Print();
std::cout << "\n"; std::cout << "\n";
if (verboseOutput()) { if (verboseOutput()) {
std::cout << "rpaths:" << std::endl; std::cout << "rpaths:" << std::endl;
for (const auto& rpath : rpaths) for (const auto &rpath : rpaths)
std::cout << "* " << rpath << std::endl; std::cout << "* " << rpath << std::endl;
} }
// copy & fix up dependencies // copy & fix up dependencies
if (bundleLibs()) { if (bundleLibs()) {
createDestDir(); createDestDir();
for (const auto& dep : deps) { for (const auto &dep : deps) {
dep->CopyToBundle(); dep->CopyToBundle();
changeLibPathsOnFile(dep->InstallPath()); changeLibPathsOnFile(dep->InstallPath());
fixRpathsOnFile(dep->OriginalPath(), dep->InstallPath()); fixRpathsOnFile(dep->OriginalPath(), dep->InstallPath());
@ -168,7 +175,7 @@ void DylibBundler::bundleDependencies()
} }
// fix up input files // fix up input files
const auto files = filesToFix(); const auto files = filesToFix();
for (const auto& file : files) { for (const auto &file : files) {
changeLibPathsOnFile(file); changeLibPathsOnFile(file);
fixRpathsOnFile(file, file); fixRpathsOnFile(file, file);
} }
@ -190,7 +197,7 @@ void DylibBundler::bundleQtPlugins()
bool qtWebViewFound = false; bool qtWebViewFound = false;
std::string original_file; std::string original_file;
for (const auto& framework : frameworks) { for (const auto &framework : frameworks) {
if (framework.find("QtCore") != std::string::npos) { if (framework.find("QtCore") != std::string::npos) {
qtCoreFound = true; qtCoreFound = true;
original_file = framework; original_file = framework;
@ -225,17 +232,17 @@ void DylibBundler::bundleQtPlugins()
createQtConf(resourcesFolder()); createQtConf(resourcesFolder());
qt_plugins_called = true; qt_plugins_called = true;
const auto fixupPlugin = [&](const std::string& plugin) { const auto fixupPlugin = [&](const std::string &plugin) {
std::string dest = pluginsFolder(); std::string dest = pluginsFolder();
std::string framework_root = getFrameworkRoot(original_file); std::string framework_root = getFrameworkRoot(original_file);
std::string prefix = filePrefix(framework_root); std::string prefix = filePrefix(framework_root);
std::string qt_prefix = filePrefix(prefix.substr(0, prefix.size()-1)); std::string qt_prefix = filePrefix(prefix.substr(0, prefix.size() - 1));
std::string qt_plugins_prefix = qt_prefix + "plugins/"; std::string qt_plugins_prefix = qt_prefix + "plugins/";
if (fileExists(qt_plugins_prefix + plugin)) { if (fileExists(qt_plugins_prefix + plugin)) {
mkdir(dest + plugin); mkdir(dest + plugin);
copyFile(qt_plugins_prefix + plugin, dest); copyFile(qt_plugins_prefix + plugin, dest);
std::vector<std::string> files = lsDir(dest + plugin + "/"); std::vector<std::string> files = lsDir(dest + plugin + "/");
for (const auto& file : files) { for (const auto &file : files) {
std::string file_to_fix = dest + plugin + "/" + file; std::string file_to_fix = dest + plugin + "/" + file;
std::string new_rpath = std::string("@rpath/") + plugin + "/" + file; std::string new_rpath = std::string("@rpath/") + plugin + "/" + file;
addFileToFix(file_to_fix); addFileToFix(file_to_fix);
@ -247,7 +254,7 @@ void DylibBundler::bundleQtPlugins()
std::string framework_root = getFrameworkRoot(original_file); std::string framework_root = getFrameworkRoot(original_file);
std::string prefix = filePrefix(framework_root); std::string prefix = filePrefix(framework_root);
std::string qt_prefix = filePrefix(prefix.substr(0, prefix.size()-1)); std::string qt_prefix = filePrefix(prefix.substr(0, prefix.size() - 1));
std::string qt_plugins_prefix = qt_prefix + "plugins/"; std::string qt_plugins_prefix = qt_prefix + "plugins/";
std::string dest = pluginsFolder(); std::string dest = pluginsFolder();
@ -292,11 +299,11 @@ void DylibBundler::bundleQtPlugins()
collectSubDependencies(); collectSubDependencies();
} }
std::string DylibBundler::getUserInputDirForFile(const std::string& filename, const std::string& dependent_file) std::string DylibBundler::getUserInputDirForFile(const std::string &filename, const std::string &dependent_file)
{ {
std::vector<std::string> search_paths = userSearchPaths(); std::vector<std::string> search_paths = userSearchPaths();
for (auto& search_path : search_paths) { for (auto &search_path : search_paths) {
if (!search_path.empty() && search_path[search_path.size()-1] != '/') if (!search_path.empty() && search_path[search_path.size() - 1] != '/')
search_path += "/"; search_path += "/";
if (fileExists(search_path + filename)) { if (fileExists(search_path + filename)) {
if (!quietOutput()) { if (!quietOutput()) {
@ -318,14 +325,13 @@ std::string DylibBundler::getUserInputDirForFile(const std::string& filename, co
if (prefix == "quit" || prefix == "exit" || prefix == "abort") if (prefix == "quit" || prefix == "exit" || prefix == "abort")
exit(1); exit(1);
if (!prefix.empty() && prefix[prefix.size()-1] != '/') if (!prefix.empty() && prefix[prefix.size() - 1] != '/')
prefix += "/"; prefix += "/";
if (!fileExists(prefix+filename)) { if (!fileExists(prefix + filename)) {
std::cerr << (prefix+filename) << " does not exist. Try again...\n"; std::cerr << (prefix + filename) << " does not exist. Try again...\n";
continue; continue;
} } else {
else { std::cerr << (prefix + filename) << " was found\n"
std::cerr << (prefix+filename) << " was found\n"
<< "/!\\ WARNING: dylibbundler MAY NOT CORRECTLY HANDLE THIS DEPENDENCY: Check the executable with 'otool -L'\n"; << "/!\\ WARNING: dylibbundler MAY NOT CORRECTLY HANDLE THIS DEPENDENCY: Check the executable with 'otool -L'\n";
addUserSearchPath(prefix); addUserSearchPath(prefix);
return prefix; return prefix;
@ -333,7 +339,7 @@ std::string DylibBundler::getUserInputDirForFile(const std::string& filename, co
} }
} }
std::string DylibBundler::searchFilenameInRpaths(const std::string& rpath_file, const std::string& dependent_file) std::string DylibBundler::searchFilenameInRpaths(const std::string &rpath_file, const std::string &dependent_file)
{ {
if (verboseOutput()) { if (verboseOutput()) {
if (dependent_file != rpath_file) if (dependent_file != rpath_file)
@ -341,7 +347,7 @@ std::string DylibBundler::searchFilenameInRpaths(const std::string& rpath_file,
std::cout << " dependency: " << rpath_file << std::endl; std::cout << " dependency: " << rpath_file << std::endl;
} }
std::string fullpath; std::string fullpath;
std::string suffix = rpath_file.substr(rpath_file.rfind('/')+1); std::string suffix = rpath_file.substr(rpath_file.rfind('/') + 1);
char fullpath_buffer[PATH_MAX]; char fullpath_buffer[PATH_MAX];
const auto check_path = [&](std::string path) { const auto check_path = [&](std::string path) {
@ -363,8 +369,7 @@ std::string DylibBundler::searchFilenameInRpaths(const std::string& rpath_file,
rpathToFullPath(rpath_file, fullpath); rpathToFullPath(rpath_file, fullpath);
return true; return true;
} }
} } else if (path.find("@rpath") != std::string::npos) {
else if (path.find("@rpath") != std::string::npos) {
if (appBundleProvided()) { if (appBundleProvided()) {
std::string pathE = std::regex_replace(path, std::regex("@rpath/"), executableFolder()); std::string pathE = std::regex_replace(path, std::regex("@rpath/"), executableFolder());
if (verboseOutput()) if (verboseOutput())
@ -392,11 +397,10 @@ std::string DylibBundler::searchFilenameInRpaths(const std::string& rpath_file,
// fullpath previously stored // fullpath previously stored
if (rpathFound(rpath_file)) { if (rpathFound(rpath_file)) {
fullpath = getFullPath(rpath_file); fullpath = getFullPath(rpath_file);
} } else if (!check_path(rpath_file)) {
else if (!check_path(rpath_file)) {
auto rpaths_for_file = getRpathsForFile(dependent_file); auto rpaths_for_file = getRpathsForFile(dependent_file);
for (auto rpath : rpaths_for_file) { for (auto rpath : rpaths_for_file) {
if (rpath[rpath.size()-1] != '/') if (rpath[rpath.size() - 1] != '/')
rpath += "/"; rpath += "/";
std::string path = rpath + suffix; std::string path = rpath + suffix;
if (verboseOutput()) if (verboseOutput())
@ -408,8 +412,8 @@ std::string DylibBundler::searchFilenameInRpaths(const std::string& rpath_file,
if (fullpath.empty()) { if (fullpath.empty()) {
std::vector<std::string> search_paths = searchPaths(); std::vector<std::string> search_paths = searchPaths();
for (const auto& search_path : search_paths) { for (const auto &search_path : search_paths) {
if (fileExists(search_path+suffix)) { if (fileExists(search_path + suffix)) {
if (verboseOutput()) if (verboseOutput())
std::cout << "FOUND " << suffix << " in " << search_path << std::endl; std::cout << "FOUND " << suffix << " in " << search_path << std::endl;
fullpath = search_path + suffix; fullpath = search_path + suffix;
@ -426,18 +430,16 @@ std::string DylibBundler::searchFilenameInRpaths(const std::string& rpath_file,
std::cerr << "\n/!\\ WARNING: Can't get path for '" << rpath_file << "'\n"; std::cerr << "\n/!\\ WARNING: Can't get path for '" << rpath_file << "'\n";
if (realpath(fullpath.c_str(), fullpath_buffer)) if (realpath(fullpath.c_str(), fullpath_buffer))
fullpath = fullpath_buffer; fullpath = fullpath_buffer;
} } else if (verboseOutput()) {
else if (verboseOutput()) {
std::cout << " ** rpath fullpath: " << fullpath << std::endl; std::cout << " ** rpath fullpath: " << fullpath << std::endl;
} }
} } else if (verboseOutput()) {
else if (verboseOutput()) {
std::cout << " ** rpath fullpath: " << fullpath << std::endl; std::cout << " ** rpath fullpath: " << fullpath << std::endl;
} }
return fullpath; return fullpath;
} }
std::string DylibBundler::searchFilenameInRpaths(const std::string& rpath_file) std::string DylibBundler::searchFilenameInRpaths(const std::string &rpath_file)
{ {
return searchFilenameInRpaths(rpath_file, rpath_file); return searchFilenameInRpaths(rpath_file, rpath_file);
} }
@ -450,13 +452,13 @@ void DylibBundler::initSearchPaths()
searchPaths = dyldLibPath; searchPaths = dyldLibPath;
dyldLibPath = std::getenv("DYLD_FALLBACK_FRAMEWORK_PATH"); dyldLibPath = std::getenv("DYLD_FALLBACK_FRAMEWORK_PATH");
if (dyldLibPath != nullptr) { if (dyldLibPath != nullptr) {
if (!searchPaths.empty() && searchPaths[searchPaths.size()-1] != ':') if (!searchPaths.empty() && searchPaths[searchPaths.size() - 1] != ':')
searchPaths += ":"; searchPaths += ":";
searchPaths += dyldLibPath; searchPaths += dyldLibPath;
} }
dyldLibPath = std::getenv("DYLD_FALLBACK_LIBRARY_PATH"); dyldLibPath = std::getenv("DYLD_FALLBACK_LIBRARY_PATH");
if (dyldLibPath != nullptr) { if (dyldLibPath != nullptr) {
if (!searchPaths.empty() && searchPaths[searchPaths.size()-1] != ':') if (!searchPaths.empty() && searchPaths[searchPaths.size() - 1] != ':')
searchPaths += ":"; searchPaths += ":";
searchPaths += dyldLibPath; searchPaths += dyldLibPath;
} }
@ -464,7 +466,7 @@ void DylibBundler::initSearchPaths()
std::stringstream ss(searchPaths); std::stringstream ss(searchPaths);
std::string item; std::string item;
while (std::getline(ss, item, ':')) { while (std::getline(ss, item, ':')) {
if (item[item.size()-1] != '/') if (item[item.size() - 1] != '/')
item += "/"; item += "/";
addSearchPath(item); addSearchPath(item);
} }
@ -480,7 +482,7 @@ void DylibBundler::createDestDir()
bool dest_exists = fileExists(dest_folder); bool dest_exists = fileExists(dest_folder);
if (dest_exists && canOverwriteDir()) { if (dest_exists && canOverwriteDir()) {
std::cout << "Erasing old output directory " << dest_folder << "\n"; std::cout << "Erasing old output directory " << dest_folder << "\n";
std::string command = std::string("/bin/rm -r ").append(dest_folder); std::string command = std::string("/bin/rm -r ") + dest_folder;
if (systemp(command) != 0) { if (systemp(command) != 0) {
std::cerr << "\n\n/!\\ ERROR: An error occured while attempting to overwrite destination folder\n"; std::cerr << "\n\n/!\\ ERROR: An error occured while attempting to overwrite destination folder\n";
exit(1); exit(1);
@ -495,34 +497,36 @@ void DylibBundler::createDestDir()
std::cerr << "\n/!\\ ERROR: An error occured while creating " << dest_folder << std::endl; std::cerr << "\n/!\\ ERROR: An error occured while creating " << dest_folder << std::endl;
exit(1); exit(1);
} }
} } else {
else { std::cerr
std::cerr << "\n\n/!\\ ERROR: Destination folder does not exist. Create it or pass the '-cd' or '-od' flag\n"; << "\n\n/!\\ ERROR: Destination folder does not exist. Create it or pass the '-cd' or '-od' flag\n";
exit(1); exit(1);
} }
} }
} }
void DylibBundler::changeId(const std::string& binary_file, const std::string& new_id) void DylibBundler::changeId(const std::string &binary_file, const std::string &new_id)
{ {
std::string command = std::string("/usr/bin/install_name_tool -id ").append(new_id).append(" ").append(binary_file); std::string command = std::string("/usr/bin/install_name_tool -id ") + new_id + " " + binary_file;
if (systemp(command) != 0) { if (systemp(command) != 0) {
std::cerr << "\n\nError: An error occured while trying to change identity of library " << binary_file << std::endl; std::cerr << "\n\nError: An error occured while trying to change identity of library " << binary_file
<< std::endl;
exit(1); exit(1);
} }
} }
void DylibBundler::changeInstallName(const std::string& binary_file, const std::string& old_name, const std::string& new_name) void DylibBundler::changeInstallName(const std::string &binary_file, const std::string &old_name,
{ const std::string &new_name)
std::string command = std::string("/usr/bin/install_name_tool -change ").append(old_name).append(" "); {
command.append(new_name).append(" ").append(binary_file); std::string command = std::string("/usr/bin/install_name_tool -change ");
command += old_name + " " + new_name + " " + binary_file;
if (systemp(command) != 0) { if (systemp(command) != 0) {
std::cerr << "\n\nError: An error occured while trying to fix dependencies of " << binary_file << std::endl; std::cerr << "\n\nError: An error occured while trying to fix dependencies of " << binary_file << std::endl;
exit(1); exit(1);
} }
} }
void DylibBundler::copyFile(const std::string& from, const std::string& to) void DylibBundler::copyFile(const std::string &from, const std::string &to)
{ {
bool overwrite = canOverwriteFiles(); bool overwrite = canOverwriteFiles();
if (fileExists(to) && !overwrite) { if (fileExists(to) && !overwrite) {
@ -532,42 +536,41 @@ void DylibBundler::copyFile(const std::string& from, const std::string& to)
// copy file/directory // copy file/directory
std::string overwrite_permission = std::string(overwrite ? "-f " : "-n "); std::string overwrite_permission = std::string(overwrite ? "-f " : "-n ");
std::string command = std::string("/bin/cp -R ").append(overwrite_permission); std::string command = std::string("/bin/cp -R ") + overwrite_permission + from + " " + to;
command.append(from).append(" ").append(to);
if (from != to && systemp(command) != 0) { if (from != to && systemp(command) != 0) {
std::cerr << "\n\nError: An error occured while trying to copy file " << from << " to " << to << std::endl; std::cerr << "\n\nError: An error occured while trying to copy file " << from << " to " << to << std::endl;
exit(1); exit(1);
} }
// give file/directory write permission // give file/directory write permission
std::string command2 = std::string("/bin/chmod -R +w ").append(to); std::string command2 = std::string("/bin/chmod -R +w ") + to;
if (systemp(command2) != 0) { if (systemp(command2) != 0) {
std::cerr << "\n\nError: An error occured while trying to set write permissions on file " << to << std::endl; std::cerr << "\n\nError: An error occured while trying to set write permissions on file " << to << std::endl;
exit(1); exit(1);
} }
} }
void DylibBundler::deleteFile(const std::string& path, bool overwrite) void DylibBundler::deleteFile(const std::string &path, bool overwrite)
{ {
std::string overwrite_permission = std::string(overwrite ? "-f " : " "); std::string overwrite_permission = std::string(overwrite ? "-f " : " ");
std::string command = std::string("/bin/rm -r ").append(overwrite_permission).append(path); std::string command = std::string("/bin/rm -r ") + overwrite_permission + path;
if (systemp(command) != 0) { if (systemp(command) != 0) {
std::cerr << "\n\nError: An error occured while trying to delete " << path << std::endl; std::cerr << "\n\nError: An error occured while trying to delete " << path << std::endl;
exit(1); exit(1);
} }
} }
void DylibBundler::deleteFile(const std::string& path) void DylibBundler::deleteFile(const std::string &path)
{ {
bool overwrite = canOverwriteFiles(); bool overwrite = canOverwriteFiles();
deleteFile(path, overwrite); deleteFile(path, overwrite);
} }
bool DylibBundler::mkdir(const std::string& path) bool DylibBundler::mkdir(const std::string &path)
{ {
if (verboseOutput()) if (verboseOutput())
std::cout << "Creating directory " << path << std::endl; std::cout << "Creating directory " << path << std::endl;
std::string command = std::string("/bin/mkdir -p ").append(path); std::string command = std::string("/bin/mkdir -p ") + path;
if (systemp(command) != 0) { if (systemp(command) != 0) {
std::cerr << "\n/!\\ ERROR: An error occured while creating " << path << std::endl; std::cerr << "\n/!\\ ERROR: An error occured while creating " << path << std::endl;
return false; return false;
@ -575,9 +578,11 @@ bool DylibBundler::mkdir(const std::string& path)
return true; return true;
} }
int DylibBundler::systemp(const std::string& cmd) int DylibBundler::systemp(const std::string &cmd)
{ {
if (!quietOutput()) if (!quietOutput())
std::cout << " " << cmd << "\n"; std::cout << " " << cmd << "\n";
return system(cmd.c_str()); return system(cmd.c_str());
} }
} // namespace macDylibBundler

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#ifndef DYLIBBUNDLER_DYLIBBUNDLER_H #ifndef MACDYLIBBUNDLER_DYLIBBUNDLER_H
#define DYLIBBUNDLER_DYLIBBUNDLER_H #define MACDYLIBBUNDLER_DYLIBBUNDLER_H
#include <map> #include <map>
#include <set> #include <set>
@ -10,11 +10,14 @@
#include "Settings.h" #include "Settings.h"
namespace macDylibBundler {
class Dependency; class Dependency;
class DylibBundler : public Settings { class DylibBundler : public Settings {
public: public:
DylibBundler(); DylibBundler();
~DylibBundler() override; ~DylibBundler() override;
void addDependency(const std::string &path, const std::string &dependent_file); void addDependency(const std::string &path, const std::string &dependent_file);
@ -25,28 +28,23 @@ public:
void bundleDependencies(); void bundleDependencies();
void bundleQtPlugins(); void bundleQtPlugins();
std::string getUserInputDirForFile(const std::string& filename, const std::string& dependent_file); std::string getUserInputDirForFile(const std::string &filename, const std::string &dependent_file);
std::string searchFilenameInRpaths(const std::string& rpath_file, const std::string& dependent_file); std::string searchFilenameInRpaths(const std::string &rpath_file, const std::string &dependent_file);
std::string searchFilenameInRpaths(const std::string& rpath_file); std::string searchFilenameInRpaths(const std::string &rpath_file);
// check the same paths the system would search for dylibs
void initSearchPaths(); void initSearchPaths();
void createDestDir(); void createDestDir();
void changeId(const std::string &binary_file, const std::string &new_id);
void changeId(const std::string& binary_file, const std::string& new_id); void changeInstallName(const std::string &binary_file, const std::string &old_name, const std::string &new_name);
void changeInstallName(const std::string& binary_file, const std::string& old_name, const std::string& new_name); void copyFile(const std::string &from, const std::string &to);
void deleteFile(const std::string &path, bool overwrite);
void copyFile(const std::string& from, const std::string& to); void deleteFile(const std::string &path);
void deleteFile(const std::string& path, bool overwrite); bool mkdir(const std::string &path);
void deleteFile(const std::string& path);
bool mkdir(const std::string& path);
// run a command in the system shell (like 'system') but also print the command to stdout // run a command in the system shell (like 'system') but also print the command to stdout
int systemp(const std::string& cmd); int systemp(const std::string &cmd);
private: private:
std::vector<Dependency*> deps; std::vector<Dependency *> deps;
std::map<std::string, std::vector<Dependency*>> deps_per_file; std::map<std::string, std::vector<Dependency *>> deps_per_file;
std::map<std::string, bool> deps_collected; std::map<std::string, bool> deps_collected;
std::set<std::string> frameworks; std::set<std::string> frameworks;
std::set<std::string> rpaths; std::set<std::string> rpaths;
@ -54,4 +52,6 @@ private:
bool qt_plugins_called; bool qt_plugins_called;
}; };
} // namespace macDylibBundler
#endif #endif

View File

@ -4,6 +4,8 @@
#include "Utils.h" #include "Utils.h"
namespace macDylibBundler {
Settings::Settings() : overwrite_files(false), Settings::Settings() : overwrite_files(false),
overwrite_dir(false), overwrite_dir(false),
create_dir(false), create_dir(false),
@ -24,14 +26,13 @@ Settings::Settings() : overwrite_files(false),
Settings::~Settings() = default; Settings::~Settings() = default;
void Settings::appBundle(std::string path) void Settings::appBundle(std::string path) {
{
app_bundle = std::move(path); app_bundle = std::move(path);
char buffer[PATH_MAX]; char buffer[PATH_MAX];
if (realpath(app_bundle.c_str(), buffer)) if (realpath(app_bundle.c_str(), buffer))
app_bundle = buffer; app_bundle = buffer;
// fix path if needed so it ends with '/' // fix path if needed so it ends with '/'
if (app_bundle[app_bundle.size()-1] != '/') if (app_bundle[app_bundle.size() - 1] != '/')
app_bundle += "/"; app_bundle += "/";
std::string bundle_executable_path = app_bundle + "Contents/MacOS/" + bundleExecutableName(app_bundle); std::string bundle_executable_path = app_bundle + "Contents/MacOS/" + bundleExecutableName(app_bundle);
@ -47,7 +48,7 @@ void Settings::appBundle(std::string path)
dest_path = app_bundle + "Contents/" + stripLSlash(dest_folder); dest_path = app_bundle + "Contents/" + stripLSlash(dest_folder);
if (realpath(dest_path.c_str(), buffer)) if (realpath(dest_path.c_str(), buffer))
dest_path = buffer; dest_path = buffer;
if (dest_path[dest_path.size()-1] != '/') if (dest_path[dest_path.size() - 1] != '/')
dest_path += "/"; dest_path += "/";
} }
@ -59,7 +60,7 @@ void Settings::destFolder(std::string path)
char buffer[PATH_MAX]; char buffer[PATH_MAX];
if (realpath(dest_path.c_str(), buffer)) if (realpath(dest_path.c_str(), buffer))
dest_path = buffer; dest_path = buffer;
if (dest_path[dest_path.size()-1] != '/') if (dest_path[dest_path.size() - 1] != '/')
dest_path += "/"; dest_path += "/";
} }
@ -67,7 +68,7 @@ void Settings::destFolder(std::string path)
void Settings::insideLibPath(std::string p) void Settings::insideLibPath(std::string p)
{ {
inside_path = std::move(p); inside_path = std::move(p);
if (inside_path[inside_path.size()-1] != '/') if (inside_path[inside_path.size() - 1] != '/')
inside_path += "/"; inside_path += "/";
} }
@ -81,21 +82,21 @@ void Settings::addFileToFix(std::string path)
void Settings::ignorePrefix(std::string prefix) void Settings::ignorePrefix(std::string prefix)
{ {
if (prefix[prefix.size()-1] != '/') if (prefix[prefix.size() - 1] != '/')
prefix += "/"; prefix += "/";
prefixes_to_ignore.push_back(prefix); prefixes_to_ignore.push_back(prefix);
} }
bool Settings::isPrefixIgnored(const std::string& prefix) bool Settings::isPrefixIgnored(const std::string &prefix)
{ {
for (const auto& prefix_to_ignore : prefixes_to_ignore) { for (const auto &prefix_to_ignore : prefixes_to_ignore) {
if (prefix == prefix_to_ignore) if (prefix == prefix_to_ignore)
return true; return true;
} }
return false; return false;
} }
bool Settings::isPrefixBundled(const std::string& prefix) bool Settings::isPrefixBundled(const std::string &prefix)
{ {
if (!bundle_frameworks && prefix.find(".framework") != std::string::npos) if (!bundle_frameworks && prefix.find(".framework") != std::string::npos)
return false; return false;
@ -109,3 +110,5 @@ bool Settings::isPrefixBundled(const std::string& prefix)
return false; return false;
return true; return true;
} }
} // namespace macDylibBundler

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#ifndef DYLIBBUNDLER_SETTINGS_H #ifndef MACDYLIBBUNDLER_SETTINGS_H
#define DYLIBBUNDLER_SETTINGS_H #define MACDYLIBBUNDLER_SETTINGS_H
#include <cstdlib> #include <cstdlib>
#include <map> #include <map>
@ -13,71 +13,83 @@
#include <sys/types.h> #include <sys/types.h>
#endif #endif
using namespace std;
namespace macDylibBundler {
class Settings { class Settings {
public: public:
Settings(); Settings();
virtual ~Settings(); virtual ~Settings();
virtual bool isPrefixBundled(const std::string &prefix); virtual bool isPrefixBundled(const string &prefix);
virtual bool isPrefixIgnored(const std::string &prefix); virtual bool isPrefixIgnored(const string &prefix);
virtual void ignorePrefix(std::string prefix); virtual void ignorePrefix(string prefix);
virtual std::string appBundle() { return app_bundle; }
virtual void appBundle(std::string path); virtual string appBundle() { return app_bundle; }
virtual void appBundle(string path);
virtual bool appBundleProvided() { return !app_bundle.empty(); } virtual bool appBundleProvided() { return !app_bundle.empty(); }
virtual std::string destFolder() { return dest_path; }
virtual void destFolder(std::string path);
virtual std::string insideLibPath() { return inside_path; }
virtual void insideLibPath(std::string p);
virtual std::string executableFolder() { return app_bundle + "Contents/MacOS/"; }
virtual std::string frameworksFolder() { return app_bundle + "Contents/Frameworks/"; }
virtual std::string pluginsFolder() { return app_bundle + "Contents/PlugIns/"; }
virtual std::string resourcesFolder() { return app_bundle + "Contents/Resources/"; }
virtual std::vector<std::string> filesToFix() { return files; }
virtual void addFileToFix(std::string path);
virtual size_t filesToFixCount() { return files.size(); }
virtual std::vector<std::string> searchPaths() { return search_paths; } virtual string destFolder() { return dest_path; }
virtual void addSearchPath(const std::string& path) { search_paths.push_back(path); } virtual void destFolder(string path);
virtual string insideLibPath() { return inside_path; }
virtual void insideLibPath(string p);
virtual std::vector<std::string> userSearchPaths() { return user_search_paths; } virtual string executableFolder() { return app_bundle + "Contents/MacOS/"; }
virtual void addUserSearchPath(const std::string& path) { user_search_paths.push_back(path); } virtual string frameworksFolder() { return app_bundle + "Contents/Frameworks/"; }
virtual string pluginsFolder() { return app_bundle + "Contents/PlugIns/"; }
virtual string resourcesFolder() { return app_bundle + "Contents/Resources/"; }
virtual vector<string> filesToFix() { return files; }
virtual void addFileToFix(string path);
virtual vector<string> searchPaths() { return search_paths; }
virtual void addSearchPath(const string &path) { search_paths.push_back(path); }
virtual vector<string> userSearchPaths() { return user_search_paths; }
virtual void addUserSearchPath(const string &path) { user_search_paths.push_back(path); }
virtual bool canCreateDir() { return create_dir; } virtual bool canCreateDir() { return create_dir; }
virtual void canCreateDir(bool permission) { create_dir = permission; } virtual void canCreateDir(bool permission) { create_dir = permission; }
virtual bool canOverwriteDir() { return overwrite_dir; } virtual bool canOverwriteDir() { return overwrite_dir; }
virtual void canOverwriteDir(bool permission) { overwrite_dir = permission; } virtual void canOverwriteDir(bool permission) { overwrite_dir = permission; }
virtual bool canOverwriteFiles() { return overwrite_files; } virtual bool canOverwriteFiles() { return overwrite_files; }
virtual void canOverwriteFiles(bool permission) { overwrite_files = permission; } virtual void canOverwriteFiles(bool permission) { overwrite_files = permission; }
virtual bool bundleLibs() { return bundle_libs; } virtual bool bundleLibs() { return bundle_libs; }
virtual void bundleLibs(bool status) { bundle_libs = status; } virtual void bundleLibs(bool status) { bundle_libs = status; }
virtual bool bundleFrameworks() { return bundle_frameworks; } virtual bool bundleFrameworks() { return bundle_frameworks; }
virtual void bundleFrameworks(bool status) { bundle_frameworks = status; } virtual void bundleFrameworks(bool status) { bundle_frameworks = status; }
virtual bool quietOutput() { return quiet_output; } virtual bool quietOutput() { return quiet_output; }
virtual void quietOutput(bool status) { quiet_output = status; } virtual void quietOutput(bool status) { quiet_output = status; }
virtual bool verboseOutput() { return verbose_output; } virtual bool verboseOutput() { return verbose_output; }
virtual void verboseOutput(bool status) { verbose_output = status; } virtual void verboseOutput(bool status) { verbose_output = status; }
virtual bool missingPrefixes() { return missing_prefixes; } virtual bool missingPrefixes() { return missing_prefixes; }
virtual void missingPrefixes(bool status) { missing_prefixes = status; } virtual void missingPrefixes(bool status) { missing_prefixes = status; }
virtual std::string getFullPath(const std::string& rpath) { return rpath_to_fullpath[rpath]; } virtual string getFullPath(const string &rpath) { return rpath_to_fullpath[rpath]; }
virtual void rpathToFullPath(const std::string& rpath, const std::string& fullpath) { rpath_to_fullpath[rpath] = fullpath; } virtual void rpathToFullPath(const string &rpath, const string &fullpath)
virtual bool rpathFound(const std::string& rpath) { return rpath_to_fullpath.find(rpath) != rpath_to_fullpath.end(); } {
rpath_to_fullpath[rpath] = fullpath;
}
virtual bool rpathFound(const string &rpath)
{
return rpath_to_fullpath.find(rpath) != rpath_to_fullpath.end();
}
virtual std::vector<std::string> getRpathsForFile(const std::string& file) { return rpaths_per_file[file]; } virtual vector<string> getRpathsForFile(const string &file)
virtual void addRpathForFile(const std::string& file, const std::string& rpath) { rpaths_per_file[file].push_back(rpath); } {
virtual bool fileHasRpath(const std::string& file) { return rpaths_per_file.find(file) != rpaths_per_file.end(); } return rpaths_per_file[file];
}
virtual void addRpathForFile(const string &file, const string &rpath)
{
rpaths_per_file[file].push_back(rpath);
}
virtual bool fileHasRpath(const string &file)
{
return rpaths_per_file.find(file) != rpaths_per_file.end();
}
protected: private:
bool overwrite_files; bool overwrite_files;
bool overwrite_dir; bool overwrite_dir;
bool create_dir; bool create_dir;
@ -87,23 +99,25 @@ protected:
bool bundle_frameworks; bool bundle_frameworks;
bool missing_prefixes; bool missing_prefixes;
std::string dest_folder_str; string dest_folder_str;
std::string dest_folder_str_app; string dest_folder_str_app;
std::string dest_folder; string dest_folder;
std::string dest_path; string dest_path;
std::string inside_path_str; string inside_path_str;
std::string inside_path_str_app; string inside_path_str_app;
std::string inside_path; string inside_path;
std::string app_bundle; string app_bundle;
std::vector<std::string> prefixes_to_ignore; vector<string> prefixes_to_ignore;
std::vector<std::string> search_paths; vector<string> search_paths;
std::vector<std::string> files; vector<string> files;
std::vector<std::string> user_search_paths; vector<string> user_search_paths;
std::map<std::string, std::string> rpath_to_fullpath; map<string, string> rpath_to_fullpath;
std::map<std::string, std::vector<std::string>> rpaths_per_file; map<string, vector<string>> rpaths_per_file;
}; };
} // namespace macDylibBundler
#endif #endif

View File

@ -7,34 +7,36 @@
#include <unistd.h> #include <unistd.h>
std::string filePrefix(const std::string& in) namespace macDylibBundler {
std::string filePrefix(const std::string &in)
{ {
return in.substr(0, in.rfind('/')+1); return in.substr(0, in.rfind('/') + 1);
} }
std::string stripPrefix(const std::string& in) std::string stripPrefix(const std::string &in)
{ {
return in.substr(in.rfind('/')+1); return in.substr(in.rfind('/') + 1);
} }
std::string stripLSlash(const std::string& in) std::string stripLSlash(const std::string &in)
{ {
if (in[0] == '.' && in[1] == '/') if (in[0] == '.' && in[1] == '/')
return in.substr(2, in.size()); return in.substr(2, in.size());
return in; return in;
} }
std::string getFrameworkRoot(const std::string& in) std::string getFrameworkRoot(const std::string &in)
{ {
return in.substr(0, in.find(".framework")+10); return in.substr(0, in.find(".framework") + 10);
} }
std::string getFrameworkPath(const std::string& in) std::string getFrameworkPath(const std::string &in)
{ {
return in.substr(in.rfind(".framework/")+11); return in.substr(in.rfind(".framework/") + 11);
} }
void rtrim_in_place(std::string& s) void rtrim_in_place(std::string &s)
{ {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char c) { s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char c) {
return !std::isspace(c); return !std::isspace(c);
@ -47,11 +49,10 @@ std::string rtrim(std::string s)
return s; return s;
} }
void tokenize(const std::string& str, const char* delim, std::vector<std::string>* tokens) void tokenize(const std::string &str, const char *delim, std::vector<std::string> *tokens)
{ {
std::vector<std::string>& out = *tokens; std::vector<std::string> &out = *tokens;
std::string delimiters(delim); std::string delimiters(delim);
// skip delimiters at beginning // skip delimiters at beginning
std::string::size_type end = str.find_first_not_of(delimiters, 0); std::string::size_type end = str.find_first_not_of(delimiters, 0);
// find first non-delimiter // find first non-delimiter
@ -64,7 +65,7 @@ void tokenize(const std::string& str, const char* delim, std::vector<std::string
} }
} }
std::vector<std::string> lsDir(const std::string& path) std::vector<std::string> lsDir(const std::string &path)
{ {
std::string cmd = "/bin/ls " + path; std::string cmd = "/bin/ls " + path;
std::string output = systemOutput(cmd); std::string output = systemOutput(cmd);
@ -73,34 +74,34 @@ std::vector<std::string> lsDir(const std::string& path)
return files; return files;
} }
bool fileExists(const std::string& filename) bool fileExists(const std::string &filename)
{ {
if (access(filename.c_str(), F_OK) != -1) if (access(filename.c_str(), F_OK) != -1)
return true; return true;
const std::string delims = " \f\n\r\t\v"; const std::string delims = " \f\n\r\t\v";
std::string rtrimmed = filename.substr(0, filename.find_last_not_of(delims)+1); std::string rtrimmed = filename.substr(0, filename.find_last_not_of(delims) + 1);
std::string ftrimmed = rtrimmed.substr(rtrimmed.find_first_not_of(delims)); std::string ftrimmed = rtrimmed.substr(rtrimmed.find_first_not_of(delims));
if (access(ftrimmed.c_str(), F_OK) != -1) if (access(ftrimmed.c_str(), F_OK) != -1)
return true; return true;
return false; return false;
} }
bool isRpath(const std::string& path) bool isRpath(const std::string &path)
{ {
return path.find("@rpath") != std::string::npos || path.find("@loader_path") != std::string::npos; return path.find("@rpath") != std::string::npos || path.find("@loader_path") != std::string::npos;
} }
std::string bundleExecutableName(const std::string& app_bundle_path) std::string bundleExecutableName(const std::string &app_bundle_path)
{ {
std::string cmd = std::string("/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "); std::string cmd = std::string("/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' ");
cmd += app_bundle_path; cmd += app_bundle_path;
cmd += "Contents/Info.plist"; cmd += "Contents/Info.plist";
return rtrim(systemOutput(cmd)); return rtrim(systemOutput(cmd));
} }
std::string systemOutput(const std::string& cmd) std::string systemOutput(const std::string &cmd)
{ {
FILE* command_output = nullptr; FILE *command_output = nullptr;
char output[128]; char output[128];
int amount_read = 1; int amount_read = 1;
std::string full_output; std::string full_output;
@ -114,8 +115,7 @@ std::string systemOutput(const std::string& cmd)
amount_read = fread(output, 1, 127, command_output); amount_read = fread(output, 1, 127, command_output);
if (amount_read <= 0) { if (amount_read <= 0) {
break; break;
} } else {
else {
output[amount_read] = '\0'; output[amount_read] = '\0';
full_output += output; full_output += output;
} }
@ -132,68 +132,35 @@ std::string systemOutput(const std::string& cmd)
return full_output; return full_output;
} }
void otool(const std::string& flags, const std::string& file, std::vector<std::string>& lines) void otool(const std::string &flags, const std::string &file, std::vector<std::string> &lines)
{ {
std::string command = std::string("/usr/bin/otool ").append(flags).append(" ").append(file); std::string command = std::string("/usr/bin/otool ") + flags + " " + file;
std::string output = systemOutput(command); std::string output = systemOutput(command);
if (output.find("can't open file") != std::string::npos if (output.find("can't open file") != std::string::npos
|| output.find("No such file") != std::string::npos || output.find("No such file") != std::string::npos
|| output.find("at least one file must be specified") != std::string::npos || output.find("at least one file must be specified") != std::string::npos
|| output.empty()) { || output.empty()) {
std::cerr << "\n\n/!\\ ERROR: Cannot find file " << file << " to read its load commands\n"; std::cerr << "\n\n/!\\ ERROR: Cannot find file " << file << " to read its load commands\n";
exit(1); exit(1);
} }
tokenize(output, "\n", &lines); tokenize(output, "\n", &lines);
} }
void parseLoadCommands(const std::string& file, const std::string& cmd, const std::string& value, std::vector<std::string>& lines) void parseLoadCommands(const std::string &file, const std::map<std::string, std::string> &cmds_values,
std::map<std::string, std::vector<std::string>> &cmds_results)
{ {
std::vector<std::string> raw_lines; std::vector<std::string> raw_lines;
otool("-l", file, raw_lines); otool("-l", file, raw_lines);
bool searching = false; for (const auto &cmd_value : cmds_values) {
std::string cmd_line = std::string("cmd ").append(cmd);
std::string value_line = std::string(value).append(" ");
for (const auto& raw_line : raw_lines) {
if (raw_line.find(cmd_line) != std::string::npos) {
if (searching) {
std::cerr << "\n\n/!\\ ERROR: Failed to find " << value << " before next cmd\n";
exit(1);
}
searching = true;
}
else if (searching) {
size_t start_pos = raw_line.find(value_line);
if (start_pos == std::string::npos)
continue;
size_t start = start_pos + value.size() + 1; // exclude data label "|value| "
size_t end = std::string::npos;
if (value == "name" || value == "path") {
size_t end_pos = raw_line.find(" (");
if (end_pos == std::string::npos)
continue;
end = end_pos - start;
}
lines.push_back(raw_line.substr(start, end));
searching = false;
}
}
}
void parseLoadCommands(const std::string& file, const std::map<std::string,std::string>& cmds_values, std::map<std::string,std::vector<std::string>>& cmds_results)
{
std::vector<std::string> raw_lines;
otool("-l", file, raw_lines);
for (const auto& cmd_value : cmds_values) {
std::vector<std::string> lines; std::vector<std::string> lines;
std::string cmd = cmd_value.first; std::string cmd = cmd_value.first;
std::string value = cmd_value.second; std::string value = cmd_value.second;
std::string cmd_line = std::string("cmd ").append(cmd); std::string cmd_line = std::string("cmd ") + cmd;
std::string value_line = std::string(value).append(" "); std::string value_line = std::string(value) + " ";
bool searching = false; bool searching = false;
for (const auto& raw_line : raw_lines) { for (const auto &raw_line : raw_lines) {
if (raw_line.find(cmd_line) != std::string::npos) { if (raw_line.find(cmd_line) != std::string::npos) {
if (searching) { if (searching) {
std::cerr << "\n\n/!\\ ERROR: Failed to find " << value << " before next cmd\n"; std::cerr << "\n\n/!\\ ERROR: Failed to find " << value << " before next cmd\n";
@ -226,9 +193,11 @@ void createQtConf(std::string directory)
"Plugins = PlugIns\n" "Plugins = PlugIns\n"
"Imports = Resources/qml\n" "Imports = Resources/qml\n"
"Qml2Imports = Resources/qml\n"; "Qml2Imports = Resources/qml\n";
if (directory[directory.size()-1] != '/') if (directory[directory.size() - 1] != '/')
directory += "/"; directory += "/";
std::ofstream out(directory + "qt.conf"); std::ofstream out(directory + "qt.conf");
out << contents; out << contents;
out.close(); out.close();
} }
} //namespace macDylibBundler

View File

@ -1,33 +1,50 @@
#pragma once #pragma once
#ifndef DYLIBBUNDLER_UTILS_H #ifndef MACDYLIBBUNDLER_UTILS_H
#define DYLIBBUNDLER_UTILS_H #define MACDYLIBBUNDLER_UTILS_H
#include <map> #include <map>
#include <string> #include <string>
#include <vector> #include <vector>
std::string filePrefix(const std::string& in); namespace macDylibBundler {
std::string stripPrefix(const std::string& in);
std::string stripLSlash(const std::string& in);
std::string getFrameworkRoot(const std::string& in); std::string filePrefix(const std::string &in);
std::string getFrameworkPath(const std::string& in);
std::string stripPrefix(const std::string &in);
std::string stripLSlash(const std::string &in);
std::string getFrameworkRoot(const std::string &in);
std::string getFrameworkPath(const std::string &in);
void rtrim_in_place(std::string &s);
void rtrim_in_place(std::string& s);
std::string rtrim(std::string s); std::string rtrim(std::string s);
void tokenize(const std::string& str, const char* delimiters, std::vector<std::string>* tokens);
bool fileExists(const std::string& filename); void tokenize(const std::string &str, const char *delimiters, std::vector<std::string> *tokens);
bool isRpath(const std::string& path);
std::string bundleExecutableName(const std::string& app_bundle_path);
std::vector<std::string> lsDir(const std::string& path);
std::string systemOutput(const std::string& cmd);
void otool(const std::string& flags, const std::string& file, std::vector<std::string>& lines); bool fileExists(const std::string &filename);
void parseLoadCommands(const std::string& file, const std::string& cmd, const std::string& value, std::vector<std::string>& lines);
void parseLoadCommands(const std::string& file, const std::map<std::string,std::string>& cmds_values, std::map<std::string,std::vector<std::string>>& cmds_results); bool isRpath(const std::string &path);
std::string bundleExecutableName(const std::string &app_bundle_path);
std::vector<std::string> lsDir(const std::string &path);
std::string systemOutput(const std::string &cmd);
void otool(const std::string &flags, const std::string &file, std::vector<std::string> &lines);
void parseLoadCommands(const std::string &file, const std::string &cmd, const std::string &value,
std::vector<std::string> &lines);
void parseLoadCommands(const std::string &file, const std::map<std::string, std::string> &cmds_values,
std::map<std::string, std::vector<std::string>> &cmds_results);
void createQtConf(std::string directory); void createQtConf(std::string directory);
} // namespace macDylibBundler
#endif #endif

View File

@ -34,7 +34,7 @@ void showHelp()
int main(int argc, const char* argv[]) int main(int argc, const char* argv[])
{ {
DylibBundler* db = new DylibBundler(); macDylibBundler::DylibBundler* db = new macDylibBundler::DylibBundler();
// parse arguments // parse arguments
for (int i=0; i<argc; i++) { for (int i=0; i<argc; i++) {
if (strcmp(argv[i],"-a") == 0 || strcmp(argv[i],"--app") == 0) { if (strcmp(argv[i],"-a") == 0 || strcmp(argv[i],"--app") == 0) {
@ -116,17 +116,15 @@ int main(int argc, const char* argv[])
} }
} }
if (db->filesToFixCount() < 1) { const std::vector<std::string> files_to_fix = db->filesToFix();
if (files_to_fix.empty()) {
showHelp(); showHelp();
exit(0); exit(0);
} }
std::cout << "Collecting dependencies...\n"; std::cout << "Collecting dependencies...\n";
for (const auto& file_to_fix : files_to_fix)
const std::vector<std::string> files_to_fix = db->filesToFix();
for (const auto& file_to_fix : files_to_fix) {
db->collectDependenciesRpaths(file_to_fix); db->collectDependenciesRpaths(file_to_fix);
}
db->collectSubDependencies(); db->collectSubDependencies();
db->bundleDependencies(); db->bundleDependencies();