634 lines
20 KiB
C++
634 lines
20 KiB
C++
#include <picli.h>
|
|
#include <pidir.h>
|
|
#include <piprocess.h>
|
|
|
|
#define DELIM "::"
|
|
|
|
using namespace PICoutManipulators;
|
|
|
|
PIString cmd_copy, cmd_copydir, cmd_suffix;
|
|
PIString qplatforms;
|
|
|
|
void setCommands() {
|
|
#ifdef WINDOWS
|
|
cmd_copy = "copy /y ";
|
|
cmd_copydir = "copy /y ";
|
|
cmd_suffix = " 1> NUL";
|
|
qplatforms = "windows";
|
|
#else
|
|
cmd_copy = "cp -f ";
|
|
cmd_copydir = "cp -rf ";
|
|
# ifdef MAC_OS
|
|
qplatforms = "cocoa";
|
|
# else
|
|
qplatforms = "xcb";
|
|
# endif
|
|
#endif
|
|
}
|
|
|
|
|
|
void usage() {
|
|
piCout << Bold << "Deploy tool";
|
|
piCout << Cyan << "Version PIP" << Bold << PIPVersion();
|
|
piCout << "";
|
|
piCout << "Copy all dependencies of <file> to directory <out_path>";
|
|
piCout << "You can specify any file or directory as <file>.";
|
|
piCout << "In case of directory it will be scan recursively.";
|
|
piCout << "";
|
|
piCout << "If some Qt dependency found, copy corresponding Qt plugins.";
|
|
piCout << "Styles and platforms selected by -S and -P flags,";
|
|
piCout << "any other plugins described by --qt-plugins flag in next format:";
|
|
piCout << "\"[*=" DELIM "]<plugins>=<regexp>,<regexp>" DELIM "<plugins>=<regexp>,<regexp>\", e.g.";
|
|
piCout << "\"sqldrivers=lite,mysql" DELIM "geoservices=" DELIM "position=nmea\".";
|
|
piCout << "If no regexp specified for plugins, nothing will be copied.";
|
|
piCout << "Default regexp set by \"*=<regexp>\".";
|
|
piCout << "\"*=\" disable optional plugins.";
|
|
piCout << "";
|
|
piCout << Green << Bold << "Usage:" << Default << "\"deploy_tool [-hvfC] [--dependencies [--prefix <text>]] "
|
|
"[-p <qt_plugins>] [-s <search_path>] [--ignore <libs>] [-S <styles>] "
|
|
"[-l <ldd>] [-D <dpkg>] [-L <readelf> | -W <objdump> | -M <otool>] "
|
|
"[--name-tool <pathS>] [-d <depth>] [-q <qtdir>] [-a <add_libs>] [-S <styles>] "
|
|
"[-P <platforms>] [--qt-plugins <d>] -o <out_path> <file> [<file2> ...]\"" << NewLine;
|
|
piCout << Green << Bold << "Details:";
|
|
piCout << Bold << "Debug control";
|
|
piCout << "-h, --help " << Green << "- display this message and exit";
|
|
piCout << "-v, --verbose " << Green << "- be verbose";
|
|
piCout << "";
|
|
piCout << Bold << "Processing control";
|
|
piCout << "-f, --fake " << Green << "- don`t copy, only print";
|
|
piCout << "-s <search_path> " << Green << "- set search pathes for system libraries, may be separated by \"" DELIM "\", default \"/usr/lib\"";
|
|
piCout << "--ignore <libs> " << Green << "- ignore libraries names, may be separated by \"" DELIM "\", default \"\"";
|
|
piCout << "-l <ldd> " << Green << "- \"ldd\" path, default \"/usr/bin/ldd\"";
|
|
piCout << "-L <readelf> " << Green << "- \"readelf\" path, overrides \"ldd\"";
|
|
piCout << "-W <objdump> " << Green << "- \"objdump\" path, overrides \"ldd\"";
|
|
piCout << "-M <otool> " << Green << "- \"otool\" path, overrides \"ldd\"";
|
|
piCout << "-D <dpkg> " << Green << "- \"dpkg\" path, default \"/usr/bin/dpkg\"";
|
|
piCout << "--name-tool <path> " << Green << "- \"install_name_tool\" path, default \"install_name_tool\"";
|
|
piCout << "-d <depth> " << Green << "- maximum dependepcies depth, default 5";
|
|
//piCout << "-Q, --Qt-force " << Green << "- force add Qt root dir, default takes from \"qmake -v\"";
|
|
piCout << "";
|
|
piCout << Bold << "Qt control";
|
|
piCout << "-q <qtdir> " << Green << "- path where Qt root dir, default takes from \"qmake -v\"";
|
|
//piCout << "-C, --Conf " << Green << "- make \"qt.conf\"";
|
|
piCout << "-S <styles> " << Green << "- set Qt styles (e.g. \"oxygen,breeze\"), default \"*\"";
|
|
piCout << "-P <platforms> " << Green << "- set Qt platforms (e.g. \"win,mini\"), default by host system";
|
|
piCout << "--qt-plugins <d> " << Green << "- set Qt plugins description";
|
|
piCout << "";
|
|
piCout << Bold << "Output control";
|
|
piCout << "-o <out_path> " << Green << "- path for libraries copy to";
|
|
piCout << "-p <qt_plugins> " << Green << "- path for Qt plugins, default \"<out_path>/plugins\"";
|
|
piCout << "--dependencies " << Green << "- search dependencies by <dpkg>, print them and copy missing libraries";
|
|
piCout << "--prefix <text> " << Green << "- print <text> before dependencies";
|
|
piCout << "";
|
|
piCout << Bold << "Input control";
|
|
piCout << "<file> ... " << Green << "- executable to process";
|
|
piCout << "-a <add_libs> " << Green << "- additional libs, separated by \"" DELIM "\". Libraries will be searched in <search_path>";
|
|
}
|
|
|
|
struct QtDep {
|
|
QtDep(const PIString & l = PIString(), const PIStringList & p = PIStringList()): lib(l), plugins(p) {}
|
|
PIString lib;
|
|
PIStringList plugins;
|
|
};
|
|
QtDep qt_deps[] = {
|
|
QtDep("core" , PIStringList() << "platforms"),
|
|
QtDep("gui" , PIStringList() << "imageformats"),
|
|
QtDep("widgets" , PIStringList() << "styles"),
|
|
QtDep("sql" , PIStringList() << "sqldrivers"),
|
|
QtDep("positioning" , PIStringList() << "position"),
|
|
QtDep("location" , PIStringList() << "geoservices"),
|
|
QtDep("multimedia" , PIStringList() << "audio" << "mediaservice" << "playlistformats"),
|
|
QtDep("printsupport" , PIStringList() << "printsupport"),
|
|
QtDep("virtualkeyboard", PIStringList() << "platforminputcontexts"),
|
|
QtDep("sensors" , PIStringList() << "sensors" << "sensorgestures"),
|
|
QtDep("texttospeech" , PIStringList() << "texttospeech"),
|
|
QtDep("serialbus" , PIStringList() << "canbus"),
|
|
QtDep()
|
|
};
|
|
|
|
|
|
int depth = 5;
|
|
bool fake = false, is_ldd = true, is_deps = false, need_qt = false;
|
|
PIString ldd, readelf, objdump, otool, dpkg, nametool, out_dir, qt_dir, out_plugins_dir;
|
|
PIStringList styles, lib_dirs, add_libs, platforms, sqldrivers, input_files, plugin_libs;
|
|
PISet<PIString> all_libs, miss_libs, all_deps, frameworks, framework_libs, miss_frameworks, qt_plugins, ignore_libs;
|
|
PIMap<PIString, PIStringList> qt_filters;
|
|
|
|
|
|
PIString findLib(const PIString & l) {
|
|
if (PIFile::isExists(l)) return l;
|
|
piForeachC (PIString & s, lib_dirs) {
|
|
if (PIFile::isExists(s + l)) {
|
|
return s + l;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
|
|
PIString frameworkName(const PIString & l) {
|
|
if (!l.contains(".framework/")) return "";
|
|
PIStringList ll = l.split("/");
|
|
piForeachRC (PIString & _f, ll) {
|
|
if (_f.endsWith(".framework")) {
|
|
return _f;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
|
|
PIString frameworkInternalPath(const PIString & l) {
|
|
return l.right(l.size_s() - l.lastIndexOf(".framework") - 11);
|
|
}
|
|
|
|
|
|
PIString execute(const PIString & cmd) {
|
|
FILE * fp = popen(cmd.dataAscii(), "r");
|
|
PIString ret;
|
|
if (fp) {
|
|
const int sz = 256;
|
|
char in[sz];
|
|
memset(in, 0, sz);
|
|
while (true) {
|
|
int r = fread(in, 1, sz, fp);
|
|
if (r <= 0) break;
|
|
ret += PIString(in, r);
|
|
}
|
|
pclose(fp);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
void checkQtLib(PIString lib) {
|
|
if (lib.startsWith("lib")) lib.cutLeft(3);
|
|
if (lib.startsWith("qt5")) lib.cutLeft(3);
|
|
if (lib.startsWith("qt")) lib.cutLeft(2);
|
|
if (lib.find(".")) lib = lib.left(lib.find("."));
|
|
//piCout << "checkQt" << lib;
|
|
for (int i = 0; ; ++i) {
|
|
if (qt_deps[i].lib.isEmpty()) break;
|
|
if (qt_deps[i].lib == lib) {
|
|
qt_plugins << qt_deps[i].plugins;
|
|
//piCout << "add qt plugins" << qt_deps[i].plugins << "now" << qt_plugins;
|
|
need_qt = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void procLdd(PIString file, bool ext_lib = false, int cur_depth = 0) {
|
|
++cur_depth;
|
|
if (cur_depth > depth) return;
|
|
piCout << "scan" << file << "...";
|
|
PISet<PIString> cur_libs;
|
|
if (ext_lib) {
|
|
if (!all_libs[file]) {
|
|
cur_libs << file;
|
|
all_libs << file;
|
|
}
|
|
}
|
|
PIStringList lines;
|
|
if (is_ldd) {
|
|
lines = execute(ldd + " " + file).split("\n");
|
|
} else {
|
|
PIString cmd;
|
|
if (!readelf.isEmpty()) {
|
|
cmd = readelf + " -a " + file;
|
|
cmd += " | grep \"Shared library:\" | grep -oG \"\\[.*\\]\"";
|
|
}
|
|
if (!objdump.isEmpty()) {
|
|
cmd = objdump + " -p " + file;
|
|
cmd += " | grep \"DLL Name:\"";
|
|
lines = execute(cmd).split("\n");
|
|
cmd = objdump + " -p " + file;
|
|
cmd += " | grep \"NEEDED\"";
|
|
lines << execute(cmd).split("\n");
|
|
cmd.clear();
|
|
}
|
|
if (!otool.isEmpty()) {
|
|
cmd = otool + " -L " + file;
|
|
cmd += " | grep -o \".*(\"";
|
|
}
|
|
//piCout << cmd;
|
|
if (!cmd.isEmpty())
|
|
lines = execute(cmd).split("\n");
|
|
if (!objdump.isEmpty()) {
|
|
piForeach (PIString & l, lines) {
|
|
l.trim();
|
|
if (l.startsWith("DLL")) l.cutLeft(9).trim();
|
|
else l.cutLeft(6).trim();
|
|
l.append('.').prepend('.');
|
|
}
|
|
}
|
|
if (!otool.isEmpty()) {
|
|
piForeach (PIString & l, lines) {
|
|
l.trim().cutRight(1).trim();
|
|
l.append('.').prepend('.');
|
|
}
|
|
}
|
|
//piCout << "readelf:" << vs;
|
|
}
|
|
piForeachC (PIString & sl, lines) {
|
|
PIString l = sl.trimmed();
|
|
if (!otool.isEmpty()) {
|
|
PIString fname = frameworkName(l);
|
|
if (!fname.isEmpty()) {
|
|
frameworks << fname;
|
|
framework_libs << l.cutLeft(1).cutRight(1);
|
|
checkQtLib(fname.toLowerCase());
|
|
continue;
|
|
}
|
|
}
|
|
if (is_ldd) {
|
|
if (!l.contains("=>")) continue;
|
|
l.cutLeft(l.find("=>") + 2);
|
|
if (l.contains("("))
|
|
l.cutRight(l.length() - l.find("("));
|
|
l.trim();
|
|
if (l.toLowerCase() == "not found") {
|
|
miss_libs << sl.left(sl.find("=>")).trim();
|
|
continue;
|
|
}
|
|
} else {
|
|
l.cutLeft(1).cutRight(1).trim();
|
|
if (l.isEmpty()) continue;
|
|
if (!otool.isEmpty()) {
|
|
if (!l.startsWith("/usr/local/opt")) {
|
|
PIFile::FileInfo fi;
|
|
fi.path = l;
|
|
l = fi.name();
|
|
}
|
|
}
|
|
PIString flp = findLib(l);
|
|
if (flp.isEmpty()) {
|
|
//piCout << "Can`t find" << l;
|
|
miss_libs << l;
|
|
continue;
|
|
}
|
|
l = flp;
|
|
}
|
|
if (all_libs[l]) continue;
|
|
PIFile::FileInfo fi;
|
|
fi.path = l;
|
|
PIString lname = fi.baseName();
|
|
if (lname.startsWith("lib")) lname.cutLeft(3);
|
|
//piCout << "check ignore" << lname << ignore_libs;
|
|
if (ignore_libs.contains(lname)) {
|
|
continue;
|
|
}
|
|
checkQtLib(fi.name().toLowerCase());
|
|
cur_libs << l;
|
|
all_libs << l;
|
|
}
|
|
PIVector<PIString> clibs = cur_libs.toVector();
|
|
if (!clibs.isEmpty())
|
|
piCout << " new dependencies:\n -" << PIStringList(clibs).join("\n - ");
|
|
piForeachC (PIString & l, clibs) {
|
|
procLdd(l, false, cur_depth);
|
|
}
|
|
}
|
|
|
|
void copyWildcard(const PIString & from, const PIString & to) {
|
|
piCout << "copy" << from;
|
|
if (fake || is_deps) return;
|
|
PIDir(to).make();
|
|
#ifdef WINDOWS
|
|
PIFile::FileInfo fi; fi.path = from;
|
|
system("robocopy \"" + fi.dir() + "\" \"" + to + "\" \"" + fi.name() + "\" /NJH /NJS /NP /NDL /NS /NC /NFL 1> NUL");
|
|
#else
|
|
system(cmd_copy + from + " \"" + to + "/\"" + cmd_suffix);
|
|
#endif
|
|
}
|
|
|
|
|
|
void procQt() {
|
|
//piCout << "qmake ...";
|
|
PIString vs;
|
|
if (qt_dir.isEmpty()) {
|
|
vs = execute("qmake -v");
|
|
if (vs.isEmpty()) {
|
|
piCout << "Can`t exec \"qmake -v\"!";
|
|
return;
|
|
}
|
|
} else
|
|
vs = "QMake version ?.?\nUsing Qt version ?.?.? in " + qt_dir;
|
|
PIStringList vsl = vs.split("\n");
|
|
PIStringList pdirs = qt_plugins.toVector();
|
|
if (!fake && !is_deps)
|
|
PIDir(out_plugins_dir).make(true);
|
|
piForeach (PIString l, vsl) {
|
|
if (l.trim().contains("Qt version")) {
|
|
l.cutLeft(l.find("Qt version") + 10).trim();
|
|
PIString qv = l.takeWord();
|
|
l.takeWord();
|
|
PIString qloc = l.trim();
|
|
piCout << "Qt" << qv << "in" << qloc;
|
|
PIString qdir = qloc;
|
|
#ifdef WINDOWS
|
|
if (qt_dir.isEmpty())
|
|
qdir += "/../plugins/";
|
|
else
|
|
qdir += "/plugins/";
|
|
#else
|
|
if (qt_dir.isEmpty())
|
|
qdir += "/qt5/plugins/";
|
|
else
|
|
qdir += "/plugins/";
|
|
#endif
|
|
piForeachC (PIString & plugin, pdirs) {
|
|
PIStringList filters = qt_filters[plugin];
|
|
/*if (plugin == "platforms") filters = platforms;
|
|
if (plugin == "styles") filters = styles;
|
|
if (plugin == "sqldrivers") filters = sqldrivers;*/
|
|
piForeachC (PIString & f, filters) {
|
|
if (f.isEmpty()) continue;
|
|
copyWildcard(qdir + plugin + "/" + f, out_plugins_dir + plugin);
|
|
PIVector<PIFile::FileInfo> copied = PIDir(out_plugins_dir + plugin).entries();
|
|
piForeachC (PIFile::FileInfo & fi, copied) {
|
|
if (fi.isFile()) {
|
|
procLdd(fi.path);
|
|
plugin_libs << fi.path;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
piBreak;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool procDpkg(const PIString & l) {
|
|
PIString cmd = dpkg + " -S " + l + " 2> /dev/null";
|
|
PIString vs = execute(cmd);
|
|
if (!vs.isEmpty()) {
|
|
vs = vs.left(vs.find(":"));
|
|
if (!vs.isEmpty())
|
|
all_deps << vs;
|
|
return true;
|
|
}
|
|
//piCout << "No dep on" << l;
|
|
return false;
|
|
}
|
|
|
|
|
|
void patchNameTool() {
|
|
if (nametool.isEmpty()) return;
|
|
PIStringList clibs = all_libs.toVector(), flibs = framework_libs.toVector(), patch_list;
|
|
PIStringList dlibs;
|
|
PIString libname, cmd;
|
|
//PICout(DefaultControls) << "start patch" << clibs;
|
|
PIFile::FileInfo fi;
|
|
patch_list = input_files;
|
|
patch_list << plugin_libs;
|
|
piForeach (PIString l, clibs) {
|
|
piCout << "ALL:" << l;
|
|
fi.path = l;
|
|
patch_list << (out_dir + fi.name());
|
|
}
|
|
piForeach (PIString f, flibs) {
|
|
PIString fl = findLib(frameworkName(f));
|
|
if (fl.isEmpty()) continue;
|
|
patch_list << (out_dir + frameworkName(f) + "/" + frameworkInternalPath(f));
|
|
//PICout(DefaultControls) << "map" << f << "->" << (out_dir + frameworkName(f) + "/" + frameworkInternalPath(f));
|
|
}
|
|
piForeach (PIString local_lib, patch_list) {
|
|
cmd = otool + " -L \"" + local_lib;
|
|
cmd += "\" | grep -o \".*(\"";
|
|
dlibs = execute(cmd).split("\n");
|
|
if (!dlibs.isEmpty()) {
|
|
execute("chmod +w \"" + local_lib + "\"");
|
|
}
|
|
piCout << "patch" << local_lib;
|
|
piForeach (PIString sys_lib, dlibs) {
|
|
sys_lib.cutRight(1).trim();
|
|
fi.path = sys_lib;
|
|
libname = fi.name();
|
|
PIString fl = findLib(libname), fname = frameworkName(sys_lib);
|
|
piCout << " check" << sys_lib;
|
|
PIString new_path;
|
|
if (all_libs.contains(fl)) {
|
|
new_path = "@executable_path/../Frameworks/" + libname;
|
|
piCout << " depend on lib" << fl;
|
|
}
|
|
if (frameworks.contains(fname)) {
|
|
fl = findLib(fname);
|
|
if (fl.isEmpty()) continue;
|
|
new_path = "@executable_path/../Frameworks/" + fname + "/" + frameworkInternalPath(sys_lib);
|
|
piCout << " depend on framework" << fl;
|
|
}
|
|
if (!new_path.isEmpty()) {
|
|
cmd = nametool + " -change \"" + sys_lib + "\"";
|
|
cmd += " \"" + new_path + "\"";
|
|
cmd += " \"" + local_lib + "\" 2> /dev/null";
|
|
piCout << " " << cmd;
|
|
execute(cmd);
|
|
}
|
|
}
|
|
}
|
|
piForeach (PIString bin, input_files) {
|
|
cmd = nametool + " -add_rpath \"@executable_path/../Frameworks\"";
|
|
cmd += " \"" + bin + "\" 2> /dev/null";
|
|
execute(cmd);
|
|
}
|
|
}
|
|
|
|
|
|
int main(int argc, char * argv[]) {
|
|
PICLI cli(argc, argv);
|
|
//piCout << cli.rawArguments();
|
|
cli.setOptionalArgumentsCount(-1);
|
|
cli.addArgument("help");
|
|
cli.addArgument("verbose");
|
|
cli.addArgument("Conf");
|
|
cli.addArgument("fake");
|
|
cli.addArgument("dependencies", PIChar('\0'));
|
|
cli.addArgument("prefix", PIChar('\0'), true);
|
|
cli.addArgument("output", true);
|
|
cli.addArgument("pqt_out_plugins", true);
|
|
cli.addArgument("search_path", true);
|
|
cli.addArgument("ignore", PIChar('\0'), true);
|
|
cli.addArgument("Styles", true);
|
|
cli.addArgument("Platforms", true);
|
|
cli.addArgument("qt-plugins", PIChar('\0'), true);
|
|
cli.addArgument("ldd", true);
|
|
cli.addArgument("Lreadelf", true);
|
|
cli.addArgument("Wobjdump", true);
|
|
cli.addArgument("Motool", true);
|
|
cli.addArgument("name-tool", PIChar('\0'), true);
|
|
cli.addArgument("Dpkg", true);
|
|
cli.addArgument("depth", true);
|
|
cli.addArgument("qtdir", true);
|
|
cli.addArgument("add_libs", true);
|
|
if (cli.hasArgument("help") || cli.argumentValue("output").isEmpty() || cli.optionalArguments().isEmpty()) {
|
|
usage();
|
|
return 0;
|
|
}
|
|
setCommands();
|
|
|
|
fake = cli.hasArgument("fake");
|
|
piDebug = cli.hasArgument("verbose");
|
|
is_deps = cli.hasArgument("dependencies");
|
|
out_dir = cli.argumentValue("output");
|
|
lib_dirs = cli.argumentValue("search_path").split(DELIM);
|
|
add_libs = cli.argumentValue("add_libs").split(DELIM);
|
|
ignore_libs = cli.argumentValue("ignore").split(DELIM);
|
|
qt_dir = cli.argumentValue("qtdir");
|
|
ldd = cli.argumentValue("ldd");
|
|
readelf = cli.argumentValue("Lreadelf");
|
|
objdump = cli.argumentValue("Wobjdump");
|
|
otool = cli.argumentValue("Motool");
|
|
nametool = cli.argumentValue("name-tool");
|
|
if (nametool.isEmpty())
|
|
nametool = "install_name_tool";
|
|
dpkg = cli.argumentValue("Dpkg");
|
|
#ifdef WINDOWS
|
|
readelf.replaceAll("/", "\\");
|
|
objdump.replaceAll("/", "\\");
|
|
otool.replaceAll("/", "\\");
|
|
nametool.replaceAll("/", "\\");
|
|
dpkg.replaceAll("/", "\\");
|
|
#endif
|
|
if (dpkg.isEmpty())
|
|
dpkg = "/usr/bin/dpkg";
|
|
out_plugins_dir = out_dir;
|
|
if (!out_plugins_dir.endsWith("/")) out_plugins_dir.append('/');
|
|
if (!cli.argumentValue("pqt_out_plugins").isEmpty()) {
|
|
out_plugins_dir = cli.argumentValue("pqt_out_plugins");
|
|
if (!out_plugins_dir.endsWith("/"))
|
|
out_plugins_dir.append('/');
|
|
}
|
|
int etcnt = 0;
|
|
if (!readelf.isEmpty()) ++etcnt;
|
|
if (!objdump.isEmpty()) ++etcnt;
|
|
if (!otool.isEmpty()) ++etcnt;
|
|
if (etcnt > 1) {
|
|
piCout << "Can use only one of \"readelf\", \"objdump\" and \"otool\"!";
|
|
return 1;
|
|
}
|
|
if (etcnt > 0) is_ldd = false;
|
|
if (!qt_dir.isEmpty()) {
|
|
PIString qroot = qt_dir;
|
|
if (!qroot.endsWith("/")) qroot.append("/");
|
|
lib_dirs << (qroot + "bin") << (qroot + "lib") << (qroot + "Frameworks");
|
|
}
|
|
piForeach (PIString & s, lib_dirs) {
|
|
s.trim();
|
|
if (!s.endsWith("/")) s += "/";
|
|
}
|
|
if (out_dir.isEmpty()) out_dir = ".";
|
|
if (!out_dir.endsWith("/")) out_dir += "/";
|
|
if (ldd.isEmpty()) ldd = "/usr/bin/ldd";
|
|
|
|
out_dir.replaceAll("//", "/");
|
|
out_plugins_dir.replaceAll("//", "/");
|
|
|
|
for (int i = 0; ; ++i) {
|
|
if (qt_deps[i].lib.isEmpty()) break;
|
|
qt_deps[i].plugins.forEach([&](const PIString & p){qt_filters[p] = PIStringList("*");});
|
|
}
|
|
if (!cli.argumentValue("Platforms").isEmpty())
|
|
qplatforms = cli.argumentValue("Platforms");
|
|
platforms = qplatforms.split(",");
|
|
styles = cli.argumentValue("Styles").split(",");
|
|
if (styles.isEmpty()) styles << "";
|
|
PIStringList qpd = cli.argumentValue("qt-plugins").toLowerCase().split(DELIM);
|
|
piForeachC (PIString & qp, qpd) {
|
|
int _i = qp.indexOf("=");
|
|
if (_i < 0) continue;
|
|
PIString pname = qp.left(_i).trim();
|
|
PIString pfilt = qp.mid(_i + 1).trim();
|
|
if (pname == "*") {
|
|
for (int i = 0; ; ++i) {
|
|
if (qt_deps[i].lib.isEmpty()) break;
|
|
qt_deps[i].plugins.forEach([&](const PIString & p){qt_filters[p] = pfilt.split(",");});
|
|
}
|
|
} else
|
|
qt_filters[pname] = pfilt.split(",");
|
|
}
|
|
qt_filters["platforms"] = platforms;
|
|
qt_filters["styles" ] = styles ;
|
|
|
|
for (PIMap<PIString, PIStringList>::iterator it = qt_filters.begin(); it != qt_filters.end(); ++it)
|
|
it.value().forEachInplace([](PIString i)->PIString{
|
|
if (!i.startsWith("*")) i.prepend("*");
|
|
if (!i.endsWith("*")) i.append("*");
|
|
return i;
|
|
});
|
|
//PICout(PICoutManipulators::DefaultControls) << qt_filters;
|
|
|
|
if (!fake)
|
|
PIDir(out_dir).make();
|
|
if (!cli.argumentValue("depth").isEmpty())
|
|
depth = cli.argumentValue("depth").toInt();
|
|
|
|
cli.optionalArguments().forEach([&](const PIString & a){
|
|
if (PIDir::isExists(a)) {
|
|
PIDir(a).allEntries().forEach([&](const PIFile::FileInfo & fi){
|
|
if (fi.isFile())
|
|
input_files << fi.path;
|
|
});
|
|
} else {
|
|
if (PIFile::isExists(a))
|
|
input_files << a;
|
|
}
|
|
});
|
|
//piCout << files;
|
|
if (depth > 0)
|
|
input_files.forEach([&](const PIString & f){procLdd(f);});
|
|
piForeach (PIString & s, add_libs) {
|
|
if (s.isEmpty()) continue;
|
|
piCout << s << "->" << findLib(s);
|
|
procLdd(findLib(s), true);
|
|
}
|
|
if (need_qt && !is_deps)
|
|
procQt();
|
|
|
|
#ifdef WINDOWS
|
|
out_dir.replaceAll("/", "\\");
|
|
#endif
|
|
PIVector<PIString> clibs = all_libs.toVector();
|
|
piForeach (PIString l, clibs) {
|
|
#ifdef WINDOWS
|
|
l.replaceAll("/", "\\");
|
|
#endif
|
|
bool need_cp = true;
|
|
if (is_deps)
|
|
need_cp = !procDpkg(l);
|
|
if (need_cp) {
|
|
piCout << "copy" << l;
|
|
if (!fake)
|
|
system(cmd_copy + "\"" + l + "\" \"" + out_dir + "\"" + cmd_suffix);
|
|
}
|
|
}
|
|
PIVector<PIString> fwdirs = frameworks.toVector();
|
|
piForeachC (PIString & f, fwdirs) {
|
|
PIString fd = findLib(f);
|
|
if (!fd.isEmpty()) {
|
|
piCout << "copy framework" << f;
|
|
if (!fake)
|
|
system(cmd_copydir + "\"" + fd + "\" \"" + out_dir + "\"" + cmd_suffix);
|
|
} else
|
|
miss_frameworks << f;
|
|
}
|
|
|
|
if (!otool.isEmpty())
|
|
patchNameTool();
|
|
|
|
if (is_deps) {
|
|
PICout(PICoutManipulators::AddNone) << cli.argumentValue("prefix");
|
|
PICout(PICoutManipulators::AddNewLine) << PIStringList(all_deps.toVector()).join(", ");
|
|
} else {
|
|
piCout << "copied" << clibs.size_s() << "files";
|
|
if (!miss_libs.isEmpty())
|
|
piCout << "Missing libraries:\n -" << PIStringList(miss_libs.toVector()).join("\n - ");
|
|
if (!miss_frameworks.isEmpty())
|
|
piCout << "Missing frameworks:\n -" << PIStringList(miss_frameworks.toVector()).join("\n - ");
|
|
}
|
|
|
|
return 0;
|
|
}
|