move searchFilenameInRpaths to Util.cpp

This commit is contained in:
SCG82 2020-01-03 21:05:39 -08:00
parent ab607a8e66
commit bc8c55e6c2
8 changed files with 240 additions and 314 deletions

View File

@ -17,7 +17,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include "DylibBundler.h" // #include "DylibBundler.h"
#include "Settings.h" #include "Settings.h"
#include "Utils.h" #include "Utils.h"

View File

@ -2,11 +2,9 @@
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <fstream>
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <numeric> #include <numeric>
#include <regex>
#include <set> #include <set>
#ifdef __linux #ifdef __linux
#include <linux/limits.h> #include <linux/limits.h>
@ -21,218 +19,10 @@ 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;
std::map<std::string, std::vector<std::string>> rpaths_per_file; // std::map<std::string, std::vector<std::string>> rpaths_per_file;
std::map<std::string, std::string> rpath_to_fullpath; // std::map<std::string, std::string> rpath_to_fullpath;
bool qt_plugins_called = false; bool qt_plugins_called = false;
void changeLibPathsOnFile(std::string file_to_fix)
{
if (deps_collected.find(file_to_fix) == deps_collected.end())
collectDependenciesForFile(file_to_fix);
std::cout << "* Fixing dependencies on " << file_to_fix << "\n";
const size_t dep_amount = deps_per_file[file_to_fix].size();
for (size_t n=0; n<dep_amount; ++n) {
deps_per_file[file_to_fix][n].fixFileThatDependsOnMe(file_to_fix);
}
}
// void collectRpaths(const std::string& filename)
// {
// if (!fileExists(filename)) {
// std::cerr << "\n/!\\ WARNING: Can't collect rpaths for nonexistent file '" << filename << "'\n";
// return;
// }
// if (Settings::verboseOutput())
// std::cout << " collecting rpaths for: " << filename << std::endl;
// std::string cmd = "otool -l " + filename;
// std::string output = systemOutput(cmd);
// 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.size() < 1) {
// std::cerr << "\n\n/!\\ ERROR: Cannot find file " << filename << " to read its rpaths\n";
// exit(1);
// }
// std::vector<std::string> lc_lines;
// tokenize(output, "\n", &lc_lines);
// bool searching = false;
// for (const auto& line : lc_lines) {
// if (line.find("cmd LC_RPATH") != std::string::npos) {
// if (searching) {
// std::cerr << "\n\n/!\\ ERROR: Failed to find path before next cmd" << std::endl;
// exit(1);
// }
// searching = true;
// }
// else if (searching) {
// size_t start_pos = line.find("path ");
// size_t end_pos = line.find(" (");
// if (start_pos == std::string::npos || end_pos == std::string::npos)
// continue;
// start_pos += 5; // to exclude "path "
// std::string rpath = line.substr(start_pos, end_pos - start_pos);
// rpaths.insert(rpath);
// rpaths_per_file[filename].push_back(rpath);
// searching = false;
// if (Settings::verboseOutput())
// std::cout << " rpath: " << rpath << std::endl;
// }
// }
// }
void collectRpaths(const std::string& filename)
{
std::vector<std::string> lines;
parseLoadCommands(filename, std::string("LC_RPATH"), std::string("path"), lines);
for (const auto& line : lines) {
rpaths.insert(line);
rpaths_per_file[filename].push_back(line);
}
}
void collectRpathsForFilename(const std::string& filename)
{
if (rpaths_per_file.find(filename) == rpaths_per_file.end())
collectRpaths(filename);
}
std::string searchFilenameInRpaths(const std::string& rpath_file, const std::string& dependent_file)
{
if (Settings::verboseOutput()) {
if (dependent_file != rpath_file)
std::cout << " dependent file: " << dependent_file << std::endl;
std::cout << " dependency: " << rpath_file << std::endl;
}
std::string fullpath;
std::string suffix = rpath_file.substr(rpath_file.rfind("/")+1);
char fullpath_buffer[PATH_MAX];
const auto check_path = [&](std::string path) {
char buffer[PATH_MAX];
std::string file_prefix = filePrefix(dependent_file);
if (path.find("@executable_path") != std::string::npos || path.find("@loader_path") != std::string::npos) {
if (path.find("@executable_path") != std::string::npos) {
if (Settings::appBundleProvided())
path = std::regex_replace(path, std::regex("@executable_path/"), Settings::executableFolder());
}
if (dependent_file != rpath_file) {
if (path.find("@loader_path") != std::string::npos)
path = std::regex_replace(path, std::regex("@loader_path/"), file_prefix);
}
if (Settings::verboseOutput())
std::cout << " path to search: " << path << std::endl;
if (realpath(path.c_str(), buffer)) {
fullpath = buffer;
rpath_to_fullpath[rpath_file] = fullpath;
return true;
}
}
else if (path.find("@rpath") != std::string::npos) {
if (Settings::appBundleProvided()) {
std::string pathE = std::regex_replace(path, std::regex("@rpath/"), Settings::executableFolder());
if (Settings::verboseOutput())
std::cout << " path to search: " << pathE << std::endl;
if (realpath(pathE.c_str(), buffer)) {
fullpath = buffer;
rpath_to_fullpath[rpath_file] = fullpath;
return true;
}
}
if (dependent_file != rpath_file) {
std::string pathL = std::regex_replace(path, std::regex("@rpath/"), file_prefix);
if (Settings::verboseOutput())
std::cout << " path to search: " << pathL << std::endl;
if (realpath(pathL.c_str(), buffer)) {
fullpath = buffer;
rpath_to_fullpath[rpath_file] = fullpath;
return true;
}
}
}
return false;
};
// fullpath previously stored
if (rpath_to_fullpath.find(rpath_file) != rpath_to_fullpath.end()) {
fullpath = rpath_to_fullpath[rpath_file];
}
else if (!check_path(rpath_file)) {
for (auto it = rpaths_per_file[dependent_file].begin(); it != rpaths_per_file[dependent_file].end(); ++it) {
std::string rpath = *it;
if (rpath[rpath.size()-1] != '/')
rpath += "/";
std::string path = rpath + suffix;
if (Settings::verboseOutput())
std::cout << " trying rpath: " << path << std::endl;
if (check_path(path))
break;
}
}
if (fullpath.empty()) {
size_t search_path_count = Settings::searchPathCount();
for (size_t i=0; i<search_path_count; ++i) {
std::string search_path = Settings::searchPath(i);
if (fileExists(search_path+suffix)) {
if (Settings::verboseOutput())
std::cout << "FOUND " + suffix + " in " + search_path + "\n";
fullpath = search_path + suffix;
break;
}
}
if (fullpath.empty()) {
if (Settings::verboseOutput())
std::cout << " ** rpath fullpath: not found" << std::endl;
if (!Settings::quietOutput())
std::cerr << "\n/!\\ WARNING: Can't get path for '" << rpath_file << "'\n";
fullpath = getUserInputDirForFile(suffix) + suffix;
if (Settings::quietOutput() && fullpath.empty())
std::cerr << "\n/!\\ WARNING: Can't get path for '" << rpath_file << "'\n";
if (realpath(fullpath.c_str(), fullpath_buffer))
fullpath = fullpath_buffer;
}
else if (Settings::verboseOutput()) {
std::cout << " ** rpath fullpath: " << fullpath << std::endl;
}
} else if (Settings::verboseOutput()) {
std::cout << " ** rpath fullpath: " << fullpath << std::endl;
}
return fullpath;
}
std::string searchFilenameInRpaths(const std::string& rpath_file)
{
return searchFilenameInRpaths(rpath_file, rpath_file);
}
void fixRpathsOnFile(const std::string& original_file, const std::string& file_to_fix)
{
std::vector<std::string> rpaths_to_fix;
std::map<std::string, std::vector<std::string>>::iterator found = rpaths_per_file.find(original_file);
if (found != rpaths_per_file.end())
rpaths_to_fix = found->second;
for (size_t i=0; i < rpaths_to_fix.size(); ++i) {
std::string command =
std::string("install_name_tool -rpath ")
+ rpaths_to_fix[i] + " "
+ Settings::insideLibPath() + " "
+ file_to_fix;
if (systemp(command) != 0) {
std::cerr << "\n\n/!\\ ERROR: An error occured while trying to fix dependencies of " << file_to_fix << "\n";
exit(1);
}
}
}
void addDependency(std::string path, std::string dependent_file) void addDependency(std::string path, std::string dependent_file)
{ {
Dependency dep(path, dependent_file); Dependency dep(path, dependent_file);
@ -265,43 +55,10 @@ void addDependency(std::string path, std::string dependent_file)
deps_per_file[dependent_file].push_back(dep); deps_per_file[dependent_file].push_back(dep);
} }
// void collectDependencies(const std::string& dependent_file, std::vector<std::string>& lines) std::string searchFilenameInRpaths(const std::string& rpath_file)
// { {
// std::string cmd = "otool -l " + dependent_file; return searchFilenameInRpaths(rpath_file, rpath_file);
// std::string output = systemOutput(cmd); }
// 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.size() < 1) {
// std::cerr << "\n\n/!\\ ERROR: Cannot find file " << dependent_file << " to read its dependencies\n";
// exit(1);
// }
// std::vector<std::string> raw_lines;
// tokenize(output, "\n", &raw_lines);
// bool searching = false;
// for (const auto& line : raw_lines) {
// if (line.find("cmd LC_LOAD_DYLIB") != std::string::npos) {
// if (searching) {
// std::cerr << "\n\n/!\\ ERROR: Failed to find name before next cmd" << std::endl;
// exit(1);
// }
// searching = true;
// }
// else if (searching) {
// size_t found = line.find("name ");
// size_t start_pos = line.find("name ");
// size_t end_pos = line.find(" (");
// if (start_pos == std::string::npos || end_pos == std::string::npos)
// continue;
// start_pos += 5; // to exclude "name "
// lines.push_back('\t' + line.substr(start_pos, end_pos - start_pos));
// searching = false;
// }
// }
// }
void collectDependencies(const std::string& dependent_file, std::vector<std::string>& lines) void collectDependencies(const std::string& dependent_file, std::vector<std::string>& lines)
{ {
@ -321,20 +78,32 @@ void collectDependenciesForFile(const std::string& dependent_file)
collectRpathsForFilename(dependent_file); collectRpathsForFilename(dependent_file);
for (size_t i=0; i<lines.size(); ++i) { for (size_t i=0; i<lines.size(); ++i) {
// lines containing path begin with a tab
if (lines[i][0] != '\t')
continue;
if (!Settings::isPrefixBundled(lines[i])) if (!Settings::isPrefixBundled(lines[i]))
continue; continue; // skip system/ignored prefixes
// trim useless info, keep only library path addDependency(lines[i], dependent_file);
std::string dep_path = lines[i].substr(1, lines[i].rfind(" (") - 1);
// if (isRpath(dep_path))
// collectRpathsForFilename(searchFilenameInRpaths(dep_path, dependent_file));
addDependency(dep_path, dependent_file);
} }
deps_collected[dependent_file] = true; deps_collected[dependent_file] = true;
} }
void collectRpaths(const std::string& filename)
{
std::vector<std::string> lines;
parseLoadCommands(filename, std::string("LC_RPATH"), std::string("path"), lines);
for (const auto& line : lines) {
rpaths.insert(line);
// rpaths_per_file[filename].push_back(line);
Settings::addRpathForFile(filename, line);
if (Settings::verboseOutput())
std::cout << " rpath: " << line << std::endl;
}
}
void collectRpathsForFilename(const std::string& filename)
{
if (!Settings::fileHasRpath(filename))
collectRpaths(filename);
}
void collectSubDependencies() void collectSubDependencies()
{ {
size_t dep_counter = deps.size(); size_t dep_counter = deps.size();
@ -346,7 +115,6 @@ void collectSubDependencies()
size_t deps_size = deps.size(); size_t deps_size = deps.size();
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].getOriginalPath(); std::string original_path = deps[n].getOriginalPath();
if (Settings::verboseOutput()) if (Settings::verboseOutput())
@ -354,22 +122,14 @@ void collectSubDependencies()
if (isRpath(original_path)) if (isRpath(original_path))
original_path = searchFilenameInRpaths(original_path); original_path = searchFilenameInRpaths(original_path);
collectRpathsForFilename(original_path);
std::vector<std::string> lines; std::vector<std::string> lines;
collectDependenciesForFile(original_path, lines); collectDependenciesForFile(original_path, lines);
collectRpathsForFilename(original_path);
for (size_t i=0; i<lines.size(); ++i) { for (size_t i=0; i<lines.size(); ++i) {
// lines containing path begin with a tab
if (lines[i][0] != '\t')
continue;
// skip system/ignored prefixes
if (!Settings::isPrefixBundled(lines[i])) if (!Settings::isPrefixBundled(lines[i]))
continue; continue; // skip system/ignored prefixes
// trim useless info, keep only library name addDependency(lines[i], original_path);
std::string dep_path = lines[i].substr(1, lines[i].rfind(" (") - 1);
// if (isRpath(dep_path))
// collectRpathsForFilename(searchFilenameInRpaths(dep_path, original_path));
addDependency(dep_path, original_path);
} }
} }
// if no more dependencies were added on this iteration, stop searching // if no more dependencies were added on this iteration, stop searching
@ -377,30 +137,62 @@ void collectSubDependencies()
break; break;
} }
} }
if (Settings::verboseOutput()) { if (Settings::verboseOutput()) {
std::cout << "(post sub) # OF FILES: " << Settings::filesToFixCount() << std::endl; std::cout << "(post sub) # OF FILES: " << Settings::filesToFixCount() << std::endl;
std::cout << "(post sub) # OF DEPS: " << deps.size() << std::endl; std::cout << "(post sub) # OF DEPS: " << deps.size() << std::endl;
} }
if (Settings::bundleFrameworks()) { if (Settings::bundleLibs() && Settings::bundleFrameworks()) {
if (!qt_plugins_called || (deps.size() != dep_counter)) if (!qt_plugins_called || (deps.size() != dep_counter))
copyQtPlugins(); copyQtPlugins();
} }
} }
void doneWithDeps_go() void changeLibPathsOnFile(std::string file_to_fix)
{ {
if (Settings::verboseOutput()) { if (deps_collected.find(file_to_fix) == deps_collected.end())
for (std::set<std::string>::iterator it = rpaths.begin(); it != rpaths.end(); ++it) { collectDependenciesForFile(file_to_fix);
std::cout << "rpaths: " << *it << std::endl;
std::cout << "* Fixing dependencies on " << file_to_fix << "\n";
const size_t dep_amount = deps_per_file[file_to_fix].size();
for (size_t n=0; n<dep_amount; ++n) {
deps_per_file[file_to_fix][n].fixFileThatDependsOnMe(file_to_fix);
}
}
void fixRpathsOnFile(const std::string& original_file, const std::string& file_to_fix)
{
std::vector<std::string> rpaths_to_fix;
if (Settings::fileHasRpath(original_file))
rpaths_to_fix = Settings::getRpathsForFile(original_file);
for (size_t i=0; i < rpaths_to_fix.size(); ++i) {
std::string command =
std::string("install_name_tool -rpath ")
+ rpaths_to_fix[i] + " "
+ Settings::insideLibPath() + " "
+ file_to_fix;
if (systemp(command) != 0) {
std::cerr << "\n\n/!\\ ERROR: An error occured while trying to fix dependencies of " << file_to_fix << "\n";
exit(1);
} }
} }
}
void doneWithDeps_go()
{
const size_t deps_size = deps.size(); const size_t deps_size = deps.size();
for (size_t n=0; n<deps_size; ++n) { for (size_t n=0; n<deps_size; ++n) {
deps[n].print(); deps[n].print();
} }
std::cout << "\n"; std::cout << "\n";
if (Settings::verboseOutput()) {
for (std::set<std::string>::iterator it = rpaths.begin(); it != rpaths.end(); ++it) {
std::cout << "rpaths: " << *it << std::endl;
}
}
// copy & fix up dependencies
if (Settings::bundleLibs()) { if (Settings::bundleLibs()) {
createDestDir(); createDestDir();
for (size_t n=0; n<deps_size; ++n) { for (size_t n=0; n<deps_size; ++n) {
@ -409,7 +201,7 @@ void doneWithDeps_go()
fixRpathsOnFile(deps[n].getOriginalPath(), deps[n].getInstallPath()); fixRpathsOnFile(deps[n].getOriginalPath(), deps[n].getInstallPath());
} }
} }
// fix up selected files
const size_t filesToFixSize = Settings::filesToFix().size(); const size_t filesToFixSize = Settings::filesToFix().size();
for (size_t j=0; j<filesToFixSize; ++j) { for (size_t j=0; j<filesToFixSize; ++j) {
changeLibPathsOnFile(Settings::fileToFix(j)); changeLibPathsOnFile(Settings::fileToFix(j));
@ -417,22 +209,8 @@ void doneWithDeps_go()
} }
} }
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::ofstream out(directory + "qt.conf");
out << contents;
out.close();
}
void copyQtPlugins() void copyQtPlugins()
{ {
qt_plugins_called = true;
bool qtCoreFound = false; bool qtCoreFound = false;
bool qtGuiFound = false; bool qtGuiFound = false;
bool qtNetworkFound = false; bool qtNetworkFound = false;
@ -477,12 +255,12 @@ void copyQtPlugins()
if (!qtCoreFound) if (!qtCoreFound)
return; return;
if (!qt_plugins_called)
createQtConf(Settings::resourcesFolder());
qt_plugins_called = true;
createQtConf(Settings::resourcesFolder()); const auto fixupPlugin = [original_file](std::string plugin) {
std::string dest = Settings::pluginsFolder();
std::string dest = Settings::pluginsFolder();
const auto fixupPlugin = [original_file,dest] (std::string plugin) {
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));
@ -504,6 +282,7 @@ void copyQtPlugins()
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 = Settings::pluginsFolder();
mkdir(dest + "platforms"); mkdir(dest + "platforms");
copyFile(qt_plugins_prefix + "platforms/libqcocoa.dylib", dest + "platforms"); copyFile(qt_plugins_prefix + "platforms/libqcocoa.dylib", dest + "platforms");
Settings::addFileToFix(dest + "platforms/libqcocoa.dylib"); Settings::addFileToFix(dest + "platforms/libqcocoa.dylib");
@ -541,6 +320,5 @@ void copyQtPlugins()
fixupPlugin("texttospeech"); fixupPlugin("texttospeech");
if (qtWebViewFound) if (qtWebViewFound)
fixupPlugin("webview"); fixupPlugin("webview");
collectSubDependencies(); collectSubDependencies();
} }

View File

@ -2,30 +2,29 @@
#define _DYLIB_BUNDLER_H_ #define _DYLIB_BUNDLER_H_
#include <string> #include <string>
#include <vector>
void changeLibPathsOnFile(std::string file_to_fix); void addDependency(std::string path, std::string dependent_file);
void collectRpaths(const std::string& filename);
void collectRpathsForFilename(const std::string& filename);
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);
void fixRpathsOnFile(const std::string& original_file, const std::string& file_to_fix);
void addDependency(std::string path, std::string dependent_file);
// fill |lines| with dependencies of |dependent_file| // fill |lines| with dependencies of |dependent_file|
void collectDependencies(const std::string& dependent_file, std::vector<std::string>& lines); void collectDependencies(const std::string& dependent_file, std::vector<std::string>& lines);
void collectDependenciesForFile(const std::string& dependent_file, std::vector<std::string>& lines); void collectDependenciesForFile(const std::string& dependent_file, std::vector<std::string>& lines);
void collectDependenciesForFile(const std::string& dependent_file); void collectDependenciesForFile(const std::string& dependent_file);
void collectRpaths(const std::string& filename);
void collectRpathsForFilename(const std::string& filename);
// recursively collect each dependency's dependencies // recursively collect each dependency's dependencies
void collectSubDependencies(); void collectSubDependencies();
void changeLibPathsOnFile(std::string file_to_fix);
void fixRpathsOnFile(const std::string& original_file, const std::string& file_to_fix);
void doneWithDeps_go(); void doneWithDeps_go();
void createQtConf(std::string directory);
void copyQtPlugins(); void copyQtPlugins();
#endif #endif

View File

@ -1,4 +1,7 @@
#include "Settings.h" #include "Settings.h"
#include <map>
#include "Utils.h" #include "Utils.h"
namespace Settings { namespace Settings {
@ -153,4 +156,14 @@ bool missing_prefixes = false;
bool missingPrefixes() { return missing_prefixes; } bool missingPrefixes() { return missing_prefixes; }
void missingPrefixes(bool status) { missing_prefixes = status; } void missingPrefixes(bool status) { missing_prefixes = status; }
std::map<std::string, std::string> rpath_to_fullpath;
std::string getFullPath(const std::string& rpath) { return rpath_to_fullpath[rpath]; }
void rpathToFullPath(const std::string& rpath, const std::string& fullpath) { rpath_to_fullpath[rpath] = fullpath; }
bool rpathFound(const std::string& rpath) { return rpath_to_fullpath.find(rpath) != rpath_to_fullpath.end(); }
std::map<std::string, std::vector<std::string>> rpaths_per_file;
std::vector<std::string> getRpathsForFile(const std::string& file) { return rpaths_per_file[file]; }
void addRpathForFile(const std::string& file, const std::string& rpath) { rpaths_per_file[file].push_back(rpath); }
bool fileHasRpath(const std::string& file) { return rpaths_per_file.find(file) != rpaths_per_file.end(); }
} // namespace Settings } // namespace Settings

View File

@ -62,6 +62,14 @@ void verboseOutput(bool status);
bool missingPrefixes(); bool missingPrefixes();
void missingPrefixes(bool status); void missingPrefixes(bool status);
std::string getFullPath(const std::string& rpath);
void rpathToFullPath(const std::string& rpath, const std::string& fullpath);
bool rpathFound(const std::string& rpath);
std::vector<std::string> getRpathsForFile(const std::string& file);
void addRpathForFile(const std::string& file, const std::string& rpath);
bool fileHasRpath(const std::string& file);
} // namespace Settings } // namespace Settings
#endif #endif

View File

@ -2,7 +2,9 @@
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <fstream>
#include <iostream> #include <iostream>
#include <regex>
#include <sstream> #include <sstream>
#include <stdio.h> #include <stdio.h>
@ -152,7 +154,7 @@ std::string bundleExecutableName(const std::string& app_bundle_path)
{ {
std::string cmd = "/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' " std::string cmd = "/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "
+ app_bundle_path + "Contents/Info.plist"; + app_bundle_path + "Contents/Info.plist";
return systemOutput(cmd); return rtrim(systemOutput(cmd));
} }
void changeId(const std::string& binary_file, const std::string& new_id) void changeId(const std::string& binary_file, const std::string& new_id)
@ -349,6 +351,114 @@ void parseLoadCommands(const std::string& file, const std::string& cmd, const st
} }
} }
std::string searchFilenameInRpaths(const std::string& rpath_file, const std::string& dependent_file)
{
if (Settings::verboseOutput()) {
if (dependent_file != rpath_file)
std::cout << " dependent file: " << dependent_file << std::endl;
std::cout << " dependency: " << rpath_file << std::endl;
}
std::string fullpath;
std::string suffix = rpath_file.substr(rpath_file.rfind("/")+1);
char fullpath_buffer[PATH_MAX];
const auto check_path = [&](std::string path) {
char buffer[PATH_MAX];
std::string file_prefix = filePrefix(dependent_file);
if (path.find("@executable_path") != std::string::npos || path.find("@loader_path") != std::string::npos) {
if (path.find("@executable_path") != std::string::npos) {
if (Settings::appBundleProvided())
path = std::regex_replace(path, std::regex("@executable_path/"), Settings::executableFolder());
}
if (dependent_file != rpath_file) {
if (path.find("@loader_path") != std::string::npos)
path = std::regex_replace(path, std::regex("@loader_path/"), file_prefix);
}
if (Settings::verboseOutput())
std::cout << " path to search: " << path << std::endl;
if (realpath(path.c_str(), buffer)) {
fullpath = buffer;
Settings::rpathToFullPath(rpath_file, fullpath);
return true;
}
}
else if (path.find("@rpath") != std::string::npos) {
if (Settings::appBundleProvided()) {
std::string pathE = std::regex_replace(path, std::regex("@rpath/"), Settings::executableFolder());
if (Settings::verboseOutput())
std::cout << " path to search: " << pathE << std::endl;
if (realpath(pathE.c_str(), buffer)) {
fullpath = buffer;
Settings::rpathToFullPath(rpath_file, fullpath);
return true;
}
}
if (dependent_file != rpath_file) {
std::string pathL = std::regex_replace(path, std::regex("@rpath/"), file_prefix);
if (Settings::verboseOutput())
std::cout << " path to search: " << pathL << std::endl;
if (realpath(pathL.c_str(), buffer)) {
fullpath = buffer;
Settings::rpathToFullPath(rpath_file, fullpath);
return true;
}
}
}
return false;
};
// fullpath previously stored
if (Settings::rpathFound(rpath_file)) {
fullpath = Settings::getFullPath(rpath_file);
}
else if (!check_path(rpath_file)) {
auto rpaths_for_file = Settings::getRpathsForFile(dependent_file);
for (auto it = rpaths_for_file.begin(); it != rpaths_for_file.end(); ++it) {
std::string rpath = *it;
if (rpath[rpath.size()-1] != '/')
rpath += "/";
std::string path = rpath + suffix;
if (Settings::verboseOutput())
std::cout << " trying rpath: " << path << std::endl;
if (check_path(path))
break;
}
}
if (fullpath.empty()) {
size_t search_path_count = Settings::searchPathCount();
for (size_t i=0; i<search_path_count; ++i) {
std::string search_path = Settings::searchPath(i);
if (fileExists(search_path+suffix)) {
if (Settings::verboseOutput())
std::cout << "FOUND " + suffix + " in " + search_path + "\n";
fullpath = search_path + suffix;
break;
}
}
if (fullpath.empty()) {
if (Settings::verboseOutput())
std::cout << " ** rpath fullpath: not found" << std::endl;
if (!Settings::quietOutput())
std::cerr << "\n/!\\ WARNING: Can't get path for '" << rpath_file << "'\n";
fullpath = getUserInputDirForFile(suffix) + suffix;
if (Settings::quietOutput() && fullpath.empty())
std::cerr << "\n/!\\ WARNING: Can't get path for '" << rpath_file << "'\n";
if (realpath(fullpath.c_str(), fullpath_buffer))
fullpath = fullpath_buffer;
}
else if (Settings::verboseOutput()) {
std::cout << " ** rpath fullpath: " << fullpath << std::endl;
}
}
else if (Settings::verboseOutput()) {
std::cout << " ** rpath fullpath: " << fullpath << std::endl;
}
return fullpath;
}
void initSearchPaths() void initSearchPaths()
{ {
std::string searchPaths; std::string searchPaths;
@ -377,3 +487,16 @@ void initSearchPaths()
} }
} }
} }
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::ofstream out(directory + "qt.conf");
out << contents;
out.close();
}

View File

@ -38,14 +38,19 @@ void changeInstallName(const std::string& binary_file, const std::string& old_na
void copyFile(const std::string& from, const std::string& to); 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 overwrite);
void deleteFile(const std::string& path); void deleteFile(const std::string& path);
bool mkdir(const std::string& path); bool mkdir(const std::string& path);
void createDestDir(); void createDestDir();
std::string getUserInputDirForFile(const std::string& filename); std::string getUserInputDirForFile(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::string& cmd, const std::string& value, std::vector<std::string>& lines);
std::string searchFilenameInRpaths(const std::string& rpath_file, const std::string& dependent_file);
// check the same paths the system would search for dylibs // check the same paths the system would search for dylibs
void initSearchPaths(); void initSearchPaths();
void createQtConf(std::string directory);
#endif #endif

View File

@ -94,6 +94,10 @@ int main(int argc, const char* argv[])
Settings::verboseOutput(true); Settings::verboseOutput(true);
continue; continue;
} }
else if (strcmp(argv[i],"-b") == 0 || strcmp(argv[i],"--bundle-libs") == 0) {
// old flag, on by default now. ignore.
continue;
}
else if (strcmp(argv[i],"-V") == 0 || strcmp(argv[i],"--version") == 0) { else if (strcmp(argv[i],"-V") == 0 || strcmp(argv[i],"--version") == 0) {
std::cout << "dylibbundler " << VERSION << std::endl; std::cout << "dylibbundler " << VERSION << std::endl;
exit(0); exit(0);
@ -102,10 +106,6 @@ int main(int argc, const char* argv[])
showHelp(); showHelp();
exit(0); exit(0);
} }
else if (strcmp(argv[i],"-b") == 0 || strcmp(argv[i],"--bundle-libs") == 0) {
// old flag, on by default now. ignore.
continue;
}
else if (i > 0) { else if (i > 0) {
// unknown flag, abort // unknown flag, abort
std::cerr << "Unknown flag " << argv[i] << std::endl << std::endl; std::cerr << "Unknown flag " << argv[i] << std::endl << std::endl;
@ -114,7 +114,7 @@ int main(int argc, const char* argv[])
} }
} }
if (!Settings::bundleLibs() && Settings::filesToFixCount() < 1) { if (Settings::filesToFixCount() < 1) {
showHelp(); showHelp();
exit(0); exit(0);
} }