7

ArchLinux 下 mpv: undefined symbol: vkCreateWaylandSurfaceKHR 问题解决

 2 years ago
source link: https://ttys3.dev/post/archlinux-mpv-undefined-symbol-vkcreatewaylandsurfacekhr/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

问题现象

  1. 在Gnome Terminal 直接执行 mpv filename.mp4 报错:

mpv: symbol lookup error: mpv: undefined symbol: vkCreateWaylandSurfaceKHR

  1. 使用 smplayer 打开同样的文件, 也是同样的报错.

解决办法

这个解决办法很简单.

但是我要说的是, 这个问题其实我花了很长时间才解决, 并且不是我自己想到的.

产生这个问题的时候, 一般是更新了某些软件之后.

当时我想, 这个是视频相关的, 可能跟显卡驱动相关. 但是后面发现, 即使重启系统, 或者重新编译mpv, 这个问题还是不能解决. 但是有时候重启系统后又能成功打开文件.

报错是 undefined symbol: vkCreateWaylandSurfaceKHR , 但是其实这个问题跟 wayland 无关, 因为我用的是 N 卡 + X11.

搜索了一下, 得知 vkCreateWaylandSurfaceKHR 这个符号来自 libvulkan, 但是本机有正常安装 libvulkan.

❯ paru -Ss libvulkan | rg installed
extra/vulkan-icd-loader 1.2.203-1 [0B 481.45KiB] [Installed]


❯ ls -l /usr/lib/libvulkan* 
lrwxrwxrwx root root  14 B  Fri Jan 21 23:07:49 2022  /usr/lib/libvulkan.so ⇒ libvulkan.so.1
lrwxrwxrwx root root  20 B  Fri Jan 21 23:07:49 2022  /usr/lib/libvulkan.so.1 ⇒ libvulkan.so.1.2.203
.rwxr-xr-x root root 470 KB Fri Jan 21 23:07:49 2022  /usr/lib/libvulkan.so.1.2.203
.rwxr-xr-x root root  11 MB Sat Mar  5 08:14:57 2022  /usr/lib/libvulkan_intel.so


 ❯ strings /usr/lib/libvulkan.so.1 | rg vkCreateWaylandSurfaceKHR  
vkCreateWaylandSurfaceKHR
vkCreateWaylandSurfaceKHR
VK_KHR_wayland_surface extension not enabled. vkCreateWaylandSurfaceKHR not executed!
vkCreateWaylandSurfaceKHR: Invalid instance [VUID-vkCreateWaylandSurfaceKHR-instance-parameter]
  1. 重新编译 mpv 不能解决
  2. 问题只在有时候出现(条件不明确)
  3. undefined symbol 这种错误按以往的经常是特别容易解决的, 安装好对应的lib就好了, 但是现在的情况是, 有正确的 lib 安装了, 依旧报错

所以, 一时间找不到思路了.

直到有一天, 通过搜索看到了 reddit 上一个回答. 终于找到了正确的答案.

This is because chrome provides a broken copy of vulkan which is loaded while it tries to execute mpv. The fix is to make a little wrapper at /usr/local/bin/mpv that preloads the system version of vulkan:

#!/bin/sh
export LD_PRELOAD=/usr/lib/libvulkan.so.1
exec /usr/bin/mpv "$@"

简单来说就是, Google Chrome 自带了一个 没有 vkCreateWaylandSurfaceKHR 符号的 libvulkan.so, 并且优先于系统的 libvulkan.so 加载了.

解决办法是通过一个脚本wrapper来启动mpv. 然后设置 smplayer 调用这个wrapper.

未解之迷

这个方法可以解决问题, 但是有一点老灯还没想明白.

为什么 Chrome 会影响整个系统的 LD_LIBRARY_PATH 环境变量 ? 一般来说, 通过一个 shell 脚本设置的变量, 不会影响其它 shell 的.

通过 kitty 执行 /usr/bin/env | rg LD_LIBRARY_PATH 无结果.

在 kitty 下面:

❯ ldd /usr/bin/mpv | rg libvulkan.so.1
	libvulkan.so.1 => /usr/lib/libvulkan.so.1 (0x00007fa58880a000)

唯独在 gnome terminal 下得到的结果是 LD_LIBRARY_PATH=/opt/google/chrome:/opt/google/chrome/lib

自然而然, 加载的是 Google 的 /opt/google/chrome/libvulkan.so.1

❯ /usr/bin/env | rg LD_LIBRARY_PATH
LD_LIBRARY_PATH=/opt/google/chrome:/opt/google/chrome/lib


❯ ldd /usr/bin/mpv | rg libvulkan.so.1
	libvulkan.so.1 => /opt/google/chrome/libvulkan.so.1 (0x00007fd41628b000)

所以, 现在的问题是, 为什么Chrome 启动脚本里的 LD_LIBRARY_PATH 会对 Gome Terminal 或者 smplayer 有效,

而在 kitty 等其它终端里面却获取不到?

尝试重启一次系统, 这次发现, 连 gnome terminal 下也没有 LD_LIBRARY_PATH 这个值了.

所以, 当gnome terminal 下能取到 LD_LIBRARY_PATH 这个值的时候, 发生了什么?

由于无法复现, 这里老灯也已经无法继续探索了.

/usr/lib/gnome-terminal-server (gnome terminal实际干活的进程) 和 smplayer 获取环境变量的方式, 和 kitty 有什么不同?

是否跟安装了 chrome-gnome-shell 有关系?

在 Linux 下面的 Google Chrome 启动实际上是通过 google-chrome 这个shell 脚本启动的 (edge 也一样, 只是重命名为了 microsoft-edge ), 在 ArchLinux 下这个路径是 /opt/google/chrome/google-chrome

其内容如下:

#!/bin/bash
#
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# Let the wrapped binary know that it has been run through the wrapper.
export CHROME_WRAPPER="`readlink -f "$0"`"

HERE="`dirname "$CHROME_WRAPPER"`"

# We include some xdg utilities next to the binary, and we want to prefer them
# over the system versions when we know the system versions are very old. We
# detect whether the system xdg utilities are sufficiently new to be likely to
# work for us by looking for xdg-settings. If we find it, we leave $PATH alone,
# so that the system xdg utilities (including any distro patches) will be used.
if ! command -v xdg-settings &> /dev/null; then
  # Old xdg utilities. Prepend $HERE to $PATH to use ours instead.
  export PATH="$HERE:$PATH"
else
  # Use system xdg utilities. But first create mimeapps.list if it doesn't
  # exist; some systems have bugs in xdg-mime that make it fail without it.
  xdg_app_dir="${XDG_DATA_HOME:-$HOME/.local/share/applications}"
  mkdir -p "$xdg_app_dir"
  [ -f "$xdg_app_dir/mimeapps.list" ] || touch "$xdg_app_dir/mimeapps.list"
fi

# Always use our versions of ffmpeg libs.
# This also makes RPMs find the compatibly-named library symlinks.
if [[ -n "$LD_LIBRARY_PATH" ]]; then
  LD_LIBRARY_PATH="$HERE:$HERE/lib:$LD_LIBRARY_PATH"
else
  LD_LIBRARY_PATH="$HERE:$HERE/lib"
fi
export LD_LIBRARY_PATH

export CHROME_VERSION_EXTRA="stable"

# We don't want bug-buddy intercepting our crashes. http://crbug.com/24120
export GNOME_DISABLE_CRASH_DIALOG=SET_BY_GOOGLE_CHROME


# Sanitize std{in,out,err} because they'll be shared with untrusted child
# processes (http://crbug.com/376567).
exec < /dev/null
exec > >(exec cat)
exec 2> >(exec cat >&2)

# Note: exec -a below is a bashism.
exec -a "$0" "$HERE/chrome" "$@"

搜索了系统其它地方(如 /etc/environment, /etc/profile.d 等), 也没有发现设置 LD_LIBRARY_PATH 的, 唯一的只有这个脚本有 export LD_LIBRARY_PATH, 而这个脚本只有在Chrome 启动的时候才会执行, 并且, 这样执行 export LD_LIBRARY_PATH 不应该影响到 gnome terminal 或 smplayer 的环境变量啊?


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK