用于Linux平台库的蒸汽,导致Qt应用程序的不当行为。

时间:2022-08-17 12:33:05

I'm currently having difficulties with a very simple launcher application that's intended to display a webpage and have some buttons to launch a game. When you click a link inside of the launcher it is intended to simply launch your default webbrowser with the link, rather than accepting and handling navigation requests.

我目前在一个非常简单的启动应用程序上遇到了困难,这个应用程序的目的是显示一个网页,并有一些按钮来启动一个游戏。当你点击启动器内部的一个链接时,它只是简单地用这个链接启动你的默认web浏览器,而不是接受和处理导航请求。

However, when launched via Steam, links fail to open in a new webbrowser. Exact behavior depends on the environment, I've had reports of copies of gvfs-open and xdg-open hanging, though on my environment it simply gives mouse indication that firefox is opening for a split second and does nothing (including no processes launched at all according to strace, possibly has something to do with KDE's message passing system, I don't know). Vexingly enough, there are also reports that it just works fine. And so I'm having quite a problem hammering down the exact issue as a result.

然而,当通过Steam发布时,链接无法在新的web浏览器中打开。精确的行为取决于环境,我已经报告的副本gvfs-open xdg-open挂,不过在我的环境中它只是使鼠标表明firefox是一瞬间开放和没有(包括任何流程启动据strace,可能与KDE的消息传递系统,我不知道)。令人懊恼的是,也有报道称它很有效。所以我有一个相当大的问题要解决。

I've managed to narrow down the issues to Steam modifying the LD_LIBARRY_PATH of the executable to use Steam's Linux platforms. I've bundled all of the libraries needed by the launcher with the launcher.

我已经设法缩小了问题的范围,通过修改可执行文件的LD_LIBARRY_PATH来使用Steam的Linux平台。我已经将启动程序所需的所有库与启动程序绑定在一起。

Here is a minimal reproducible guide:

这里有一个最小的可重复的指南:

main.cpp

main.cpp

#include <QApplication>
#include <QWebFrame>
#include <QDesktopServices>
#include <QNetworkRequest>
#include <QMessageBox>
#include <QWebView>

class WebPage : public QWebPage {
public:
  bool acceptNavigationRequest(QWebFrame*, const QNetworkRequest &request, NavigationType) {
    QDesktopServices::openUrl(request.url());
    return false;
  }
};

class WebView : public QWebView {
public:
  QWebView* createWindow(QWebPage::WebWindowType) {
    WebView* res = new WebView;
    WebPage* page = new WebPage;
    res->setPage(page);
    return res;
  }
};

int main(int argc, char *argv[]) {
  QApplication a(argc, argv);

  WebView v;
  v.load(QUrl("http://example.com/"));
  v.show();

  return a.exec();
}

launcher.pro

launcher.pro

QT += core gui network webkitwidgets widgets

TARGET = launcher
TEMPLATE = app

SOURCES = main.cpp

You will also need to copy and bundle the following libraries (standard Qt deployment):

您还需要复制和捆绑以下库(标准Qt部署):

libQt5Widgets.so libQt5Gui.so libQt5Core.so libQt5Network.so libQt5WebKitWidgets.so libQt5WebKit.so libQt5MultimediaWidgets.so libQt5OpenGL.so libQt5PrintSupport.so libQt5Multimedia.so libQt5Sensors.so libQt5Quick.so libQt5Qml.so libQt5Sql.so libQt5Positioning.so libQt5DBus.so libicui18n.so libicuuc.so libicudata.so libssl.so libcrypto.so libstdc++.so libgcc_s.so

libQt5Widgets。所以libQt5Gui。所以libQt5Core。所以libQt5Network。所以libQt5WebKitWidgets。所以libQt5WebKit。所以libQt5MultimediaWidgets。所以libQt5OpenGL。所以libQt5PrintSupport。所以libQt5Multimedia。所以libQt5Sensors。所以libQt5Quick。所以libQt5Qml。所以libQt5Sql。所以libQt5Positioning。所以libQt5DBus。所以libicui18n。所以libicuuc。所以libicudata。所以libssl。所以libcrypto。所以libstdc + +。所以libgcc_s.so

And in a subdirectory called platforms:

在一个叫platform的子目录中:

libqxcb.so

libqxcb.so

And then finally a script to tie it together:

最后一个脚本将它联系在一起:

launch_launcher.sh

launch_launcher.sh

#!/bin/sh -e

cd "$(dirname "$0")"

LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./launcher

Finally, have steam installed and set it's LD_LIBRARY_PATH as your own and export it and run launch_launcher.sh (these exact paths depends on your steam installation.)

最后,安装并设置它的LD_LIBRARY_PATH作为您自己的,并导出它并运行launch_launcher。sh(这些精确的路径取决于您的蒸汽安装。)

Essentially, if you remove $LD_LIBRARY_PATH from the launch_launcher script so that the line reads only LD_LIBRARY_PATH=. ./launcher then the links work. However with $LD_LIBRARY_PATH enabled links do not work. We need $LD_LIBRARY_PATH working in order to use the Steam Linux platform libraries (which makes the game work.)

本质上,如果您从launch_launcher脚本中删除$LD_LIBRARY_PATH,使该行只读取LD_LIBRARY_PATH=. ./launcher,那么链接就可以工作了。但是,启用了$LD_LIBRARY_PATH的链接不能工作。我们需要$LD_LIBRARY_PATH,以便使用Steam Linux平台库(这使游戏工作)。

What's the best way to troubleshoot this issue? How can I find the responsible library and exclude it or otherwise workaround this problem?

解决这个问题的最佳方法是什么?如何找到负责任的库并排除它或以其他方式解决这个问题?

2 个解决方案

#1


1  

So, I'm addressing this part (as explained in an earlier question comment)

因此,我正在处理这一部分(正如前面的问题注释所解释的)

What's the best way to troubleshoot this issue? How can I find the responsible library

解决这个问题的最佳方法是什么?如何找到负责任的图书馆

and not this

而不是这个

and exclude it or otherwise workaround this problem?

排除它或者解决这个问题?

the reasoning being that if you're using a steam-supported Linux config, LD_LIBRARY_PATHs are supposed to be a last-resort setting for any app (especially commercial ones). If it messes with other libraries/apps, it's their bug.

理由是,如果您正在使用蒸汽支持的Linux配置,LD_LIBRARY_PATHs应该是任何应用(尤其是商业应用)的最后选择。如果它与其他库/应用程序混淆,那就是它们的bug。

Your approach in isolating a repro is fundamentally valid that way. The logical extension is to (like in the comment) continue with:

从根本上来说,您隔离repro的方法是有效的。逻辑扩展是(如注释)继续:

LD_LIBRARY_PATH={myentry}:A:B:C
./launcher

instead of

而不是

LD_LIBRARY_PATH={myentry}:${LD_LIBRARY_PATH}
./launcher

this allows you to cherry pick among "A:B:C" (which is the current LD_LIBRARY_PATH including Steam library entries) and determine leaving which entries out makes your app start working again.

这允许您在“A:B:C”(这是当前的LD_LIBRARY_PATH,包括Steam库条目)中进行挑选,并确定留下哪些条目可以使您的应用程序重新开始工作。

As for addressing it, it depends on several variables on your system (your distro, other installed libs under LD_LIBRARY_PATH, your Qt version vs KDE's Qt version). You could try:

至于寻址,它取决于系统上的几个变量(发行版、LD_LIBRARY_PATH下的其他安装libs、Qt版本和KDE的Qt版本)。你可以试试:

  1. googling for workarounds - it may be as simple as a replacement library file, or Qt patch, or a single function you call from your main function (similar to @fbucek's answer).
  2. google查找变通方法——它可以简单到替换库文件、Qt补丁或从主函数调用的单个函数(类似于@fbucek的答案)。
  3. logging bug-reports with Steam and Qt - so this workaround isn't specific to your system, and isn't broken again with the next Steam update.
  4. 使用Steam和Qt来记录bug——所以这个解决方案不是针对您的系统的,并且不会随着下一次的Steam更新而再次崩溃。

edit: you observe that it is QDesktopServices which is affected - my most likely guess would be differing Qt versions between two of KDE, yours and Steam.

编辑:您注意到QDesktopServices受到了影响——我最可能的猜测是KDE、yours和Steam两个版本之间的Qt版本不同。

#2


0  

I guess you problem is more complex. Just thought what you can try.

我想你的问题比较复杂。想想你能尝试什么。

1) You app maybe does not need to use LD_LIBRARY_PATH

1)您的app可能不需要使用LD_LIBRARY_PATH

Not to mess with LD_LIBRARY_PATH in your app, you can put library search path into you program. ( linux solution )

不要在应用程序中打乱LD_LIBRARY_PATH,可以将库搜索路径放入程序中。(linux解决方案)

App structue
/app/bin
/app/lib    // where all my libraries are including Qt libraries

.pro file

.pro文件

QMAKE_RPATHDIR = \$\$ORIGIN/../lib
QMAKE_LFLAGS_RELEASE += \'-Wl,-rpath,$${QMAKE_RPATHDIR}\'
QMAKE_RPATHDIR =

( do not remember why it looks this stupid in my old app - but it works and at this moment I am not on linux to simplify it )

(不记得为什么在我以前的应用程序中它看起来这么愚蠢——但是它可以工作,现在我不在linux上简化它)

2) Set LD_LIBRARY_PATH only for processes within your app ( not to make LD_LIBARY_PATH too complex. path to your app, steam etc. )

2)只为应用程序中的进程设置LD_LIBRARY_PATH(不要使LD_LIBARY_PATH过于复杂)。通往你的应用程序、蒸汽等的路径。

I do not know in what context is new browser executed but if it is your app you can use this aproach. This ensures only processes within your app will have this LD_LIBRARY_PATH

我不知道新浏览器是在什么环境下执行的,但是如果是你的应用,你可以使用这个aproach。这确保只有应用程序中的进程才具有这个LD_LIBRARY_PATH

You can set LD_LIBRARY_PATH within your app using

你可以在你的应用中设置LD_LIBRARY_PATH

setenv("LD_LIBRARY_PATH", yourPath.toLatin1().data(), 1)
// You can test it using
QProcessEnvironment::systemEnvironment().value("LD_LIBRARY_PATH");

I guess you don use QProcess so, setting environment for process itself is out of question.

我猜您不使用QProcess,所以为process本身设置环境是不可能的。

#1


1  

So, I'm addressing this part (as explained in an earlier question comment)

因此,我正在处理这一部分(正如前面的问题注释所解释的)

What's the best way to troubleshoot this issue? How can I find the responsible library

解决这个问题的最佳方法是什么?如何找到负责任的图书馆

and not this

而不是这个

and exclude it or otherwise workaround this problem?

排除它或者解决这个问题?

the reasoning being that if you're using a steam-supported Linux config, LD_LIBRARY_PATHs are supposed to be a last-resort setting for any app (especially commercial ones). If it messes with other libraries/apps, it's their bug.

理由是,如果您正在使用蒸汽支持的Linux配置,LD_LIBRARY_PATHs应该是任何应用(尤其是商业应用)的最后选择。如果它与其他库/应用程序混淆,那就是它们的bug。

Your approach in isolating a repro is fundamentally valid that way. The logical extension is to (like in the comment) continue with:

从根本上来说,您隔离repro的方法是有效的。逻辑扩展是(如注释)继续:

LD_LIBRARY_PATH={myentry}:A:B:C
./launcher

instead of

而不是

LD_LIBRARY_PATH={myentry}:${LD_LIBRARY_PATH}
./launcher

this allows you to cherry pick among "A:B:C" (which is the current LD_LIBRARY_PATH including Steam library entries) and determine leaving which entries out makes your app start working again.

这允许您在“A:B:C”(这是当前的LD_LIBRARY_PATH,包括Steam库条目)中进行挑选,并确定留下哪些条目可以使您的应用程序重新开始工作。

As for addressing it, it depends on several variables on your system (your distro, other installed libs under LD_LIBRARY_PATH, your Qt version vs KDE's Qt version). You could try:

至于寻址,它取决于系统上的几个变量(发行版、LD_LIBRARY_PATH下的其他安装libs、Qt版本和KDE的Qt版本)。你可以试试:

  1. googling for workarounds - it may be as simple as a replacement library file, or Qt patch, or a single function you call from your main function (similar to @fbucek's answer).
  2. google查找变通方法——它可以简单到替换库文件、Qt补丁或从主函数调用的单个函数(类似于@fbucek的答案)。
  3. logging bug-reports with Steam and Qt - so this workaround isn't specific to your system, and isn't broken again with the next Steam update.
  4. 使用Steam和Qt来记录bug——所以这个解决方案不是针对您的系统的,并且不会随着下一次的Steam更新而再次崩溃。

edit: you observe that it is QDesktopServices which is affected - my most likely guess would be differing Qt versions between two of KDE, yours and Steam.

编辑:您注意到QDesktopServices受到了影响——我最可能的猜测是KDE、yours和Steam两个版本之间的Qt版本不同。

#2


0  

I guess you problem is more complex. Just thought what you can try.

我想你的问题比较复杂。想想你能尝试什么。

1) You app maybe does not need to use LD_LIBRARY_PATH

1)您的app可能不需要使用LD_LIBRARY_PATH

Not to mess with LD_LIBRARY_PATH in your app, you can put library search path into you program. ( linux solution )

不要在应用程序中打乱LD_LIBRARY_PATH,可以将库搜索路径放入程序中。(linux解决方案)

App structue
/app/bin
/app/lib    // where all my libraries are including Qt libraries

.pro file

.pro文件

QMAKE_RPATHDIR = \$\$ORIGIN/../lib
QMAKE_LFLAGS_RELEASE += \'-Wl,-rpath,$${QMAKE_RPATHDIR}\'
QMAKE_RPATHDIR =

( do not remember why it looks this stupid in my old app - but it works and at this moment I am not on linux to simplify it )

(不记得为什么在我以前的应用程序中它看起来这么愚蠢——但是它可以工作,现在我不在linux上简化它)

2) Set LD_LIBRARY_PATH only for processes within your app ( not to make LD_LIBARY_PATH too complex. path to your app, steam etc. )

2)只为应用程序中的进程设置LD_LIBRARY_PATH(不要使LD_LIBARY_PATH过于复杂)。通往你的应用程序、蒸汽等的路径。

I do not know in what context is new browser executed but if it is your app you can use this aproach. This ensures only processes within your app will have this LD_LIBRARY_PATH

我不知道新浏览器是在什么环境下执行的,但是如果是你的应用,你可以使用这个aproach。这确保只有应用程序中的进程才具有这个LD_LIBRARY_PATH

You can set LD_LIBRARY_PATH within your app using

你可以在你的应用中设置LD_LIBRARY_PATH

setenv("LD_LIBRARY_PATH", yourPath.toLatin1().data(), 1)
// You can test it using
QProcessEnvironment::systemEnvironment().value("LD_LIBRARY_PATH");

I guess you don use QProcess so, setting environment for process itself is out of question.

我猜您不使用QProcess,所以为process本身设置环境是不可能的。