From c08880cb47153598ce3c71fa0afb6c279e4b9c7b Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 27 Dec 2024 11:05:14 +0000 Subject: [PATCH 01/28] RFC: cfg_os_version_min --- text/0000-cfg-os-version-min.md | 113 ++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 text/0000-cfg-os-version-min.md diff --git a/text/0000-cfg-os-version-min.md b/text/0000-cfg-os-version-min.md new file mode 100644 index 00000000000..d55c5e6fb69 --- /dev/null +++ b/text/0000-cfg-os-version-min.md @@ -0,0 +1,113 @@ +- Feature Name: `cfg_os_version_min` +- Start Date: 2024-12-27 +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) + +# Summary +[summary]: #summary + +A new `cfg` predicate `os_version_min` that allows users to declare the minimum primary (target-defined) API level required/supported by a block. +E.g. `cfg!(os_version_min("windows", "6.1.7600"))` would match Windows version >= 6.1.7600. + +# Motivation +[motivation]: #motivation + +The target API version is the version number of the "API set" that a particular binary relies on in order to run properly. An API set is the set of APIs that a host operating system makes available for use by binaries running on that platform. Newer versions of a platform may either add or remove APIs from the API set. + +Crates including the standard library must account for various API version requirements for the crate to be able to run. Rust currently has no mechanism for crates to compile different code (or to gracefully fail to compile) depending on the minimum targeted API version. This leads to the following issues: + +* Relying on dynamic detection of API support has a runtime cost. The standard library often performs [dynamic API detection](https://github.com/rust-lang/rust/blob/f283d3f02cf3ed261a519afe05cde9e23d1d9278/library/std/src/sys/windows/compat.rs) falling back to older (and less ideal) APIs or forgoing entire features when a certain API is not available. For example, the [current `Mutex` impl](https://github.com/rust-lang/rust/blob/234099d1d12bef9d6e81a296222fbc272dc51d89/library/std/src/sys/windows/mutex.rs#L1-L20) has a Windows XP fallback. Users who only ever intend to run their code on newer versions of Windows will still pay a runtime cost for this dynamic API detection. Providing a mechanism for specifying which minimum API version the user cares about, allows for statically specifying which APIs a binary can use. +* Certain features cannot be dynamically detected and thus limit possible implementations. The libc crate must use [a raw syscalls on Android for `accept4`](https://github.com/rust-lang/libc/pull/1968), because this was only exposed in libc in version 21 of the Android API. Additionally libstd must dynamically load `signal` for all versions of Android despite it being required only for versions 19 and below. In the future there might be similar changes where there is no way to implement a solution for older versions. +* Trying to compile code with an implicit dependency on a API version greater than what is supported by the target platform leads to linker errors. For example, the `x86_64-pc-windows-msvc` target's rustc implementation requires `SetThreadErrorMode` which was introduced in Windows 7. This means trying to build the compiler on older versions of Windows will fail with [a less than helpful linker error](https://github.com/rust-lang/rust/issues/35471). + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +Rust targets are often thought of as monoliths. +The thought is that if you compile a binary for that target, that binary should be able to run on any system that fits that target's description. +However, this is not actually true. +For example, when compiling for `x86_64-pc-windows-msvc` and linking with the standard library, my binary has implicitly taken a dependency on a set of APIs that Windows exposes for certain functionality. +If I try to run my binary on older systems that do not have those APIs, then my binary will fail to run. +When compiling for a certain target, you are therefore declaring a dependency on a minimum target API version that you rely on for your binary to run. + +Each standard library target uses a sensible minimum API version. for `x86_64-pc-windows-msvc` the minimum API version is "10.0.10240" which corresponds to Windows 10's initial release. +For `x86_64-win7-pc-windows-msvc` the minimum API version is "6.1.7600" which corresponds to Windows 7. +However, inferring the API version from the target name isn't ideal especially as it can change over time. + +Instead you use the `os_version_min` predicates to specify the minimum API levels of various parts of the operating system. For example: + +* `os_version_min(“windows”, )` would test the [minimum build version](https://gaijin.at/en/infos/windows-version-numbers) of Windows. +* `os_version_min(“libc”, )` would test the version of libc in use. +* `os_version_min(“kernel”, )` would test the version of the kernel in use. + +Let’s use `os_version_min(“windows”, …)` as an example. It should be clear how this example would be extended to the other `cfg` predicates. The predicate allows you to conditionally compile code based on the set minimum API version. For example an implementation of mutex locking on Windows might look like this: + +```rust +pub unsafe fn unlock(&self) { + *self.held.get() = false; + if cfg!(os_version_min(“windows”, "6.0.6000") { // API version greater than Vista + c::ReleaseSRWLockExclusive(raw(self)) // Use the optimized ReleaseSRWLockExclusive routine + } else { + (*self.remutex()).unlock() // Fall back to an alternative that works on older Windows versions + } +} +``` + +For targets where `os_version_min(“windows”, …)` does not make sense (i.e., non-Windows targets), the `cfg` predicate will return `false` and emit a warning saying that the particular `cfg` predicate is not supported on that target. Therefore, it's important to pair `os_version_min(“windows”, …)` with a `cfg(windows)` using the existing mechanisms for combining `cfg` predicates. + +The above example works exactly the same way with the other platform API `cfg` predicates just with different values and different target support. + +These predicates do not assume any semantic versioning information. The specified predicates are simply listed in order. The only semantics that are assumed is that code compiled with the `cfg` predicates works for all versions greater than or equal to that version. + +**Note:** Here it would be important to link to documentation showing the `cfg` predicates and the different version strings that are supported. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +The `os_version_min` predicate allows users to conditionally compile code based on the API version supported by the target platform. +Each platform is responsible for defining a default key, a set of keys it supports, and functions that are able to compare the version strings they use. +A set of comparison functions can be provided by `rustc` for common formats such as 2- and 3-part semantic versioning. +When a platform detects a key it doesn’t support it will return `false` and emit a warning. + +Each target platform will set the minimum API versions it supports. + +## Versioning Schema + +Version strings can take on nearly any form and while there are some standard formats, such as semantic versioning or release dates, projects can change schemas or provide aliases for some or all of their releases. +Because of this diversity in version strings each platform will be responsible for defining a type implementing `FromStr`, `Display`, and `Ord` for each key they support (or using one of the pre-defined types). + +## Future Compatibility + +The functions for parsing and comparing version strings will need to be updated whenever a new API is added, when the version format changes, or when new aliases need to be added. + +# Drawbacks +[drawbacks]: #drawbacks + +Each supported platform will need to implement version string parsing logic (or re-use some provided defaults), maintain the logic in response to future changes, and update any version alias tables. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +The overall mechanism proposed here builds on other well established primitives in Rust such as `cfg`. + +A mechanism which tries to bridge cross-platform differences under one `min_target_api_version` predicate [was suggested](https://github.com/rust-lang/rfcs/blob/b0f94000a3ddbd159013e100e48cd887ba2a0b54/text/0000-min-target-api-version.md) but was rejected due to different platforms having divergent needs. + +# Prior art +[prior-art]: #prior-art + +The Swift package manager has a way to [specify the supported platforms for a given package](https://docs.swift.org/package-manager/PackageDescription/PackageDescription.html#supportedplatform). + +This RFC is largely a version of [RFC #3379](https://github.com/rust-lang/rfcs/pull/3036) more narrowly scoped to just the most minimal lang changes. +That RFC was in turn an updated version of [this RFC draft](https://github.com/rust-lang/rfcs/pull/3036), with the changes reflecting conversations from the draft review process and [further Zulip discussion](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/CFG.20OS.20Redux.20.28migrated.29/near/294738760). + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +Custom targets usually specify their configurations in JSON files. +It is unclear how the target maintainers would add functions, types, and version compatibility information to these files. + +# Future possibilities +[future-possibilities]: #future-possibilities + +The compiler could allow setting a higher minimum OS version than the target's default. +With the `build-std` feature, each target could optionally support lowering the API version below the default. From d78f82b5a18393d817c2bd121c49a439b5b6ab68 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 27 Dec 2024 11:11:21 +0000 Subject: [PATCH 02/28] Update RFC PR number --- text/{0000-cfg-os-version-min.md => 3750-cfg-os-version-min.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename text/{0000-cfg-os-version-min.md => 3750-cfg-os-version-min.md} (99%) diff --git a/text/0000-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md similarity index 99% rename from text/0000-cfg-os-version-min.md rename to text/3750-cfg-os-version-min.md index d55c5e6fb69..0e977cae92b 100644 --- a/text/0000-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -1,6 +1,6 @@ - Feature Name: `cfg_os_version_min` - Start Date: 2024-12-27 -- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- RFC PR: [rust-lang/rfcs#3750](https://github.com/rust-lang/rfcs/pull/3750) - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) # Summary From 58ae3de38f5a8c936fdd7034456502770f139771 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 2 Jan 2025 11:19:47 +0000 Subject: [PATCH 03/28] Remove "in use" --- text/3750-cfg-os-version-min.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 0e977cae92b..c13e3a97311 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -37,8 +37,8 @@ However, inferring the API version from the target name isn't ideal especially a Instead you use the `os_version_min` predicates to specify the minimum API levels of various parts of the operating system. For example: * `os_version_min(“windows”, )` would test the [minimum build version](https://gaijin.at/en/infos/windows-version-numbers) of Windows. -* `os_version_min(“libc”, )` would test the version of libc in use. -* `os_version_min(“kernel”, )` would test the version of the kernel in use. +* `os_version_min(“libc”, )` would test the version of libc. +* `os_version_min(“kernel”, )` would test the version of the kernel. Let’s use `os_version_min(“windows”, …)` as an example. It should be clear how this example would be extended to the other `cfg` predicates. The predicate allows you to conditionally compile code based on the set minimum API version. For example an implementation of mutex locking on Windows might look like this: From 0b8f9125307abd0bd9dc4bb9f7ea522bf3c8db7a Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 4 Jan 2025 19:19:24 +0000 Subject: [PATCH 04/28] Update text/3750-cfg-os-version-min.md Co-authored-by: Mads Marquart --- text/3750-cfg-os-version-min.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index c13e3a97311..58181d6a4b2 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -97,7 +97,7 @@ A mechanism which tries to bridge cross-platform differences under one `min_targ The Swift package manager has a way to [specify the supported platforms for a given package](https://docs.swift.org/package-manager/PackageDescription/PackageDescription.html#supportedplatform). -This RFC is largely a version of [RFC #3379](https://github.com/rust-lang/rfcs/pull/3036) more narrowly scoped to just the most minimal lang changes. +This RFC is largely a version of [RFC #3379](https://github.com/rust-lang/rfcs/pull/3379) more narrowly scoped to just the most minimal lang changes. That RFC was in turn an updated version of [this RFC draft](https://github.com/rust-lang/rfcs/pull/3036), with the changes reflecting conversations from the draft review process and [further Zulip discussion](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/CFG.20OS.20Redux.20.28migrated.29/near/294738760). # Unresolved questions From c3f33b8b3df497cb02c7656078b4375ad1ebf3e4 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 5 Jan 2025 14:09:58 +0000 Subject: [PATCH 05/28] Mention other possible syntax --- text/3750-cfg-os-version-min.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 58181d6a4b2..ff7ccce9043 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -89,9 +89,15 @@ Each supported platform will need to implement version string parsing logic (or [rationale-and-alternatives]: #rationale-and-alternatives The overall mechanism proposed here builds on other well established primitives in Rust such as `cfg`. - A mechanism which tries to bridge cross-platform differences under one `min_target_api_version` predicate [was suggested](https://github.com/rust-lang/rfcs/blob/b0f94000a3ddbd159013e100e48cd887ba2a0b54/text/0000-min-target-api-version.md) but was rejected due to different platforms having divergent needs. +For many platforms, the `target_os` name and the `os_version_min` name will be identical. +Even platforms that have multiple possible `versions` relevant to the OS will still have one primary version. +E.g. for `linux` the primary version would refer to the kernel with `libc` being a secondary OS library version. +Therefore it would be possible to simplify the syntax for the primary target OS version. +E.g.: `cfg(target_os("macos", min_version = "..."))` or by having `os_version_min("macos", "...")` imply `#[cfg(target_os = "macos")]`. +This means we'd need a more general syntax for `libc` and potentially other versioned libraries where the target OS is ambiguous. + # Prior art [prior-art]: #prior-art @@ -106,6 +112,9 @@ That RFC was in turn an updated version of [this RFC draft](https://github.com/r Custom targets usually specify their configurations in JSON files. It is unclear how the target maintainers would add functions, types, and version compatibility information to these files. +What exactly should the syntax be? +Should we draw a distinction between cases where the `os_version_min` directly implies a specific `target_os` and cases where it doesn't (see alternatives)? + # Future possibilities [future-possibilities]: #future-possibilities From 6e2245c41b7e5507752986c72d9a525cbb4b1c7a Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 5 Jan 2025 14:40:57 +0000 Subject: [PATCH 06/28] Update prior art to include how C does it --- text/3750-cfg-os-version-min.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index ff7ccce9043..852801b2e6e 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -101,7 +101,15 @@ This means we'd need a more general syntax for `libc` and potentially other vers # Prior art [prior-art]: #prior-art -The Swift package manager has a way to [specify the supported platforms for a given package](https://docs.swift.org/package-manager/PackageDescription/PackageDescription.html#supportedplatform). +In C it's common to be able to target different versions based on a preprocessor macro. +For example, on Windows `WINVER` can be used: + +```c +// If the minimum version is at least Windows 10 +#if (WINVER >= _WIN32_WINNT_WIN10) +// ... +#endif +``` This RFC is largely a version of [RFC #3379](https://github.com/rust-lang/rfcs/pull/3379) more narrowly scoped to just the most minimal lang changes. That RFC was in turn an updated version of [this RFC draft](https://github.com/rust-lang/rfcs/pull/3036), with the changes reflecting conversations from the draft review process and [further Zulip discussion](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/CFG.20OS.20Redux.20.28migrated.29/near/294738760). From 35dc984ddd56eacf40671680f6ed898486484306 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 27 Jan 2025 05:30:47 +0000 Subject: [PATCH 07/28] Update motivation and guide --- text/3750-cfg-os-version-min.md | 87 ++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 22 deletions(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 852801b2e6e..50f271d47d3 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -12,13 +12,24 @@ E.g. `cfg!(os_version_min("windows", "6.1.7600"))` would match Windows version > # Motivation [motivation]: #motivation -The target API version is the version number of the "API set" that a particular binary relies on in order to run properly. An API set is the set of APIs that a host operating system makes available for use by binaries running on that platform. Newer versions of a platform may either add or remove APIs from the API set. +Operating systems and their libraries are continually advancing, adding and sometimes removing APIs or otherwise changing behaviour. +Versioning of APIs is common so that developers can target the set of APIs they support. +Crates including the standard library must account for various API version requirements for the crate to be able to run. +Rust currently has no mechanism for crates to compile different code (or to gracefully fail to compile) depending on the minimum targeted API version. +This leads to the following issues: + +* Relying on dynamic detection of API support has a runtime cost. +The standard library often performs [dynamic API detection](https://github.com/rust-lang/rust/blob/f283d3f02cf3ed261a519afe05cde9e23d1d9278/library/std/src/sys/windows/compat.rs) falling back to older (and less ideal) APIs or forgoing entire features when a certain API is not available. +For example, the [current `Mutex` impl](https://github.com/rust-lang/rust/blob/234099d1d12bef9d6e81a296222fbc272dc51d89/library/std/src/sys/windows/mutex.rs#L1-L20) has a Windows 7 fallback. Users who only ever intend to run their code on newer versions of Windows will still pay a runtime cost for this dynamic API detection. +Providing a mechanism for specifying which minimum API version the user cares about, allows for statically specifying which APIs a binary can use. +* Certain features cannot be dynamically detected and thus limit possible implementations. +The libc crate must use [a raw syscalls on Android for `accept4`](https://github.com/rust-lang/libc/pull/1968), because this was only exposed in libc in version 21 of the Android API. +Additionally libstd must dynamically load `signal` for all versions of Android despite it being required only for versions 19 and below. +In the future there might be similar changes where there is no way to implement a solution for older versions. +* Trying to compile code with an implicit dependency on a API version greater than what is supported by the target platform leads to linker errors. +For example, the `x86_64-pc-windows-msvc` target's rustc implementation requires `SetThreadErrorMode` which was introduced in Windows 7. +This means trying to build the compiler on older versions of Windows will fail with [a less than helpful linker error](https://github.com/rust-lang/rust/issues/35471). -Crates including the standard library must account for various API version requirements for the crate to be able to run. Rust currently has no mechanism for crates to compile different code (or to gracefully fail to compile) depending on the minimum targeted API version. This leads to the following issues: - -* Relying on dynamic detection of API support has a runtime cost. The standard library often performs [dynamic API detection](https://github.com/rust-lang/rust/blob/f283d3f02cf3ed261a519afe05cde9e23d1d9278/library/std/src/sys/windows/compat.rs) falling back to older (and less ideal) APIs or forgoing entire features when a certain API is not available. For example, the [current `Mutex` impl](https://github.com/rust-lang/rust/blob/234099d1d12bef9d6e81a296222fbc272dc51d89/library/std/src/sys/windows/mutex.rs#L1-L20) has a Windows XP fallback. Users who only ever intend to run their code on newer versions of Windows will still pay a runtime cost for this dynamic API detection. Providing a mechanism for specifying which minimum API version the user cares about, allows for statically specifying which APIs a binary can use. -* Certain features cannot be dynamically detected and thus limit possible implementations. The libc crate must use [a raw syscalls on Android for `accept4`](https://github.com/rust-lang/libc/pull/1968), because this was only exposed in libc in version 21 of the Android API. Additionally libstd must dynamically load `signal` for all versions of Android despite it being required only for versions 19 and below. In the future there might be similar changes where there is no way to implement a solution for older versions. -* Trying to compile code with an implicit dependency on a API version greater than what is supported by the target platform leads to linker errors. For example, the `x86_64-pc-windows-msvc` target's rustc implementation requires `SetThreadErrorMode` which was introduced in Windows 7. This means trying to build the compiler on older versions of Windows will fail with [a less than helpful linker error](https://github.com/rust-lang/rust/issues/35471). # Guide-level explanation [guide-level-explanation]: #guide-level-explanation @@ -36,30 +47,62 @@ However, inferring the API version from the target name isn't ideal especially a Instead you use the `os_version_min` predicates to specify the minimum API levels of various parts of the operating system. For example: -* `os_version_min(“windows”, )` would test the [minimum build version](https://gaijin.at/en/infos/windows-version-numbers) of Windows. -* `os_version_min(“libc”, )` would test the version of libc. -* `os_version_min(“kernel”, )` would test the version of the kernel. +* `os_version_min("windows", )` would test the [minimum build version](https://gaijin.at/en/infos/windows-version-numbers) of Windows. +* `os_version_min("libc", )` would test the version of libc. +* `os_version_min("kernel", )` would test the version of the kernel. -Let’s use `os_version_min(“windows”, …)` as an example. It should be clear how this example would be extended to the other `cfg` predicates. The predicate allows you to conditionally compile code based on the set minimum API version. For example an implementation of mutex locking on Windows might look like this: +Let’s use `os_version_min("windows", …)` for a simple example. ```rust -pub unsafe fn unlock(&self) { - *self.held.get() = false; - if cfg!(os_version_min(“windows”, "6.0.6000") { // API version greater than Vista - c::ReleaseSRWLockExclusive(raw(self)) // Use the optimized ReleaseSRWLockExclusive routine +pub fn random_u64() -> u64 { + let mut rand = 0_u64.to_ne_bytes(); + if cfg!(os_version_min("windows", "10.0.10240")) { + // For an API version greater or equal to Windows 10, we use `ProcessPrng` + unsafe { ProcessPrng(rand.as_mut_ptr(), rand.len()) }; } else { - (*self.remutex()).unlock() // Fall back to an alternative that works on older Windows versions + // Otherwise we fallback to `RtlGenRandom` + unsafe { RtlGenRandom(rand.as_mut_ptr().cast(), rand.len() as u32) }; } + u64::from_ne_bytes(rand) } ``` -For targets where `os_version_min(“windows”, …)` does not make sense (i.e., non-Windows targets), the `cfg` predicate will return `false` and emit a warning saying that the particular `cfg` predicate is not supported on that target. Therefore, it's important to pair `os_version_min(“windows”, …)` with a `cfg(windows)` using the existing mechanisms for combining `cfg` predicates. - -The above example works exactly the same way with the other platform API `cfg` predicates just with different values and different target support. +A more involved example would be to attempt to dynamically load the symbol. +On macOS we use weak linking to do this: -These predicates do not assume any semantic versioning information. The specified predicates are simply listed in order. The only semantics that are assumed is that code compiled with the `cfg` predicates works for all versions greater than or equal to that version. - -**Note:** Here it would be important to link to documentation showing the `cfg` predicates and the different version strings that are supported. +```rust +// Always available under these conditions. +#[any( + os_version_min("macos", "11.0"), + os_version_min("ios", "14.0"), + os_version_min("tvos", "14.0"), + os_version_min("watchos", "7.0"), + os_version_min("visionos", "1.0") +)] +let preadv = { + extern "C" { + fn preadv(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize; + } + Some(preadv) +}; + +// Otherwise `preadv` needs to be weakly linked. +// We do that using a `weak!` macro, defined elsewhere. +#[cfg(not(any( + os_version_min("macos", "11.0"), + os_version_min("ios", "14.0"), + os_version_min("tvos", "14.0"), + os_version_min("watchos", "7.0"), + os_version_min("visionos", "1.0") +)))] +weak!(fn preadv(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); + +if let Some(preadv) = preadv { + preadv(...) // Use preadv, it's available +} else { + // ... fallback impl +} +``` # Reference-level explanation [reference-level-explanation]: #reference-level-explanation @@ -111,7 +154,7 @@ For example, on Windows `WINVER` can be used: #endif ``` -This RFC is largely a version of [RFC #3379](https://github.com/rust-lang/rfcs/pull/3379) more narrowly scoped to just the most minimal lang changes. +This RFC is a continuation of [RFC #3379](https://github.com/rust-lang/rfcs/pull/3379) more narrowly scoped to just `os_version_min`. That RFC was in turn an updated version of [this RFC draft](https://github.com/rust-lang/rfcs/pull/3036), with the changes reflecting conversations from the draft review process and [further Zulip discussion](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/CFG.20OS.20Redux.20.28migrated.29/near/294738760). # Unresolved questions From 5332c9b8cf0cb2da45a3b95fb5f0771710344228 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 27 Jan 2025 05:46:32 +0000 Subject: [PATCH 08/28] Update reference level explanation --- text/3750-cfg-os-version-min.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 50f271d47d3..6b9554fc56d 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -107,12 +107,13 @@ if let Some(preadv) = preadv { # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -The `os_version_min` predicate allows users to conditionally compile code based on the API version supported by the target platform. -Each platform is responsible for defining a default key, a set of keys it supports, and functions that are able to compare the version strings they use. -A set of comparison functions can be provided by `rustc` for common formats such as 2- and 3-part semantic versioning. -When a platform detects a key it doesn’t support it will return `false` and emit a warning. +The `os_version_min` predicate allows users to conditionally compile code based on the API version supported by the target platform using `cfg`. +It requires a key and a version string. For example, `#[cfg("macos", "11.0")]` has the key `macos` and version string `11.0`. +The key can be either a `target_os` string or else one of a set of target-defined strings. +Version strings are always target defined (see [Versioning Schema](#versioning-schema)). +If a target doesn't support a key, then the `cfg` will always return `false`. -Each target platform will set the minimum API versions it supports. +Each target platform will set the minimum API versions it supports for each key. ## Versioning Schema @@ -121,7 +122,7 @@ Because of this diversity in version strings each platform will be responsible f ## Future Compatibility -The functions for parsing and comparing version strings will need to be updated whenever a new API is added, when the version format changes, or when new aliases need to be added. +The functions for parsing and comparing version strings may need to be updated whenever a new API is added, when the version format changes, or when new aliases need to be added. # Drawbacks [drawbacks]: #drawbacks From 859a73352233b8cf718e1a60133da05ed4a8eb76 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 27 Jan 2025 05:46:44 +0000 Subject: [PATCH 09/28] Add a linting section --- text/3750-cfg-os-version-min.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 6b9554fc56d..895837d0e83 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -120,6 +120,12 @@ Each target platform will set the minimum API versions it supports for each key. Version strings can take on nearly any form and while there are some standard formats, such as semantic versioning or release dates, projects can change schemas or provide aliases for some or all of their releases. Because of this diversity in version strings each platform will be responsible for defining a type implementing `FromStr`, `Display`, and `Ord` for each key they support (or using one of the pre-defined types). +## Linting + +By default `os_version_min` will be linted by `check_cfg` in a similar way to `target_os`. +That is, all valid values for `target_os` will be accepted as valid keys for `os_version_min` on all platforms. +Additionally the list of additional keys supported by the target will be consulted, which will then be allowed on a per-target basis. + ## Future Compatibility The functions for parsing and comparing version strings may need to be updated whenever a new API is added, when the version format changes, or when new aliases need to be added. From 6c7e0c6d7f69aab6557c691a168a322d6007f4b8 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 27 Jan 2025 05:51:51 +0000 Subject: [PATCH 10/28] Remove double "additional" --- text/3750-cfg-os-version-min.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 895837d0e83..17ae0ea3116 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -124,7 +124,7 @@ Because of this diversity in version strings each platform will be responsible f By default `os_version_min` will be linted by `check_cfg` in a similar way to `target_os`. That is, all valid values for `target_os` will be accepted as valid keys for `os_version_min` on all platforms. -Additionally the list of additional keys supported by the target will be consulted, which will then be allowed on a per-target basis. +The list of additional keys supported by the target will be consulted, which will then be allowed on a per-target basis. ## Future Compatibility From 16c6321a1b0e385d5ebb7325eaf1786d8a318295 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 27 Jan 2025 05:54:47 +0000 Subject: [PATCH 11/28] Add default supported target motivation --- text/3750-cfg-os-version-min.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 17ae0ea3116..93201cbb18c 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -29,7 +29,9 @@ In the future there might be similar changes where there is no way to implement * Trying to compile code with an implicit dependency on a API version greater than what is supported by the target platform leads to linker errors. For example, the `x86_64-pc-windows-msvc` target's rustc implementation requires `SetThreadErrorMode` which was introduced in Windows 7. This means trying to build the compiler on older versions of Windows will fail with [a less than helpful linker error](https://github.com/rust-lang/rust/issues/35471). - +* Bumping the minimum supported version of a platform in Rust is a large endeavour. +By adding this feature, we enable [rustc to more gradually raise the supported version](https://github.com/rust-lang/rust/pull/104385#issuecomment-1453520239) or to have more "levels" of version support. +This would allow for having the "default" supported target be higher than the "minimum" supported target. # Guide-level explanation [guide-level-explanation]: #guide-level-explanation From 68c00f83a4e1a37f6e9a32e8de5366d55990a007 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 27 Jan 2025 06:08:56 +0000 Subject: [PATCH 12/28] Add a note about the standard library --- text/3750-cfg-os-version-min.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 93201cbb18c..211b2b92bc8 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -117,6 +117,11 @@ If a target doesn't support a key, then the `cfg` will always return `false`. Each target platform will set the minimum API versions it supports for each key. +## The standard library + +Currently the standard library is pre-compiled meaning that only a single version of each API can be supported, which must be the minimum version. +Third party crates can use a higher API level so long as it's compatible with the baseline API version. + ## Versioning Schema Version strings can take on nearly any form and while there are some standard formats, such as semantic versioning or release dates, projects can change schemas or provide aliases for some or all of their releases. From 6b54296533cf3dc79281bc69722bf00e23ed0c52 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 27 Jan 2025 06:14:52 +0000 Subject: [PATCH 13/28] Expand on the version string --- text/3750-cfg-os-version-min.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 211b2b92bc8..050a11b98d5 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -110,9 +110,10 @@ if let Some(preadv) = preadv { [reference-level-explanation]: #reference-level-explanation The `os_version_min` predicate allows users to conditionally compile code based on the API version supported by the target platform using `cfg`. -It requires a key and a version string. For example, `#[cfg("macos", "11.0")]` has the key `macos` and version string `11.0`. +It requires a key and a version string. The key can be either a `target_os` string or else one of a set of target-defined strings. -Version strings are always target defined (see [Versioning Schema](#versioning-schema)). +Version strings are always target defined (see [Versioning Schema](#versioning-schema)) and will be compared against the target's supported version. +For example, `#[cfg("macos", "11.0")]` has the key `macos` and the minimum version `11.0`, which will match any macos version greater than or equal to `11.0`. If a target doesn't support a key, then the `cfg` will always return `false`. Each target platform will set the minimum API versions it supports for each key. From a9b5b744b759216bbba28aeb9a9c1f6254339876 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 27 Jan 2025 06:20:00 +0000 Subject: [PATCH 14/28] Note that a higher baseline isn't yet supported --- text/3750-cfg-os-version-min.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 050a11b98d5..032e35051ed 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -121,7 +121,8 @@ Each target platform will set the minimum API versions it supports for each key. ## The standard library Currently the standard library is pre-compiled meaning that only a single version of each API can be supported, which must be the minimum version. -Third party crates can use a higher API level so long as it's compatible with the baseline API version. +Third party crates can choose to use a higher API level so long as it's compatible with the baseline API version. +However, there is currently no support (see [Future Possibilities][future-possibilities]). ## Versioning Schema From b71051ba08c03fca13c6b498988948a2f37257e8 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 27 Jan 2025 06:21:03 +0000 Subject: [PATCH 15/28] Fix some headings --- text/3750-cfg-os-version-min.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 032e35051ed..303fa7ed469 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -112,30 +112,34 @@ if let Some(preadv) = preadv { The `os_version_min` predicate allows users to conditionally compile code based on the API version supported by the target platform using `cfg`. It requires a key and a version string. The key can be either a `target_os` string or else one of a set of target-defined strings. -Version strings are always target defined (see [Versioning Schema](#versioning-schema)) and will be compared against the target's supported version. +Version strings are always target defined (see [Versioning Schema][versioning-schema]) and will be compared against the target's supported version. For example, `#[cfg("macos", "11.0")]` has the key `macos` and the minimum version `11.0`, which will match any macos version greater than or equal to `11.0`. If a target doesn't support a key, then the `cfg` will always return `false`. Each target platform will set the minimum API versions it supports for each key. ## The standard library +[the-standard-library]: #the-standard-library Currently the standard library is pre-compiled meaning that only a single version of each API can be supported, which must be the minimum version. Third party crates can choose to use a higher API level so long as it's compatible with the baseline API version. However, there is currently no support (see [Future Possibilities][future-possibilities]). ## Versioning Schema +[versioning-schema]: #versioning-schema Version strings can take on nearly any form and while there are some standard formats, such as semantic versioning or release dates, projects can change schemas or provide aliases for some or all of their releases. Because of this diversity in version strings each platform will be responsible for defining a type implementing `FromStr`, `Display`, and `Ord` for each key they support (or using one of the pre-defined types). ## Linting +[linting]: #linting By default `os_version_min` will be linted by `check_cfg` in a similar way to `target_os`. That is, all valid values for `target_os` will be accepted as valid keys for `os_version_min` on all platforms. The list of additional keys supported by the target will be consulted, which will then be allowed on a per-target basis. ## Future Compatibility +[future-compatibility]: #future-compatibility The functions for parsing and comparing version strings may need to be updated whenever a new API is added, when the version format changes, or when new aliases need to be added. From 5cde247835a399a5df80ce875e307d2c1d53d91f Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 27 Jan 2025 06:23:17 +0000 Subject: [PATCH 16/28] Update 3750-cfg-os-version-min.md --- text/3750-cfg-os-version-min.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 303fa7ed469..2f635574378 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -123,7 +123,7 @@ Each target platform will set the minimum API versions it supports for each key. Currently the standard library is pre-compiled meaning that only a single version of each API can be supported, which must be the minimum version. Third party crates can choose to use a higher API level so long as it's compatible with the baseline API version. -However, there is currently no support (see [Future Possibilities][future-possibilities]). +However, there is currently no support for setting a `os_version_min` version above the target's baseline (see [Future Possibilities][future-possibilities]). ## Versioning Schema [versioning-schema]: #versioning-schema From 35896d1603eb4a7ef00ff9ab17ecc544781f2f88 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 27 Jan 2025 06:26:54 +0000 Subject: [PATCH 17/28] Update 3750-cfg-os-version-min.md --- text/3750-cfg-os-version-min.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 2f635574378..641a1407cac 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -157,8 +157,8 @@ A mechanism which tries to bridge cross-platform differences under one `min_targ For many platforms, the `target_os` name and the `os_version_min` name will be identical. Even platforms that have multiple possible `versions` relevant to the OS will still have one primary version. E.g. for `linux` the primary version would refer to the kernel with `libc` being a secondary OS library version. -Therefore it would be possible to simplify the syntax for the primary target OS version. -E.g.: `cfg(target_os("macos", min_version = "..."))` or by having `os_version_min("macos", "...")` imply `#[cfg(target_os = "macos")]`. +Therefore it would make sense for the primary target OS version to be a property of `target_os`. +E.g.: `cfg(target_os("macos", min_version = "..."))`. This means we'd need a more general syntax for `libc` and potentially other versioned libraries where the target OS is ambiguous. # Prior art From 439fcea4a13873e1c0e290f05cd26a842230b4fc Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 29 Jan 2025 20:09:30 +0000 Subject: [PATCH 18/28] Make future possibilities use bullet points --- text/3750-cfg-os-version-min.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 641a1407cac..3cbc185de7e 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -189,5 +189,5 @@ Should we draw a distinction between cases where the `os_version_min` directly i # Future possibilities [future-possibilities]: #future-possibilities -The compiler could allow setting a higher minimum OS version than the target's default. -With the `build-std` feature, each target could optionally support lowering the API version below the default. +* The compiler could allow setting a higher minimum OS version than the target's default. +* With the `build-std` feature, each target could optionally support lowering the API version below the default. From 89b604dab728c0782e51cdcddea85a421072f351 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 29 Jan 2025 20:10:14 +0000 Subject: [PATCH 19/28] Clarify version string comparision --- text/3750-cfg-os-version-min.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 3cbc185de7e..a8b11254c38 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -129,7 +129,8 @@ However, there is currently no support for setting a `os_version_min` version ab [versioning-schema]: #versioning-schema Version strings can take on nearly any form and while there are some standard formats, such as semantic versioning or release dates, projects can change schemas or provide aliases for some or all of their releases. -Because of this diversity in version strings each platform will be responsible for defining a type implementing `FromStr`, `Display`, and `Ord` for each key they support (or using one of the pre-defined types). +Because of this diversity in version strings each platform will be responsible for defining an `is_gte` comparison function for each key they support. +Alternatively they can use one of the pre-defined functions. ## Linting [linting]: #linting From c889a32ed4a75dd0db2c713fd28533184fc3a6ae Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 29 Jan 2025 20:15:08 +0000 Subject: [PATCH 20/28] Update 3750-cfg-os-version-min.md --- text/3750-cfg-os-version-min.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index a8b11254c38..1c2fca405f7 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -182,7 +182,7 @@ That RFC was in turn an updated version of [this RFC draft](https://github.com/r [unresolved-questions]: #unresolved-questions Custom targets usually specify their configurations in JSON files. -It is unclear how the target maintainers would add functions, types, and version compatibility information to these files. +It is unclear how the target maintainers would add version comparison information to these files. What exactly should the syntax be? Should we draw a distinction between cases where the `os_version_min` directly implies a specific `target_os` and cases where it doesn't (see alternatives)? From d9715b4b6bbaa4560b40a15fd86fce192433f0ac Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 9 Apr 2025 23:46:21 +0000 Subject: [PATCH 21/28] Update text/3750-cfg-os-version-min.md Co-authored-by: Mads Marquart --- text/3750-cfg-os-version-min.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 1c2fca405f7..a3b92343bcb 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -14,7 +14,7 @@ E.g. `cfg!(os_version_min("windows", "6.1.7600"))` would match Windows version > Operating systems and their libraries are continually advancing, adding and sometimes removing APIs or otherwise changing behaviour. Versioning of APIs is common so that developers can target the set of APIs they support. -Crates including the standard library must account for various API version requirements for the crate to be able to run. +Crates, including the standard library, must account for various API version requirements for the crate to be able to run. Rust currently has no mechanism for crates to compile different code (or to gracefully fail to compile) depending on the minimum targeted API version. This leads to the following issues: From 35ee57078a19c3136e5211012c84fdaa8eca7d84 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 9 Apr 2025 23:46:53 +0000 Subject: [PATCH 22/28] Update text/3750-cfg-os-version-min.md Co-authored-by: Mads Marquart --- text/3750-cfg-os-version-min.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index a3b92343bcb..075657c382c 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -23,7 +23,7 @@ The standard library often performs [dynamic API detection](https://github.com/r For example, the [current `Mutex` impl](https://github.com/rust-lang/rust/blob/234099d1d12bef9d6e81a296222fbc272dc51d89/library/std/src/sys/windows/mutex.rs#L1-L20) has a Windows 7 fallback. Users who only ever intend to run their code on newer versions of Windows will still pay a runtime cost for this dynamic API detection. Providing a mechanism for specifying which minimum API version the user cares about, allows for statically specifying which APIs a binary can use. * Certain features cannot be dynamically detected and thus limit possible implementations. -The libc crate must use [a raw syscalls on Android for `accept4`](https://github.com/rust-lang/libc/pull/1968), because this was only exposed in libc in version 21 of the Android API. +The libc crate must use [a raw syscall on Android for `accept4`](https://github.com/rust-lang/libc/pull/1968), because this was only exposed in libc in version 21 of the Android API. Additionally libstd must dynamically load `signal` for all versions of Android despite it being required only for versions 19 and below. In the future there might be similar changes where there is no way to implement a solution for older versions. * Trying to compile code with an implicit dependency on a API version greater than what is supported by the target platform leads to linker errors. From 157b501d4b5f0f38434087c02ec9376eaa6e2f82 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 9 Apr 2025 23:47:19 +0000 Subject: [PATCH 23/28] Update text/3750-cfg-os-version-min.md Co-authored-by: Mads Marquart --- text/3750-cfg-os-version-min.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 075657c382c..d76ba39a1af 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -74,13 +74,13 @@ On macOS we use weak linking to do this: ```rust // Always available under these conditions. -#[any( +#[cfg(any( os_version_min("macos", "11.0"), os_version_min("ios", "14.0"), os_version_min("tvos", "14.0"), os_version_min("watchos", "7.0"), os_version_min("visionos", "1.0") -)] +))] let preadv = { extern "C" { fn preadv(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize; From 0edbe04084745d80b43b671ae034980936240107 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 9 Apr 2025 23:47:45 +0000 Subject: [PATCH 24/28] Update text/3750-cfg-os-version-min.md Co-authored-by: Mads Marquart --- text/3750-cfg-os-version-min.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index d76ba39a1af..98b484dce9b 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -113,7 +113,7 @@ The `os_version_min` predicate allows users to conditionally compile code based It requires a key and a version string. The key can be either a `target_os` string or else one of a set of target-defined strings. Version strings are always target defined (see [Versioning Schema][versioning-schema]) and will be compared against the target's supported version. -For example, `#[cfg("macos", "11.0")]` has the key `macos` and the minimum version `11.0`, which will match any macos version greater than or equal to `11.0`. +For example, `#[cfg(os_version_min("macos", "11.0"))]` has the key `macos` and the minimum version `11.0`, which will match any macOS version greater than or equal to macOS 11 Big Sur. If a target doesn't support a key, then the `cfg` will always return `false`. Each target platform will set the minimum API versions it supports for each key. From cd0e8a925a6b69f4edd44bfdddd87204d377b216 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 9 Apr 2025 23:48:52 +0000 Subject: [PATCH 25/28] Update text/3750-cfg-os-version-min.md Co-authored-by: Mads Marquart --- text/3750-cfg-os-version-min.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index 98b484dce9b..c526fa47fdd 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -1,7 +1,7 @@ - Feature Name: `cfg_os_version_min` - Start Date: 2024-12-27 - RFC PR: [rust-lang/rfcs#3750](https://github.com/rust-lang/rfcs/pull/3750) -- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) +- Rust Issue: [rust-lang/rust#136866](https://github.com/rust-lang/rust/issues/136866) # Summary [summary]: #summary From fb06a58ec6327093ed5645affb53f8007f0424a1 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 10 Apr 2025 21:44:41 +0000 Subject: [PATCH 26/28] Update text/3750-cfg-os-version-min.md Co-authored-by: Mads Marquart --- text/3750-cfg-os-version-min.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index c526fa47fdd..d3071637389 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -128,9 +128,8 @@ However, there is currently no support for setting a `os_version_min` version ab ## Versioning Schema [versioning-schema]: #versioning-schema -Version strings can take on nearly any form and while there are some standard formats, such as semantic versioning or release dates, projects can change schemas or provide aliases for some or all of their releases. -Because of this diversity in version strings each platform will be responsible for defining an `is_gte` comparison function for each key they support. -Alternatively they can use one of the pre-defined functions. +Version strings can take on nearly any form and while there are some standard formats, such as semantic versioning or release dates, projects/platforms can change schemas or provide aliases for some or all of their releases. +Because of this diversity in version strings, each target will be responsible for validating the version, and defining comparisons on it. ## Linting [linting]: #linting From cf3cd1dd01d9b620cc16143f7622121daee826b2 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 20 May 2025 09:30:58 +0000 Subject: [PATCH 27/28] Rename os_version_min to target_version --- text/3750-cfg-os-version-min.md | 57 +++++++++++++++++---------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-os-version-min.md index d3071637389..2326c899d3a 100644 --- a/text/3750-cfg-os-version-min.md +++ b/text/3750-cfg-os-version-min.md @@ -1,4 +1,4 @@ -- Feature Name: `cfg_os_version_min` +- Feature Name: `cfg_target_version` - Start Date: 2024-12-27 - RFC PR: [rust-lang/rfcs#3750](https://github.com/rust-lang/rfcs/pull/3750) - Rust Issue: [rust-lang/rust#136866](https://github.com/rust-lang/rust/issues/136866) @@ -6,8 +6,8 @@ # Summary [summary]: #summary -A new `cfg` predicate `os_version_min` that allows users to declare the minimum primary (target-defined) API level required/supported by a block. -E.g. `cfg!(os_version_min("windows", "6.1.7600"))` would match Windows version >= 6.1.7600. +A new `cfg` predicate `target_version` that allows users to declare the minimum primary (target-defined) API level required/supported by a block. +E.g. `cfg!(target_version("windows", "6.1.7600"))` would match Windows version >= 6.1.7600. # Motivation [motivation]: #motivation @@ -47,18 +47,18 @@ Each standard library target uses a sensible minimum API version. for `x86_64-pc For `x86_64-win7-pc-windows-msvc` the minimum API version is "6.1.7600" which corresponds to Windows 7. However, inferring the API version from the target name isn't ideal especially as it can change over time. -Instead you use the `os_version_min` predicates to specify the minimum API levels of various parts of the operating system. For example: +Instead you use the `target_version` predicates to specify the minimum API levels of various parts of the operating system. For example: -* `os_version_min("windows", )` would test the [minimum build version](https://gaijin.at/en/infos/windows-version-numbers) of Windows. -* `os_version_min("libc", )` would test the version of libc. -* `os_version_min("kernel", )` would test the version of the kernel. +* `target_version("windows", )` would test the [minimum build version](https://gaijin.at/en/infos/windows-version-numbers) of Windows. +* `target_version("libc", )` would test the version of libc. +* `target_version("kernel", )` would test the version of the kernel. -Let’s use `os_version_min("windows", …)` for a simple example. +Let’s use `target_version("windows", …)` for a simple example. ```rust pub fn random_u64() -> u64 { let mut rand = 0_u64.to_ne_bytes(); - if cfg!(os_version_min("windows", "10.0.10240")) { + if cfg!(target_version("windows", "10.0.10240")) { // For an API version greater or equal to Windows 10, we use `ProcessPrng` unsafe { ProcessPrng(rand.as_mut_ptr(), rand.len()) }; } else { @@ -75,11 +75,11 @@ On macOS we use weak linking to do this: ```rust // Always available under these conditions. #[cfg(any( - os_version_min("macos", "11.0"), - os_version_min("ios", "14.0"), - os_version_min("tvos", "14.0"), - os_version_min("watchos", "7.0"), - os_version_min("visionos", "1.0") + target_version("macos", "11.0"), + target_version("ios", "14.0"), + target_version("tvos", "14.0"), + target_version("watchos", "7.0"), + target_version("visionos", "1.0") ))] let preadv = { extern "C" { @@ -91,11 +91,11 @@ let preadv = { // Otherwise `preadv` needs to be weakly linked. // We do that using a `weak!` macro, defined elsewhere. #[cfg(not(any( - os_version_min("macos", "11.0"), - os_version_min("ios", "14.0"), - os_version_min("tvos", "14.0"), - os_version_min("watchos", "7.0"), - os_version_min("visionos", "1.0") + target_version("macos", "11.0"), + target_version("ios", "14.0"), + target_version("tvos", "14.0"), + target_version("watchos", "7.0"), + target_version("visionos", "1.0") )))] weak!(fn preadv(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); @@ -109,11 +109,11 @@ if let Some(preadv) = preadv { # Reference-level explanation [reference-level-explanation]: #reference-level-explanation -The `os_version_min` predicate allows users to conditionally compile code based on the API version supported by the target platform using `cfg`. +The `target_version` predicate allows users to conditionally compile code based on the API version supported by the target platform using `cfg`. It requires a key and a version string. The key can be either a `target_os` string or else one of a set of target-defined strings. Version strings are always target defined (see [Versioning Schema][versioning-schema]) and will be compared against the target's supported version. -For example, `#[cfg(os_version_min("macos", "11.0"))]` has the key `macos` and the minimum version `11.0`, which will match any macOS version greater than or equal to macOS 11 Big Sur. +For example, `#[cfg(target_version("macos", "11.0"))]` has the key `macos` and the minimum version `11.0`, which will match any macOS version greater than or equal to macOS 11 Big Sur. If a target doesn't support a key, then the `cfg` will always return `false`. Each target platform will set the minimum API versions it supports for each key. @@ -123,7 +123,7 @@ Each target platform will set the minimum API versions it supports for each key. Currently the standard library is pre-compiled meaning that only a single version of each API can be supported, which must be the minimum version. Third party crates can choose to use a higher API level so long as it's compatible with the baseline API version. -However, there is currently no support for setting a `os_version_min` version above the target's baseline (see [Future Possibilities][future-possibilities]). +However, there is currently no support for setting a `target_version` version above the target's baseline (see [Future Possibilities][future-possibilities]). ## Versioning Schema [versioning-schema]: #versioning-schema @@ -134,8 +134,8 @@ Because of this diversity in version strings, each target will be responsible fo ## Linting [linting]: #linting -By default `os_version_min` will be linted by `check_cfg` in a similar way to `target_os`. -That is, all valid values for `target_os` will be accepted as valid keys for `os_version_min` on all platforms. +By default `target_version` will be linted by `check_cfg` in a similar way to `target_os`. +That is, all valid values for `target_os` will be accepted as valid keys for `target_version` on all platforms. The list of additional keys supported by the target will be consulted, which will then be allowed on a per-target basis. ## Future Compatibility @@ -154,7 +154,7 @@ Each supported platform will need to implement version string parsing logic (or The overall mechanism proposed here builds on other well established primitives in Rust such as `cfg`. A mechanism which tries to bridge cross-platform differences under one `min_target_api_version` predicate [was suggested](https://github.com/rust-lang/rfcs/blob/b0f94000a3ddbd159013e100e48cd887ba2a0b54/text/0000-min-target-api-version.md) but was rejected due to different platforms having divergent needs. -For many platforms, the `target_os` name and the `os_version_min` name will be identical. +For many platforms, the `target_os` name and the `target_version` name will be identical. Even platforms that have multiple possible `versions` relevant to the OS will still have one primary version. E.g. for `linux` the primary version would refer to the kernel with `libc` being a secondary OS library version. Therefore it would make sense for the primary target OS version to be a property of `target_os`. @@ -174,7 +174,7 @@ For example, on Windows `WINVER` can be used: #endif ``` -This RFC is a continuation of [RFC #3379](https://github.com/rust-lang/rfcs/pull/3379) more narrowly scoped to just `os_version_min`. +This RFC is a continuation of [RFC #3379](https://github.com/rust-lang/rfcs/pull/3379) more narrowly scoped to just `os_version_min` (renamed to `target_version` in this RFC). That RFC was in turn an updated version of [this RFC draft](https://github.com/rust-lang/rfcs/pull/3036), with the changes reflecting conversations from the draft review process and [further Zulip discussion](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/CFG.20OS.20Redux.20.28migrated.29/near/294738760). # Unresolved questions @@ -183,8 +183,9 @@ That RFC was in turn an updated version of [this RFC draft](https://github.com/r Custom targets usually specify their configurations in JSON files. It is unclear how the target maintainers would add version comparison information to these files. -What exactly should the syntax be? -Should we draw a distinction between cases where the `os_version_min` directly implies a specific `target_os` and cases where it doesn't (see alternatives)? +Bikeshedding the name. `platform_version` and `os_version` are among other suggestions. + +Should we draw a distinction between cases where the `target_version` directly implies a specific `target_os` and cases where it doesn't (see alternatives)? # Future possibilities [future-possibilities]: #future-possibilities From 482144c3b4713b0f167da2d2159d0410e0db4994 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 20 May 2025 09:31:44 +0000 Subject: [PATCH 28/28] Rename file --- text/{3750-cfg-os-version-min.md => 3750-cfg-target_version.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename text/{3750-cfg-os-version-min.md => 3750-cfg-target_version.md} (100%) diff --git a/text/3750-cfg-os-version-min.md b/text/3750-cfg-target_version.md similarity index 100% rename from text/3750-cfg-os-version-min.md rename to text/3750-cfg-target_version.md