Check for env::var("DOCS_RS")
in your build.rs
and omit
linking if it is set.
Where to find this: read the complete About
section on docs.rs
.
If you’ve written wrapper crates, e.g. using bindgen
, you may have ran
into this. You have:
- A low level, possibly auto-generated wrapper that sits directly atop the FFI of some C/C++ lib.
- A nifty, oxidized, safe, high level wrapper you wrote. Including excellent documentation of course.
Now you want to publish on crates.io
. And certainly, you don’t want
people to have to build the documentation for your high level wrapper
locally. They should just go to docs.rs/libfoo
.
The issue is that the high level wrapper will not build without the
low-level wrapper and the low level wrapper, docs.rs/libfoo-sys
,
won’t build if the lib it wraps can’t be linked against. And having
that C/C++ lib around involves building it and possibly a plethora of
dependencies it has beforehand. At least in the common case, it seems.
One option is to include the full FFI dependencies in the low level
crate and use cc
, cmake
or the like from within build.rs
to build
the required artifacts. This is often impractical. Crate sizes are limited
and the amount of work involved making this work in the first place can
be excessive.
However, docs.rs
does not actually run any Rust code in your crate when
building the documentation. I.e. it does not run tests or the like. So it
doesn’t need to link at all.
Which means we do not actually need to have the C/C++ lib artifact(s) around. All we need are the files defining the FFI for Rust.
If you use bindgen
these are the C/C++ headers exporting the FFI. And
that’s it. All we need is to determine if we’re building on docs.rs
.
And luckily this is made easiy because the DOCS_RS
environment variable is
defined if we are.
So your build.rs
you just do this:
fn main() -> Result<(), Box<dyn std::error::Error>> {
...
// Regular code path we take when we're not on docs.rs.
if env::var("DOCS_RS").is_err() {
...
println!("cargo:rustc-link-search={}", libfoo.display());
// Link to libfoo.
println!("cargo:rustc-link-lib=foo");
// Code path we take when on docs.rs.
} else {
// Do not link and maybe do something else.
}
...
// Run e.g. bindgen or the like to generate the wrapper.
...
}
Condition: your crate docs look the same on all hosts.
This is nice to do in general as we want to use less electrity, if possible.
[package.metadata.docs.rs]
# This sets the default target to `x86_64-unknown-linux-gnu`
# and only builds that target
targets = ["x86_64-unknown-linux-gnu"]