diff --git a/src/Dependency.cpp b/src/Dependency.cpp index 00ebd79..37c8c09 100644 --- a/src/Dependency.cpp +++ b/src/Dependency.cpp @@ -27,6 +27,7 @@ std::vector paths; // initialize the dylib search paths void initSearchPaths() { + std::cout << "**** RUNNING initSearchPaths() ****\n"; // check the same paths the system would search for dylibs std::string searchPaths; char *dyldLibPath = std::getenv("DYLD_LIBRARY_PATH"); @@ -67,12 +68,12 @@ Dependency::Dependency(std::string path) : is_framework(false) if (isRpath(path)) { original_file = searchFilenameInRpaths(path); } - else if (!realpath(rtrim(path).c_str(), original_file_buffer)) { - warning_msg = "\n/!\\ WARNING: Cannot resolve path '" + path + "'\n"; - original_file = path; + else if (realpath(rtrim(path).c_str(), original_file_buffer)) { + original_file = original_file_buffer; } else { - original_file = original_file_buffer; + warning_msg = "\n/!\\ WARNING: Cannot resolve path '" + path + "'\n"; + original_file = path; } // check if given path is a symlink @@ -92,12 +93,16 @@ Dependency::Dependency(std::string path) : is_framework(false) if (getOriginalPath().find(".framework") != std::string::npos) { is_framework = true; - original_file = path; std::string framework_root = getFrameworkRoot(original_file); std::string framework_path = getFrameworkPath(original_file); std::string framework_name = stripPrefix(framework_root); filename = framework_name + "/" + framework_path; prefix = filePrefix(framework_root); + if (Settings::verboseOutput()) { + std::cout << "framework root: " << framework_root << std::endl; + std::cout << "framework path: " << framework_path << std::endl; + std::cout << "framework name: " << framework_name << std::endl; + } } // check if the lib is in a known location @@ -179,30 +184,18 @@ void Dependency::copyYourself() std::string original_path = getOriginalPath(); std::string dest_path = getInstallPath(); std::string inner_path = getInnerPath(); - std::string install_path = dest_path; - - if (Settings::verboseOutput()) - std::cout << "original path: " << original_path << std::endl; + std::string install_path = getInstallPath(); if (is_framework) { - std::string framework_root = getFrameworkRoot(original_path); - std::string framework_path = getFrameworkPath(original_path); - std::string framework_name = stripPrefix(framework_root); - if (Settings::verboseOutput()) { - std::cout << "framework root: " << framework_root << std::endl; - std::cout << "framework path: " << framework_path << std::endl; - std::cout << "framework name: " << framework_name << std::endl; - } - original_path = framework_root; - dest_path = Settings::destFolder() + framework_name; - inner_path = Settings::insideLibPath() + framework_name + "/" + framework_path; - install_path = dest_path + "/" + framework_path; + original_path = getFrameworkRoot(original_path); + dest_path = Settings::destFolder() + stripPrefix(original_path); } if (Settings::verboseOutput()) { - std::cout << "inner path: " << inner_path << std::endl; - std::cout << "dest_path: " << dest_path << std::endl; - std::cout << "install path: " << install_path << std::endl; + std::cout << "original path: " << original_path << std::endl; + std::cout << "inner path: " << inner_path << std::endl; + std::cout << "dest_path: " << dest_path << std::endl; + std::cout << "install path: " << install_path << std::endl; } copyFile(original_path, dest_path); @@ -216,54 +209,30 @@ void Dependency::copyYourself() headers_realpath = buffer; if (Settings::verboseOutput()) - std::cout << "headers path: " << headers_realpath << std::endl; + std::cout << "headers path: " << headers_realpath << std::endl; deleteFile(headers_path, true); deleteFile(headers_realpath, true); } // fix the lib's inner name - std::string command = std::string("install_name_tool -id ") + inner_path + " " + install_path; - if (systemp(command) != 0) { - std::cerr << "\n\nError: An error occured while trying to change identity of library " << install_path << "\n"; - exit(1); - } + changeId(install_path, inner_path); } void Dependency::fixFileThatDependsOnMe(std::string file_to_fix) { // for main lib file - std::string command = std::string("install_name_tool -change ") + getOriginalPath() + " " + getInnerPath() + " " + file_to_fix; - if (systemp(command) != 0) { - std::cerr << "\n\nError: An error occured while trying to fix dependencies of " << file_to_fix << "\n"; - exit(1); - } - + changeInstallName(file_to_fix, getOriginalPath(), getInnerPath()); // for symlinks - for (size_t n=0; n #include +#include #include #include #include @@ -28,10 +29,9 @@ void changeLibPathsOnFile(std::string file_to_fix) std::cout << "* Fixing dependencies on " << file_to_fix << "\n"; - std::vector deps_in_file = deps_per_file[file_to_fix]; - const int dep_amount = deps_in_file.size(); + const int dep_amount = deps_per_file[file_to_fix].size(); for (size_t n=0; n::iterator it = frameworks.begin(); it != frameworks.end(); ++it) { + std::string framework = *it; + if (framework.find("QtCore") != std::string::npos) { + qtCoreFound = true; + original_file = framework; + } + if (framework.find("QtNetwork") != std::string::npos) + qtNetworkFound = true; + if (framework.find("QtSql") != std::string::npos) + qtSqlFound = true; + if (framework.find("QtSvg") != std::string::npos) + qtSvgFound = true; + if (framework.find("QtMultimedia") != std::string::npos) + qtMultimediaFound = true; + if (framework.find("Qt3DRender") != std::string::npos) + qt3dRenderFound = true; + if (framework.find("Qt3DQuickRender") != std::string::npos) + qt3dQuickRenderFound = true; + if (framework.find("QtPositioning") != std::string::npos) + qtPositioningFound = true; + if (framework.find("QtLocation") != std::string::npos) + qtLocationFound = true; + } + + if (!qtCoreFound) + return; + + createQtConf(Settings::resourcesFolder()); + + std::string framework_root = getFrameworkRoot(original_file); + std::string prefix = filePrefix(framework_root); + std::string qt_prefix = filePrefix(prefix.substr(0, prefix.size()-1)); + std::string qt_plugins_prefix = qt_prefix + "plugins/"; + std::string dest = Settings::pluginsFolder(); + + auto fixupPlugin = [original_file,dest](std::string plugin) { + std::string framework_root = getFrameworkRoot(original_file); + std::string prefix = filePrefix(framework_root); + std::string qt_prefix = filePrefix(prefix.substr(0, prefix.size()-1)); + std::string qt_plugins_prefix = qt_prefix + "plugins/"; + mkdir(dest + plugin); + copyFile(qt_plugins_prefix + plugin, dest); + std::vector files = lsDir(dest + plugin+"/"); + for (const auto& file : files) { + Settings::addFileToFix(dest + plugin+"/"+file); + collectDependencies(dest + plugin+"/"+file); + changeId(dest + plugin+"/"+file, "@rpath/" + plugin+"/"+file); + } + }; + + mkdir(dest + "platforms"); + copyFile(qt_plugins_prefix + "platforms/libqcocoa.dylib", dest + "platforms"); + Settings::addFileToFix(dest + "platforms/libqcocoa.dylib"); + collectDependencies(dest + "platforms/libqcocoa.dylib"); + + fixupPlugin("printsupport"); + fixupPlugin("styles"); + fixupPlugin("imageformats"); + if (!qtSvgFound) + systemp("rm -f " + dest + "imageformats/libqsvg.dylib"); + if (qtNetworkFound) + fixupPlugin("bearer"); + if (qtSqlFound) + fixupPlugin("sqldrivers"); + if (qtMultimediaFound) { + fixupPlugin("mediaservice"); + fixupPlugin("audio"); + } + if (qt3dRenderFound) { + fixupPlugin("sceneparsers"); + fixupPlugin("geometryloaders"); + } + if (qt3dQuickRenderFound) + fixupPlugin("renderplugins"); + if (qtPositioningFound) + fixupPlugin("position"); + if (qtLocationFound) + fixupPlugin("geoservices"); + + std::cout << "(post qt) # OF FILES: " << Settings::filesToFixCount() << std::endl; + std::cout << "(post qt) # OF DEPS: " << deps.size() << std::endl; + + // TODO: evaluate deps of Qt plugins to see if this can be skipped + collectSubDependencies(); + + std::cout << "(post qt, post sub) # OF FILES: " << Settings::filesToFixCount() << std::endl; + std::cout << "(post qt, post sub) # OF DEPS: " << deps.size() << std::endl; +} + void addDependency(std::string path, std::string filename) { Dependency dep(path); @@ -158,8 +273,8 @@ void addDependency(std::string path, std::string filename) if (!Settings::isPrefixBundled(dep.getPrefix())) return; - if (dep.isFramework()) - frameworks.insert(dep.getOriginalFileName()); + if (!in_deps && dep.isFramework()) + frameworks.insert(dep.getOriginalPath()); if (!in_deps) deps.push_back(dep); @@ -209,7 +324,8 @@ void collectDependencies(std::string filename) void collectSubDependencies() { size_t deps_size = deps.size(); - + std::cout << "(pre sub) # OF FILES: " << Settings::filesToFixCount() << std::endl; + std::cout << "(pre sub) # OF DEPS: " << deps.size() << std::endl; // recursively collect each dependency's dependencies while (true) { deps_size = deps.size(); @@ -248,6 +364,8 @@ void collectSubDependencies() if (deps.size() == deps_size) break; } + std::cout << "(post sub) # OF FILES: " << Settings::filesToFixCount() << std::endl; + std::cout << "(post sub) # OF DEPS: " << deps.size() << std::endl; } void doneWithDeps_go() diff --git a/src/DylibBundler.h b/src/DylibBundler.h index d5f655f..c941c6d 100644 --- a/src/DylibBundler.h +++ b/src/DylibBundler.h @@ -10,6 +10,9 @@ void collectRpathsForFilename(const std::string& filename); std::string searchFilenameInRpaths(const std::string& rpath_dep); void fixRpathsOnFile(const std::string& original_file, const std::string& file_to_fix); +void createQtConf(std::string directory); +void copyQtPlugins(); + void addDependency(std::string path, std::string filename); void collectDependencies(std::string filename); void collectSubDependencies(); diff --git a/src/Settings.cpp b/src/Settings.cpp index 7763d14..8bb978a 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -8,28 +8,15 @@ bool overwrite_dir = false; bool create_dir = false; bool quiet_output = false; bool verbose_output = false; -bool bundleLibs_bool = false; +bool bundle_libs = false; bool bundle_frameworks = false; std::string dest_folder_str = "Frameworks"; std::string inside_path_str = "@executable_path/../Frameworks/"; -bool canOverwriteFiles() { return overwrite_files; } -bool canOverwriteDir() { return overwrite_dir; } -bool canCreateDir() { return create_dir; } - -void canOverwriteFiles(bool permission) { overwrite_files = permission; } -void canOverwriteDir(bool permission) { overwrite_dir = permission; } -void canCreateDir(bool permission) { create_dir = permission; } - -bool bundleLibs() { return bundleLibs_bool; } -void bundleLibs(bool on) { bundleLibs_bool = on; } - -bool bundleFrameworks() { return bundle_frameworks; } -void bundleFrameworks(bool status) { bundle_frameworks = status; } - std::string app_bundle; std::string dest_folder; + std::string appBundle() { return app_bundle; } void appBundle(std::string path) { app_bundle = path; @@ -37,7 +24,8 @@ void appBundle(std::string path) { if (app_bundle[app_bundle.size()-1] != '/') app_bundle += "/"; - std::string cmd = "/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' " + app_bundle + "Contents/Info.plist"; + std::string cmd = "/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "; + cmd += app_bundle + "Contents/Info.plist"; std::string bundle_executable = systemOutput(cmd); addFileToFix(app_bundle + "Contents/MacOS/" + bundle_executable); @@ -56,15 +44,22 @@ void destFolder(std::string path) if (dest_folder_str[dest_folder_str.size()-1] != '/') dest_folder_str += "/"; dest_folder = dest_folder_str; - if (!app_bundle.empty()) { + if (!app_bundle.empty()) dest_folder = app_bundle + "Contents/" + dest_folder_str; - } } +std::string pluginsFolder() { return app_bundle + "Contents/PlugIns/"; } + +std::string resourcesFolder() { return app_bundle + "Contents/Resources/"; } + std::vector files; + void addFileToFix(std::string path) { files.push_back(path); } + std::string fileToFix(const int n) { return files[n]; } + std::vector filesToFix() { return files; } + size_t filesToFixCount() { return files.size(); } std::string insideLibPath() { return inside_path_str; } @@ -77,6 +72,7 @@ void insideLibPath(std::string p) } std::vector prefixes_to_ignore; + void ignorePrefix(std::string prefix) { if (prefix[prefix.size()-1] != '/') @@ -90,7 +86,6 @@ bool isPrefixIgnored(std::string prefix) if (prefix.compare(prefixes_to_ignore[n]) == 0) return true; } - return false; } @@ -106,15 +101,29 @@ bool isPrefixBundled(std::string prefix) return false; if (isPrefixIgnored(prefix)) return false; - return true; } std::vector searchPaths; void addSearchPath(std::string path) { searchPaths.push_back(path); } -int searchPathCount() { return searchPaths.size(); } +size_t searchPathCount() { return searchPaths.size(); } std::string searchPath(const int n) { return searchPaths[n]; } +bool canCreateDir() { return create_dir; } +void canCreateDir(bool permission) { create_dir = permission; } + +bool canOverwriteDir() { return overwrite_dir; } +void canOverwriteDir(bool permission) { overwrite_dir = permission; } + +bool canOverwriteFiles() { return overwrite_files; } +void canOverwriteFiles(bool permission) { overwrite_files = permission; } + +bool bundleLibs() { return bundle_libs; } +void bundleLibs(bool status) { bundle_libs = status; } + +bool bundleFrameworks() { return bundle_frameworks; } +void bundleFrameworks(bool status) { bundle_frameworks = status; } + bool quietOutput() { return quiet_output; } void quietOutput(bool status) { quiet_output = status; } diff --git a/src/Settings.h b/src/Settings.h index c73682c..9baa2f6 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -10,27 +10,15 @@ bool isPrefixBundled(std::string prefix); bool isPrefixIgnored(std::string prefix); void ignorePrefix(std::string prefix); -bool canOverwriteFiles(); -void canOverwriteFiles(bool permission); - -bool canOverwriteDir(); -void canOverwriteDir(bool permission); - -bool canCreateDir(); -void canCreateDir(bool permission); - -bool bundleLibs(); -void bundleLibs(bool on); - -bool bundleFrameworks(); -void bundleFrameworks(bool status); - std::string appBundle(); void appBundle(std::string path); std::string destFolder(); void destFolder(std::string path); +std::string pluginsFolder(); +std::string resourcesFolder(); + void addFileToFix(std::string path); std::string fileToFix(int n); std::vector filesToFix(); @@ -40,9 +28,24 @@ std::string insideLibPath(); void insideLibPath(std::string p); void addSearchPath(std::string path); -int searchPathCount(); +size_t searchPathCount(); std::string searchPath(int n); +bool canCreateDir(); +void canCreateDir(bool permission); + +bool canOverwriteDir(); +void canOverwriteDir(bool permission); + +bool canOverwriteFiles(); +void canOverwriteFiles(bool permission); + +bool bundleLibs(); +void bundleLibs(bool status); + +bool bundleFrameworks(); +void bundleFrameworks(bool status); + bool quietOutput(); void quietOutput(bool status); diff --git a/src/Utils.cpp b/src/Utils.cpp index 47dc062..ea35017 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -110,6 +110,15 @@ void tokenize(const std::string& str, const char* delim, std::vector lsDir(std::string path) +{ + std::string cmd = "ls " + path; + std::string output = systemOutput(cmd); + std::vector files; + tokenize(output, "\n", &files); + return files; +} + bool fileExists(std::string filename) { if (access(filename.c_str(), F_OK) != -1) { @@ -131,11 +140,29 @@ bool isRpath(const std::string& path) return path.find("@rpath") == 0 || path.find("@loader_path") == 0; } +void changeId(std::string binary_file, std::string new_id) +{ + std::string command = std::string("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 << "\n"; + exit(1); + } +} + +void changeInstallName(std::string binary_file, std::string old_name, std::string new_name) +{ + std::string command = std::string("install_name_tool -change ") + 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 << "\n"; + exit(1); + } +} + void copyFile(std::string from, std::string to) { bool overwrite = Settings::canOverwriteFiles(); if (fileExists(to) && !overwrite) { - std::cerr << "\n\nError: File " << to << " already exists. Remove it or enable overwriting\n"; + std::cerr << "\n\nError: File " << to << " already exists. Remove it or enable overwriting (-of)\n"; exit(1); } @@ -172,6 +199,18 @@ void deleteFile(std::string path) deleteFile(path, overwrite); } +bool mkdir(std::string path) +{ + if (Settings::verboseOutput()) + std::cout << "* Creating directory " << path << "\n\n"; + std::string command = std::string("mkdir -p ") + path; + if (systemp(command) != 0) { + std::cerr << "\n/!\\ ERROR: An error occured while creating " + path + "\n"; + return false; + } + return true; +} + void createDestDir() { std::string dest_folder = Settings::destFolder(); @@ -192,9 +231,8 @@ void createDestDir() if (!dest_exists) { if (Settings::canCreateDir()) { std::cout << "* Creating output directory " << dest_folder << "\n\n"; - std::string command = std::string("mkdir -p ") + dest_folder; - if (systemp(command) != 0) { - std::cerr << "\n/!\\ ERROR: An error occured while creating dest folder\n"; + if (!mkdir(dest_folder)) { + std::cerr << "\n/!\\ ERROR: An error occured while creating " + dest_folder + "\n"; exit(1); } } diff --git a/src/Utils.h b/src/Utils.h index 75da119..7557e92 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -23,13 +23,19 @@ std::string systemOutput(const std::string& cmd); int systemp(const std::string& cmd); void tokenize(const std::string& str, const char* delimiters, std::vector*); + +std::vector lsDir(std::string path); bool fileExists(std::string filename); bool isRpath(const std::string& path); +void changeId(std::string binary_file, std::string new_id); +void changeInstallName(std::string binary_file, std::string old_name, std::string new_name); + void copyFile(std::string from, std::string to); void deleteFile(std::string path, bool overwrite); void deleteFile(std::string path); +bool mkdir(std::string path); void createDestDir(); std::string getUserInputDirForFile(const std::string& filename); diff --git a/src/main.cpp b/src/main.cpp index cdeb241..89a5a74 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -133,6 +133,7 @@ int main (int argc, char * const argv[]) collectDependencies(Settings::fileToFix(n)); collectSubDependencies(); + copyQtPlugins(); doneWithDeps_go(); return 0;