1use crate::core::compiler::UnitInterner;
4use crate::core::compiler::unit_dependencies::IsArtifact;
5use crate::core::compiler::{CompileKind, CompileMode, RustcTargetData, Unit};
6use crate::core::profiles::{Profiles, UnitFor};
7use crate::core::resolver::HasDevUnits;
8use crate::core::resolver::features::{CliFeatures, FeaturesFor, ResolvedFeatures};
9use crate::core::{PackageId, PackageSet, Resolve, Workspace};
10use crate::ops::{self, Packages};
11use crate::util::errors::CargoResult;
12
13use std::collections::{HashMap, HashSet};
14use std::path::PathBuf;
15
16use super::BuildConfig;
17
18fn std_crates<'a>(crates: &'a [String], default: &'static str, units: &[Unit]) -> HashSet<&'a str> {
19 let mut crates = HashSet::from_iter(crates.iter().map(|s| s.as_str()));
20 if crates.is_empty() {
23 crates.insert(default);
24 }
25 if crates.contains("std") {
26 crates.insert("core");
27 crates.insert("alloc");
28 crates.insert("proc_macro");
29 crates.insert("panic_unwind");
30 crates.insert("compiler_builtins");
31 if units
34 .iter()
35 .any(|unit| unit.mode.is_rustc_test() && unit.target.harness())
36 {
37 crates.insert("test");
38 }
39 } else if crates.contains("core") {
40 crates.insert("compiler_builtins");
41 }
42
43 crates
44}
45
46pub fn resolve_std<'gctx>(
50 ws: &Workspace<'gctx>,
51 target_data: &mut RustcTargetData<'gctx>,
52 build_config: &BuildConfig,
53 crates: &[String],
54 kinds: &[CompileKind],
55) -> CargoResult<(PackageSet<'gctx>, Resolve, ResolvedFeatures)> {
56 if build_config.build_plan {
57 ws.gctx()
58 .shell()
59 .warn("-Zbuild-std does not currently fully support --build-plan")?;
60 }
61
62 let src_path = detect_sysroot_src_path(target_data)?;
63 let std_ws_manifest_path = src_path.join("Cargo.toml");
64 let gctx = ws.gctx();
65 let mut std_ws = Workspace::new(&std_ws_manifest_path, gctx)?;
68 std_ws.set_require_optional_deps(false);
72 let specs = {
73 let maybe_std = kinds
78 .iter()
79 .any(|kind| target_data.info(*kind).maybe_support_std());
80 let mut crates = std_crates(crates, if maybe_std { "std" } else { "core" }, &[]);
81 crates.insert("sysroot");
84 let specs = Packages::Packages(crates.into_iter().map(Into::into).collect());
85 specs.to_package_id_specs(&std_ws)?
86 };
87 let features = match &gctx.cli_unstable().build_std_features {
88 Some(list) => list.clone(),
89 None => vec![
90 "panic-unwind".to_string(),
91 "backtrace".to_string(),
92 "default".to_string(),
93 ],
94 };
95 let cli_features = CliFeatures::from_command_line(
96 &features, false, false,
97 )?;
98 let dry_run = false;
99 let mut resolve = ops::resolve_ws_with_opts(
100 &std_ws,
101 target_data,
102 &build_config.requested_kinds,
103 &cli_features,
104 &specs,
105 HasDevUnits::No,
106 crate::core::resolver::features::ForceAllTargets::No,
107 dry_run,
108 )?;
109 debug_assert_eq!(resolve.specs_and_features.len(), 1);
110 Ok((
111 resolve.pkg_set,
112 resolve.targeted_resolve,
113 resolve
114 .specs_and_features
115 .pop()
116 .expect("resolve should have a single spec with resolved features")
117 .resolved_features,
118 ))
119}
120
121pub fn generate_std_roots(
126 crates: &[String],
127 units: &[Unit],
128 std_resolve: &Resolve,
129 std_features: &ResolvedFeatures,
130 kinds: &[CompileKind],
131 package_set: &PackageSet<'_>,
132 interner: &UnitInterner,
133 profiles: &Profiles,
134 target_data: &RustcTargetData<'_>,
135) -> CargoResult<HashMap<CompileKind, Vec<Unit>>> {
136 let mut ret = HashMap::new();
138 let (maybe_std, maybe_core): (Vec<&CompileKind>, Vec<_>) = kinds
139 .iter()
140 .partition(|kind| target_data.info(**kind).maybe_support_std());
141 for (default_crate, kinds) in [("core", maybe_core), ("std", maybe_std)] {
142 if kinds.is_empty() {
143 continue;
144 }
145 generate_roots(
146 &mut ret,
147 default_crate,
148 crates,
149 units,
150 std_resolve,
151 std_features,
152 &kinds,
153 package_set,
154 interner,
155 profiles,
156 target_data,
157 )?;
158 }
159
160 Ok(ret)
161}
162
163fn generate_roots(
164 ret: &mut HashMap<CompileKind, Vec<Unit>>,
165 default: &'static str,
166 crates: &[String],
167 units: &[Unit],
168 std_resolve: &Resolve,
169 std_features: &ResolvedFeatures,
170 kinds: &[&CompileKind],
171 package_set: &PackageSet<'_>,
172 interner: &UnitInterner,
173 profiles: &Profiles,
174 target_data: &RustcTargetData<'_>,
175) -> CargoResult<()> {
176 let std_ids = std_crates(crates, default, units)
177 .iter()
178 .map(|crate_name| std_resolve.query(crate_name))
179 .collect::<CargoResult<Vec<PackageId>>>()?;
180 let std_pkgs = package_set.get_many(std_ids)?;
181
182 for pkg in std_pkgs {
183 let lib = pkg
184 .targets()
185 .iter()
186 .find(|t| t.is_lib())
187 .expect("std has a lib");
188 let mode = CompileMode::Build;
192 let features = std_features.activated_features(pkg.package_id(), FeaturesFor::NormalOrDev);
193 for kind in kinds {
194 let kind = **kind;
195 let list = ret.entry(kind).or_insert_with(Vec::new);
196 let unit_for = UnitFor::new_normal(kind);
197 let profile = profiles.get_profile(
198 pkg.package_id(),
199 false,
200 false,
201 unit_for,
202 kind,
203 );
204 list.push(interner.intern(
205 pkg,
206 lib,
207 profile,
208 kind,
209 mode,
210 features.clone(),
211 target_data.info(kind).rustflags.clone(),
212 target_data.info(kind).rustdocflags.clone(),
213 target_data.target_config(kind).links_overrides.clone(),
214 true,
215 0,
216 IsArtifact::No,
217 None,
218 false,
219 ));
220 }
221 }
222 Ok(())
223}
224
225fn detect_sysroot_src_path(target_data: &RustcTargetData<'_>) -> CargoResult<PathBuf> {
226 if let Some(s) = target_data.gctx.get_env_os("__CARGO_TESTS_ONLY_SRC_ROOT") {
227 return Ok(s.into());
228 }
229
230 let src_path = target_data
232 .info(CompileKind::Host)
233 .sysroot
234 .join("lib")
235 .join("rustlib")
236 .join("src")
237 .join("rust")
238 .join("library");
239 let lock = src_path.join("Cargo.lock");
240 if !lock.exists() {
241 let msg = format!(
242 "{:?} does not exist, unable to build with the standard \
243 library, try:\n rustup component add rust-src",
244 lock
245 );
246 match target_data.gctx.get_env("RUSTUP_TOOLCHAIN") {
247 Ok(rustup_toolchain) => {
248 anyhow::bail!("{} --toolchain {}", msg, rustup_toolchain);
249 }
250 Err(_) => {
251 anyhow::bail!(msg);
252 }
253 }
254 }
255 Ok(src_path)
256}