How to conditionally compile examples

Let's say I have a multiplatform crate with an example that only works on win32:

// examples/win32.rs
use std::error::Error;
use my_crate::platform::win32::foo;

fn main() -> Result<(), Box<dyn Error>> {
    foo()?;
    Ok(())
}

If I run cargo check on Linux, it will fail. Fair enough. But what's the simplest way to fix it? If I try the obvious #![cfg(windows)], Rust complains that fn main() is missing on Linux. I couldn't figure out a way to get cargo to ignore the example entirely, so I came up with this monstrosity:

use std::error::Error;

#[cfg(not(windows))]
fn main() -> Result<(), Box<dyn Error>> {
    Err("example requires win32".into())
}

#[cfg(windows)]
fn main() -> Result<(), Box<dyn Error>> {
    use my_crate::platform::win32::foo;

    foo()?;
    Ok(())
}

Yikes. A new user is just trying to see an example, and it's buried under all this boilerplate :frowning:

Is there a better way?

You can put cfg attributes on blocks, so you can avoid having two mains at the cost of an extra level of indentation:

use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    #[cfg(windows)]
    {
        use my_crate::platform::win32::foo;
    
        foo()?;
    }
    Ok(())
}

Edit: Another version that preserves the exact behaviour:

use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    #[cfg(windows)]
    {
        use my_crate::platform::win32::foo;
    
        foo()?;

        Ok(())
    }
    #[cfg(not(windows))]
    Err("example requires win32".into())
}

There is a way to make examples conditional on features, but i don't know if it would work in your case

That's better in that I don't have to pollute the examples themselves, but it would make running the examples require the --features flag and it would mean I couldn't rely on cargo's auto discovery anymore and I would have to list every example by hand in a massive Cargo.toml.

I might suggest creating a makefile to call cargo?

I actually really like this idea. It's slightly inconvenient not to be able to use standard cargo commands, but it avoids cluttering the code with extra attributes and such. Thanks for the idea!

1 Like

If it makes you feel any better, "make" is pretty standard for compiled languages. The only issue I see is users of your library might not have make? (Is it required to run cargo? I don't know) and if they are trained on "rust" they may have no clue what a makefile is. I think I have seen the word makefile zero times in the rust docs.

I know that make can be a little annoying to set up on windows. I think I'm going to try out cargo-make or cargo-just since they're easy to set up on windows with cargo install. And I don't think it should be needed for users of the crate, only maintainers

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.