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 let src_path = detect_sysroot_src_path(target_data)?;
57 let std_ws_manifest_path = src_path.join("Cargo.toml");
58 let gctx = ws.gctx();
59 let mut std_ws = Workspace::new(&std_ws_manifest_path, gctx)?;
62 std_ws.set_require_optional_deps(false);
66 let specs = {
67 let maybe_std = kinds
72 .iter()
73 .any(|kind| target_data.info(*kind).maybe_support_std());
74 let mut crates = std_crates(crates, if maybe_std { "std" } else { "core" }, &[]);
75 crates.insert("sysroot");
78 let specs = Packages::Packages(crates.into_iter().map(Into::into).collect());
79 specs.to_package_id_specs(&std_ws)?
80 };
81 let features = match &gctx.cli_unstable().build_std_features {
82 Some(list) => list.clone(),
83 None => vec![
84 "panic-unwind".to_string(),
85 "backtrace".to_string(),
86 "default".to_string(),
87 ],
88 };
89 let cli_features = CliFeatures::from_command_line(
90 &features, false, false,
91 )?;
92 let dry_run = false;
93 let mut resolve = ops::resolve_ws_with_opts(
94 &std_ws,
95 target_data,
96 &build_config.requested_kinds,
97 &cli_features,
98 &specs,
99 HasDevUnits::No,
100 crate::core::resolver::features::ForceAllTargets::No,
101 dry_run,
102 )?;
103 debug_assert_eq!(resolve.specs_and_features.len(), 1);
104 Ok((
105 resolve.pkg_set,
106 resolve.targeted_resolve,
107 resolve
108 .specs_and_features
109 .pop()
110 .expect("resolve should have a single spec with resolved features")
111 .resolved_features,
112 ))
113}
114
115pub fn generate_std_roots(
120 crates: &[String],
121 units: &[Unit],
122 std_resolve: &Resolve,
123 std_features: &ResolvedFeatures,
124 kinds: &[CompileKind],
125 package_set: &PackageSet<'_>,
126 interner: &UnitInterner,
127 profiles: &Profiles,
128 target_data: &RustcTargetData<'_>,
129) -> CargoResult<HashMap<CompileKind, Vec<Unit>>> {
130 let mut ret = HashMap::new();
132 let (maybe_std, maybe_core): (Vec<&CompileKind>, Vec<_>) = kinds
133 .iter()
134 .partition(|kind| target_data.info(**kind).maybe_support_std());
135 for (default_crate, kinds) in [("core", maybe_core), ("std", maybe_std)] {
136 if kinds.is_empty() {
137 continue;
138 }
139 generate_roots(
140 &mut ret,
141 default_crate,
142 crates,
143 units,
144 std_resolve,
145 std_features,
146 &kinds,
147 package_set,
148 interner,
149 profiles,
150 target_data,
151 )?;
152 }
153
154 Ok(ret)
155}
156
157fn generate_roots(
158 ret: &mut HashMap<CompileKind, Vec<Unit>>,
159 default: &'static str,
160 crates: &[String],
161 units: &[Unit],
162 std_resolve: &Resolve,
163 std_features: &ResolvedFeatures,
164 kinds: &[&CompileKind],
165 package_set: &PackageSet<'_>,
166 interner: &UnitInterner,
167 profiles: &Profiles,
168 target_data: &RustcTargetData<'_>,
169) -> CargoResult<()> {
170 let std_ids = std_crates(crates, default, units)
171 .iter()
172 .map(|crate_name| std_resolve.query(crate_name))
173 .collect::<CargoResult<Vec<PackageId>>>()?;
174 let std_pkgs = package_set.get_many(std_ids)?;
175
176 for pkg in std_pkgs {
177 let lib = pkg
178 .targets()
179 .iter()
180 .find(|t| t.is_lib())
181 .expect("std has a lib");
182 let mode = CompileMode::Build;
186 let features = std_features.activated_features(pkg.package_id(), FeaturesFor::NormalOrDev);
187 for kind in kinds {
188 let kind = **kind;
189 let list = ret.entry(kind).or_insert_with(Vec::new);
190 let unit_for = UnitFor::new_normal(kind);
191 let profile = profiles.get_profile(
192 pkg.package_id(),
193 false,
194 false,
195 unit_for,
196 kind,
197 );
198 list.push(interner.intern(
199 pkg,
200 lib,
201 profile,
202 kind,
203 mode,
204 features.clone(),
205 target_data.info(kind).rustflags.clone(),
206 target_data.info(kind).rustdocflags.clone(),
207 target_data.target_config(kind).links_overrides.clone(),
208 true,
209 0,
210 IsArtifact::No,
211 None,
212 false,
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}