diff --git a/src/Dependency.cpp b/src/Dependency.cpp index 63b2dfd..3ac8849 100644 --- a/src/Dependency.cpp +++ b/src/Dependency.cpp @@ -13,7 +13,9 @@ #include "DylibBundler.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) { char buffer[PATH_MAX]; @@ -23,17 +25,15 @@ Dependency::Dependency(std::string path, const std::string& dependent_file, Dyli if (isRpath(path)) { original_file = db->searchFilenameInRpaths(path, dependent_file); - } - else if (realpath(path.c_str(), buffer)) { + } else if (realpath(path.c_str(), buffer)) { original_file = buffer; - } - else { + } else { warning_msg = "\n/!\\ WARNING: Cannot resolve path '" + path + "'\n"; original_file = path; } if (db->verboseOutput()) { - std::cout<< "** Dependency ctor **" << std::endl; + std::cout << "** Dependency ctor **" << std::endl; if (path != dependent_file) std::cout << " dependent file: " << dependent_file << std::endl; std::cout << " dependency path: " << path << std::endl; @@ -47,7 +47,7 @@ Dependency::Dependency(std::string path, const std::string& dependent_file, Dyli prefix = filePrefix(original_file); filename = stripPrefix(original_file); - if (!prefix.empty() && prefix[prefix.size()-1] != '/') + if (!prefix.empty() && prefix[prefix.size() - 1] != '/') prefix += "/"; // 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 - if (prefix.empty() || !fileExists(prefix+filename)) { + if (prefix.empty() || !fileExists(prefix + filename)) { std::vector search_paths = db->searchPaths(); if (search_paths.empty()) db->initSearchPaths(); // check if file is contained in one of the paths - for (const auto& search_path : search_paths) { - if (fileExists(search_path+filename)) { + for (const auto &search_path : search_paths) { + if (fileExists(search_path + filename)) { warning_msg += "FOUND " + filename + " in " + search_path + "\n"; prefix = search_path; db->missingPrefixes(true); @@ -92,7 +92,7 @@ Dependency::Dependency(std::string path, const std::string& dependent_file, Dyli if (!db->quietOutput()) std::cerr << "\n/!\\ WARNING: Dependency " << filename << " of " << dependent_file << " not found\n"; if (db->verboseOutput()) - std::cout << " path: " << (prefix+filename) << std::endl; + std::cout << " path: " << (prefix + filename) << std::endl; db->missingPrefixes(true); db->addSearchPath(db->getUserInputDirForFile(filename, dependent_file)); } @@ -110,16 +110,16 @@ std::string Dependency::InstallPath() const 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()) symlinks.push_back(path); } -bool Dependency::MergeIfIdentical(Dependency* dependency) +bool Dependency::MergeIfIdentical(Dependency *dependency) { if (dependency->OriginalFilename() == filename) { - for (const auto& symlink : symlinks) + for (const auto &symlink : symlinks) dependency->AddSymlink(symlink); return true; } @@ -129,7 +129,7 @@ bool Dependency::MergeIfIdentical(Dependency* dependency) void Dependency::Print() const { std::cout << "\n* " << filename << " from " << prefix << std::endl; - for (const auto& symlink : symlinks) + for (const auto &symlink : symlinks) std::cout << " symlink --> " << symlink << std::endl; } @@ -165,15 +165,17 @@ void Dependency::CopyToBundle() const 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()); - for (const auto& symlink : symlinks) + for (const auto &symlink : symlinks) db->changeInstallName(dependent_file, symlink, InnerPath()); if (!db->missingPrefixes()) return; db->changeInstallName(dependent_file, filename, InnerPath()); - for (const auto& symlink : symlinks) + for (const auto &symlink : symlinks) db->changeInstallName(dependent_file, symlink, InnerPath()); } + +} //namespace macDylibBundler \ No newline at end of file diff --git a/src/Dependency.h b/src/Dependency.h index 3d95ba4..76e9984 100644 --- a/src/Dependency.h +++ b/src/Dependency.h @@ -1,33 +1,34 @@ #pragma once -#ifndef DYLIBBUNDLER_DEPENDENCY_H -#define DYLIBBUNDLER_DEPENDENCY_H +#ifndef MACDYLIBBUNDLER_DEPENDENCY_H +#define MACDYLIBBUNDLER_DEPENDENCY_H #include #include +namespace macDylibBundler { + class DylibBundler; class Dependency { 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]] std::string Prefix() const { return prefix; } [[nodiscard]] std::string OriginalFilename() const { return filename; } [[nodiscard]] std::string OriginalPath() const { return prefix + filename; } - [[nodiscard]] std::string InnerPath() 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. - bool MergeIfIdentical(Dependency* dependency); + bool MergeIfIdentical(Dependency *dependency); + void Print() const; void CopyToBundle() const; - void FixDependentFile(const std::string& dependent_file) const; + + void FixDependentFile(const std::string &dependent_file) const; private: bool is_framework; @@ -40,7 +41,9 @@ private: // installation std::string new_name; - DylibBundler* db; + DylibBundler *db; }; #endif + +} // namespace macDylibBundler \ No newline at end of file diff --git a/src/DylibBundler.cpp b/src/DylibBundler.cpp index a3d9277..2f3b1ef 100644 --- a/src/DylibBundler.cpp +++ b/src/DylibBundler.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -15,23 +14,26 @@ #include "Dependency.h" #include "Utils.h" +namespace macDylibBundler { + DylibBundler::DylibBundler() : qt_plugins_called(false) {} + 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 bool in_deps = false; - for (auto& dep : deps) { + for (auto &dep : deps) { if (dependency->MergeIfIdentical(dep)) 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; - for (auto& dep : deps_per_file[dependent_file]) { + for (auto &dep : deps_per_file[dependent_file]) { if (dependency->MergeIfIdentical(dep)) 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); } -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)) return; @@ -64,7 +66,7 @@ void DylibBundler::collectDependenciesRpaths(const std::string& dependent_file) if (rpaths_collected.find(dependent_file) == rpaths_collected.end()) { auto rpath_results = cmds_results[rpath]; - for (const auto& rpath_result : rpath_results) { + for (const auto &rpath_result : rpath_results) { rpaths.insert(rpath_result); addRpathForFile(dependent_file, rpath_result); if (verboseOutput()) @@ -75,7 +77,7 @@ void DylibBundler::collectDependenciesRpaths(const std::string& dependent_file) if (deps_collected.find(dependent_file) == deps_collected.end()) { auto dylib_results = cmds_results[dylib]; - for (const auto& dylib_result : dylib_results) { + for (const auto &dylib_result : dylib_results) { // skip system/ignored prefixes if (isPrefixBundled(dylib_result)) addDependency(dylib_result, dependent_file); @@ -86,21 +88,22 @@ void DylibBundler::collectDependenciesRpaths(const std::string& dependent_file) void DylibBundler::collectSubDependencies() { - if (verboseOutput()) { - std::cout << "(pre sub) # OF FILES: " << filesToFixCount() << std::endl; - std::cout << "(pre sub) # OF DEPS: " << deps.size() << std::endl; - } + std::vector files_to_fix = filesToFix(); size_t dep_counter = 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) { deps_size = deps.size(); - for (size_t n=0; nOriginalPath(); if (verboseOutput()) std::cout << " (collect sub deps) original path: " << original_path << std::endl; if (isRpath(original_path)) original_path = searchFilenameInRpaths(original_path); - collectDependenciesRpaths(original_path); } // if no more dependencies were added on this iteration, stop searching @@ -109,7 +112,8 @@ void DylibBundler::collectSubDependencies() } 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; } 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); + } std::cout << "* Fixing dependencies on " << file_to_fix << "\n"; - std::vector dependencies = deps_per_file[file_to_fix]; + std::vector dependencies = deps_per_file[file_to_fix]; for (auto& dependency : dependencies) 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 rpaths_to_fix; if (!fileHasRpath(original_file)) @@ -137,10 +143,11 @@ void DylibBundler::fixRpathsOnFile(const std::string& original_file, const std:: rpaths_to_fix = getRpathsForFile(original_file); for (const auto& rpath_to_fix : rpaths_to_fix) { - std::string command = std::string("/usr/bin/install_name_tool -rpath ").append(rpath_to_fix); - command += std::string(" ").append(insideLibPath()).append(" ").append(file_to_fix); + std::string command = std::string("/usr/bin/install_name_tool -rpath "); + command += rpath_to_fix + " " + insideLibPath() + " " + file_to_fix; 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); } } @@ -148,19 +155,19 @@ void DylibBundler::fixRpathsOnFile(const std::string& original_file, const std:: void DylibBundler::bundleDependencies() { - for (const auto& dep : deps) + for (const auto &dep : deps) dep->Print(); std::cout << "\n"; if (verboseOutput()) { std::cout << "rpaths:" << std::endl; - for (const auto& rpath : rpaths) + for (const auto &rpath : rpaths) std::cout << "* " << rpath << std::endl; } // copy & fix up dependencies if (bundleLibs()) { createDestDir(); - for (const auto& dep : deps) { + for (const auto &dep : deps) { dep->CopyToBundle(); changeLibPathsOnFile(dep->InstallPath()); fixRpathsOnFile(dep->OriginalPath(), dep->InstallPath()); @@ -168,7 +175,7 @@ void DylibBundler::bundleDependencies() } // fix up input files const auto files = filesToFix(); - for (const auto& file : files) { + for (const auto &file : files) { changeLibPathsOnFile(file); fixRpathsOnFile(file, file); } @@ -190,7 +197,7 @@ void DylibBundler::bundleQtPlugins() bool qtWebViewFound = false; std::string original_file; - for (const auto& framework : frameworks) { + for (const auto &framework : frameworks) { if (framework.find("QtCore") != std::string::npos) { qtCoreFound = true; original_file = framework; @@ -225,17 +232,17 @@ void DylibBundler::bundleQtPlugins() createQtConf(resourcesFolder()); qt_plugins_called = true; - const auto fixupPlugin = [&](const std::string& plugin) { + const auto fixupPlugin = [&](const std::string &plugin) { std::string dest = pluginsFolder(); 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_prefix = filePrefix(prefix.substr(0, prefix.size() - 1)); std::string qt_plugins_prefix = qt_prefix + "plugins/"; if (fileExists(qt_plugins_prefix + plugin)) { mkdir(dest + plugin); copyFile(qt_plugins_prefix + plugin, dest); std::vector files = lsDir(dest + plugin + "/"); - for (const auto& file : files) { + for (const auto &file : files) { std::string file_to_fix = dest + plugin + "/" + file; std::string new_rpath = std::string("@rpath/") + plugin + "/" + file; addFileToFix(file_to_fix); @@ -247,7 +254,7 @@ void DylibBundler::bundleQtPlugins() 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_prefix = filePrefix(prefix.substr(0, prefix.size() - 1)); std::string qt_plugins_prefix = qt_prefix + "plugins/"; std::string dest = pluginsFolder(); @@ -292,11 +299,11 @@ void DylibBundler::bundleQtPlugins() 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 search_paths = userSearchPaths(); - for (auto& search_path : search_paths) { - if (!search_path.empty() && search_path[search_path.size()-1] != '/') + for (auto &search_path : search_paths) { + if (!search_path.empty() && search_path[search_path.size() - 1] != '/') search_path += "/"; if (fileExists(search_path + filename)) { if (!quietOutput()) { @@ -318,14 +325,13 @@ std::string DylibBundler::getUserInputDirForFile(const std::string& filename, co if (prefix == "quit" || prefix == "exit" || prefix == "abort") exit(1); - if (!prefix.empty() && prefix[prefix.size()-1] != '/') + if (!prefix.empty() && prefix[prefix.size() - 1] != '/') prefix += "/"; - if (!fileExists(prefix+filename)) { - std::cerr << (prefix+filename) << " does not exist. Try again...\n"; + if (!fileExists(prefix + filename)) { + std::cerr << (prefix + filename) << " does not exist. Try again...\n"; continue; - } - else { - std::cerr << (prefix+filename) << " was found\n" + } else { + std::cerr << (prefix + filename) << " was found\n" << "/!\\ WARNING: dylibbundler MAY NOT CORRECTLY HANDLE THIS DEPENDENCY: Check the executable with 'otool -L'\n"; addUserSearchPath(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 (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::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]; const auto check_path = [&](std::string path) { @@ -363,8 +369,7 @@ std::string DylibBundler::searchFilenameInRpaths(const std::string& rpath_file, rpathToFullPath(rpath_file, fullpath); return true; } - } - else if (path.find("@rpath") != std::string::npos) { + } else if (path.find("@rpath") != std::string::npos) { if (appBundleProvided()) { std::string pathE = std::regex_replace(path, std::regex("@rpath/"), executableFolder()); if (verboseOutput()) @@ -392,11 +397,10 @@ std::string DylibBundler::searchFilenameInRpaths(const std::string& rpath_file, // fullpath previously stored if (rpathFound(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); for (auto rpath : rpaths_for_file) { - if (rpath[rpath.size()-1] != '/') + if (rpath[rpath.size() - 1] != '/') rpath += "/"; std::string path = rpath + suffix; if (verboseOutput()) @@ -408,8 +412,8 @@ std::string DylibBundler::searchFilenameInRpaths(const std::string& rpath_file, if (fullpath.empty()) { std::vector search_paths = searchPaths(); - for (const auto& search_path : search_paths) { - if (fileExists(search_path+suffix)) { + for (const auto &search_path : search_paths) { + if (fileExists(search_path + suffix)) { if (verboseOutput()) std::cout << "FOUND " << suffix << " in " << search_path << std::endl; 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"; if (realpath(fullpath.c_str(), fullpath_buffer)) fullpath = fullpath_buffer; - } - else if (verboseOutput()) { + } else if (verboseOutput()) { std::cout << " ** rpath fullpath: " << fullpath << std::endl; } - } - else if (verboseOutput()) { + } else if (verboseOutput()) { std::cout << " ** rpath fullpath: " << fullpath << std::endl; } 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); } @@ -450,13 +452,13 @@ void DylibBundler::initSearchPaths() searchPaths = dyldLibPath; dyldLibPath = std::getenv("DYLD_FALLBACK_FRAMEWORK_PATH"); if (dyldLibPath != nullptr) { - if (!searchPaths.empty() && searchPaths[searchPaths.size()-1] != ':') + if (!searchPaths.empty() && searchPaths[searchPaths.size() - 1] != ':') searchPaths += ":"; searchPaths += dyldLibPath; } dyldLibPath = std::getenv("DYLD_FALLBACK_LIBRARY_PATH"); if (dyldLibPath != nullptr) { - if (!searchPaths.empty() && searchPaths[searchPaths.size()-1] != ':') + if (!searchPaths.empty() && searchPaths[searchPaths.size() - 1] != ':') searchPaths += ":"; searchPaths += dyldLibPath; } @@ -464,7 +466,7 @@ void DylibBundler::initSearchPaths() std::stringstream ss(searchPaths); std::string item; while (std::getline(ss, item, ':')) { - if (item[item.size()-1] != '/') + if (item[item.size() - 1] != '/') item += "/"; addSearchPath(item); } @@ -480,7 +482,7 @@ void DylibBundler::createDestDir() bool dest_exists = fileExists(dest_folder); if (dest_exists && canOverwriteDir()) { 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) { std::cerr << "\n\n/!\\ ERROR: An error occured while attempting to overwrite destination folder\n"; exit(1); @@ -495,34 +497,36 @@ void DylibBundler::createDestDir() std::cerr << "\n/!\\ ERROR: An error occured while creating " << dest_folder << std::endl; exit(1); } - } - else { - std::cerr << "\n\n/!\\ ERROR: Destination folder does not exist. Create it or pass the '-cd' or '-od' flag\n"; + } else { + std::cerr + << "\n\n/!\\ ERROR: Destination folder does not exist. Create it or pass the '-cd' or '-od' flag\n"; 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) { - 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); } } -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); +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 "); + command += old_name + " " + new_name + " " + binary_file; if (systemp(command) != 0) { std::cerr << "\n\nError: An error occured while trying to fix dependencies of " << binary_file << std::endl; 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(); if (fileExists(to) && !overwrite) { @@ -532,42 +536,41 @@ void DylibBundler::copyFile(const std::string& from, const std::string& to) // copy file/directory std::string overwrite_permission = std::string(overwrite ? "-f " : "-n "); - std::string command = std::string("/bin/cp -R ").append(overwrite_permission); - command.append(from).append(" ").append(to); + std::string command = std::string("/bin/cp -R ") + overwrite_permission + from + " " + to; if (from != to && systemp(command) != 0) { std::cerr << "\n\nError: An error occured while trying to copy file " << from << " to " << to << std::endl; exit(1); } // 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) { std::cerr << "\n\nError: An error occured while trying to set write permissions on file " << to << std::endl; 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 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) { std::cerr << "\n\nError: An error occured while trying to delete " << path << std::endl; exit(1); } } -void DylibBundler::deleteFile(const std::string& path) +void DylibBundler::deleteFile(const std::string &path) { bool overwrite = canOverwriteFiles(); deleteFile(path, overwrite); } -bool DylibBundler::mkdir(const std::string& path) +bool DylibBundler::mkdir(const std::string &path) { if (verboseOutput()) 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) { std::cerr << "\n/!\\ ERROR: An error occured while creating " << path << std::endl; return false; @@ -575,9 +578,11 @@ bool DylibBundler::mkdir(const std::string& path) return true; } -int DylibBundler::systemp(const std::string& cmd) +int DylibBundler::systemp(const std::string &cmd) { if (!quietOutput()) std::cout << " " << cmd << "\n"; return system(cmd.c_str()); } + +} // namespace macDylibBundler diff --git a/src/DylibBundler.h b/src/DylibBundler.h index 9d27088..bd0d7f1 100644 --- a/src/DylibBundler.h +++ b/src/DylibBundler.h @@ -1,7 +1,7 @@ #pragma once -#ifndef DYLIBBUNDLER_DYLIBBUNDLER_H -#define DYLIBBUNDLER_DYLIBBUNDLER_H +#ifndef MACDYLIBBUNDLER_DYLIBBUNDLER_H +#define MACDYLIBBUNDLER_DYLIBBUNDLER_H #include #include @@ -10,11 +10,14 @@ #include "Settings.h" +namespace macDylibBundler { + class Dependency; class DylibBundler : public Settings { public: DylibBundler(); + ~DylibBundler() override; void addDependency(const std::string &path, const std::string &dependent_file); @@ -25,28 +28,23 @@ public: void bundleDependencies(); void bundleQtPlugins(); - 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); - - // check the same paths the system would search for dylibs + 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); void initSearchPaths(); void createDestDir(); - - 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 copyFile(const std::string& from, const std::string& to); - void deleteFile(const std::string& path, bool overwrite); - void deleteFile(const std::string& path); - bool mkdir(const std::string& path); - + 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 copyFile(const std::string &from, const std::string &to); + void deleteFile(const std::string &path, bool overwrite); + 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 - int systemp(const std::string& cmd); + int systemp(const std::string &cmd); private: - std::vector deps; - std::map> deps_per_file; + std::vector deps; + std::map> deps_per_file; std::map deps_collected; std::set frameworks; std::set rpaths; @@ -54,4 +52,6 @@ private: bool qt_plugins_called; }; +} // namespace macDylibBundler + #endif diff --git a/src/Settings.cpp b/src/Settings.cpp index 8dd51ce..0f00487 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -4,6 +4,8 @@ #include "Utils.h" +namespace macDylibBundler { + Settings::Settings() : overwrite_files(false), overwrite_dir(false), create_dir(false), @@ -24,14 +26,13 @@ Settings::Settings() : overwrite_files(false), Settings::~Settings() = default; -void Settings::appBundle(std::string path) -{ +void Settings::appBundle(std::string path) { app_bundle = std::move(path); char buffer[PATH_MAX]; if (realpath(app_bundle.c_str(), buffer)) app_bundle = buffer; // fix path if needed so it ends with '/' - if (app_bundle[app_bundle.size()-1] != '/') + if (app_bundle[app_bundle.size() - 1] != '/') 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); if (realpath(dest_path.c_str(), buffer)) dest_path = buffer; - if (dest_path[dest_path.size()-1] != '/') + if (dest_path[dest_path.size() - 1] != '/') dest_path += "/"; } @@ -59,7 +60,7 @@ void Settings::destFolder(std::string path) char buffer[PATH_MAX]; if (realpath(dest_path.c_str(), buffer)) dest_path = buffer; - if (dest_path[dest_path.size()-1] != '/') + if (dest_path[dest_path.size() - 1] != '/') dest_path += "/"; } @@ -67,7 +68,7 @@ void Settings::destFolder(std::string path) void Settings::insideLibPath(std::string p) { inside_path = std::move(p); - if (inside_path[inside_path.size()-1] != '/') + if (inside_path[inside_path.size() - 1] != '/') inside_path += "/"; } @@ -81,21 +82,21 @@ void Settings::addFileToFix(std::string path) void Settings::ignorePrefix(std::string prefix) { - if (prefix[prefix.size()-1] != '/') + if (prefix[prefix.size() - 1] != '/') 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) return true; } 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) return false; @@ -109,3 +110,5 @@ bool Settings::isPrefixBundled(const std::string& prefix) return false; return true; } + +} // namespace macDylibBundler diff --git a/src/Settings.h b/src/Settings.h index 7b4a2d9..9aadf28 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -1,7 +1,7 @@ #pragma once -#ifndef DYLIBBUNDLER_SETTINGS_H -#define DYLIBBUNDLER_SETTINGS_H +#ifndef MACDYLIBBUNDLER_SETTINGS_H +#define MACDYLIBBUNDLER_SETTINGS_H #include #include @@ -13,71 +13,83 @@ #include #endif +using namespace std; +namespace macDylibBundler { + class Settings { public: Settings(); + virtual ~Settings(); - virtual bool isPrefixBundled(const std::string &prefix); - virtual bool isPrefixIgnored(const std::string &prefix); - virtual void ignorePrefix(std::string prefix); - virtual std::string appBundle() { return app_bundle; } - virtual void appBundle(std::string path); + virtual bool isPrefixBundled(const string &prefix); + virtual bool isPrefixIgnored(const string &prefix); + virtual void ignorePrefix(string prefix); + + virtual string appBundle() { return app_bundle; } + virtual void appBundle(string path); 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 filesToFix() { return files; } - virtual void addFileToFix(std::string path); - virtual size_t filesToFixCount() { return files.size(); } - virtual std::vector searchPaths() { return search_paths; } - virtual void addSearchPath(const std::string& path) { search_paths.push_back(path); } + virtual string destFolder() { return dest_path; } + virtual void destFolder(string path); + virtual string insideLibPath() { return inside_path; } + virtual void insideLibPath(string p); - virtual std::vector userSearchPaths() { return user_search_paths; } - virtual void addUserSearchPath(const std::string& path) { user_search_paths.push_back(path); } + virtual string executableFolder() { return app_bundle + "Contents/MacOS/"; } + 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 filesToFix() { return files; } + virtual void addFileToFix(string path); + + virtual vector searchPaths() { return search_paths; } + virtual void addSearchPath(const string &path) { search_paths.push_back(path); } + virtual vector userSearchPaths() { return user_search_paths; } + virtual void addUserSearchPath(const string &path) { user_search_paths.push_back(path); } virtual bool canCreateDir() { return create_dir; } virtual void canCreateDir(bool permission) { create_dir = permission; } - virtual bool canOverwriteDir() { return overwrite_dir; } virtual void canOverwriteDir(bool permission) { overwrite_dir = permission; } - virtual bool canOverwriteFiles() { return overwrite_files; } virtual void canOverwriteFiles(bool permission) { overwrite_files = permission; } - virtual bool bundleLibs() { return bundle_libs; } virtual void bundleLibs(bool status) { bundle_libs = status; } - virtual bool bundleFrameworks() { return bundle_frameworks; } virtual void bundleFrameworks(bool status) { bundle_frameworks = status; } - virtual bool quietOutput() { return quiet_output; } virtual void quietOutput(bool status) { quiet_output = status; } - virtual bool verboseOutput() { return verbose_output; } virtual void verboseOutput(bool status) { verbose_output = status; } virtual bool missingPrefixes() { return missing_prefixes; } virtual void missingPrefixes(bool status) { missing_prefixes = status; } - virtual std::string getFullPath(const std::string& rpath) { return rpath_to_fullpath[rpath]; } - virtual void rpathToFullPath(const std::string& rpath, const std::string& fullpath) { rpath_to_fullpath[rpath] = fullpath; } - virtual bool rpathFound(const std::string& rpath) { return rpath_to_fullpath.find(rpath) != rpath_to_fullpath.end(); } + virtual string getFullPath(const string &rpath) { return rpath_to_fullpath[rpath]; } + virtual void rpathToFullPath(const string &rpath, const string &fullpath) + { + rpath_to_fullpath[rpath] = fullpath; + } + virtual bool rpathFound(const string &rpath) + { + return rpath_to_fullpath.find(rpath) != rpath_to_fullpath.end(); + } - virtual std::vector getRpathsForFile(const std::string& file) { return rpaths_per_file[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(); } + virtual vector getRpathsForFile(const string &file) + { + 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_dir; bool create_dir; @@ -87,23 +99,25 @@ protected: bool bundle_frameworks; bool missing_prefixes; - std::string dest_folder_str; - std::string dest_folder_str_app; - std::string dest_folder; - std::string dest_path; + string dest_folder_str; + string dest_folder_str_app; + string dest_folder; + string dest_path; - std::string inside_path_str; - std::string inside_path_str_app; - std::string inside_path; + string inside_path_str; + string inside_path_str_app; + string inside_path; - std::string app_bundle; - std::vector prefixes_to_ignore; - std::vector search_paths; - std::vector files; + string app_bundle; + vector prefixes_to_ignore; + vector search_paths; + vector files; - std::vector user_search_paths; - std::map rpath_to_fullpath; - std::map> rpaths_per_file; + vector user_search_paths; + map rpath_to_fullpath; + map> rpaths_per_file; }; +} // namespace macDylibBundler + #endif diff --git a/src/Utils.cpp b/src/Utils.cpp index f3db510..f94f649 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -7,34 +7,36 @@ #include -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] == '/') return in.substr(2, in.size()); 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) { return !std::isspace(c); @@ -47,11 +49,10 @@ std::string rtrim(std::string s) return s; } -void tokenize(const std::string& str, const char* delim, std::vector* tokens) +void tokenize(const std::string &str, const char *delim, std::vector *tokens) { - std::vector& out = *tokens; + std::vector &out = *tokens; std::string delimiters(delim); - // skip delimiters at beginning std::string::size_type end = str.find_first_not_of(delimiters, 0); // find first non-delimiter @@ -64,7 +65,7 @@ void tokenize(const std::string& str, const char* delim, std::vector lsDir(const std::string& path) +std::vector lsDir(const std::string &path) { std::string cmd = "/bin/ls " + path; std::string output = systemOutput(cmd); @@ -73,34 +74,34 @@ std::vector lsDir(const std::string& path) return files; } -bool fileExists(const std::string& filename) +bool fileExists(const std::string &filename) { if (access(filename.c_str(), F_OK) != -1) return true; 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)); if (access(ftrimmed.c_str(), F_OK) != -1) return true; 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; } -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' "); - cmd += app_bundle_path; - cmd += "Contents/Info.plist"; + cmd += app_bundle_path; + cmd += "Contents/Info.plist"; 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]; int amount_read = 1; std::string full_output; @@ -114,8 +115,7 @@ std::string systemOutput(const std::string& cmd) amount_read = fread(output, 1, 127, command_output); if (amount_read <= 0) { break; - } - else { + } else { output[amount_read] = '\0'; full_output += output; } @@ -132,68 +132,35 @@ std::string systemOutput(const std::string& cmd) return full_output; } -void otool(const std::string& flags, const std::string& file, std::vector& lines) +void otool(const std::string &flags, const std::string &file, std::vector &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); if (output.find("can't open 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.empty()) { + || output.find("No such file") != std::string::npos + || output.find("at least one file must be specified") != std::string::npos + || output.empty()) { std::cerr << "\n\n/!\\ ERROR: Cannot find file " << file << " to read its load commands\n"; exit(1); } tokenize(output, "\n", &lines); } -void parseLoadCommands(const std::string& file, const std::string& cmd, const std::string& value, std::vector& lines) +void parseLoadCommands(const std::string &file, const std::map &cmds_values, + std::map> &cmds_results) { std::vector raw_lines; otool("-l", file, raw_lines); - bool searching = false; - 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& cmds_values, std::map>& cmds_results) -{ - std::vector raw_lines; - otool("-l", file, raw_lines); - - for (const auto& cmd_value : cmds_values) { + for (const auto &cmd_value : cmds_values) { std::vector lines; std::string cmd = cmd_value.first; std::string value = cmd_value.second; - std::string cmd_line = std::string("cmd ").append(cmd); - std::string value_line = std::string(value).append(" "); + std::string cmd_line = std::string("cmd ") + cmd; + std::string value_line = std::string(value) + " "; 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 (searching) { 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" "Imports = Resources/qml\n" "Qml2Imports = Resources/qml\n"; - if (directory[directory.size()-1] != '/') + if (directory[directory.size() - 1] != '/') directory += "/"; std::ofstream out(directory + "qt.conf"); out << contents; out.close(); } + +} //namespace macDylibBundler \ No newline at end of file diff --git a/src/Utils.h b/src/Utils.h index 7afe9b1..02699d0 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -1,33 +1,50 @@ #pragma once -#ifndef DYLIBBUNDLER_UTILS_H -#define DYLIBBUNDLER_UTILS_H +#ifndef MACDYLIBBUNDLER_UTILS_H +#define MACDYLIBBUNDLER_UTILS_H #include #include #include -std::string filePrefix(const std::string& in); -std::string stripPrefix(const std::string& in); -std::string stripLSlash(const std::string& in); +namespace macDylibBundler { -std::string getFrameworkRoot(const std::string& in); -std::string getFrameworkPath(const std::string& in); +std::string filePrefix(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); -void tokenize(const std::string& str, const char* delimiters, std::vector* tokens); -bool fileExists(const std::string& filename); -bool isRpath(const std::string& path); -std::string bundleExecutableName(const std::string& app_bundle_path); -std::vector lsDir(const std::string& path); -std::string systemOutput(const std::string& cmd); +void tokenize(const std::string &str, const char *delimiters, std::vector *tokens); -void otool(const std::string& flags, const std::string& file, std::vector& lines); -void parseLoadCommands(const std::string& file, const std::string& cmd, const std::string& value, std::vector& lines); -void parseLoadCommands(const std::string& file, const std::map& cmds_values, std::map>& cmds_results); +bool fileExists(const std::string &filename); + +bool isRpath(const std::string &path); + +std::string bundleExecutableName(const std::string &app_bundle_path); + +std::vector lsDir(const std::string &path); + +std::string systemOutput(const std::string &cmd); + +void otool(const std::string &flags, const std::string &file, std::vector &lines); + +void parseLoadCommands(const std::string &file, const std::string &cmd, const std::string &value, + std::vector &lines); + +void parseLoadCommands(const std::string &file, const std::map &cmds_values, + std::map> &cmds_results); void createQtConf(std::string directory); +} // namespace macDylibBundler + #endif diff --git a/src/main.cpp b/src/main.cpp index 6058b40..413dd2c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -34,7 +34,7 @@ void showHelp() int main(int argc, const char* argv[]) { - DylibBundler* db = new DylibBundler(); + macDylibBundler::DylibBundler* db = new macDylibBundler::DylibBundler(); // parse arguments for (int i=0; ifilesToFixCount() < 1) { + const std::vector files_to_fix = db->filesToFix(); + if (files_to_fix.empty()) { showHelp(); exit(0); } std::cout << "Collecting dependencies...\n"; - - const std::vector files_to_fix = db->filesToFix(); - for (const auto& file_to_fix : files_to_fix) { + for (const auto& file_to_fix : files_to_fix) db->collectDependenciesRpaths(file_to_fix); - } db->collectSubDependencies(); db->bundleDependencies();