Skip to content

Distributed slice members in dependency crates are discarded #36

New issue

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

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

Already on GitHub? # to your account

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
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants