Load shared libraries at runtime


#1

Hi all.
I’m new to rust and system programming. I need to make native application that run web application inside. I choose sciter-rs crate for that purpose and want to distribute my application as single binary but I can’t link sciter statically because of license restrictions. Acceptable way would be checking library existence at runtime, download it from http link if missing and load.

I tried libloading and libc to achieve result, but nothing worked.

use sciter::window;
//use std::ffi::CString;

extern crate sciter;
//extern crate libc;
//extern crate libloading as lib;

fn main() {
    // first try was libloading
    // lib::Library::new("lib/libsciter-gtk-64.so").unwrap();

    // next libc
    // let lib = CString::new("lib/libsciter-gtk-64.so").unwrap();
    // unsafe {
    //     libc::dlopen(lib.as_ptr(), 0);
    // }

    let mut frame = window::Window::with_size((150, 50), window::Flags::main_window(true));
    frame.load_file("minimal.htm");
    frame.run_app();
}

I don’t want to ask users doing some preparements or make installer. Application must work in an “download-and-run” fashion.


#2

What exact problems did you face with libloading onyn? Maybe the author of the crate @nagisa can help.


#3

When I place libsciter-gtk-64.so into /usr/lib or run binary with LD_LIBRARY_PATH env var, then application run perfectly fine:

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 2.1 secs
     Running `target/debug/hello`
target/debug/hello: error while loading shared libraries: libsciter-gtk-64.so: cannot open shared object file: No such file or directory

$ sudo ln -s /my/custom/lib/location/libsciter-gtk-64.so /usr/lib/
$ cargo run
- success, gui window appeared

$ sudo rm /usr/lib/libsciter-gtk-64.so
$ LD_LIBRARY_PATH=/my/custom/lib/location cargo run
- ok too

Same results when I load library from application itself:

lib::Library::new("/my/custom/lib/location/libsciter-gtk-64.so").unwrap();

// OR

let lib = CString::new("/my/custom/lib/location/libsciter-gtk-64.so").unwrap();
unsafe {
    libc::dlopen(lib.as_ptr(), 0);
}

My goal is to run application without dancing with /usr/lib/ or LD_LIBRARY_PATH.


#4

I think this is more a packaging problem than a compilation one.

You can create a package (deb or rpm, for example) with your dependencies either declared in the package (if they are in the distro) or packaged and installed in a predefined path.

Or you can create a bundle with flatpak or snap.

The alternative could be to download the library on your program’s first run and save it into ~/.yourprogram


#5

Compilation is not a problem. Problems with running already compiled application.

I want to avoid additional complexities for end user. Application need to work just right after downloading from my site. That’s why I want to avoid intermediate steps between those two actions (download binary and run it).

That’s exactly what I want. Main problem is how to link application with shared library that is located at arbitrary path.


#6

Does setting LD_LIBRARY_PATH in your program before loading the library work?

https://doc.rust-lang.org/stable/std/env/fn.set_var.html


#7

Well, this is might be outdated but I just came across this thread and have added support for specifying a custom path for the dynamic library. So now you can drop a dll/so in whatever path and use it from there.

Currently it is on testing, requires --feature "shared" to be enabled on OSX/Linux.


#8

All I need was rpath. But no one pointed that out to me.

For which crate you implemented this? And is there any plans to support windows?