diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f43cda673d37..411f90387e76 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -97,20 +97,7 @@ We have two automated tests running on ## Breaking change policy -Sometimes an upstream adds a breaking change to their API e.g. removing outdated -items, changing the type signature, etc. And we probably should follow that -change to build the `libc` crate successfully. It's annoying to do the -equivalent of semver-major versioning for each such change. Instead, we mark the -item as deprecated and do the actual change after a certain period. The steps -are: - -1. Add `#[deprecated(since = "", note="")]` attribute to the item. - - The `since` field should have a next version of `libc` (e.g., if the current - version is `0.2.1`, it should be `0.2.2`). - - The `note` field should have a reason to deprecate and a tracking issue to - call for comments (e.g., "We consider removing this as the upstream removed - it. If you're using it, please comment on #XXX"). -2. If we don't see any concerns for a while, do the change actually. +See `src/lib.rs` for details. ## Supported target policy diff --git a/README.md b/README.md index f8b2d5831340..b05a52d113ec 100644 --- a/README.md +++ b/README.md @@ -41,14 +41,6 @@ Add the following to your `Cargo.toml`: libc = "0.2" ``` -## Features - -* `std`: by default `libc` links to the standard library. Disable this feature - to remove this dependency and be able to use `libc` in `#![no_std]` crates. - -* `extra_traits`: all `struct`s implemented in `libc` are `Copy` and `Clone`. - This feature derives `Debug`, `Eq`, `Hash`, and `PartialEq`. - ## Rust version support The minimum supported Rust toolchain version is currently **Rust 1.65**. diff --git a/src/lib.rs b/src/lib.rs index 6e6577fda3e8..a77fd45ef38d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,131 @@ -//! libc - Raw FFI bindings to platforms' system libraries +//! Raw FFI bindings to platforms' system libraries. +//! +//! # Usage Recommendations +//! +//! `libc` takes a differe +//! +//! - *Never* construct a `libc` struct with `MaybeUninit::uninit()`, initialize it, then call +//! `assume_init`. Many structures have padding fields or may gain fields in the future, and +//! it is far too easy to end up calling `assume_init` on partially initialized data. +//! +//! Instead, use `MaybeUninit::zeroed()` or the `Default` implementations that are slowly being +//! added. Alternatively, access fields only via raw pointer without ever using `assume_init`. +//! +//! - Avoid relying on the exact value of constants or the exact length of arrays, as they may +//! change across `libc` versions. That is, if `libc` contains code like: +//! +//! +//! ```ignore +//! const IFNAMSIZ: usize = 16; +//! +//! pub struct ifreq { +//! pub ifr_name: [c_char; IFNAMSIZ], +//! // ... +//! } +//! ``` +//! +//! Then avoid writing code like: +//! +//! ```ignore +//! // Bad assumption that `IFNAMSIZ` will be 16 forever +//! fn foo(ifr_name: [c_char; 16]) { /* ... */ } +//! +//! fn bar(ifr: ifreq) { +//! foo(ifr.ifr_name); +//! } +//! ``` +//! +//! Instead, use `[c_char; IFNAMSIZ]` to specify the type, or just `&[c_char]`. +//! +//! Along the same lines, if you write code along the lines of `assert_eq!(libc::ELAST, 97)`, +//! expect that there may be a release where this starts to fail. +//! +//! - Do not name `__c_anonymous_*` types anywhere, which exist to represent anonymous fields in +//! C. For example, FreeBSD defines: +//! +//! ```c +//! struct filestat { +//! int fs_type; +//! // ... +//! struct { struct filestat stqe_next; } next; +//! }; +//! ``` +//! +//! Which is represented in `libc` as: +//! +//! ```ignore +//! struct filestat { +//! fs_type: c_int, +//! // ... +//! next: __c_anonymous_filestat, +//! } +//! +//! struct __c_anonymous_filestat { stqe_next: *mut filestat } +//! ``` +//! +//! Accessing `some_filestat.next.stqe_next` is completely fine, but `__c_anonymous_filestat` +//! should not be used anywhere (e.g. in a function signature). This is done to permit `libc` to +//! switch to anonymous fields if the feature is ever added to Rust. +//! +//! - Be aware of deprecation warnings. These are used as a way to migrate necessary API changes. +//! +//! # Cargo Features +//! +//! - `std`: by default `libc` assumes that the standard library contains link directives necessary +//! to use the APIs in this crate. If `std` is disabled, `libc` will emit directives necessary to +//! link the necessary C libraries. +//! +//! This feature is slated for removal in `libc` 1.0. The intention is that no-std users of +//! `libc` should use their own `#[link]` attributes, `rustc-link-lib` build script directives, +//! or `-l` arguments for only the system libraries they need to link, rather than `libc` +//! possibly linking more than is needed or available. If you are using `libc` without the `std` +//! feature, consider starting to add link directives now for a smoother 1.0 transition. +//! +//! - `extra_traits`: all types in `libc` implement `Clone`, `Copy`, and `Debug`. The +//! `extra_traits` feature adds `Eq`, `Hash`, and `PartialEq`. +//! +//! This feature is expected to be removed in libc 1.0. Libraries should instead hash or check +//! equality of only needed fields. +//! +//! - The features `const-extern-function`, `align`, and `use_std` are all deprecated. +//! +//! # Stability Expectations +//! +//! Due to `libc`'s position in the ecosystem, it can effectively never publish semver-breaking +//! releases. However, the API that `libc` binds changes _all the time_; sometimes in ways that +//! are harmless, sometimes in ways that are technically API-breaking for C users but unlikely +//! to be noticed (e.g. removing deprecated API), and sometimes in ways that are nonbreaking in +//! C but translate to breaking changes in Rust (e.g. changing integer size). `libc` tries to +//! strike a balance but all of this means that unfortunately, `libc` must occasionally ship +//! changes within a semver-compatible release that are technically semver-breaking. +//! +//! The following are examples of changes that fall into this category: +//! +//! - Fields are added to a struct that is currently exhaustive. +//! - Fields with names such as `padding` or `reserved` change type or are removed. +//! - The length of an array type changes. +//! - A struct field (with available padding) is changed from `int` to `long`. +//! +//! In general, `libc` aims to follow platform API changes, even when this means changes that are +//! user-visible in Rust. There are a few guidelines used here: +//! +//! - Adding struct fields is not considered breaking, nor is changing fields named `reserved`, +//! `padding`, or similar. This is because users are expected to use field-by-field +//! initialization. +//! - Changing type aliases, values of constants, or array lengths is not considered breaking. +//! - If the platform libc has accepted breakage on the C side (typically in the form of removing +//! old API), the `libc` crate will follow suit. +//! - Where possible, `#[deprecated(...)]` will be used to warn about changes before applying them. +//! Alternative mitigations may be considered. +//! - Potentially breaking changes will be well-identified in release notes. +//! - Beyond this, public API is not expected to change on Tier 1 targets. Tier 2 targets have +//! relaxed API stability requirements, and API stability is not enforced on tier 3 targets. +//! +//! While this section seems scary, keep in mind that it is meant to cover worst-case scenarios. In +//! practice, breakage is rare and following the above-discussed [Best Practices](#best-practices) +//! means that most `libc` users will never encounter a problem. + #![crate_name = "libc"] #![crate_type = "rlib"] #![allow( diff --git a/src/unix/mod.rs b/src/unix/mod.rs index ff440d5a13f1..854091c8a529 100644 --- a/src/unix/mod.rs +++ b/src/unix/mod.rs @@ -430,6 +430,9 @@ extern "C" { pub static in6addr_any: in6_addr; } +// FIXME(1.0): We want to remove these directives and instead expect that no-std users add their +// own link configuration when required, rather than unconditionally linking everything that may +// possibly be needed. cfg_if! { if #[cfg(any( target_os = "l4re",