7

I build a Rust program that calls a C++ function via a C interface. In order to execute the program, I have to run:

export LD_LIBRARY_PATH=<path to shared c lib>

or I get an error:

error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory

I tried to set the variable in a build script using std::process::Command

Command::new("sh").arg("export").arg("LD_LIBRARY_PATH=<path to shared c lib>");

Although the command executes without an error, the variable is not set. How can I set the variable from my program while it is being executed?

To be more concrete, I want to type only this:

cargo run

instead of

export LD_LIBRARY_PATH=<path to shared c lib>
cargo run

My code so far:

main.rs

/*---compile all with---
    g++ -c -fpic foo.cpp
    gcc -c -fpic test.c
    g++ -shared foo.o test.o -o libtest.so

    in order to execute we have to set the variable
    export LD_LIBRARY_PATH=/home/jan/Uni/Bachelorarbeit/Programme/Rust_Cpp_crossover_erneut/$LD_LIBARY_PATH

*/
//pub extern crate c_interface;
pub extern crate libc;
use libc::{c_int};



#[link(name = "test")]
extern "C" {
    fn hello_world () -> c_int;
}


fn main() {
    let x;
    unsafe {
        x = hello_world();
    }
    println!("x is: {}", x);
}

test.c

#include "foo.h"

int hello_world () {
    int a = foo();
    return a;
}

foo.cpp

#include <iostream>
#include "foo.h"

using namespace std;

int foo() {
    cout << "Hello, World!" << endl;
    return 0;
}

foo.h

#ifdef __cplusplus
extern "C" {
#endif

int foo();

#ifdef __cplusplus
}
#endif

build.rs

fn main () {
    println!(r"cargo:rustc-link-search=native=/home/jan/Uni/Bachelorarbeit/Programme/Rust_Cpp_crossover_erneut");
}

I have seen How do I specify the linker path in Rust? and it is not a solution to my problem.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Mateholiker
  • 329
  • 2
  • 9
  • 1
    Well, there are two problems: one, environment variables don't survive beyond a process, so that command will set the variable and then immediately exit, not having any effect. Secondly, setting an environment variable during build won't have any impact on when you *run* the program. You need to either install the library somewhere the system knows to look for it, get the compiler to hard-code the path to the library into your program (don't know how), or continue to set the path before running the program. – DK. Aug 11 '18 at 04:41
  • I tried to set the variable in the build.rs. And from my understanding build.rs is executed before the program links the c-code so it could come off. But hard code cargo where to look for it would be a solution to my problem but i do not know how to hard code this. – Mateholiker Aug 11 '18 at 04:45
  • Without a specific example to try repeating this, I can't really test this, but have you tried having your `build.rs` output a line something like `cargo:rustc-link-search=directory-of-shared-lib`? See [the docs](https://doc.rust-lang.org/cargo/reference/build-scripts.html). – David Brown Aug 11 '18 at 05:28
  • What's wrong wirth [`set_var`](https://doc.rust-lang.org/std/env/fn.set_var.html)? – Boiethios Aug 11 '18 at 08:43
  • I do not know why but i tried to use [`set var`](https://doc.rust-lang.org/std/env/fn.set_var.html) and it did not set the variable at the right place. What i mean by that is neither could i run the program nor was the variable set on my terminal when i tested it with echo – Mateholiker Aug 11 '18 at 11:27

1 Answers1

6

Add the following line to build.rs:

println!("cargo:rustc-env=LD_LIBRARY_PATH=/home/jan/Uni/Bachelorarbeit/Programme/Rust_Cpp_crossover_erneut/");

This only works with cargo run and not with cargo build and then executing the output. The environment variable does not get saved into the binary.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Mateholiker
  • 329
  • 2
  • 9
  • 1
    Can you verify that this continues to work if you run the program directly, outside of Cargo? That is, instead of running `cargo run`, try `cargo build` followed by `./target/debug/name_of_project`. My guess is that your original error will return. Is this your intended goal, it only working in `cargo run`, but not in any context outside of Cargo? – Shepmaster Aug 13 '18 at 17:57
  • Unfortunately it dose only work with `cargo run` and not with `cargo build` an then executing the output. Because as you said the environment variable dose not get saved into the binary. But if you run `export LD_LIBRARY_PATH=` by hand and then run `./target/debug/name_of_project` everything is just fine so i think you could just write a script that exports the variable and than run `./target/debug/name_of_project` if you do not want to use `cargo run` to execute the program. – Mateholiker Aug 13 '18 at 19:46
  • *you could just write a script that exports the variable* — You could have done that *without* this answer. The entire purpose of your question was: "how can I set the variable from my program **while it is being executed**?" and this answer doesn't accomplish that... – Shepmaster Aug 13 '18 at 19:48
  • 1
    I ask how I could run my program with only typing `cargo run` so this is the answer. If you want to execute you program without cargo the only two option I see are first: write a script that runs first(you could to this in the build.rs) or second: you add the `export LD_LIBRARY_PATH=` to the `.bashrc` file but this is a really bad way of doing it because you cannot set the variable to two different values. – Mateholiker Aug 13 '18 at 20:00