Problem
Iced is a cross-platform Rust GUI library. An application built with it fails to launch on NixOS with an error message like this:
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
winit, the
underlying library for window management, tries to access libwayland via
dlopen. However dlopen cannot find the library
because search path is unset on Nix.
Although winit has wayland-dlopen
default-on feature, iced does not have a way to disable the flag.
Solution
Use autoPatchelfHook (or patchelf) for
derivation, and LD_LIBRARY_PATH environment variable for
dev shell.
Derivation
In your derivation Nix file,
{
rustPlatform,
autoPatchelfHook,
libgcc,
libxkbcommon,
vulkan-loader,
wayland,
}
rustPlatform.buildRustPackage rec {
# ...
nativeBuildInputs = [
# ... your other native build inputs ...
# This automatically patches built binary based on "runtimeDependencies".
autoPatchelfHook
];
# autoPatchelfHook picks this attribute up and patches the binary with them.
runtimeDependencies = [
# These are libraries required by iced.
libxkbcommon
vulkan-loader
wayland
# This seems necessary too.
libgcc
];
# This installs these packages to the environment.
buildInputs = [
# ... your other build inputs ...
] ++ runtimeDependencies;
# ...
}Shell
Assuming you've already configured your derivation using the above method.
pkgs.mkShell {
packages = [
# ... your packages ...
];
# mkShell (mkDerivation) sets an unrecognized field as an environment variable.
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath your-derivation.runtimeDependencies;
}If you're using Nix Flakes, then your mkShell will look
like this:
{
# flake.nix
# ...
outputs = { nixpkgs, ... }:
let
# Simplified
system = "...";
pkgs = nixpkgs.legacyPackages.${system};
in rec {
packages.${system}.default = pkgs.callPackage ./path/to/derivation.nix { };
devShells.${system}.default = pkgs.mkShell {
packages = [
# ... your packages ...
];
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath packages.${system}.default.runtimeDependencies;
};
};
}