-
-
Notifications
You must be signed in to change notification settings - Fork 43
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
inventory::submit!() doesn't work unless code from downstream crate is actually used #7
Comments
This minimizes to: #!/bin/bash
rustc <<<'
#[used]
#[link_section = ".ctors"]
static STATIC: unsafe extern "C" fn() = print_msg;
unsafe extern "C" fn print_msg() {
use core::ffi::c_void;
extern {
fn write(fd: i32, buf: *const c_void, count: usize) -> isize;
}
write(
1i32,
"CTOR CALLED\n".as_ptr() as *const c_void,
12usize,
);
}
pub fn f() {}
' \
--edition=2018 \
--crate-name dep \
--crate-type lib \
--emit=link \
/dev/stdin
rustc <<<'
fn main() {
dep::f();
}
' \
--edition=2018 \
--crate-name repro \
--emit=link \
--extern dep=libdep.rlib \
/dev/stdin
./repro If you comment out |
This seems to be the same issue: rust-lang/rust#47384. I checked that
so it appears to be a linker problem. One suggested solution is from rust-lang/rust#47384 (comment):
However I'm not sure that is applicable in this case as no linker script is being used. |
Seeing the same issue. Is any workaround available? Seems like changing crate-type to "dylib" helps my case (presumably, because linker would keep all symbols for the dynamically loadable library), but are there any other workaround? |
Started working on #4 (support for stable Rust). First issue we need to solve is to get access to the harness (since we don't really want to implement it ourselves). There is https://crates.io/crates/libtest crate, which is recent version of Rust internal test harness, extracted as a crate. However, it only compiles on nightly, so it won't help us here. There is also https://crates.io/crates/rustc-test, but it is 2 years old. I haven't checked its features, but might not support some of the desired functionality (like, JSON output in tests? colored output?). So, the third option (which I'm using here) is to use `test` crate from the Rust itself and also set `RUSTC_BOOTSTRAP=1` for our crate so we can access it on stable channel. Not great, but works for now. Second issue is to get access to the tests. On nightly, we use `#[test_case]` to hijack Rust tests registration so we can get access to them in nightly. Cannot do that on stable. What would help here is something along the lines of https://internals.rust-lang.org/t/idea-global-static-variables-extendable-at-compile-time/9879 or https://internals.rust-lang.org/t/pre-rfc-add-language-support-for-global-constructor-functions. Don't have that, so we use https://crates.io/crates/ctor crate to build our own registry of tests, similar to https://crates.io/crates/inventory. The caveat here is potentially hitting dtolnay/inventory#7 issue which would manifest itself as test being silently ignored. Not great, but let's see how bad it will be. Third piece of the puzzle is to intercept execution of tests. This is done by asking users to use `harness = false` in their `Cargo.toml`, in which case we take full control of test execution. Finally, the last challenge is that with `harness = false`, we don't have a good way to intercept "standard" tests (`#[test]`): https://users.rust-lang.org/t/capturing-test-when-harness-false-in-cargo-toml/28115 So, the plan here is to provide `#[datatest::test]` attribute that will behave similar to built-in `#[test]` attribute, but will use our own registry for tests. No need to support `#[bench]` as it is not supported on stable channel anyway. The caveat in this case is that if you use built-in `#[test]`, your test will be silently ignored. Not great, not sure what to do about it. Proper solution, of course, would be driving RFC for custom test frameworks: rust-lang/rust#50297 😅
Started working on #4 (support for stable Rust). First issue we need to solve is to get access to the harness (since we don't really want to implement it ourselves). There is https://crates.io/crates/libtest crate, which is recent version of Rust internal test harness, extracted as a crate. However, it only compiles on nightly, so it won't help us here. There is also https://crates.io/crates/rustc-test, but it is 2 years old. I haven't checked its features, but might not support some of the desired functionality (like, JSON output in tests? colored output?). So, the third option (which I'm using here) is to use `test` crate from the Rust itself and also set `RUSTC_BOOTSTRAP=1` for our crate so we can access it on stable channel. Not great, but works for now. Second issue is to get access to the tests. On nightly, we use `#[test_case]` to hijack Rust tests registration so we can get access to them in nightly. Cannot do that on stable. What would help here is something along the lines of https://internals.rust-lang.org/t/idea-global-static-variables-extendable-at-compile-time/9879 or https://internals.rust-lang.org/t/pre-rfc-add-language-support-for-global-constructor-functions. Don't have that, so we use https://crates.io/crates/ctor crate to build our own registry of tests, similar to https://crates.io/crates/inventory. The caveat here is potentially hitting dtolnay/inventory#7 issue which would manifest itself as test being silently ignored. Not great, but let's see how bad it will be. Third piece of the puzzle is to intercept execution of tests. This is done by asking users to use `harness = false` in their `Cargo.toml`, in which case we take full control of test execution. Finally, the last challenge is that with `harness = false`, we don't have a good way to intercept "standard" tests (`#[test]`): https://users.rust-lang.org/t/capturing-test-when-harness-false-in-cargo-toml/28115 So, the plan here is to provide `#[datatest::test]` attribute that will behave similar to built-in `#[test]` attribute, but will use our own registry for tests. No need to support `#[bench]` as it is not supported on stable channel anyway. The caveat in this case is that if you use built-in `#[test]`, your test will be silently ignored. Not great, not sure what to do about it. Proper solution, of course, would be driving RFC for custom test frameworks: rust-lang/rust#50297 😅
Started working on #4 (support for stable Rust). First issue we need to solve is to get access to the harness (since we don't really want to implement it ourselves). There is https://crates.io/crates/libtest crate, which is recent version of Rust internal test harness, extracted as a crate. However, it only compiles on nightly, so it won't help us here. There is also https://crates.io/crates/rustc-test, but it is 2 years old. I haven't checked its features, but might not support some of the desired functionality (like, JSON output in tests? colored output?). So, the third option (which I'm using here) is to use `test` crate from the Rust itself and also set `RUSTC_BOOTSTRAP=1` for our crate so we can access it on stable channel. Not great, but works for now. Second issue is to get access to the tests. On nightly, we use `#[test_case]` to hijack Rust tests registration so we can get access to them in nightly. Cannot do that on stable. What would help here is something along the lines of https://internals.rust-lang.org/t/idea-global-static-variables-extendable-at-compile-time/9879 or https://internals.rust-lang.org/t/pre-rfc-add-language-support-for-global-constructor-functions. Don't have that, so we use https://crates.io/crates/ctor crate to build our own registry of tests, similar to https://crates.io/crates/inventory. The caveat here is potentially hitting dtolnay/inventory#7 issue which would manifest itself as test being silently ignored. Not great, but let's see how bad it will be. Third piece of the puzzle is to intercept execution of tests. This is done by asking users to use `harness = false` in their `Cargo.toml`, in which case we take full control of test execution. Finally, the last challenge is that with `harness = false`, we don't have a good way to intercept "standard" tests (`#[test]`): https://users.rust-lang.org/t/capturing-test-when-harness-false-in-cargo-toml/28115 So, the plan here is to provide `#[datatest::test]` attribute that will behave similar to built-in `#[test]` attribute, but will use our own registry for tests. No need to support `#[bench]` as it is not supported on stable channel anyway. The caveat in this case is that if you use built-in `#[test]`, your test will be silently ignored. Not great, not sure what to do about it. Proper solution, of course, would be driving RFC for custom test frameworks: rust-lang/rust#50297 😅
Started working on #4 (support for stable Rust). First issue we need to solve is to get access to the harness (since we don't really want to implement it ourselves). There is https://crates.io/crates/libtest crate, which is recent version of Rust internal test harness, extracted as a crate. However, it only compiles on nightly, so it won't help us here. There is also https://crates.io/crates/rustc-test, but it is 2 years old. I haven't checked its features, but might not support some of the desired functionality (like, JSON output in tests? colored output?). So, the third option (which I'm using here) is to use `test` crate from the Rust itself and also set `RUSTC_BOOTSTRAP=1` for our crate so we can access it on stable channel. Not great, but works for now. Second issue is to get access to the tests. On nightly, we use `#[test_case]` to hijack Rust tests registration so we can get access to them in nightly. Cannot do that on stable. What would help here is something along the lines of https://internals.rust-lang.org/t/idea-global-static-variables-extendable-at-compile-time/9879 or https://internals.rust-lang.org/t/pre-rfc-add-language-support-for-global-constructor-functions. Don't have that, so we use https://crates.io/crates/ctor crate to build our own registry of tests, similar to https://crates.io/crates/inventory. The caveat here is potentially hitting dtolnay/inventory#7 issue which would manifest itself as test being silently ignored. Not great, but let's see how bad it will be. Third piece of the puzzle is to intercept execution of tests. This is done by asking users to use `harness = false` in their `Cargo.toml`, in which case we take full control of test execution. Finally, the last challenge is that with `harness = false`, we don't have a good way to intercept "standard" tests (`#[test]`): https://users.rust-lang.org/t/capturing-test-when-harness-false-in-cargo-toml/28115 So, the plan here is to provide `#[datatest::test]` attribute that will behave similar to built-in `#[test]` attribute, but will use our own registry for tests. No need to support `#[bench]` as it is not supported on stable channel anyway. The caveat in this case is that if you use built-in `#[test]`, your test will be silently ignored. Not great, not sure what to do about it. Proper solution, of course, would be driving RFC for custom test frameworks: rust-lang/rust#50297 😅 Partially fixes #4 (still missing support for standard tests and also documentation).
Started working on #4 (support for stable Rust). First issue we need to solve is to get access to the harness (since we don't really want to implement it ourselves). There is https://crates.io/crates/libtest crate, which is recent version of Rust internal test harness, extracted as a crate. However, it only compiles on nightly, so it won't help us here. There is also https://crates.io/crates/rustc-test, but it is 2 years old. I haven't checked its features, but might not support some of the desired functionality (like, JSON output in tests? colored output?). So, the third option (which I'm using here) is to use `test` crate from the Rust itself and also set `RUSTC_BOOTSTRAP=1` for our crate so we can access it on stable channel. Not great, but works for now. Second issue is to get access to the tests. On nightly, we use `#[test_case]` to hijack Rust tests registration so we can get access to them in nightly. Cannot do that on stable. What would help here is something along the lines of https://internals.rust-lang.org/t/idea-global-static-variables-extendable-at-compile-time/9879 or https://internals.rust-lang.org/t/pre-rfc-add-language-support-for-global-constructor-functions. Don't have that, so we use https://crates.io/crates/ctor crate to build our own registry of tests, similar to https://crates.io/crates/inventory. The caveat here is potentially hitting dtolnay/inventory#7 issue which would manifest itself as test being silently ignored. Not great, but let's see how bad it will be. Third piece of the puzzle is to intercept execution of tests. This is done by asking users to use `harness = false` in their `Cargo.toml`, in which case we take full control of test execution. Finally, the last challenge is that with `harness = false`, we don't have a good way to intercept "standard" tests (`#[test]`): https://users.rust-lang.org/t/capturing-test-when-harness-false-in-cargo-toml/28115 So, the plan here is to provide `#[datatest::test]` attribute that will behave similar to built-in `#[test]` attribute, but will use our own registry for tests. No need to support `#[bench]` as it is not supported on stable channel anyway. The caveat in this case is that if you use built-in `#[test]`, your test will be silently ignored. Not great, not sure what to do about it. Proper solution, of course, would be driving RFC for custom test frameworks: rust-lang/rust#50297 😅 Partially fixes #4 (still missing support for standard tests and also documentation).
Started working on #4 (support for stable Rust). First issue we need to solve is to get access to the harness (since we don't really want to implement it ourselves). There is https://crates.io/crates/libtest crate, which is recent version of Rust internal test harness, extracted as a crate. However, it only compiles on nightly, so it won't help us here. There is also https://crates.io/crates/rustc-test, but it is 2 years old. I haven't checked its features, but might not support some of the desired functionality (like, JSON output in tests? colored output?). So, the third option (which I'm using here) is to use `test` crate from the Rust itself and also set `RUSTC_BOOTSTRAP=1` for our crate so we can access it on stable channel. Not great, but works for now. Second issue is to get access to the tests. On nightly, we use `#[test_case]` to hijack Rust tests registration so we can get access to them in nightly. Cannot do that on stable. What would help here is something along the lines of https://internals.rust-lang.org/t/idea-global-static-variables-extendable-at-compile-time/9879 or https://internals.rust-lang.org/t/pre-rfc-add-language-support-for-global-constructor-functions. Don't have that, so we use https://crates.io/crates/ctor crate to build our own registry of tests, similar to https://crates.io/crates/inventory. The caveat here is potentially hitting dtolnay/inventory#7 issue which would manifest itself as test being silently ignored. Not great, but let's see how bad it will be. Third piece of the puzzle is to intercept execution of tests. This is done by asking users to use `harness = false` in their `Cargo.toml`, in which case we take full control of test execution. Finally, the last challenge is that with `harness = false`, we don't have a good way to intercept "standard" tests (`#[test]`): https://users.rust-lang.org/t/capturing-test-when-harness-false-in-cargo-toml/28115 So, the plan here is to provide `#[datatest::test]` attribute that will behave similar to built-in `#[test]` attribute, but will use our own registry for tests. No need to support `#[bench]` as it is not supported on stable channel anyway. The caveat in this case is that if you use built-in `#[test]`, your test will be silently ignored. Not great, not sure what to do about it. Proper solution, of course, would be driving RFC for custom test frameworks: rust-lang/rust#50297 😅 Partially fixes #4 (still missing support for standard tests and also documentation).
What platform is this on? macOS has some odd behaviors in that static initializers are not guaranteed to run until something in the object file is actually needed. If nothing is triggering the object file (crate) with the initializer to actually get resolved/looked at by the linker, it may not run. I don't know if there's a plausibly implementable solution for this in Rust. We do this reliably in a C++ codebase at work, but it involves code generation to basically inject a trigger for the static initializer into any TUs including a static initializer-needing header. I don't think there's an equivalent in Rust. |
Just wanted to note- I just ran into this issue, and it appears that (at least with rustc 1.43 on linux) the restriction is even narrower - the module in the downstream crate must be actually used, not just the crate itself:
|
Is it the linker or the compiler culling the symbols from the executable? |
My experience in C++ is that build tools like bazel usually expose an option you can set on libraries to link even if symbols are unused. In bazel the option is called always_link=1. See the gcc option discussed here: https://stackoverflow.com/q/14116420/50385 Presumably there is some way to get rustc to give the same option to the linker? |
This is fixed in rustc 1.62.0 / inventory 0.3.0. |
Here's my setup: I have a workspace with two crates,
primary
andsecondary
.primary
defines a structFoo
that's registered withinventory::collect!()
.secondary
registers an instance ofFoo
usinginventory::submit!()
. Insecondary/tests/test.rs
, I attempt to iterate over all registeredFoo
instances.$ exa -T
primary/src/lib.rs
secondary/src/lib.rs
secondary/tests/test.rs
When running
cargo test -- --nocapture
, I expect to seeFoo { name: "asdf" }
in the output. However, the test has no output. I think the problem is that the test is compiled as a separate crate and since it doesn't refer tosecondary
at all, the code to register theFoo
instance is not run.From this forum post, I discovered a workaround: by adding a dummy function
pub fn dummy() {}
to thesecondary
crate, and calling that function from the test, the output is what I expect.I was wondering if there are any other ways around this issue or if you could shed some light on why it occurs. Thanks!
The text was updated successfully, but these errors were encountered: