Skip to content

Implementation of target_api_features #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,11 @@
# probably don't want to use this.
#qemu-rootfs = "..."

# Comma separated list of target api features for the target. Currently, *all*
# features have to be passed if this is specified. Inherited features are not
# supported here yet.
#target-api-feature = "...,..."

# =============================================================================
# Distribution options
#
Expand Down
41 changes: 41 additions & 0 deletions src/bootstrap/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,43 @@ fn copy_self_contained_objects(
target_deps
}

fn add_target_api_features_cargo(
builder: &Builder<'_>,
target: TargetSelection,
cargo: &mut Cargo,
) {
if let Some(api_features) = builder.target_api_feature(target) {
for api_feature in api_features {
cargo.rustflag("--cfg");
cargo.rustflag(&format!("target_api_feature=\"{}\"", api_feature));
}
} else {
if target.contains("windows") {
// all `target_api_feature`s for the currently officially supported
// windows version for rust
const WINDOWS_VERSIONS: [&str; 12] = [
"3.10.511", // NT 3.1
"3.10.528", // NT 3.1 SP3
"3.50.807", // NT 3.5
"3.51.1057", // NT 3.51
"4.0.1381", // NT 4
"5.0.2195", // 2000
"5.1.2600", // XP
"5.2.3790", // XP 64bit, Server 2003
"6.0.6000", // Vista, Server 2008
"6.0.6001", // Vista SP1, Server 2008 SP1
"6.0.6002", // Vista SP2, Server 2008 SP2
"6.1.7600", // 7, Server 2008 R2
];

for v in &WINDOWS_VERSIONS {
cargo.rustflag("--cfg");
cargo.rustflag(&format!("target_api_feature=\"{}\"", v));
}
}
}
}

/// Configure cargo to compile the standard library, adding appropriate env vars
/// and such.
pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, cargo: &mut Cargo) {
Expand Down Expand Up @@ -296,6 +333,8 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
if target.contains("riscv") {
cargo.rustflag("-Cforce-unwind-tables=yes");
}

add_target_api_features_cargo(builder, target, cargo);
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -603,6 +642,8 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS
cargo.env("LLVM_NDEBUG", "1");
}
}

add_target_api_features_cargo(builder, target, cargo);
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
Expand Down
6 changes: 6 additions & 0 deletions src/bootstrap/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ pub struct Target {
pub wasi_root: Option<PathBuf>,
pub qemu_rootfs: Option<PathBuf>,
pub no_std: bool,
pub target_api_feature: Option<Vec<String>>,
}

impl Target {
Expand Down Expand Up @@ -432,6 +433,7 @@ struct TomlTarget {
wasi_root: Option<String>,
qemu_rootfs: Option<String>,
no_std: Option<bool>,
target_api_feature: Option<String>,
}

impl Config {
Expand Down Expand Up @@ -703,6 +705,10 @@ impl Config {
target.musl_libdir = cfg.musl_libdir.clone().map(PathBuf::from);
target.wasi_root = cfg.wasi_root.clone().map(PathBuf::from);
target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from);
target.target_api_feature = cfg
.target_api_feature
.as_ref()
.map(|s| s.split(',').map(String::from).collect());

config.target_config.insert(TargetSelection::from_user(triple), target);
}
Expand Down
5 changes: 5 additions & 0 deletions src/bootstrap/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,11 @@ impl Build {
self.config.target_config.get(&target).and_then(|t| t.qemu_rootfs.as_ref()).map(|p| &**p)
}

/// Returns the target api feature list if they are present
fn target_api_feature(&self, target: TargetSelection) -> Option<&Vec<String>> {
self.config.target_config.get(&target).and_then(|t| t.target_api_feature.as_ref())
}

/// Path to the python interpreter to use
fn python(&self) -> &Path {
self.config.python.as_ref().unwrap()
Expand Down
30 changes: 30 additions & 0 deletions src/doc/rustc/src/codegen-options/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,36 @@ point instructions in software. It takes one of the following values:
* `y`, `yes`, `on`, or no value: use soft floats.
* `n`, `no`, or `off`: use hardware floats (the default).

## target-api-feature

This option tells `rustc` which operating system APIs are expected to be supported for the target.
Implied features are added as well.

API features are added as a comma-separated list (`-C target_api_feature=a,b`). The option can be
specified more than once to add more features the the list.

#### Windows

Currently, this option is only used for Windows targets, where the feature
names are the `<major>.<minor>.<build>` versions of all major releases (e.g. `10.0.10240`).
Any version selected adds all previous versions as well, allowing for "greater than"
comparisons:

```rs
if cfg!(target_api_feature = "10.0.10240") {
println!("new win10 api here");
} else if cfg!(target_api_feature = "6.1.7600") {
println!("regular win7 api here");
} else if cfg!(target_api_feature = "5.1.2600") {
println!("legacy winxp api here");
} else {
println!("not supported");
}
```

Currently, the default for regular Windows targets is Windows 7 (`6.1.7600`).
For UWP targets, it is Windows 10, Version 1509 (`10.0.10240`).

## target-cpu

This instructs `rustc` to generate code specifically for a particular processor.
Expand Down
1 change: 1 addition & 0 deletions src/librustc_interface/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ rustc_privacy = { path = "../librustc_privacy" }
rustc_resolve = { path = "../librustc_resolve" }
rustc_trait_selection = { path = "../librustc_trait_selection" }
rustc_ty = { path = "../librustc_ty" }
rustc_target = { path = "../librustc_target" }
tempfile = "3.0.5"
once_cell = "1"

Expand Down
1 change: 1 addition & 0 deletions src/librustc_interface/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ fn test_codegen_options_tracking_hash() {
tracked!(profile_use, Some(PathBuf::from("abc")));
tracked!(relocation_model, Some(RelocModel::Pic));
tracked!(soft_float, true);
tracked!(target_api_features, Some(vec![String::from("1"), String::from("2")]));
tracked!(target_cpu, Some(String::from("abc")));
tracked!(target_feature, String::from("all the features, all of them"));
}
Expand Down
22 changes: 22 additions & 0 deletions src/librustc_interface/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,28 @@ pub fn add_configuration(
if sess.crt_static(None) {
cfg.insert((tf, Some(sym::crt_dash_static)));
}

let ta = sym::target_api_feature;
let target_options = &sess.target.target.options;
let mut selected_target_apis = sess.opts.cg.target_api_feature.as_ref();

if let Some(target_api_kind) = &target_options.target_api_kind {
let target_api_defaults = &target_options.target_api_default_features;

let api_features_to_check = selected_target_apis.unwrap_or(target_api_defaults);
selected_target_apis = Some(api_features_to_check);

let apis = rustc_target::api::get_enabled_target_api_features(
target_api_kind,
api_features_to_check,
);

cfg.extend(apis.into_iter().map(|api| (ta, Some(Symbol::intern(api)))));
}

if let Some(selected_target_apis) = selected_target_apis {
cfg.extend(selected_target_apis.into_iter().map(|api| (ta, Some(Symbol::intern(api)))));
}
}

pub fn create_session(
Expand Down
15 changes: 15 additions & 0 deletions src/librustc_session/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ macro_rules! options {
pub const parse_tls_model: &str =
"one of supported TLS models (`rustc --print tls-models`)";
pub const parse_target_feature: &str = parse_string;
pub const parse_target_api_feature: &str = parse_opt_comma_list;
}

#[allow(dead_code)]
Expand Down Expand Up @@ -673,6 +674,17 @@ macro_rules! options {
None => false,
}
}

fn parse_target_api_feature(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool {
match (slot, v) {
(Some(vec), Some(s)) => { vec.extend(s.split(',').map(|s| s.to_string())); true },
(slot @ None, Some(s)) => {
*slot = Some(s.split(',').map(|s| s.to_string()).collect());
true
},
_ => false,
}
}
}
) }

Expand Down Expand Up @@ -768,6 +780,9 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
"save all temporary output files during compilation (default: no)"),
soft_float: bool = (false, parse_bool, [TRACKED],
"use soft float ABI (*eabihf targets only) (default: no)"),
target_api_feature: Option<Vec<String>> = (None, parse_target_api_feature, [TRACKED],
"a comma-separated list of target APIs that are expected to be be available on the target
(default: use target default) (can be used multiple times)"),
target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
"select target processor (`rustc --print target-cpus` for details)"),
target_feature: String = (String::new(), parse_target_feature, [TRACKED],
Expand Down
1 change: 1 addition & 0 deletions src/librustc_span/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,7 @@ symbols! {
sym,
sync,
sync_trait,
target_api_feature,
target_arch,
target_endian,
target_env,
Expand Down
11 changes: 11 additions & 0 deletions src/librustc_target/api/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
pub mod windows;

pub fn get_enabled_target_api_features(
target_kind: &str,
requested_apis: &[String],
) -> Vec<&'static str> {
match target_kind {
"windows" => windows::get_enabled_target_api_features(requested_apis),
_ => vec![],
}
}
40 changes: 40 additions & 0 deletions src/librustc_target/api/windows.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const WINDOWS_VERSIONS: [&str; 26] = [
"3.10.511", // NT 3.1
"3.10.528", // NT 3.1 SP3
"3.50.807", // NT 3.5
"3.51.1057", // NT 3.51
"4.0.1381", // NT 4
"5.0.2195", // 2000
"5.1.2600", // XP
"5.2.3790", // XP 64bit, Server 2003
"6.0.6000", // Vista, Server 2008
"6.0.6001", // Vista SP1, Server 2008 SP1
"6.0.6002", // Vista SP2, Server 2008 SP2
"6.1.7600", // 7, Server 2008 R2
"6.1.7601", // 7 SP1, Server 2008 R2 SP1
"6.1.8400", // Home Server 2011
"6.2.9200", // 8, Server 2012
"6.3.9600", // 8.1, Server 2012 R2
"10.0.10240", // 10 1507
"10.0.10586", // 10 1511
"10.0.14393", // 10 1607, Server 2016 1607
"10.0.15063", // 10 1703
"10.0.16299", // 10 1709, Server 2016 1709
"10.0.17134", // 10 1803
"10.0.17763", // 10 1809, Server 2019 1809
"10.0.18362", // 10 1903
"10.0.18363", // 10 1909
"10.0.19041", // 10 2004
];

pub fn get_enabled_target_api_features(requested_apis: &[String]) -> Vec<&'static str> {
let highest_index = requested_apis.iter().fold(None, |old_highest_index, api| {
if let Some((index, _)) = WINDOWS_VERSIONS.iter().enumerate().find(|&(_, ver)| ver == api) {
old_highest_index.map(|old_index| std::cmp::max(old_index, index)).or(Some(index))
} else {
old_highest_index
}
});

highest_index.map(|i| WINDOWS_VERSIONS[..=i].into()).unwrap_or(vec![])
}
1 change: 1 addition & 0 deletions src/librustc_target/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ extern crate rustc_macros;
extern crate tracing;

pub mod abi;
pub mod api;
pub mod asm;
pub mod spec;

Expand Down
19 changes: 19 additions & 0 deletions src/librustc_target/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -993,6 +993,12 @@ pub struct TargetOptions {
/// used to locate unwinding information is passed
/// (only has effect if the linker is `ld`-like).
pub eh_frame_header: bool,

/// Decides which logic will be used for determining the full set of target API features
pub target_api_kind: Option<String>,

/// The default API features for this target.
pub target_api_default_features: Vec<String>,
}

impl Default for TargetOptions {
Expand Down Expand Up @@ -1085,6 +1091,8 @@ impl Default for TargetOptions {
llvm_args: vec![],
use_ctors_section: false,
eh_frame_header: true,
target_api_kind: None,
target_api_default_features: vec![],
}
}
}
Expand Down Expand Up @@ -1478,6 +1486,8 @@ impl Target {
key!(llvm_args, list);
key!(use_ctors_section, bool);
key!(eh_frame_header, bool);
key!(target_api_kind, optional);
key!(target_api_default_features, list);

// NB: The old name is deprecated, but support for it is retained for
// compatibility.
Expand Down Expand Up @@ -1716,6 +1726,8 @@ impl ToJson for Target {
target_option_val!(llvm_args);
target_option_val!(use_ctors_section);
target_option_val!(eh_frame_header);
target_option_val!(target_api_kind);
target_option_val!(target_api_default_features);

if default.unsupported_abis != self.options.unsupported_abis {
d.insert(
Expand Down Expand Up @@ -1791,3 +1803,10 @@ impl fmt::Display for TargetTriple {
write!(f, "{}", self.debug_triple())
}
}

/// A target api function and an optional default, if any
#[derive(PartialEq, Clone, Debug)]
pub struct TargetApiDefinition {
pub api_kind: String,
pub target_api_default_features: Vec<String>,
}
2 changes: 2 additions & 0 deletions src/librustc_target/spec/windows_gnu_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ pub fn opts() -> TargetOptions {
emit_debug_gdb_scripts: false,
requires_uwtable: true,
eh_frame_header: false,
target_api_kind: Some("windows".to_string()),
target_api_default_features: vec!["6.1.7600".to_string()],

..Default::default()
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_target/spec/windows_msvc_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub fn opts() -> TargetOptions {
// linking some libraries which require a specific agreement, so it may
// not ever be possible for us to pass this flag.
no_default_libraries: false,
target_api_kind: Some("windows".to_string()),
target_api_default_features: vec!["6.1.7600".to_string()],

..base
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc_target/spec/windows_uwp_gnu_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub fn opts() -> TargetOptions {
late_link_args,
late_link_args_dynamic,
late_link_args_static,
target_api_default_features: vec!["10.0.10240".to_string()],

..base
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_target/spec/windows_uwp_msvc_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ pub fn opts() -> TargetOptions {
.unwrap()
.extend(pre_link_args_msvc);

opts.target_api_default_features = vec!["10.0.10240".to_string()];

opts
}