Pre-RFC: `min_target_api_version`

Linked here is a draft RFC for a new cfg predicate min_target_api_version which allows for conditional compilation depending on a minimum API set version. For example, on Windows if you only want certain code to run on Windows 10 you could write #[cfg(min_target_api_version = "10.0.10240")]. You can find more motivation and examples in the linked draft RFC. There are explicit open questions listed in the RFC, but any and all feedback is welcome.

There is also a Zulip thread for this RFC which you can find here. Feedback is also welcome there.

4 Likes

It would be useful for macOS too.

C compilers for macOS support env var MACOSX_DEPLOYMENT_TARGET (AKA -mmacosx-version-min) that is in the form of "10.x" or "10.x.y". It affects availability of system APIs, opts-in to new API behaviors, and makes the linker use new executable formats not compatible with older systems.

Currently core-foundation-sys uses Cargo features to select deployment target, which can be out of sync with the actual target, and it's a bit clumsy compared to Apple's convention:

4 Likes

It would be good if we could nail down how to do platform versioning. Should it be in the form x.y.z? Or should it be more like a list of versions? Or could it be a mix of both (i.e. x.y.z is the canonical form but there are text aliases)? If a list, where should platform versioning live? In rustc itself? What about json targets?


On the Windows side, this is what using the Windows Headers to do conditional compilation looks like in C++.

// The application sets a preprocessor macro with 
// the version, using a predefined constant or a literal value.
#define WINVER _WIN32_WINNT_WIN8 

// Then a library can conditionally compile based on that,
// again using either a constant or a literal value.
#if (WINVER >= 0x0601)
    // `_WIN32_WINNT_WIN8` is defined as 0x0602
	// so this section will be compiled.
#endif

For reference, the runtime equivalent to that code is simply:

if (IsWindows7OrGreater()) {
	// If, at runtime, Windows 7 or greater is detected
	// then this will run.
}

The versioning scheme is first predicated on whether we truely want this to be cross platform. I'm thoroughly on the side of making this feature work in conjunction with target platform, but there are some that would rather this be min_windows_api_version and only available on Windows related targets. If this is just a feature for Windows, then I'm confident that the x.y.z form which is used by Windows itself along with textual aliases, would be the right choice.

However, with cross platform support this is complicated, especially when considering custom targets. We could require built in compiler support to establish canonical ordering at the expense supporting custom targets.

So the questions as I see them are:

  • Do we support targets other than Windows related targets? If not, then I propose the x.y.z canonical form.
  • If yes, do we support custom targets? If yes, then I'm not sure how exactly to handle this.
  • If no:
    • Does the compiler hard code the odering?
    • What happens when the compiler does not recognize a form? Presumably the compiler should not rely on direct matching but rather a per target type schema (e.g., in the case of windows x.y.z but in other target type's maybe another schema).

I would like for this feature to be designed to eventually be available on non-Windows targets as well. For example on Linux it would become possible to use the newer io_uring APIs without needing to ship a fallback implementation.

This seems like a general-purpose mechanism to narrow down the compilation target, much like -C target-cpu allows us to target specific processors, and #[cfg(version = "")] will allow us to target specific Rust versions.

2 Likes