copy Qt plugins if Qt frameworks are found

This commit is contained in:
SCG82 2019-12-28 18:54:05 -08:00
parent a8a9f7b944
commit 84c97c017e
9 changed files with 251 additions and 103 deletions

View File

@ -27,6 +27,7 @@ std::vector<std::string> 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<symlinks.size(); ++n) {
command = std::string("install_name_tool -change ") + symlinks[n] + " " + 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);
}
}
for (size_t n=0; n<symlinks.size(); ++n)
changeInstallName(file_to_fix, symlinks[n], getInnerPath());
// FIXME - hackish
if (missing_prefixes) {
// for main lib file
command = std::string("install_name_tool -change ") + filename + " " + 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, filename, getInnerPath());
// for symlinks
for (size_t n=0; n<symlinks.size(); ++n) {
command = std::string("install_name_tool -change ") + symlinks[n] + " " + 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);
}
}
for (size_t n=0; n<symlinks.size(); ++n)
changeInstallName(file_to_fix, symlinks[n], getInnerPath());
}
}

View File

@ -27,6 +27,7 @@ public:
bool mergeIfSameAs(Dependency& dep2);
void print();
void copyYourself();
void fixFileThatDependsOnMe(std::string file);

View File

@ -2,6 +2,7 @@
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <map>
#include <numeric>
@ -28,10 +29,9 @@ void changeLibPathsOnFile(std::string file_to_fix)
std::cout << "* Fixing dependencies on " << file_to_fix << "\n";
std::vector<Dependency> 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<dep_amount; ++n)
deps_in_file[n].fixFileThatDependsOnMe(file_to_fix);
deps_per_file[file_to_fix][n].fixFileThatDependsOnMe(file_to_fix);
}
void collectRpaths(const std::string& filename)
@ -138,6 +138,121 @@ void fixRpathsOnFile(const std::string& original_file, const std::string& file_t
}
}
void createQtConf(std::string directory)
{
std::string contents = "[Paths]\n"
"Plugins = PlugIns\n"
"Imports = Resources/qml\n"
"Qml2Imports = Resources/qml\n";
if (directory[directory.size()-1] != '/')
directory += "/";
std::string out_path = directory + "qt.conf";
std::ofstream out(out_path);
out << contents;
out.close();
}
void copyQtPlugins()
{
bool qtCoreFound = false;
bool qtNetworkFound = false;
bool qtSqlFound = false;
bool qtSvgFound = false;
bool qtMultimediaFound = false;
bool qt3dRenderFound = false;
bool qt3dQuickRenderFound = false;
bool qtPositioningFound = false;
bool qtLocationFound = false;
std::string original_file;
for (std::set<std::string>::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<std::string> 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()

View File

@ -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();

View File

@ -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<std::string> files;
void addFileToFix(std::string path) { files.push_back(path); }
std::string fileToFix(const int n) { return files[n]; }
std::vector<std::string> 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<std::string> 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<std::string> 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; }

View File

@ -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<std::string> 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);

View File

@ -110,6 +110,15 @@ void tokenize(const std::string& str, const char* delim, std::vector<std::string
}
}
std::vector<std::string> lsDir(std::string path)
{
std::string cmd = "ls " + path;
std::string output = systemOutput(cmd);
std::vector<std::string> 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);
}
}

View File

@ -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::string>*);
std::vector<std::string> 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);

View File

@ -133,6 +133,7 @@ int main (int argc, char * const argv[])
collectDependencies(Settings::fileToFix(n));
collectSubDependencies();
copyQtPlugins();
doneWithDeps_go();
return 0;