Skip to content
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

Distributed slice members in dependency crates are discarded #36

Closed
kcuzner opened this issue Jan 5, 2021 · 2 comments
Closed

Distributed slice members in dependency crates are discarded #36

kcuzner opened this issue Jan 5, 2021 · 2 comments

Comments

@kcuzner
Copy link

kcuzner commented Jan 5, 2021

This probably isn't an issue with this crate per-se, but I wanted to bring up this use case just in case someone more versed in rust than me has a solution.

I have noticed that when I declare and construct a distributed_slice in a dependency crate, the entries in the slice declared in the dependency crates do not appear. This is probably due to rust-lang/rust#67209, which seems to point to some kind of linker issue that causes custom sections to disappear across crate boundaries. I don't fully understand that issue and it has been open for some time. I suspect that the issue I'm providing an example for here is just a consequence of linkme's use of custom sections (via link_section) and that bug. I've done a little inspecting of the output elf when I don't have a distributed slice member in a root binary crate (so all members are declared in dependency crates) and the custom section doesn't even appear in the output.

Again, I don't really expect a solution to appear in this crate since it is probably a deeper linker issue, but I wanted to make sure this was mentioned here and possibly advocate for this caveat to be called out on the documentation until it is fixed.

Example

  • Cargo.toml
[workspace]
members = [
    "toplevel",
    "dependency",
]
  • dependency/Cargo.toml
[package]
name = "dependency"
version = "0.1.0"
edition = "2018"

[dependencies]
linkme = "0.2"
  • dependency/src/lib.rs
use linkme::distributed_slice;

#[distributed_slice]
pub static TEST: [fn()] = [..];

mod other;

pub fn do_stuff() {
    println!("Doing stuff");
    println!("There are {} items.", TEST.len());
    for func in TEST {
        func();
    }
}


#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        crate::do_stuff();
    }
}
  • dependency/src/other.rs
use linkme::distributed_slice;

use crate::TEST;

#[distributed_slice(TEST)]
fn dependency_test() {
    println!("Dependency");
}
  • toplevel/Cargo.toml
[package]
name = "toplevel"
version = "0.1.0"
edition = "2018"

[dependencies]
dependency = { path = "../dependency" }
linkme = "0.2"
  • toplevel/src/main.rs
use dependency::do_stuff;

mod other;

fn main() {
    do_stuff();
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        dependency::do_stuff();
    }
}
  • toplevel/src/other.rs
use linkme::distributed_slice;

use dependency::TEST;

#[distributed_slice(TEST)]
fn root_test() {
    println!("Root");
}

Expected Behavior

As I have referenced the same distributed slice between crates, I would expect that running my toplevel should print:

Doing stuff
There are 2 items.
Dependency
Root

Actual Behavior

Running the toplevel gives me:

Doing stuff
There are 1 items.
Root

And running the tests gives me:

   Compiling dependency v0.1.0 (/home/kcuzner/Projects/Rust/linktest/dependency)
   Compiling toplevel v0.1.0 (/home/kcuzner/Projects/Rust/linktest/toplevel)
    Finished test [unoptimized + debuginfo] target(s) in 0.41s
     Running target/debug/deps/dependency-eafa826fb0a16142

running 1 test
Doing stuff
There are 1 items.
Dependency
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running target/debug/deps/toplevel-48a62a711f6372bb

running 1 test
Doing stuff
There are 1 items.
Root
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

   Doc-tests dependency

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
@kcuzner
Copy link
Author

kcuzner commented Jan 5, 2021

Dang, this was a duplicate of #31. I think my example is better, but the solution presented there (reference the module (dependency::other in my example) in some way, such as calling a function in that module) does fix the issue.

@dtolnay
Copy link
Owner

dtolnay commented Aug 19, 2021

Closing as a duplicate of #31.

@dtolnay dtolnay closed this as completed Aug 19, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants