You've already forked linuxdeploy-plugin-qt
mirror of
https://github.com/encounter/linuxdeploy-plugin-qt.git
synced 2026-03-30 11:19:03 -07:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7aa7b68266 |
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
add_executable(linuxdeploy-plugin-qt main.cpp qt-modules.h)
|
add_executable(linuxdeploy-plugin-qt main.cpp qt-modules.h qt_tools_utils.hpp)
|
||||||
target_link_libraries(linuxdeploy-plugin-qt linuxdeploy_core args)
|
target_link_libraries(linuxdeploy-plugin-qt linuxdeploy_core args)
|
||||||
set_target_properties(linuxdeploy-plugin-qt PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
|
set_target_properties(linuxdeploy-plugin-qt PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin")
|
||||||
|
|
||||||
|
|||||||
+129
-82
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
// local includes
|
// local includes
|
||||||
#include "qt-modules.h"
|
#include "qt-modules.h"
|
||||||
|
#include "qt_tools_utils.hpp"
|
||||||
|
|
||||||
namespace bf = boost::filesystem;
|
namespace bf = boost::filesystem;
|
||||||
|
|
||||||
@@ -29,23 +30,25 @@ typedef struct {
|
|||||||
std::string stderrOutput;
|
std::string stderrOutput;
|
||||||
} procOutput;
|
} procOutput;
|
||||||
|
|
||||||
procOutput check_command(const std::initializer_list<const char*> args) {
|
procOutput check_command(const std::initializer_list<const char*> args)
|
||||||
|
{
|
||||||
subprocess::Popen proc(args, subprocess::output(subprocess::PIPE), subprocess::error(subprocess::PIPE));
|
subprocess::Popen proc(args, subprocess::output(subprocess::PIPE), subprocess::error(subprocess::PIPE));
|
||||||
|
|
||||||
auto output = proc.communicate();
|
auto output = proc.communicate();
|
||||||
|
|
||||||
std::string out, err;
|
std::string out, err;
|
||||||
|
|
||||||
if (output.first.length > 0)
|
if (output.first.length>0)
|
||||||
out = output.first.buf.data();
|
out = output.first.buf.data();
|
||||||
|
|
||||||
if (output.second.length > 0)
|
if (output.second.length>0)
|
||||||
err = output.second.buf.data();
|
err = output.second.buf.data();
|
||||||
|
|
||||||
return {proc.retcode() == 0, proc.retcode(), out, err};
|
return {proc.retcode()==0, proc.retcode(), out, err};
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::map<std::string, std::string> queryQmake(const bf::path& qmakePath) {
|
const std::map<std::string, std::string> queryQmake(const bf::path& qmakePath)
|
||||||
|
{
|
||||||
auto qmakeCall = check_command({qmakePath.c_str(), "-query"});
|
auto qmakeCall = check_command({qmakePath.c_str(), "-query"});
|
||||||
|
|
||||||
if (!qmakeCall.success) {
|
if (!qmakeCall.success) {
|
||||||
@@ -77,7 +80,7 @@ const std::map<std::string, std::string> queryQmake(const bf::path& qmakePath) {
|
|||||||
while (std::getline(ss, line)) {
|
while (std::getline(ss, line)) {
|
||||||
auto parts = stringSplit(line, ':');
|
auto parts = stringSplit(line, ':');
|
||||||
|
|
||||||
if (parts.size() != 2)
|
if (parts.size()!=2)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
rv[parts[0]] = parts[1];
|
rv[parts[0]] = parts[1];
|
||||||
@@ -86,29 +89,32 @@ const std::map<std::string, std::string> queryQmake(const bf::path& qmakePath) {
|
|||||||
return rv;
|
return rv;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string which(const std::string& name) {
|
static std::string which(const std::string& name)
|
||||||
|
{
|
||||||
subprocess::Popen proc({"which", name.c_str()}, subprocess::output(subprocess::PIPE));
|
subprocess::Popen proc({"which", name.c_str()}, subprocess::output(subprocess::PIPE));
|
||||||
auto output = proc.communicate();
|
auto output = proc.communicate();
|
||||||
|
|
||||||
ldLog() << LD_DEBUG << "Calling 'which" << name << LD_NO_SPACE << "'" << std::endl;
|
ldLog() << LD_DEBUG << "Calling 'which" << name << LD_NO_SPACE << "'" << std::endl;
|
||||||
|
|
||||||
if (proc.retcode() != 0) {
|
if (proc.retcode()!=0) {
|
||||||
ldLog() << LD_DEBUG << "which call failed, exit code:" << proc.retcode() << std::endl;
|
ldLog() << LD_DEBUG << "which call failed, exit code:" << proc.retcode() << std::endl;
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string path = output.first.buf.data();
|
std::string path = output.first.buf.data();
|
||||||
while (path.back() == '\n') {
|
while (path.back()=='\n') {
|
||||||
path.erase(path.end() - 1, path.end());
|
path.erase(path.end()-1, path.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Iter> std::string join(Iter beg, Iter end) {
|
template<typename Iter>
|
||||||
|
std::string join(Iter beg, Iter end)
|
||||||
|
{
|
||||||
std::stringstream rv;
|
std::stringstream rv;
|
||||||
|
|
||||||
if (beg != end) {
|
if (beg!=end) {
|
||||||
rv << *beg;
|
rv << *beg;
|
||||||
|
|
||||||
std::for_each(++beg, end, [&rv](const std::string& s) {
|
std::for_each(++beg, end, [&rv](const std::string& s) {
|
||||||
@@ -119,41 +125,46 @@ template<typename Iter> std::string join(Iter beg, Iter end) {
|
|||||||
return rv.str();
|
return rv.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string join(const std::vector<std::string>& list) {
|
std::string join(const std::vector<std::string>& list)
|
||||||
|
{
|
||||||
return join(list.begin(), list.end());
|
return join(list.begin(), list.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string join(const std::set<std::string>& list) {
|
std::string join(const std::set<std::string>& list)
|
||||||
|
{
|
||||||
return join(list.begin(), list.end());
|
return join(list.begin(), list.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool strStartsWith(const std::string& str, const std::string& prefix) {
|
bool strStartsWith(const std::string& str, const std::string& prefix)
|
||||||
if (str.size() < prefix.size())
|
{
|
||||||
|
if (str.size()<prefix.size())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return strncmp(str.c_str(), prefix.c_str(), prefix.size()) == 0;
|
return strncmp(str.c_str(), prefix.c_str(), prefix.size())==0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool strEndsWith(const std::string& str, const std::string& suffix) {
|
bool strEndsWith(const std::string& str, const std::string& suffix)
|
||||||
if (str.size() < suffix.size())
|
{
|
||||||
|
if (str.size()<suffix.size())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return strncmp(str.c_str() + (str.size() - suffix.size()), suffix.c_str(), suffix.size()) == 0;
|
return strncmp(str.c_str()+(str.size()-suffix.size()), suffix.c_str(), suffix.size())==0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deployPlatformPlugins(appdir::AppDir& appDir, const bf::path& qtPluginsPath) {
|
bool deployPlatformPlugins(appdir::AppDir& appDir, const bf::path& qtPluginsPath)
|
||||||
|
{
|
||||||
ldLog() << "Deploying platform plugins" << std::endl;
|
ldLog() << "Deploying platform plugins" << std::endl;
|
||||||
|
|
||||||
if (!appDir.deployLibrary(qtPluginsPath / "platforms/libqxcb.so", appDir.path() / "usr/plugins/platforms/"))
|
if (!appDir.deployLibrary(qtPluginsPath/"platforms/libqxcb.so", appDir.path()/"usr/plugins/platforms/"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (bf::directory_iterator i(qtPluginsPath / "platforminputcontexts"); i != bf::directory_iterator(); ++i) {
|
for (bf::directory_iterator i(qtPluginsPath/"platforminputcontexts"); i!=bf::directory_iterator(); ++i) {
|
||||||
if (!appDir.deployLibrary(*i, appDir.path() / "usr/plugins/platforminputcontexts/"))
|
if (!appDir.deployLibrary(*i, appDir.path()/"usr/plugins/platforminputcontexts/"))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (bf::directory_iterator i(qtPluginsPath / "imageformats"); i != bf::directory_iterator(); ++i) {
|
for (bf::directory_iterator i(qtPluginsPath/"imageformats"); i!=bf::directory_iterator(); ++i) {
|
||||||
if (!appDir.deployLibrary(*i, appDir.path() / "usr/plugins/imageformats/"))
|
if (!appDir.deployLibrary(*i, appDir.path()/"usr/plugins/imageformats/"))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,81 +173,89 @@ bool deployPlatformPlugins(appdir::AppDir& appDir, const bf::path& qtPluginsPath
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deployXcbglIntegrationPlugins(appdir::AppDir& appDir, const bf::path& qtPluginsPath) {
|
bool deployXcbglIntegrationPlugins(appdir::AppDir& appDir, const bf::path& qtPluginsPath)
|
||||||
|
{
|
||||||
ldLog() << "Deploying xcb-gl integrations" << std::endl;
|
ldLog() << "Deploying xcb-gl integrations" << std::endl;
|
||||||
|
|
||||||
for (bf::directory_iterator i(qtPluginsPath / "xcbglintegrations"); i != bf::directory_iterator(); ++i) {
|
for (bf::directory_iterator i(qtPluginsPath/"xcbglintegrations"); i!=bf::directory_iterator(); ++i) {
|
||||||
if (!appDir.deployLibrary(*i, appDir.path() / "usr/plugins/xcbglintegrations/"))
|
if (!appDir.deployLibrary(*i, appDir.path()/"usr/plugins/xcbglintegrations/"))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deploySvgPlugins(appdir::AppDir& appDir, const bf::path& qtPluginsPath) {
|
bool deploySvgPlugins(appdir::AppDir& appDir, const bf::path& qtPluginsPath)
|
||||||
|
{
|
||||||
ldLog() << "Deploying svg icon engine" << std::endl;
|
ldLog() << "Deploying svg icon engine" << std::endl;
|
||||||
|
|
||||||
if (!appDir.deployLibrary(qtPluginsPath / "iconengines/libqsvgicon.so", appDir.path() / "usr/plugins/iconengines/"))
|
if (!appDir.deployLibrary(qtPluginsPath/"iconengines/libqsvgicon.so", appDir.path()/"usr/plugins/iconengines/"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deployBearerPlugins(appdir::AppDir& appDir, const bf::path& qtPluginsPath) {
|
bool deployBearerPlugins(appdir::AppDir& appDir, const bf::path& qtPluginsPath)
|
||||||
|
{
|
||||||
ldLog() << "Deploying bearer plugins" << std::endl;
|
ldLog() << "Deploying bearer plugins" << std::endl;
|
||||||
|
|
||||||
for (bf::directory_iterator i(qtPluginsPath / "bearer"); i != bf::directory_iterator(); ++i) {
|
for (bf::directory_iterator i(qtPluginsPath/"bearer"); i!=bf::directory_iterator(); ++i) {
|
||||||
if (!appDir.deployLibrary(*i, appDir.path() / "usr/plugins/bearer/"))
|
if (!appDir.deployLibrary(*i, appDir.path()/"usr/plugins/bearer/"))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deploySqlPlugins(appdir::AppDir& appDir, const bf::path& qtPluginsPath) {
|
bool deploySqlPlugins(appdir::AppDir& appDir, const bf::path& qtPluginsPath)
|
||||||
|
{
|
||||||
ldLog() << "Deploying SQL plugins" << std::endl;
|
ldLog() << "Deploying SQL plugins" << std::endl;
|
||||||
|
|
||||||
for (bf::directory_iterator i(qtPluginsPath / "sqldrivers"); i != bf::directory_iterator(); ++i) {
|
for (bf::directory_iterator i(qtPluginsPath/"sqldrivers"); i!=bf::directory_iterator(); ++i) {
|
||||||
if (!appDir.deployLibrary(*i, appDir.path() / "usr/plugins/sqldrivers/"))
|
if (!appDir.deployLibrary(*i, appDir.path()/"usr/plugins/sqldrivers/"))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deployPositioningPlugins(appdir::AppDir& appDir, const bf::path& qtPluginsPath) {
|
bool deployPositioningPlugins(appdir::AppDir& appDir, const bf::path& qtPluginsPath)
|
||||||
|
{
|
||||||
ldLog() << "Deploying positioning plugins" << std::endl;
|
ldLog() << "Deploying positioning plugins" << std::endl;
|
||||||
|
|
||||||
for (bf::directory_iterator i(qtPluginsPath / "position"); i != bf::directory_iterator(); ++i) {
|
for (bf::directory_iterator i(qtPluginsPath/"position"); i!=bf::directory_iterator(); ++i) {
|
||||||
if (!appDir.deployLibrary(*i, appDir.path() / "usr/plugins/position/"))
|
if (!appDir.deployLibrary(*i, appDir.path()/"usr/plugins/position/"))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deployMultimediaPlugins(appdir::AppDir& appDir, const bf::path& qtPluginsPath) {
|
bool deployMultimediaPlugins(appdir::AppDir& appDir, const bf::path& qtPluginsPath)
|
||||||
|
{
|
||||||
ldLog() << "Deploying mediaservice plugins" << std::endl;
|
ldLog() << "Deploying mediaservice plugins" << std::endl;
|
||||||
|
|
||||||
for (bf::directory_iterator i(qtPluginsPath / "mediaservice"); i != bf::directory_iterator(); ++i) {
|
for (bf::directory_iterator i(qtPluginsPath/"mediaservice"); i!=bf::directory_iterator(); ++i) {
|
||||||
if (!appDir.deployLibrary(*i, appDir.path() / "usr/plugins/mediaservice/"))
|
if (!appDir.deployLibrary(*i, appDir.path()/"usr/plugins/mediaservice/"))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ldLog() << "Deploying audio plugins" << std::endl;
|
ldLog() << "Deploying audio plugins" << std::endl;
|
||||||
|
|
||||||
for (bf::directory_iterator i(qtPluginsPath / "audio"); i != bf::directory_iterator(); ++i) {
|
for (bf::directory_iterator i(qtPluginsPath/"audio"); i!=bf::directory_iterator(); ++i) {
|
||||||
if (!appDir.deployLibrary(*i, appDir.path() / "usr/plugins/audio/"))
|
if (!appDir.deployLibrary(*i, appDir.path()/"usr/plugins/audio/"))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deployWebEnginePlugins(appdir::AppDir& appDir, const bf::path& qtLibexecsPath, const bf::path& qtDataPath, const bf::path& qtTranslationsPath) {
|
bool deployWebEnginePlugins(appdir::AppDir& appDir, const bf::path& qtLibexecsPath, const bf::path& qtDataPath,
|
||||||
|
const bf::path& qtTranslationsPath)
|
||||||
|
{
|
||||||
ldLog() << "Deploying web engine plugins" << std::endl;
|
ldLog() << "Deploying web engine plugins" << std::endl;
|
||||||
|
|
||||||
for (bf::directory_iterator i(qtLibexecsPath); i != bf::directory_iterator(); ++i) {
|
for (bf::directory_iterator i(qtLibexecsPath); i!=bf::directory_iterator(); ++i) {
|
||||||
auto& entry = *i;
|
auto& entry = *i;
|
||||||
const std::string prefix = "QtWeb";
|
const std::string prefix = "QtWeb";
|
||||||
|
|
||||||
@@ -246,7 +265,7 @@ bool deployWebEnginePlugins(appdir::AppDir& appDir, const bf::path& qtLibexecsPa
|
|||||||
if (!strStartsWith(fileName.string(), prefix))
|
if (!strStartsWith(fileName.string(), prefix))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!appDir.deployExecutable(*i, appDir.path() / "usr/libexec/"))
|
if (!appDir.deployExecutable(*i, appDir.path()/"usr/libexec/"))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,27 +273,29 @@ bool deployWebEnginePlugins(appdir::AppDir& appDir, const bf::path& qtLibexecsPa
|
|||||||
"qtwebengine_devtools_resources.pak",
|
"qtwebengine_devtools_resources.pak",
|
||||||
"qtwebengine_resources_100p.pak",
|
"qtwebengine_resources_100p.pak",
|
||||||
"qtwebengine_resources_200p.pak", "icudtl.dat"}) {
|
"qtwebengine_resources_200p.pak", "icudtl.dat"}) {
|
||||||
auto path = qtDataPath / "resources" / fileName;
|
auto path = qtDataPath/"resources"/fileName;
|
||||||
|
|
||||||
if (bf::is_regular_file(path))
|
if (bf::is_regular_file(path))
|
||||||
appDir.deployFile(path, appDir.path() / "usr/data/resources/");
|
appDir.deployFile(path, appDir.path()/"usr/data/resources/");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bf::is_directory(qtTranslationsPath / "qtwebengine_locales")) {
|
if (bf::is_directory(qtTranslationsPath/"qtwebengine_locales")) {
|
||||||
for (bf::directory_iterator i(qtTranslationsPath / "qtwebengine_locales"); i != bf::directory_iterator(); ++i) {
|
for (bf::directory_iterator i(qtTranslationsPath/"qtwebengine_locales"); i!=bf::directory_iterator(); ++i) {
|
||||||
appDir.deployFile(*i, appDir.path() / "usr/qtwebengine_locales/");
|
appDir.deployFile(*i, appDir.path()/"usr/qtwebengine_locales/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool createQtConf(appdir::AppDir& appDir) {
|
bool createQtConf(appdir::AppDir& appDir)
|
||||||
auto qtConfPath = appDir.path() / "usr" / "bin" / "qt.conf";
|
{
|
||||||
|
auto qtConfPath = appDir.path()/"usr"/"bin"/"qt.conf";
|
||||||
|
|
||||||
if (bf::is_regular_file(qtConfPath)) {
|
if (bf::is_regular_file(qtConfPath)) {
|
||||||
ldLog() << LD_WARNING << "Skipping creation of Qt conf file: file exists:" << qtConfPath << std::endl;
|
ldLog() << LD_WARNING << "Skipping creation of Qt conf file: file exists:" << qtConfPath << std::endl;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
ldLog() << "Creating Qt conf file:" << qtConfPath << std::endl;
|
ldLog() << "Creating Qt conf file:" << qtConfPath << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +316,9 @@ bool createQtConf(appdir::AppDir& appDir) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deployTranslations(appdir::AppDir& appDir, const bf::path& qtTranslationsPath, const std::vector<QtModule>& modules) {
|
bool
|
||||||
|
deployTranslations(appdir::AppDir& appDir, const bf::path& qtTranslationsPath, const std::vector<QtModule>& modules)
|
||||||
|
{
|
||||||
if (qtTranslationsPath.empty() || !bf::is_directory(qtTranslationsPath)) {
|
if (qtTranslationsPath.empty() || !bf::is_directory(qtTranslationsPath)) {
|
||||||
ldLog() << LD_WARNING << "Translation directory does not exist, skipping deployment";
|
ldLog() << LD_WARNING << "Translation directory does not exist, skipping deployment";
|
||||||
return true;
|
return true;
|
||||||
@@ -308,7 +331,8 @@ bool deployTranslations(appdir::AppDir& appDir, const bf::path& qtTranslationsPa
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// always deploy basic Qt translations
|
// always deploy basic Qt translations
|
||||||
if (strStartsWith(fileName.string(), "qt_") && bf::basename(fileName).size() >= 5 && bf::basename(fileName).size() <= 6)
|
if (strStartsWith(fileName.string(), "qt_") && bf::basename(fileName).size()>=5
|
||||||
|
&& bf::basename(fileName).size()<=6)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
for (const auto& module : modules) {
|
for (const auto& module : modules) {
|
||||||
@@ -319,35 +343,39 @@ bool deployTranslations(appdir::AppDir& appDir, const bf::path& qtTranslationsPa
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (bf::directory_iterator i(qtTranslationsPath); i != bf::directory_iterator(); ++i) {
|
for (bf::directory_iterator i(qtTranslationsPath); i!=bf::directory_iterator(); ++i) {
|
||||||
if (!bf::is_regular_file(*i))
|
if (!bf::is_regular_file(*i))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const auto fileName = (*i).path().filename();
|
const auto fileName = (*i).path().filename();
|
||||||
|
|
||||||
if (checkName(fileName))
|
if (checkName(fileName))
|
||||||
appDir.deployFile(*i, appDir.path() / "usr/translations/");
|
appDir.deployFile(*i, appDir.path()/"usr/translations/");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(const int argc, const char* const* const argv) {
|
int main(const int argc, const char* const* const argv)
|
||||||
|
{
|
||||||
// set up verbose logging if $DEBUG is set
|
// set up verbose logging if $DEBUG is set
|
||||||
if (getenv("DEBUG"))
|
if (getenv("DEBUG"))
|
||||||
ldLog::setVerbosity(LD_DEBUG);
|
ldLog::setVerbosity(LD_DEBUG);
|
||||||
|
|
||||||
args::ArgumentParser parser("linuxdeploy Qt plugin", "Bundles Qt resources. For use with an existing AppDir, created by linuxdeploy.");
|
args::ArgumentParser parser("linuxdeploy Qt plugin",
|
||||||
|
"Bundles Qt resources. For use with an existing AppDir, created by linuxdeploy.");
|
||||||
|
|
||||||
args::ValueFlag<bf::path> appDirPath(parser, "appdir path", "Path to an existing AppDir", {"appdir"});
|
args::ValueFlag<bf::path> appDirPath(parser, "appdir path", "Path to an existing AppDir", {"appdir"});
|
||||||
args::ValueFlagList<std::string> extraPlugins(parser, "plugin", "Extra Qt plugin to deploy (specified by name, filename or path)", {'p', "extra-plugin"});
|
args::ValueFlagList<std::string> extraPlugins(parser, "plugin",
|
||||||
|
"Extra Qt plugin to deploy (specified by name, filename or path)", {'p', "extra-plugin"});
|
||||||
|
|
||||||
args::Flag pluginType(parser, "", "Print plugin type and exit", {"plugin-type"});
|
args::Flag pluginType(parser, "", "Print plugin type and exit", {"plugin-type"});
|
||||||
args::Flag pluginApiVersion(parser, "", "Print plugin API version and exit", {"plugin-api-version"});
|
args::Flag pluginApiVersion(parser, "", "Print plugin API version and exit", {"plugin-api-version"});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
parser.ParseCLI(argc, argv);
|
parser.ParseCLI(argc, argv);
|
||||||
} catch (const args::ParseError&) {
|
}
|
||||||
|
catch (const args::ParseError&) {
|
||||||
std::cerr << parser;
|
std::cerr << parser;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -382,7 +410,8 @@ int main(const int argc, const char* const* const argv) {
|
|||||||
for (const auto& dependency : elf::ElfFile(path).traceDynamicDependencies()) {
|
for (const auto& dependency : elf::ElfFile(path).traceDynamicDependencies()) {
|
||||||
libraryNames.insert(dependency.filename().string());
|
libraryNames.insert(dependency.filename().string());
|
||||||
}
|
}
|
||||||
} catch (const elf::ElfFileParseError& e) {
|
}
|
||||||
|
catch (const elf::ElfFileParseError& e) {
|
||||||
ldLog() << LD_DEBUG << "Failed to parse file as ELF file:" << path << std::endl;
|
ldLog() << LD_DEBUG << "Failed to parse file as ELF file:" << path << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,20 +426,20 @@ int main(const int argc, const char* const* const argv) {
|
|||||||
libraryName = bf::path(libraryName).filename().string();
|
libraryName = bf::path(libraryName).filename().string();
|
||||||
|
|
||||||
// adding the trailing dot makes sure e.g., libQt5WebEngineCore won't be matched as webengine and webenginecore
|
// adding the trailing dot makes sure e.g., libQt5WebEngineCore won't be matched as webengine and webenginecore
|
||||||
const auto& libraryPrefix = module.libraryFilePrefix + ".";
|
const auto& libraryPrefix = module.libraryFilePrefix+".";
|
||||||
|
|
||||||
ldLog() << LD_DEBUG << "Checking library name '" << LD_NO_SPACE << libraryName
|
ldLog() << LD_DEBUG << "Checking library name '" << LD_NO_SPACE << libraryName
|
||||||
<< LD_NO_SPACE << "' against library prefix '" << LD_NO_SPACE << libraryPrefix << LD_NO_SPACE
|
<< LD_NO_SPACE << "' against library prefix '" << LD_NO_SPACE << libraryPrefix << LD_NO_SPACE
|
||||||
<< "' and module name '" << LD_NO_SPACE << module.name << LD_NO_SPACE << "'" << std::endl;
|
<< "' and module name '" << LD_NO_SPACE << module.name << LD_NO_SPACE << "'" << std::endl;
|
||||||
|
|
||||||
// match plugin filename
|
// match plugin filename
|
||||||
if (strncmp(libraryName.c_str(), libraryPrefix.c_str(), libraryPrefix.size()) == 0) {
|
if (strncmp(libraryName.c_str(), libraryPrefix.c_str(), libraryPrefix.size())==0) {
|
||||||
ldLog() << LD_DEBUG << "-> matches library filename, found module:" << module.name << std::endl;
|
ldLog() << LD_DEBUG << "-> matches library filename, found module:" << module.name << std::endl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// match plugin name
|
// match plugin name
|
||||||
if (strcmp(libraryName.c_str(), module.name.c_str()) == 0) {
|
if (strcmp(libraryName.c_str(), module.name.c_str())==0) {
|
||||||
ldLog() << LD_DEBUG << "-> matches module name, found module:" << module.name << std::endl;
|
ldLog() << LD_DEBUG << "-> matches module name, found module:" << module.name << std::endl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -418,16 +447,20 @@ int main(const int argc, const char* const* const argv) {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::copy_if(QtModules.begin(), QtModules.end(), std::back_inserter(foundQtModules), [&matchesQtModule, &libraryNames, &extraPlugins](const QtModule& module) {
|
std::copy_if(QtModules.begin(), QtModules.end(), std::back_inserter(foundQtModules),
|
||||||
return std::find_if(libraryNames.begin(), libraryNames.end(), [&matchesQtModule, &module](const std::string& libraryName) {
|
[&matchesQtModule, &libraryNames, &extraPlugins](const QtModule& module) {
|
||||||
|
return std::find_if(libraryNames.begin(), libraryNames.end(),
|
||||||
|
[&matchesQtModule, &module](const std::string& libraryName) {
|
||||||
return matchesQtModule(libraryName, module);
|
return matchesQtModule(libraryName, module);
|
||||||
}) != libraryNames.end();
|
})!=libraryNames.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
std::copy_if(QtModules.begin(), QtModules.end(), std::back_inserter(extraQtModules), [&matchesQtModule, libraryNames, &extraPlugins](const QtModule& module) {
|
std::copy_if(QtModules.begin(), QtModules.end(), std::back_inserter(extraQtModules),
|
||||||
return std::find_if(extraPlugins.Get().begin(), extraPlugins.Get().end(), [&matchesQtModule, &module](const std::string& libraryName) {
|
[&matchesQtModule, libraryNames, &extraPlugins](const QtModule& module) {
|
||||||
|
return std::find_if(extraPlugins.Get().begin(), extraPlugins.Get().end(),
|
||||||
|
[&matchesQtModule, &module](const std::string& libraryName) {
|
||||||
return matchesQtModule(libraryName, module);
|
return matchesQtModule(libraryName, module);
|
||||||
}) != extraPlugins.Get().end();
|
})!=extraPlugins.Get().end();
|
||||||
});
|
});
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -484,42 +517,56 @@ int main(const int argc, const char* const* const argv) {
|
|||||||
for (const auto& module : qtModulesToDeploy) {
|
for (const auto& module : qtModulesToDeploy) {
|
||||||
ldLog() << std::endl << "-- Deploying module:" << module.name << "--" << std::endl;
|
ldLog() << std::endl << "-- Deploying module:" << module.name << "--" << std::endl;
|
||||||
|
|
||||||
if (module.name == "gui") {
|
if (module.name=="core") {
|
||||||
|
string errStr;
|
||||||
|
string qtCoreLibraryPath;
|
||||||
|
for (auto libraryName: appDir.listSharedLibraries()) {
|
||||||
|
if (libraryName.filename().string().find("Qt5Core.")!=std::string::npos)
|
||||||
|
qtCoreLibraryPath = libraryName.string();
|
||||||
|
}
|
||||||
|
patchQtCore(qtCoreLibraryPath, &errStr);
|
||||||
|
if (!errStr.empty()) {
|
||||||
|
ldLog() << "Failed to patch QtCore. " << errStr;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (module.name=="gui") {
|
||||||
if (!deployPlatformPlugins(appDir, qtPluginsPath))
|
if (!deployPlatformPlugins(appDir, qtPluginsPath))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (module.name == "opengl" || module.name == "gui" || module.name == "xcbqpa") {
|
if (module.name=="opengl" || module.name=="gui" || module.name=="xcbqpa") {
|
||||||
if (!deployXcbglIntegrationPlugins(appDir, qtPluginsPath))
|
if (!deployXcbglIntegrationPlugins(appDir, qtPluginsPath))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (module.name == "network") {
|
if (module.name=="network") {
|
||||||
if (!deployBearerPlugins(appDir, qtPluginsPath))
|
if (!deployBearerPlugins(appDir, qtPluginsPath))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (module.name == "svg") {
|
if (module.name=="svg") {
|
||||||
if (!deploySvgPlugins(appDir, qtPluginsPath))
|
if (!deploySvgPlugins(appDir, qtPluginsPath))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (module.name == "sql") {
|
if (module.name=="sql") {
|
||||||
if (!deploySqlPlugins(appDir, qtPluginsPath))
|
if (!deploySqlPlugins(appDir, qtPluginsPath))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (module.name == "positioning") {
|
if (module.name=="positioning") {
|
||||||
if (!deployPositioningPlugins(appDir, qtPluginsPath))
|
if (!deployPositioningPlugins(appDir, qtPluginsPath))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (module.name == "multimedia") {
|
if (module.name=="multimedia") {
|
||||||
if (!deployMultimediaPlugins(appDir, qtPluginsPath))
|
if (!deployMultimediaPlugins(appDir, qtPluginsPath))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (module.name == "webenginecore") {
|
if (module.name=="webenginecore") {
|
||||||
if (!deployWebEnginePlugins(appDir, qtLibexecsPath, qtDataPath, qtTranslationsPath))
|
if (!deployWebEnginePlugins(appDir, qtLibexecsPath, qtDataPath, qtTranslationsPath))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the tools applications of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QT_TOOLS_UTILS
|
||||||
|
#define QT_TOOLS_UTILS
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
#include <boost/filesystem/operations.hpp>
|
||||||
|
|
||||||
|
#include "../lib/linuxdeploy/include/linuxdeploy/core/log.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace boost::filesystem;
|
||||||
|
using namespace linuxdeploy::core::log;
|
||||||
|
|
||||||
|
vector<char> readFileContent(const path& path, string* errorMessage);
|
||||||
|
void writeFileContent(const path& path, const vector<char>& content, string* errorMessage);
|
||||||
|
|
||||||
|
// Search for "qt_prfxpath=xxxx" in \a path, and replace it with "qt_prfxpath=."
|
||||||
|
void patchQtCore(const path& path, string* errorMessage = nullptr)
|
||||||
|
{
|
||||||
|
ldLog() << "Patching " << path.filename() << "...\n";
|
||||||
|
|
||||||
|
auto content = readFileContent(path, errorMessage);
|
||||||
|
if (content.empty()) {
|
||||||
|
*errorMessage = "Unable to patch"+path.string()+": Could not read file content";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char prfxpath[] = "qt_prfxpath=";
|
||||||
|
size_t len = strlen(prfxpath);
|
||||||
|
|
||||||
|
auto startPos = std::search(content.begin(), content.end(), prfxpath, prfxpath+len);
|
||||||
|
if (startPos==content.end()) {
|
||||||
|
*errorMessage = "Unable to patch "+path.string()+": Could not locate pattern \"qt_prfxpath=\"";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
startPos += len;
|
||||||
|
auto endPos = startPos;
|
||||||
|
while (endPos!=content.end() && *endPos!='\0')
|
||||||
|
endPos++;
|
||||||
|
|
||||||
|
if (endPos==content.end()) {
|
||||||
|
*errorMessage = "Unable to patch "+path.string()+": Internal error";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto oldValue = vector<char>(startPos, endPos);
|
||||||
|
vector<char> newValue(static_cast<unsigned long>(endPos-startPos), char(0));
|
||||||
|
newValue[0] = '.';
|
||||||
|
ldLog() << "Replaced prfxpath: " << oldValue << " by " << newValue;
|
||||||
|
|
||||||
|
for (auto i = startPos; i<endPos; i++)
|
||||||
|
*i = newValue[i-startPos];
|
||||||
|
|
||||||
|
writeFileContent(path, content, errorMessage);
|
||||||
|
}
|
||||||
|
void writeFileContent(const path& path, const vector<char>& content, string* errorMessage)
|
||||||
|
{
|
||||||
|
std::ofstream outfile(path.string(), std::ofstream::binary);
|
||||||
|
outfile.write(content.data(), content.size());
|
||||||
|
if (outfile.fail())
|
||||||
|
*errorMessage = "Unable to write : "+path.string();
|
||||||
|
|
||||||
|
outfile.close();
|
||||||
|
}
|
||||||
|
vector<char> readFileContent(const path& path, string* errorMessage)
|
||||||
|
{
|
||||||
|
std::ifstream inFileStream(path.string(), std::ifstream::binary);
|
||||||
|
if (inFileStream) {
|
||||||
|
// get length of file:
|
||||||
|
inFileStream.seekg(0, std::ifstream::end);
|
||||||
|
auto length = static_cast<unsigned long>(inFileStream.tellg());
|
||||||
|
inFileStream.seekg(0, std::ifstream::beg);
|
||||||
|
auto* buffer = new char[length];
|
||||||
|
|
||||||
|
inFileStream.read(buffer, length);
|
||||||
|
|
||||||
|
if (inFileStream.fail())
|
||||||
|
*errorMessage = "Unable to read : "+path.string();
|
||||||
|
|
||||||
|
inFileStream.close();
|
||||||
|
vector<char> output(buffer, buffer+length);
|
||||||
|
delete[] buffer;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif QT_TOOLS_UTILS
|
||||||
Reference in New Issue
Block a user