deploy_tool - no objdump errors, Qml modules support, Windows custom Qt plugins and qml root directories

This commit is contained in:
2023-06-14 23:30:48 +03:00
parent 0ae63fa9ad
commit dd56b1c142

View File

@@ -26,20 +26,22 @@
using namespace PICoutManipulators; using namespace PICoutManipulators;
PIString cmd_copy, cmd_copydir, cmd_suffix; PIString cmd_copy, cmd_copydir, cmd_suffix, ign_err_suffix;
PIString qplatforms; PIString qplatforms;
void setCommands() { void setCommands() {
#ifdef WINDOWS #ifdef WINDOWS
cmd_copy = "copy /y "; cmd_copy = "copy /y ";
cmd_copydir = "copy /y "; cmd_copydir = "copy /y ";
cmd_suffix = " 1> NUL"; cmd_suffix = " 1> NUL";
qplatforms = "windows"; ign_err_suffix = " 2> NUL";
qplatforms = "windows";
#else #else
cmd_copy = "cp -f "; cmd_copy = "cp -f ";
cmd_copydir = "cp -rf "; cmd_copydir = "cp -rf ";
ign_err_suffix = " 2> /dev/null";
# ifdef MAC_OS # ifdef MAC_OS
qplatforms = "cocoa"; qplatforms = "cocoa";
# else # else
qplatforms = "xcb,wayland"; qplatforms = "xcb,wayland";
# endif # endif
@@ -73,42 +75,45 @@ void usage() {
<< NewLine; << NewLine;
piCout << Green << Bold << "Details:"; piCout << Green << Bold << "Details:";
piCout << Bold << "Debug control"; piCout << Bold << "Debug control";
piCout << "-h, --help " << Green << "- display this message and exit"; piCout << "-h, --help " << Green << "- display this message and exit";
piCout << "-v, --verbose " << Green << "- be verbose"; piCout << "-v, --verbose " << Green << "- be verbose";
piCout << ""; piCout << "";
piCout << Bold << "Processing control"; piCout << Bold << "Processing control";
piCout << "-f, --fake " << Green << "- don`t copy, only print"; piCout << "-f, --fake " << Green << "- don`t copy, only print";
piCout << "-s <search_path> " << Green piCout << "-s <search_path> " << Green
<< "- set search pathes for system libraries, may be separated by \"" DELIM "\", default \"/usr/lib\""; << "- 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 << "--ignore <libs> " << Green << "- ignore libraries names, may be separated by \"" DELIM "\", default \"\"";
piCout << "-l <ldd> " << Green << "- \"ldd\" path, default \"/usr/bin/ldd\""; piCout << "-l <ldd> " << Green << "- \"ldd\" path, default \"/usr/bin/ldd\"";
piCout << "-L <readelf> " << Green << "- \"readelf\" path, overrides \"ldd\""; piCout << "-L <readelf> " << Green << "- \"readelf\" path, overrides \"ldd\"";
piCout << "-W <objdump> " << Green << "- \"objdump\" path, overrides \"ldd\""; piCout << "-W <objdump> " << Green << "- \"objdump\" path, overrides \"ldd\"";
piCout << "-M <otool> " << Green << "- \"otool\" path, overrides \"ldd\""; piCout << "-M <otool> " << Green << "- \"otool\" path, overrides \"ldd\"";
piCout << "-D <dpkg> " << Green << "- \"dpkg\" path, default \"/usr/bin/dpkg\""; piCout << "-D <dpkg> " << Green << "- \"dpkg\" path, default \"/usr/bin/dpkg\"";
piCout << "--dpkg-workdir <d> " << Green << "- dpkg \"admindir\" path, default \"\""; piCout << "--dpkg-workdir <d> " << Green << "- dpkg \"admindir\" path, default \"\"";
piCout << "--name-tool <path> " << Green << "- \"install_name_tool\" path, default \"install_name_tool\""; piCout << "--name-tool <path> " << Green << "- \"install_name_tool\" path, default \"install_name_tool\"";
piCout << "--strip <path> " << Green << "- \"strip\" path, default \"strip\""; piCout << "--strip <path> " << Green << "- \"strip\" path, default \"strip\"";
piCout << "--rpath " << Green << "- set rpath for copied files using \"patchelf\""; piCout << "--rpath " << Green << "- set rpath for copied files using \"patchelf\"";
piCout << "-d <depth> " << Green << "- maximum dependepcies depth, default 8"; piCout << "-d <depth> " << Green << "- maximum dependepcies depth, default 8";
piCout << ""; piCout << "";
piCout << Bold << "Qt control"; piCout << Bold << "Qt control";
piCout << "-q <qtdir> " << Green << "- path where Qt root dir, default takes from \"qmake -v\""; piCout << "-q <qtdir> " << Green << "- path where Qt root dir, default takes from \"qmake -v\"";
piCout << "-S <styles> " << Green << "- set Qt styles (e.g. \"oxygen,breeze\"), default \"*\""; 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 << "-P <platforms> " << Green << "- set Qt platforms (e.g. \"win,mini\"), default by host system";
piCout << "--qt-plugins <d> " << Green << "- set Qt plugins description"; piCout << "--qt-plugins <d> " << Green << "- set Qt plugins description";
piCout << "--qt-modules <list> " << Green << "- additional Qt modules, may be separated by \"" DELIM "\" (e.g. \"Sql" DELIM "Xml\")"; piCout << "--qt-modules <list> " << Green << "- additional Qt modules, may be separated by \"" DELIM "\" (e.g. \"Sql" DELIM "Xml\")";
piCout << "--qml-modules <list> " << Green
<< "- additional Qt QML modules, may be separated by \"" DELIM "\" (e.g. \"Qt" DELIM "QtQuick.2\")";
piCout << ""; piCout << "";
piCout << Bold << "Output control"; piCout << Bold << "Output control";
piCout << "-o <out_path> " << Green << "- path for libraries copy to"; piCout << "-o <out_path> " << Green << "- path for libraries copy to";
piCout << "--qt-plugins-dir <d>" << Green << "- dir where place Qt plugins, default \"<out_path>\""; piCout << "--qt-plugins-dir <d> " << Green << "- dir where place Qt plugins, default \"<out_path>\"";
piCout << "--qt-conf-dir <dir> " << Green << "- dir where place \"qt.conf\", default \"<out_path>\""; piCout << "--qt-qml-dir <d> " << Green << "- dir where place Qt QML modules, default \"<out_path>\"";
piCout << "--dependencies " << Green << "- search dependencies by <dpkg>, print them and copy missing libraries"; piCout << "--qt-conf-dir <dir> " << Green << "- dir where place \"qt.conf\", default \"<out_path>\"";
piCout << "--prefix <text> " << Green << "- print <text> before dependencies"; piCout << "--dependencies " << Green << "- search dependencies by <dpkg>, print them and copy missing libraries";
piCout << "--prefix <text> " << Green << "- print <text> before dependencies";
piCout << ""; piCout << "";
piCout << Bold << "Input control"; piCout << Bold << "Input control";
piCout << "<file> ... " << Green << "- executable to process"; piCout << "<file> ... " << Green << "- executable to process";
piCout << "-a <add_libs> " << Green piCout << "-a <add_libs> " << Green
<< "- additional libs, separated by \"" DELIM "\". Libraries will be searched in <search_path>"; << "- additional libs, separated by \"" DELIM "\". Libraries will be searched in <search_path>";
} }
@@ -140,8 +145,8 @@ QtDep qt_deps[] = {QtDep("core", PIStringList() << "platforms"),
int depth = 8; int depth = 8;
bool fake = false, is_ldd = true, is_deps = false, need_qt = false, make_qt_format = true, rpath = false, win_target = false; bool fake = false, is_ldd = true, is_deps = false, need_qt = false, make_qt_format = true, rpath = false, win_target = false;
PIString ldd, readelf, objdump, otool, dpkg, nametool, strip, out_dir, qt_dir, dpkg_workdir; PIString ldd, readelf, objdump, otool, dpkg, nametool, strip, out_dir, qt_dir, dpkg_workdir;
PIString qt_pref, qt_suff, qt_conf_dir, qt_plugins_dir, target_dir; PIString qt_pref, qt_suff, qt_conf_dir, qt_plugins_dir, qt_qml_dir, target_dir;
PIStringList styles, lib_dirs, add_libs, platforms, sqldrivers, input_files, plugin_libs, qt_add_libs; PIStringList styles, lib_dirs, add_libs, platforms, sqldrivers, input_files, plugin_libs, qt_add_libs, qml_list;
PISet<PIString> all_libs, miss_libs, all_deps, frameworks, framework_libs, miss_frameworks, qt_plugins, ignore_libs, qt_libs; PISet<PIString> all_libs, miss_libs, all_deps, frameworks, framework_libs, miss_frameworks, qt_plugins, ignore_libs, qt_libs;
PIMap<PIString, PIStringList> qt_filters; PIMap<PIString, PIStringList> qt_filters;
@@ -264,6 +269,10 @@ void checkQtLib(PIString lib) {
void procLdd(PIString file, bool ext_lib = false, int cur_depth = 0) { void procLdd(PIString file, bool ext_lib = false, int cur_depth = 0) {
++cur_depth; ++cur_depth;
if (cur_depth > depth) return; if (cur_depth > depth) return;
static PIStringList ignore_ext =
{"png", "jpg", "jpeg", "ico", "pdf", "txt", "conf", "json", "qml", "glsl", "fraq", "vert", "qmltypes", "metainfo", "qm", "ttf"};
PIString ext = PIFile::FileInfo(file).extension();
if (ignore_ext.contains(ext.toLowerCase())) return;
piCout << "scan" << file << "..."; piCout << "scan" << file << "...";
PISet<PIString> cur_libs; PISet<PIString> cur_libs;
if (ext_lib) { if (ext_lib) {
@@ -286,7 +295,7 @@ void procLdd(PIString file, bool ext_lib = false, int cur_depth = 0) {
} }
} }
if (!objdump.isEmpty()) { if (!objdump.isEmpty()) {
PIString out = execute(objdump + " -p \"" + file + "\""); PIString out = execute(objdump + " -p \"" + file + "\"" + ign_err_suffix);
lines = filter(out, "DLL Name:"); lines = filter(out, "DLL Name:");
lines << filter(out, "NEEDED"); lines << filter(out, "NEEDED");
for (PIString & l: lines) { for (PIString & l: lines) {
@@ -368,9 +377,8 @@ void copyWildcard(const PIString & from, const PIString & to) {
if (fake) return; if (fake) return;
PIDir(to).make(); PIDir(to).make();
#ifdef WINDOWS #ifdef WINDOWS
PIFile::FileInfo fi; PIFile::FileInfo fi(from);
fi.path = from; system(("robocopy \"" + fi.dir() + "\" \"" + to + "\" \"" + fi.name() + "\" /E /NJH /NJS /NP /NDL /NS /NC /NFL 1> NUL").data());
system(("robocopy \"" + fi.dir() + "\" \"" + to + "\" \"" + fi.name() + "\" /NJH /NJS /NP /NDL /NS /NC /NFL 1> NUL").data());
#else #else
system((cmd_copy + from + " \"" + to + "/\"" + cmd_suffix).data()); system((cmd_copy + from + " \"" + to + "/\"" + cmd_suffix).data());
#endif #endif
@@ -390,7 +398,10 @@ void procQt() {
vs = "QMake version ?.?\nUsing Qt version ?.?.? in " + qt_dir; vs = "QMake version ?.?\nUsing Qt version ?.?.? in " + qt_dir;
PIStringList vsl = vs.split("\n"); PIStringList vsl = vs.split("\n");
PIStringList pdirs = qt_plugins.toVector(); PIStringList pdirs = qt_plugins.toVector();
if (!fake) PIDir(qt_plugins_dir).make(true); if (!fake) {
PIDir(qt_plugins_dir).make(true);
PIDir(qt_qml_dir).make(true);
}
piForeach(PIString l, vsl) { piForeach(PIString l, vsl) {
if (l.trim().contains("Qt version")) { if (l.trim().contains("Qt version")) {
l.cutLeft(l.find("Qt version") + 10).trim(); l.cutLeft(l.find("Qt version") + 10).trim();
@@ -404,7 +415,7 @@ void procQt() {
PIString qd = qloc + "/" + s + "/plugins/"; PIString qd = qloc + "/" + s + "/plugins/";
if (piDebug) PICout(AddSpaces) << "Qt plugins root try" << qd << "..."; if (piDebug) PICout(AddSpaces) << "Qt plugins root try" << qd << "...";
if (PIDir::isExists(qd + "platforms")) { if (PIDir::isExists(qd + "platforms")) {
qdir = qd; qdir = qloc + "/" + s + "/";
piCout << " yes"; piCout << " yes";
break; break;
} }
@@ -413,9 +424,10 @@ void procQt() {
if (qdir.isEmpty()) break; if (qdir.isEmpty()) break;
piForeachC(PIString & plugin, pdirs) { piForeachC(PIString & plugin, pdirs) {
PIStringList filters = qt_filters[plugin]; PIStringList filters = qt_filters[plugin];
piCout << "PLUG" << plugin << filters;
piForeachC(PIString & f, filters) { piForeachC(PIString & f, filters) {
if (f.isEmpty()) continue; if (f.isEmpty()) continue;
copyWildcard(qdir + plugin + "/" + f, qt_plugins_dir + plugin); copyWildcard(qdir + "plugins/" + plugin + "/" + f, qt_plugins_dir + plugin);
PIVector<PIFile::FileInfo> copied = PIDir(qt_plugins_dir + plugin).entries(); PIVector<PIFile::FileInfo> copied = PIDir(qt_plugins_dir + plugin).entries();
piForeachC(PIFile::FileInfo & fi, copied) { piForeachC(PIFile::FileInfo & fi, copied) {
if (fi.isFile()) { if (fi.isFile()) {
@@ -425,6 +437,17 @@ void procQt() {
} }
} }
} }
for (const auto & q: qml_list) {
if (q.isEmpty()) continue;
copyWildcard(qdir + "qml/" + q + "/*", qt_qml_dir + q);
PIVector<PIFile::FileInfo> copied = PIDir(qt_qml_dir + q).allEntries();
piForeachC(PIFile::FileInfo & fi, copied) {
if (fi.isFile()) {
procLdd(fi.path);
plugin_libs << fi.path;
}
}
}
break; break;
} }
} }
@@ -436,7 +459,7 @@ bool procDpkg(const PIString & l) {
if (!dpkg_workdir.isEmpty()) dpkgdir = " --admindir=" + dpkg_workdir; if (!dpkg_workdir.isEmpty()) dpkgdir = " --admindir=" + dpkg_workdir;
PIFile::FileInfo fi; PIFile::FileInfo fi;
fi.path = l; fi.path = l;
PIString cmd = dpkg + dpkgdir + " -S " + fi.name() + " 2> /dev/null"; PIString cmd = dpkg + dpkgdir + " -S " + fi.name() + ign_err_suffix;
// PICout(true) << cmd; // PICout(true) << cmd;
PIString vs = execute(cmd); PIString vs = execute(cmd);
if (!vs.isEmpty()) { if (!vs.isEmpty()) {
@@ -466,7 +489,7 @@ void patchNameTool() {
execute("chmod +w \"" + local_lib + "\""); execute("chmod +w \"" + local_lib + "\"");
fi.path = local_lib; fi.path = local_lib;
cmd = nametool + " -id \"@executable_path/../Frameworks/" + fi.name() + "\""; cmd = nametool + " -id \"@executable_path/../Frameworks/" + fi.name() + "\"";
cmd += " \"" + local_lib + "\" 2> /dev/null"; cmd += " \"" + local_lib + "\"" + ign_err_suffix;
// piCout << " " << cmd; // piCout << " " << cmd;
execute(cmd); execute(cmd);
} }
@@ -507,7 +530,7 @@ void patchNameTool() {
if (!new_path.isEmpty() && (sys_lib != new_path)) { if (!new_path.isEmpty() && (sys_lib != new_path)) {
cmd = nametool + " -change \"" + sys_lib + "\""; cmd = nametool + " -change \"" + sys_lib + "\"";
cmd += " \"" + new_path + "\""; cmd += " \"" + new_path + "\"";
cmd += " \"" + local_lib + "\" 2> /dev/null"; cmd += " \"" + local_lib + "\"" + ign_err_suffix;
// piCout << " *" << cmd; // piCout << " *" << cmd;
execute(cmd); execute(cmd);
} }
@@ -515,7 +538,7 @@ void patchNameTool() {
} }
piForeach(PIString bin, input_files) { piForeach(PIString bin, input_files) {
cmd = nametool + " -add_rpath \"@executable_path/../Frameworks\""; cmd = nametool + " -add_rpath \"@executable_path/../Frameworks\"";
cmd += " \"" + bin + "\" 2> /dev/null"; cmd += " \"" + bin + "\"" + ign_err_suffix;
execute(cmd); execute(cmd);
} }
} }
@@ -527,14 +550,14 @@ void patchRPathFile(const PIFile::FileInfo & file) {
PIString rp = "\\$ORIGIN:\\$ORIGIN/lib"; PIString rp = "\\$ORIGIN:\\$ORIGIN/lib";
PIString arp = PIDir(file.dir()).relative(out_dir); PIString arp = PIDir(file.dir()).relative(out_dir);
if (!arp.isEmpty() && arp != "." && arp != "lib") rp.append(":\\$ORIGIN/" + arp); if (!arp.isEmpty() && arp != "." && arp != "lib") rp.append(":\\$ORIGIN/" + arp);
PIString cmd = "patchelf --set-rpath \"" + rp + "\" \"" + file.path + "\" 2> /dev/null"; PIString cmd = "patchelf --set-rpath \"" + rp + "\" \"" + file.path + "\"" + ign_err_suffix;
piCout << "set rpath" << file.path << "to" << rp; piCout << "set rpath" << file.path << "to" << rp;
execute(cmd); execute(cmd);
} }
void patchRPath() { void patchRPath() {
PIStringList dirs({out_dir, target_dir, qt_plugins_dir}); PIStringList dirs({out_dir, target_dir, qt_plugins_dir, qt_qml_dir});
dirs.removeDuplicates().removeStrings(PIString()); dirs.removeDuplicates().removeStrings(PIString());
piForeachC(PIString & d, dirs) { piForeachC(PIString & d, dirs) {
PIVector<PIFile::FileInfo> files = PIDir(d).allEntries(); PIVector<PIFile::FileInfo> files = PIDir(d).allEntries();
@@ -563,8 +586,10 @@ int main(int argc, char * argv[]) {
cli.addArgument("Platforms", true); cli.addArgument("Platforms", true);
cli.addArgument("qt-plugins", PIChar('\0'), true); cli.addArgument("qt-plugins", PIChar('\0'), true);
cli.addArgument("qt-modules", PIChar('\0'), true); cli.addArgument("qt-modules", PIChar('\0'), true);
cli.addArgument("qml-modules", PIChar('\0'), true);
cli.addArgument("qt-conf-dir", PIChar('\0'), true); cli.addArgument("qt-conf-dir", PIChar('\0'), true);
cli.addArgument("qt-plugins-dir", PIChar('\0'), true); cli.addArgument("qt-plugins-dir", PIChar('\0'), true);
cli.addArgument("qt-qml-dir", PIChar('\0'), true);
cli.addArgument("ldd", true); cli.addArgument("ldd", true);
cli.addArgument("Lreadelf", true); cli.addArgument("Lreadelf", true);
cli.addArgument("Wobjdump", true); cli.addArgument("Wobjdump", true);
@@ -663,17 +688,25 @@ int main(int argc, char * argv[]) {
qt_filters["styles"] = styles; qt_filters["styles"] = styles;
qt_add_libs = cli.argumentValue("qt-modules").split(DELIM); qt_add_libs = cli.argumentValue("qt-modules").split(DELIM);
qt_conf_dir = cli.argumentValue("qt-conf-dir").trim(); auto getQtSubdir = [&cli](const char * arg, PIString & var) {
if (qt_conf_dir.isEmpty()) qt_conf_dir = out_dir; var = cli.argumentValue(arg).trim();
if (!qt_conf_dir.endsWith("/")) qt_conf_dir += "/"; if (var.isEmpty())
qt_plugins_dir = cli.argumentValue("qt-plugins-dir").trim(); var = out_dir;
if (qt_plugins_dir.isEmpty()) qt_plugins_dir = out_dir; else {
if (!qt_plugins_dir.endsWith("/")) qt_plugins_dir += "/"; if (!PIFile::FileInfo(var).isAbsolute()) var = out_dir + "/" + var;
qt_conf_dir.replaceAll("//", "/"); }
qt_plugins_dir.replaceAll("//", "/"); if (!var.endsWith("/")) var += "/";
need_qt = !qt_add_libs.isEmpty(); var.replaceAll("//", "/");
};
getQtSubdir("qt-conf-dir", qt_conf_dir);
getQtSubdir("qt-plugins-dir", qt_plugins_dir);
getQtSubdir("qt-qml-dir", qt_qml_dir);
auto it = qt_filters.makeIterator(); qml_list = cli.argumentValue("qml-modules").split(DELIM);
need_qt = !qt_add_libs.isEmpty();
auto it = qt_filters.makeIterator();
while (it.next()) while (it.next())
it.value().forEach([](PIString & i) { it.value().forEach([](PIString & i) {
if (!i.startsWith("*")) i.prepend("*"); if (!i.startsWith("*")) i.prepend("*");
@@ -729,18 +762,19 @@ int main(int argc, char * argv[]) {
} }
if (need_qt_plugins) { if (need_qt_plugins) {
procQt(); procQt();
if (!ldd.isEmpty() || !readelf.isEmpty()) { // qt.conf for Linux if (!ldd.isEmpty() || !readelf.isEmpty()) { // qt.conf for Linux and Windows
PIFile qtc(qt_conf_dir + "qt.conf", PIIODevice::ReadWrite); PIFile qtc(qt_conf_dir + "qt.conf", PIIODevice::ReadWrite);
qtc.clear(); qtc.clear();
PIString pp = PIDir(qt_conf_dir).relative(qt_plugins_dir), lp = "lang/"; PIString pp = PIDir(qt_conf_dir).relative(qt_plugins_dir), qp = PIDir(qt_conf_dir).relative(qt_qml_dir), lp = "lang/";
if (!pp.isEmpty() && !pp.endsWith('/')) pp.append('/'); if (!pp.isEmpty() && !pp.endsWith('/')) pp.append('/');
if (!qp.isEmpty() && !qp.endsWith('/')) qp.append('/');
if (!otool.isEmpty()) { if (!otool.isEmpty()) {
pp = "PlugIns"; pp = "PlugIns";
lp = "Resources/lang"; lp = "Resources/lang";
} }
// piCout << pp; // piCout << pp;
PIIOTextStream ts(&qtc); PIIOTextStream ts(&qtc);
ts << "[Paths]\n\tPlugins = " << pp << "\n\tTranslations = " << lp << "\n"; ts << "[Paths]\n\tPlugins = " << pp << "\n\tQml2Imports = " << qp << "\n\tTranslations = " << lp << "\n";
} }
} }
} }