python - MATLAB 生成的 Python 包与 Ubuntu 上的 PyQt5 冲突——可能是库问题

标签 python linux matlab ubuntu pyqt5

我正在使用 Ubuntu 18.04 和 PyQt 5.12.1 构建一个应用程序,它导入 Python 包 generated from MATLAB code (这些包取决于 MATLAB 运行时)。 Python 中的 MATLAB 包需要设置 LD_LIBRARY_PATH 环境变量;否则,程序会在导入 MATLAB 生成的包时引发异常。

但是,我发现当设置了 LD_LIBRARY_PATH 时 PyQt 无法运行。只要未导入 MATLAB 程序包并且未设置 LD_LIBRARY_PATH,程序在安装 MATLAB Runtime 的情况下运行良好。

根据 MA​​TLAB 运行时安装程序的提示,我将其添加到我的 PyCharm 运行/调试配置中的环境变量中:

LD_LIBRARY_PATH=/usr/local/MATLAB/MATLAB_Runtime/v96/runtime/glnxa64:/usr/local/MATLAB/MATLAB_Runtime/v96/bin/glnxa64:/usr/local/MATLAB/MATLAB_Runtime/v96/sys/os/glnxa64:/usr/local/MATLAB/MATLAB_Runtime/v96/extern/bin/glnxa64.

这会导致程序的 PyQt 部分崩溃。使用QT_DEBUG_PLUGINS=1环境变量,报错信息如下:

Got keys from plugin meta data ("xcb")
QFactoryLoader::QFactoryLoader() checking directory path "<redacted>/PyMODA/venv/bin/platforms" ...
Cannot load library <redacted>/venv/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqxcb.so: (/usr/local/MATLAB/MATLAB_Runtime/v96/bin/glnxa64/libQt5XcbQpa.so.5: undefined symbol: _ZNK14QPlatformTheme14fileIconPixmapERK9QFileInfoRK6QSizeF6QFlagsINS_10IconOptionEE)
QLibraryPrivate::loadPlugin failed on "<redacted>/venv/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqxcb.so" : "Cannot load library <redacted>/venv/lib/python3.6/site-packages/PyQt5/Qt/plugins/platforms/libqxcb.so: (/usr/local/MATLAB/MATLAB_Runtime/v96/bin/glnxa64/libQt5XcbQpa.so.5: undefined symbol: _ZNK14QPlatformTheme14fileIconPixmapERK9QFileInfoRK6QSizeF6QFlagsINS_10IconOptionEE)"
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Available platform plugins are: eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, wayland-egl, wayland, wayland-xcomposite-egl, wayland-xcomposite-glx, webgl, xcb.

重要部分:

"Cannot load library <...>/libqxcb.so: (/usr/local/MATLAB/MATLAB_Runtime/v96/bin/glnxa64/libQt5XcbQpa.so.5: undefined symbol: _ZNK14QPlatformTheme14fileIconPixmapERK9QFileInfoRK6QSizeF6QFlagsINS_10IconOptionEE)"

MATLAB Runtime 在 /usr/local/MATLAB/MATLAB_Runtime/v96/bin/glnxa64/ 中提供了 libQt5XcbQpa.so.5,它必须导出到 LD_LIBRARY_PATH。这似乎是 PyQt 在设置 LD_LIBRARY_PATH 时使用的,它是一个与当前版本的 PyQt 不兼容的旧版本。

/usr/lib/x86_64-linux-gnu/ 中有另一个同名库,它的 MD5 校验和与 MATLAB 版本不同。但是,将此目录添加到 LD_LIBRARY_PATH 的开头并没有帮助。设置 QT_QPA_PLATFORM_PLUGIN_PATH 也无济于事。

有没有办法让 /usr/lib/x86_64-linux-gnu/ 中的版本比 MATLAB 提供的库具有更高的优先级?还有其他方法可以解决此问题吗?

最佳答案

我发现了一个解决方法:

  • 在新进程中运行所有 MATLAB 打包代码;这几乎不会带来不便,因为计算必须在单独的线程或进程上运行,以防止卡住 GUI。
  • 在运行 MATLAB 打包代码的每个进程中,在导入 MATLAB 模块之前以编程方式设置 LD_LIBRARY_PATH 环境变量。导入语句必须位于函数中,而不是位于文件顶部。

这是一个相对简单的例子:

class MyPlot(PlotComponent):
    """
    A class which inherits from a base class PlotComponent, which is 
    a subclass of QWidget. In this simple example, the window 
    gets the data and calls the function `plot(self, data)` on an 
    instance of this class. 
    """
    def __init__(self, parent):
        super().__init__(parent)
        self.queue = Queue()

    def plot(self, data):
        """Calculate the results from the provided data, and plot them."""
        fs = data.frequency

        self.times = data.times
        signal = data.signal.tolist()

        # Create the process, supplying all data in non-MATLAB types.
        self.proc = Process(target=generate_solutions, args=(self.queue, signal, fs))
        self.proc.start()

        # Check for a result in 1 second.
        QTimer.singleShot(1000, self.check_result)

    def check_result(self):
        """Checks for a result from the other process."""
        if self.queue.empty(): # No data yet; check again in 1 second.
            QTimer.singleShot(1000, self.check_result)
            return

        w, l = self.queue.get() # Get the data from the process.

        a = np.asarray(w)
        gh = np.asarray(l)

        # Create the plot.
        self.axes.pcolormesh(self.times, gh, np.abs(a))

def generate_solutions(queue, signal, freq):
    """
    Generates the solutions from the provided data, using the MATLAB-packaged
    code. Must be run in a new process.
    """
    import os

    # Set the LD_LIBRARY_PATH for this process. The particular value may
    # differ, depending on your installation.
    os.environ["LD_LIBRARY_PATH"] = "/usr/local/MATLAB/MATLAB_Runtime/v96/runtime/glnxa64:" \
    "/usr/local/MATLAB/MATLAB_Runtime/v96/bin/glnxa64:/usr/local/MATLAB/MATLAB_Runtime/v96/sys/os/glnxa64:" \ 
    "/usr/local/MATLAB/MATLAB_Runtime/v96/extern/bin/glnxa64"

    # Import these modules AFTER setting up the environment variables.
    import my_matlab_package
    import matlab

    package = my_matlab_package.initialize()

    # Convert the input into MATLAB data-types, to pass to the MATLAB package.
    A = matlab.double([signal])
    fs_matlab = matlab.double([freq])

    # Calculate the result.
    w, l = package.perform_my_calculation(A, fs_matlab, nargout=2)

    # Convert the results back to normal Python data-types so that the
    # main process can use them without importing matlab, and put them 
    # in the queue.
    queue.put((np.asarray(w), np.asarray(l),))

关于python - MATLAB 生成的 Python 包与 Ubuntu 上的 PyQt5 冲突——可能是库问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56758952/

相关文章:

python - 在这个算法中使用计数排序有什么好处?

python - 如何使用 intersphinx 正确链接到 PyQt5 文档?

python - 构建docker镜像时,应该在哪里 `make`编译代码?跑? CMD?

c++ - Linux 中 C++ 代码留下的文件句柄

linux - linux 默认应用程序如何在没有安装 Pthread 的情况下工作?

matlab - 从逻辑数组掩码 (MATLAB) 映射的另一个较小矩阵的值构建稀疏矩阵?

python - 在 tkinter ttk TreeView 中格式化单个单元格/项目而不是整行

linux - Unix 查找命令目录提示

c++ - 在 C/C++ 程序中使用 Matlab 元胞数组

matlab - 在 MATLAB 中查找量化层数