Cfg(test) doesn't propagate to external crates

I have 2 sub-crates in my library - to simplify, lets call them Foo and Bar. Foo wraps a C-api call to foo_ffi:

extern "C" {
    fn foo_ffi();
}

pub struct Foo {}

impl Foo {
    pub fn foo_ffi() {
        #[cfg(not(test))]
        unsafe {
            foo_ffi();
        }
    }
}

Bar calls the safe interface to foo_ffi as follows:

impl Bar {
    pub fn call_foo() {
        Foo::foo_ffi();
    }
}

The problem I am running into is when I try to compile my unit test - I don't want to link in the binary containing the C foo_ffi function, but the #[cfg(not(test))] declaration is not honored in the Foo code (apparently because cfg(test) isn't propagated to external crates when compiling with "cargo test").

So, in other words, in bar\src\lib.rs I have

#[cfg(test)]
mod tests {
    #[test]
    fn do_some_testing() {
    }
}

but "cargo test" still compiles the foo crate without passing "test".

Am I missing something to get foo to compile in "test" mode so that I don't get a link error when compiling with "cargo test"?

A similar issue was recently discussed here: Implementing quickcheck::Arbitrary only when testing crates

Although you don't control the external crate do you?

2 Likes

I do control the external crate.

So essentially I need to make the function Foo::foo_ffi() an optional feature in the Foo crate and then opt-in when running "cargo build", and that way when running "cargo test" it won't try to link to the C binary. Does that sound correct?

Thanks for the link, I'll have to play around with "features"

Whoops, the "I have 2 sub-crates in my library ..." bit went right past me for some reason :frowning:.

Yeah, sounds about right.

OK, looks like that works. Thanks for pointing me in the right direction!

1 Like