1use crate::core::compiler::unit_dependencies::IsArtifact;
4use crate::core::compiler::UnitInterner;
5use crate::core::compiler::{CompileKind, CompileMode, RustcTargetData, Unit};
6use crate::core::profiles::{Profiles, UnitFor};
7use crate::core::resolver::features::{CliFeatures, FeaturesFor, ResolvedFeatures};
8use crate::core::resolver::HasDevUnits;
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 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 Ok((
110 resolve.pkg_set,
111 resolve.targeted_resolve,
112 resolve.resolved_features,
113 ))
114}
115
116pub fn generate_std_roots(
121 crates: &[String],
122 units: &[Unit],
123 std_resolve: &Resolve,
124 std_features: &ResolvedFeatures,
125 kinds: &[CompileKind],
126 package_set: &PackageSet<'_>,
127 interner: &UnitInterner,
128 profiles: &Profiles,
129 target_data: &RustcTargetData<'_>,
130) -> CargoResult<HashMap<CompileKind, Vec<Unit>>> {
131 let mut ret = HashMap::new();
133 let (maybe_std, maybe_core): (Vec<&CompileKind>, Vec<_>) = kinds
134 .iter()
135 .partition(|kind| target_data.info(**kind).maybe_support_std());
136 for (default_crate, kinds) in [("core", maybe_core), ("std", maybe_std)] {
137 if kinds.is_empty() {
138 continue;
139 }
140 generate_roots(
141 &mut ret,
142 default_crate,
143 crates,
144 units,
145 std_resolve,
146 std_features,
147 &kinds,
148 package_set,
149 interner,
150 profiles,
151 target_data,
152 )?;
153 }
154
155 Ok(ret)
156}
157
158fn generate_roots(
159 ret: &mut HashMap<CompileKind, Vec<Unit>>,
160 default: &'static str,
161 crates: &[String],
162 units: &[Unit],
163 std_resolve: &Resolve,
164 std_features: &ResolvedFeatures,
165 kinds: &[&CompileKind],
166 package_set: &PackageSet<'_>,
167 interner: &UnitInterner,
168 profiles: &Profiles,
169 target_data: &RustcTargetData<'_>,
170) -> CargoResult<()> {
171 let std_ids = std_crates(crates, default, units)
172 .iter()
173 .map(|crate_name| std_resolve.query(crate_name))
174 .collect::<CargoResult<Vec<PackageId>>>()?;
175 let std_pkgs = package_set.get_many(std_ids)?;
176
177 for pkg in std_pkgs {
178 let lib = pkg
179 .targets()
180 .iter()
181 .find(|t| t.is_lib())
182 .expect("std has a lib");
183 let mode = CompileMode::Build;
187 let features = std_features.activated_features(pkg.package_id(), FeaturesFor::NormalOrDev);
188 for kind in kinds {
189 let kind = **kind;
190 let list = ret.entry(kind).or_insert_with(Vec::new);
191 let unit_for = UnitFor::new_normal(kind);
192 let profile = profiles.get_profile(
193 pkg.package_id(),
194 false,
195 false,
196 unit_for,
197 kind,
198 );
199 list.push(interner.intern(
200 pkg,
201 lib,
202 profile,
203 kind,
204 mode,
205 features.clone(),
206 target_data.info(kind).rustflags.clone(),
207 target_data.info(kind).rustdocflags.clone(),
208 target_data.target_config(kind).links_overrides.clone(),
209 true,
210 0,
211 IsArtifact::No,
212 None,
213 ));
214 }
215 }
216 Ok(())
217}
218
219fn detect_sysroot_src_path(target_data: &RustcTargetData<'_>) -> CargoResult<PathBuf> {
220 if let Some(s) = target_data.gctx.get_env_os("__CARGO_TESTS_ONLY_SRC_ROOT") {
221 return Ok(s.into());
222 }
223
224 let src_path = target_data
226 .info(CompileKind::Host)
227 .sysroot
228 .join("lib")
229 .join("rustlib")
230 .join("src")
231 .join("rust")
232 .join("library");
233 let lock = src_path.join("Cargo.lock");
234 if !lock.exists() {
235 let msg = format!(
236 "{:?} does not exist, unable to build with the standard \
237 library, try:\n rustup component add rust-src",
238 lock
239 );
240 match target_data.gctx.get_env("RUSTUP_TOOLCHAIN") {
241 Ok(rustup_toolchain) => {
242 anyhow::bail!("{} --toolchain {}", msg, rustup_toolchain);
243 }
244 Err(_) => {
245 anyhow::bail!(msg);
246 }
247 }
248 }
249 Ok(src_path)
250}