問題
Iced という Rust の GUI ライブラリがある。 これを使って書いたアプリケーションを NixOS で動かそうとするとエラーになって立ち上がらない。
thread 'main' panicked at /build/cargo-vendor-dir/iced_winit-0.14.0/src/lib.rs:81:10:
Create event loop: Os(OsError { line: 89, file: "/build/cargo-vendor-dir/winit-0.30.12/src/platform_impl/linux/wayland/event_loop/mod.rs", error: WaylandError(Connection(NoWaylandLib)) })
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Iced はウィンドウ管理に winit
というライブラリを使っており、これが dlopen
というものを使って Wayland にアクセスしている。 しかし NixOS
ではライブラリを探すためのパスが設定されていないため、
dlopen
がライブラリを見つけられずにエラーを返している状態。
winit は wayland-dlopen
というデフォルトで ON の機能フラグを持っており、これを OFF にして
(なんか諸々色々ごちゃごちゃ設定をして)
ビルドをすれば正常にリンクできるはずだ。 しかし Iced
がそのフラグをハードコードしているためライブラリ利用者やエンドユーザ側から変えることができない。
解決法
Derivation (パッケージ) には autoPatchelfHook
(もしくは手動で patchelf) を使い、 nix-shell
や nix develop などの mkShell には
LD_LIBRARY_PATH という環境変数を指定する。
Derivation
nativeBuildInputs に autoPatchelfHook
を追加し、 runtimeDependencies にリンクするライブラリ
(エラーが出て怒られるライブラリ) を指定するだけ。
# my-derivation.nix
{
rustPlatform,
autoPatchelfHook,
libgcc,
libxkbcommon,
vulkan-loader,
wayland,
}
rustPlatform.buildRustPackage rec {
# ...
nativeBuildInputs = [
# ... 他の nativeBuildInputs ...
autoPatchelfHook
];
# autoPatchelfHook がこのフィールドを見て勝手にビルドされたバイナリをパッチしてくれる
runtimeDependencies = [
# 明確に Iced が利用しているライブラリ
libxkbcommon
vulkan-loader
wayland
# なんか知らないけどこれも呼んでたので必要だった
libgcc
];
# ランタイムでも必要なのでこちらにも追加する
buildInputs = [
# ... 他の buildInputs ...
] ++ runtimeDependencies;
# ...
}mkShell
上記をやっている前提。
pkgs.mkShell {
packages = [
# ... 他のパッケージ ...
];
# mkShell (mkDerivation) は未知のフィールドを環境変数として設定する。
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath your-derivation.runtimeDependencies;
}Flakes を使っている場合はこんな感じになるはず。
{
# flake.nix
# ...
outputs = { nixpkgs, ... }:
let
# 人によってやり方が違うので説明用に簡潔化
system = "...";
pkgs = nixpkgs.legacyPackages.${system};
in rec {
packages.${system}.default = pkgs.callPackage ./path/to/derivation.nix { };
devShells.${system}.default = pkgs.mkShell {
packages = [
# ... 他のパッケージ ...
];
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath packages.${system}.default.runtimeDependencies;
};
};
}