Skip to content

Locating a locally built shared library dependency at runtime is not possible #9016

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
LunarLambda opened this issue Dec 25, 2020 · 2 comments
Labels
A-build-scripts Area: build.rs scripts A-linkage Area: linker issues, dylib, cdylib, shared libraries, so C-feature-request Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted` S-triage Status: This issue is waiting on initial triage.

Comments

@LunarLambda
Copy link

LunarLambda commented Dec 25, 2020

Describe the problem you are trying to solve
We are writing a -sys crate, which can either link to a globally installed library, or build it for you from source, using the cmake crate.

The latter makes dynamic linking essentially impossible, because there is no way to tell the consumer of the crate where to find the compiled library at runtime

The following problems arise:

  • You would need to set the rpath of any executable or library linking to the built library, which Cargo has no way of specifying beyond setting RUSTFLAGS, which can be considered at best a workaround. Furthermore, on Windows, which does not have any equivalent of this, the library would have to be either in the process' CWD, or in the system's PATH.
  • You would need to copy the built library (from somewhere in $CARGO_TARGET_DIR/$PROFILE/build/$CRATE_NAME-$CRATE_HASH/out/lib?) to where your built executable is ($CARGO_TARGET_DIR/$PROFILE?). Manual copying of files between different crate's build directories should never be necessary for the user.
    Most of these variables are not actually available to a build script in the first place, and even if they were, it would require the executable to have its own build.rs, tailored specifically to the crate it is depending on.
  • Installing the executable with cargo install will blow the whole thing up, because it will only install the executable, but not any libraries it may depend on.

This, in effect means that Rust and Cargo offer two ways to link to a native library:

  • statically, potentially to a locally compiled one
  • dynamically, only to a globally installed one (which may or may not exist, and may or may not be the correct version)

Describe the solution you'd like
From looking at various other issues, it seems it would be nice if crates could specify that their build script will generate its own artifacts (whatever those may be), and pass the location of said artifacts to cargo and other build scripts using a cargo: print directive, and for crates depending on said artifacts to specify such (think of it like specifying crate features).

This way, a libexample-sys crate could specify it creates an artifact abc, which consumers of the crate could then specifically request for cargo to copy to where it is needed (next to built executables / examples / libraries). (although ideally, consumers should not have to worry at all about this. this issue might need a rewrite if i can formulate the problem better)

Something along these lines (consider this nothing more than a very rough idea)

[package]
name = "libexample-sys"
artifacts = ["abc"]
// libexample-sys build script
let artifact_abc_location = build_some_artifact();
println!("cargo:artifact=abc={}", artifact_abc_location.display());
[package]
name = "example-consumer"

[dependencies]
libexample-sys = { version = "1.0", artifacts = ["abc"] }

It seems that this RFC is what we would want.

@LunarLambda LunarLambda added the C-feature-request Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted` label Dec 25, 2020
@LunarLambda LunarLambda changed the title Linking to a locally built shared library is close to impossible to do correctly Locating a locally built shared library dependency at runtime is not possible Dec 28, 2020
@ehuss ehuss added A-build-scripts Area: build.rs scripts A-linkage Area: linker issues, dylib, cdylib, shared libraries, so labels Jan 7, 2021
@AsteriskZuo
Copy link

AsteriskZuo commented Oct 20, 2021

I have the same problem.
The cc crate does not provide a way to add install_name flag with ld.
The solution is builds.rs. But there are problems.
Copy the dynamic library to the executable directory and add the rpath directory to the executable.
The problem is that the executable has not yet been created when the RPATH directory is added to the executable.

build.rs

std::fs::copy(from_existed_shared_library, to_executable_dir_library);
...
let rpath = "@executable_path";
    let executable = executable_program;
    let mut params = String::from("install_name_tool -add_rpath ");
    params += rpath;
    params += " ";
    params += executable;
    let output = Command::new("sh")
        .arg("-c")
        .arg(params)
        .output();

compile and link shared library with rust executable is no problem.

@AsteriskZuo
Copy link

I found a temporary solution.
This method is suitable for compiling, running, and debugging on vscode.
The problem solving idea is similar to what I said above, but with a twist. Add 'rpath' at compile time. This method was not found before, so it was not used.

vscode configuration:

launch.json

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "lldb",
      "request": "launch",
      "name": "debug xxx",
      "program": "${workspaceFolder}/target/debug/xxx",
      "args": [],
      "cwd": "${workspaceFolder}",
      "preLaunchTask": "rust: cargo rustc - xxx"
    },
  ]
}

tasks.json

{
	"version": "2.0.0",
	"tasks": [
		{
			"type": "shell",
			"label": "rust: cargo rustc - xxx",
			"command": "cargo rustc -- -C link-args=-Wl,-rpath,@executable_path"
		},
	]
}

@epage epage added the S-triage Status: This issue is waiting on initial triage. label Nov 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-build-scripts Area: build.rs scripts A-linkage Area: linker issues, dylib, cdylib, shared libraries, so C-feature-request Category: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted` S-triage Status: This issue is waiting on initial triage.
Projects
None yet
Development

No branches or pull requests

4 participants