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;
PIString cmd_copy, cmd_copydir, cmd_suffix;
PIString cmd_copy, cmd_copydir, cmd_suffix, ign_err_suffix;
PIString qplatforms;
void setCommands() {
#ifdef WINDOWS
cmd_copy = "copy /y ";
cmd_copydir = "copy /y ";
cmd_suffix = " 1> NUL";
qplatforms = "windows";
cmd_copy = "copy /y ";
cmd_copydir = "copy /y ";
cmd_suffix = " 1> NUL";
ign_err_suffix = " 2> NUL";
qplatforms = "windows";
#else
cmd_copy = "cp -f ";
cmd_copydir = "cp -rf ";
cmd_copy = "cp -f ";
cmd_copydir = "cp -rf ";
ign_err_suffix = " 2> /dev/null";
# ifdef MAC_OS
qplatforms = "cocoa";
qplatforms = "cocoa";
# else
qplatforms = "xcb,wayland";
# endif
@@ -73,42 +75,45 @@ void usage() {
<< 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 << "-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
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 << "--dpkg-workdir <d> " << Green << "- dpkg \"admindir\" path, default \"\"";
piCout << "--name-tool <path> " << Green << "- \"install_name_tool\" path, default \"install_name_tool\"";
piCout << "--strip <path> " << Green << "- \"strip\" path, default \"strip\"";
piCout << "--rpath " << Green << "- set rpath for copied files using \"patchelf\"";
piCout << "-d <depth> " << Green << "- maximum dependepcies depth, default 8";
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 << "--dpkg-workdir <d> " << Green << "- dpkg \"admindir\" path, default \"\"";
piCout << "--name-tool <path> " << Green << "- \"install_name_tool\" path, default \"install_name_tool\"";
piCout << "--strip <path> " << Green << "- \"strip\" path, default \"strip\"";
piCout << "--rpath " << Green << "- set rpath for copied files using \"patchelf\"";
piCout << "-d <depth> " << Green << "- maximum dependepcies depth, default 8";
piCout << "";
piCout << Bold << "Qt control";
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 << "-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-modules <list> " << Green << "- additional Qt modules, may be separated by \"" DELIM "\" (e.g. \"Sql" DELIM "Xml\")";
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 << "-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-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 << Bold << "Output control";
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-conf-dir <dir> " << Green << "- dir where place \"qt.conf\", default \"<out_path>\"";
piCout << "--dependencies " << Green << "- search dependencies by <dpkg>, print them and copy missing libraries";
piCout << "--prefix <text> " << Green << "- print <text> before dependencies";
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-qml-dir <d> " << Green << "- dir where place Qt QML modules, default \"<out_path>\"";
piCout << "--qt-conf-dir <dir> " << Green << "- dir where place \"qt.conf\", default \"<out_path>\"";
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
piCout << "<file> ... " << Green << "- executable to process";
piCout << "-a <add_libs> " << Green
<< "- 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;
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 qt_pref, qt_suff, qt_conf_dir, qt_plugins_dir, target_dir;
PIStringList styles, lib_dirs, add_libs, platforms, sqldrivers, input_files, plugin_libs, qt_add_libs;
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, qml_list;
PISet<PIString> all_libs, miss_libs, all_deps, frameworks, framework_libs, miss_frameworks, qt_plugins, ignore_libs, qt_libs;
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) {
++cur_depth;
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 << "...";
PISet<PIString> cur_libs;
if (ext_lib) {
@@ -286,7 +295,7 @@ void procLdd(PIString file, bool ext_lib = false, int cur_depth = 0) {
}
}
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, "NEEDED");
for (PIString & l: lines) {
@@ -368,9 +377,8 @@ void copyWildcard(const PIString & from, const PIString & to) {
if (fake) 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").data());
PIFile::FileInfo fi(from);
system(("robocopy \"" + fi.dir() + "\" \"" + to + "\" \"" + fi.name() + "\" /E /NJH /NJS /NP /NDL /NS /NC /NFL 1> NUL").data());
#else
system((cmd_copy + from + " \"" + to + "/\"" + cmd_suffix).data());
#endif
@@ -390,7 +398,10 @@ void procQt() {
vs = "QMake version ?.?\nUsing Qt version ?.?.? in " + qt_dir;
PIStringList vsl = vs.split("\n");
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) {
if (l.trim().contains("Qt version")) {
l.cutLeft(l.find("Qt version") + 10).trim();
@@ -404,7 +415,7 @@ void procQt() {
PIString qd = qloc + "/" + s + "/plugins/";
if (piDebug) PICout(AddSpaces) << "Qt plugins root try" << qd << "...";
if (PIDir::isExists(qd + "platforms")) {
qdir = qd;
qdir = qloc + "/" + s + "/";
piCout << " yes";
break;
}
@@ -413,9 +424,10 @@ void procQt() {
if (qdir.isEmpty()) break;
piForeachC(PIString & plugin, pdirs) {
PIStringList filters = qt_filters[plugin];
piCout << "PLUG" << plugin << filters;
piForeachC(PIString & f, filters) {
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();
piForeachC(PIFile::FileInfo & fi, copied) {
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;
}
}
@@ -436,7 +459,7 @@ bool procDpkg(const PIString & l) {
if (!dpkg_workdir.isEmpty()) dpkgdir = " --admindir=" + dpkg_workdir;
PIFile::FileInfo fi;
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;
PIString vs = execute(cmd);
if (!vs.isEmpty()) {
@@ -466,7 +489,7 @@ void patchNameTool() {
execute("chmod +w \"" + local_lib + "\"");
fi.path = local_lib;
cmd = nametool + " -id \"@executable_path/../Frameworks/" + fi.name() + "\"";
cmd += " \"" + local_lib + "\" 2> /dev/null";
cmd += " \"" + local_lib + "\"" + ign_err_suffix;
// piCout << " " << cmd;
execute(cmd);
}
@@ -507,7 +530,7 @@ void patchNameTool() {
if (!new_path.isEmpty() && (sys_lib != new_path)) {
cmd = nametool + " -change \"" + sys_lib + "\"";
cmd += " \"" + new_path + "\"";
cmd += " \"" + local_lib + "\" 2> /dev/null";
cmd += " \"" + local_lib + "\"" + ign_err_suffix;
// piCout << " *" << cmd;
execute(cmd);
}
@@ -515,7 +538,7 @@ void patchNameTool() {
}
piForeach(PIString bin, input_files) {
cmd = nametool + " -add_rpath \"@executable_path/../Frameworks\"";
cmd += " \"" + bin + "\" 2> /dev/null";
cmd += " \"" + bin + "\"" + ign_err_suffix;
execute(cmd);
}
}
@@ -527,14 +550,14 @@ void patchRPathFile(const PIFile::FileInfo & file) {
PIString rp = "\\$ORIGIN:\\$ORIGIN/lib";
PIString arp = PIDir(file.dir()).relative(out_dir);
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;
execute(cmd);
}
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());
piForeachC(PIString & d, dirs) {
PIVector<PIFile::FileInfo> files = PIDir(d).allEntries();
@@ -563,8 +586,10 @@ int main(int argc, char * argv[]) {
cli.addArgument("Platforms", true);
cli.addArgument("qt-plugins", 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-plugins-dir", PIChar('\0'), true);
cli.addArgument("qt-qml-dir", PIChar('\0'), true);
cli.addArgument("ldd", true);
cli.addArgument("Lreadelf", true);
cli.addArgument("Wobjdump", true);
@@ -663,17 +688,25 @@ int main(int argc, char * argv[]) {
qt_filters["styles"] = styles;
qt_add_libs = cli.argumentValue("qt-modules").split(DELIM);
qt_conf_dir = cli.argumentValue("qt-conf-dir").trim();
if (qt_conf_dir.isEmpty()) qt_conf_dir = out_dir;
if (!qt_conf_dir.endsWith("/")) qt_conf_dir += "/";
qt_plugins_dir = cli.argumentValue("qt-plugins-dir").trim();
if (qt_plugins_dir.isEmpty()) qt_plugins_dir = out_dir;
if (!qt_plugins_dir.endsWith("/")) qt_plugins_dir += "/";
qt_conf_dir.replaceAll("//", "/");
qt_plugins_dir.replaceAll("//", "/");
need_qt = !qt_add_libs.isEmpty();
auto getQtSubdir = [&cli](const char * arg, PIString & var) {
var = cli.argumentValue(arg).trim();
if (var.isEmpty())
var = out_dir;
else {
if (!PIFile::FileInfo(var).isAbsolute()) var = out_dir + "/" + var;
}
if (!var.endsWith("/")) var += "/";
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())
it.value().forEach([](PIString & i) {
if (!i.startsWith("*")) i.prepend("*");
@@ -729,18 +762,19 @@ int main(int argc, char * argv[]) {
}
if (need_qt_plugins) {
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);
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 (!qp.isEmpty() && !qp.endsWith('/')) qp.append('/');
if (!otool.isEmpty()) {
pp = "PlugIns";
lp = "Resources/lang";
}
// piCout << pp;
PIIOTextStream ts(&qtc);
ts << "[Paths]\n\tPlugins = " << pp << "\n\tTranslations = " << lp << "\n";
ts << "[Paths]\n\tPlugins = " << pp << "\n\tQml2Imports = " << qp << "\n\tTranslations = " << lp << "\n";
}
}
}