Skip to content

Instantly share code, notes, and snippets.

@mejrs
Created April 11, 2022 20:03
Show Gist options
  • Save mejrs/07e797df984197e464b44aaa7849f3c3 to your computer and use it in GitHub Desktop.
Save mejrs/07e797df984197e464b44aaa7849f3c3 to your computer and use it in GitHub Desktop.

Have you ever wondered how to create these feature annotations in your documentation?

image

This is done with the doc_cfg feature. However, this is an unstable feature, and it cannot be used on stable Rust. This gist is a guide on how to work around that.

Add the feature

Add this to the top of your lib.rs:

#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]

The doc_auto_cfg is yet another feature. What this does is automagically figuring out the necessary flags to place. If omitted you have to annotate these yourself.

You need cfg_attr to control when these features are activated, so that your program will compile on stable Rust.

Add metadata

Add this to your cargo.toml to make docs.rs use it when you upload your crate.

[package.metadata.docs.rs]
# Enable all your features! Otherwise they will not show up in your documentation.
all-features = true
# Enable the unstable features
rustdoc-args = ["--cfg", "docsrs"]

Testing

To locally test, you have to set the cfg, and you have to use nightly rustdoc.

For example, on PowerShell, do...

$env:RUSTDOCFLAGS = "--cfg docsrs"

...and, after installing a nightly toolchain...

rustup install nightly

...render your documentation:

cargo +nightly doc --all-features --open

Caveats and tricks:

Flags are not correctly applied on re-exports from private modules: rust-lang/rust#83428

Duplicated functions are not deduplicated. If you write the following functions...

#[cfg(target_pointer_width = "32")]
fn foo(){
    // 32 bit impl
}

#[cfg(target_pointer_width = "64")]
fn foo(){
    // 64 bit impl
}

...this function will show up (if you're on a 64 bit system) as being only available on 64 bit.

To fix this, deduplicate the function and move the cfgs to its internals:

fn foo(){
    #[cfg(target_pointer_width = "32")]
    {
        // 32 bit impl
    }

    #[cfg(target_pointer_width = "64")]
    {
        // 64 bit impl
    }
}

The same applies for structs.

Also, this system is designed to work with features that are additive! If you have features that remove things (🙀), this will work much less well.

Here are a few crates that use these: pyo3 tokio syn

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment