Rust + OpenCV = libLLVM-16.so: cannot open shared object file

I’m trying to use opencv with rust, but run into a strange issue. Rust is installed globally on the system.

Creating a hello-world app:

cargo init myapp && cd myapp

# adding OpenCV dependency in rust project
cargo add opencv --features=clang-runtime

nix-shell -p pkg-config opencv
cargo check

I got next error:

=== Detected OpenCV module header dir at: /nix/store/rlf6jmwp306wr1bv2gi7bhcq7kwn9bhj-opencv-4.9.0/include/opencv4/opencv2
  === Found OpenCV version: 4.9.0 in headers located at: /nix/store/rlf6jmwp306wr1bv2gi7bhcq7kwn9bhj-opencv-4.9.0/include/opencv4
  === Generating code in: /home/amv/Projects/dev/target/debug/build/opencv-c5368590cc5f4abf/out
  === Placing generated bindings into: /home/amv/Projects/dev/target/debug/build/opencv-c5368590cc5f4abf/out/opencv
  === Using OpenCV headers from: /nix/store/rlf6jmwp306wr1bv2gi7bhcq7kwn9bhj-opencv-4.9.0/include/opencv4
  thread 'main' panicked at /home/amv/.cargo/registry/src/index.crates.io-6f17d22bba15001f/opencv-binding-generator-0.89.0/src/generator.rs:387:33:
  Can't initialize clang: "the `libclang` shared library at /usr/lib/libclang.so.16.0.6 could not be opened: libLLVM-16.so: cannot open shared object file: No such file or directory"
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

At the same time inside nix-shell I have:

> ls /usr/lib|grep libclang
libclang-cpp.so
libclang-cpp.so.16
libclang.so
libclang.so.16
libclang.so.16.0.6

> ls /usr/lib|grep LLVM    
LLVMgold.so
libLLVM-16.0.6.so
libLLVM-16.so
libLLVM.so
libLLVMDemangle.a
libLLVMSupport.a
libLLVMTableGen.a

So I don’t understand what’s wrong and how to solve this issue.

1 Like

welcome @mamaf!
Two observations that stand out to me:

  • you’ll want to grab the llvmPackages.libclang too
  • libclang does not provide pkg-config files upstream so nix doesn’t appear to magically find them. So you need to populate the correct environment variable that points to the libraries

I ran into this before and found a solution here: How to correctly populate a clang and llvm development environment using nix-shell?

I’m curious if you can do this in a one liner. I was able to load nix-shell -p pkg-config opencv llvmPackages.libclang but couldn’t figure out how to specify a shellHook.
That said, I’d recommend you create an ad hoc shell environment as it makes this much simpler. If you are unfamiliar with that, check out the nix.dev guide: Ad hoc shell environments — nix.dev documentation

Actually, Declarative shell environments with shell.nix — nix.dev documentation is a better guide for this use case I think.

This piqued my curiosity so I took a stab at a shell.nix to do this:

let
  nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-23.11";
  pkgs = import nixpkgs {
    config = { };
    overlays = [ ];
  };
in

pkgs.mkShell {
  packages = with pkgs; [
    opencv
    llvmPackages.libclang.lib
  ];
  nativeBuildInputs = [ pkgs.pkg-config ];

  shellHook = ''
    export LIBCLANG_PATH="${pkgs.llvmPackages.libclang.lib}/lib";
  '';
}

Thanks to other contributors I found the correct syntax (details LIBCLANG_PATH environment variable from inside .nix expression · Issue #52447 · NixOS/nixpkgs · GitHub).

For me, on NixOS with Rust installed, compilation begins successfully!

/t/myapp (main)> nix-shell shell.nix

[nix-shell:/tmp/myapp]$ cargo check
   Compiling opencv v0.91.2
    Building [========================>  ] 35/37: opencv

And succeeds :slight_smile: Finished dev [unoptimized + debuginfo] target(s) in 2m 49s