Skip to content

Commit 3a65f7c

Browse files
committed
Support target setting for non-build dependencies
This is the commit message #2: ------------------------------ Add doc-test cross compile related test Even though there is no artifact code specific to doc testing, it's worth to try testing it with different target settings to validate it still works despite doc tests having some special caseing around target settings. This is the commit message rust-lang#3: ------------------------------ A test to validate profiles work as expected for build-deps and non-build deps No change is required to make this work and artifact dependencies 'just work' based on the typical rules of their non-artifact counterarts. This is the commit message rust-lang#4: ------------------------------ Adjust `cargo metadata` to deal with artifact dependencies This commit was squashed and there is probably more that changed. This is the commit message rust-lang#5: ------------------------------ Show bin-only artifacts in "resolve" of metadata as well. This is the commit message rust-lang#6: ------------------------------ minor refactoring during research for RFC-3176 This will soon need to return multiple extern-name/dep-name pairs. This is the commit message rust-lang#7: ------------------------------ See if opt-level 3 works on win-msvc in basic profile test for artifacts This is the same value as is used in the other test of the same name, which certainly runs on windows. This is the commit message rust-lang#8: ------------------------------ refactor Assure the type for targets reflect that they cannot be the host target, which removes a few unreachable!() expressions.
1 parent 6dc0705 commit 3a65f7c

File tree

9 files changed

+1235
-78
lines changed

9 files changed

+1235
-78
lines changed

src/cargo/core/compiler/build_context/target_info.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -760,11 +760,12 @@ impl<'cfg> RustcTargetData<'cfg> {
760760
.default_kind()
761761
.into_iter()
762762
.chain(p.manifest().forced_kind())
763-
.into_iter()
764-
.chain(p.manifest().dependencies().iter().filter_map(|d| {
765-
d.artifact()
766-
.and_then(|a| a.target().and_then(|t| t.to_compile_kind()))
767-
}))
763+
.chain(
764+
p.manifest()
765+
.dependencies()
766+
.iter()
767+
.filter_map(|d| d.artifact()?.target()?.to_compile_kind()),
768+
)
768769
}));
769770
for kind in all_kinds {
770771
if let CompileKind::Target(target) = kind {

src/cargo/core/compiler/unit_dependencies.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -290,13 +290,14 @@ fn compute_deps(
290290

291291
let mut ret = Vec::new();
292292
let mut dev_deps = Vec::new();
293-
for (id, deps) in filtered_deps {
294-
let dep_pkg = state.get(id);
293+
for (dep_pkg_id, deps) in filtered_deps {
294+
let dep_pkg = state.get(dep_pkg_id);
295295
// Artifact dependencies are only counted as standard libraries if they are marked
296296
// as 'library as well'. We don't filter in the closure above as we still want to get a chance
297297
// to process them as pure non-lib artifact dependencies.
298-
let (has_artifact, artifact_lib) =
299-
calc_artifact_deps(unit, unit_for, id, deps, state, dep_filter, &mut ret)?;
298+
let (has_artifact, artifact_lib) = calc_artifact_deps(
299+
unit, unit_for, dep_pkg_id, deps, state, dep_filter, &mut ret,
300+
)?;
300301

301302
let lib = package_lib(dep_pkg, has_artifact, artifact_lib);
302303
let lib = match lib {
@@ -459,7 +460,13 @@ fn calc_artifact_deps(
459460
unit,
460461
unit_for,
461462
state,
462-
unit.kind,
463+
artifact
464+
.target()
465+
.and_then(|t| match t {
466+
ArtifactTarget::BuildDependencyAssumeTarget => None,
467+
ArtifactTarget::Force(kind) => Some(CompileKind::Target(kind)),
468+
})
469+
.unwrap_or(unit.kind),
463470
artifact_pkg,
464471
dep,
465472
)?);
@@ -533,7 +540,7 @@ fn compute_deps_custom_build(
533540

534541
fn build_artifact_requirements_to_units(
535542
parent: &Unit,
536-
root_unit_compile_kind: CompileKind,
543+
root_unit_compile_target: CompileKind,
537544
artifact_deps: Vec<(PackageId, &HashSet<Dependency>)>,
538545
state: &State<'_, '_>,
539546
) -> CargoResult<Vec<UnitDep>> {
@@ -553,8 +560,8 @@ fn build_artifact_requirements_to_units(
553560
.expect("artifact dep")
554561
.target()
555562
.map(|kind| match kind {
556-
ArtifactTarget::Force(kind) => kind,
557-
ArtifactTarget::BuildDependencyAssumeTarget => root_unit_compile_kind,
563+
ArtifactTarget::Force(target) => CompileKind::Target(target),
564+
ArtifactTarget::BuildDependencyAssumeTarget => root_unit_compile_target,
558565
})
559566
.unwrap_or(CompileKind::Host),
560567
artifact_pkg,
@@ -576,7 +583,6 @@ fn artifact_targets_to_unit_deps(
576583
let ret = match_artifacts_kind_with_targets(parent, dep, artifact_pkg.targets())?
577584
.into_iter()
578585
.flat_map(|target| {
579-
// TODO(ST): handle target="target", there isn't even a test for that yet
580586
// We split target libraries into individual units, even though rustc is able to produce multiple
581587
// kinds in an single invocation for the sole reason that each artifact kind has its own output directory,
582588
// something we can't easily teach rustc for now.
@@ -904,13 +910,11 @@ fn new_unit_dep_with_profile(
904910
profile: Profile,
905911
artifact: bool,
906912
) -> CargoResult<UnitDep> {
907-
// TODO: consider making extern_crate_name return InternedString?
908913
let (extern_crate_name, dep_name) = state.resolve().extern_crate_name_and_dep_name(
909914
parent.pkg.package_id(),
910915
pkg.package_id(),
911916
target,
912917
)?;
913-
let extern_crate_name = InternedString::new(&extern_crate_name);
914918
let public = state
915919
.resolve()
916920
.is_public_dep(parent.pkg.package_id(), pkg.package_id());

src/cargo/core/dependency.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use log::trace;
33
use semver::VersionReq;
44
use serde::ser;
55
use serde::Serialize;
6+
use std::borrow::Cow;
67
use std::fmt;
78
use std::path::PathBuf;
89
use std::rc::Rc;
@@ -62,6 +63,8 @@ struct SerializedDependency<'a> {
6263
optional: bool,
6364
uses_default_features: bool,
6465
features: &'a [InternedString],
66+
#[serde(skip_serializing_if = "Option::is_none")]
67+
artifact: Option<&'a Artifact>,
6568
target: Option<&'a Platform>,
6669
/// The registry URL this dependency is from.
6770
/// If None, then it comes from the default registry (crates.io).
@@ -90,6 +93,7 @@ impl ser::Serialize for Dependency {
9093
rename: self.explicit_name_in_toml().map(|s| s.as_str()),
9194
registry: registry_id.as_ref().map(|sid| sid.url().as_str()),
9295
path: self.source_id().local_path(),
96+
artifact: self.artifact(),
9397
}
9498
.serialize(s)
9599
}
@@ -438,6 +442,30 @@ pub struct Artifact {
438442
target: Option<ArtifactTarget>,
439443
}
440444

445+
#[derive(Serialize)]
446+
pub struct SerializedArtifact<'a> {
447+
kinds: &'a [ArtifactKind],
448+
lib: bool,
449+
target: Option<&'a str>,
450+
}
451+
452+
impl ser::Serialize for Artifact {
453+
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
454+
where
455+
S: ser::Serializer,
456+
{
457+
SerializedArtifact {
458+
kinds: self.kinds(),
459+
lib: self.is_lib,
460+
target: self.target.as_ref().map(|t| match t {
461+
ArtifactTarget::BuildDependencyAssumeTarget => "target",
462+
ArtifactTarget::Force(target) => target.rustc_target(),
463+
}),
464+
}
465+
.serialize(s)
466+
}
467+
}
468+
441469
impl Artifact {
442470
pub(crate) fn parse(
443471
artifacts: &StringOrVec,
@@ -478,21 +506,21 @@ pub enum ArtifactTarget {
478506
BuildDependencyAssumeTarget,
479507
/// Then name of the platform triple, like `x86_64-apple-darwin`, that this artifact will be always be build for, no matter
480508
/// if it is a build, normal or dev dependency.
481-
Force(CompileKind),
509+
Force(CompileTarget),
482510
}
483511

484512
impl ArtifactTarget {
485513
pub fn parse(target: &str) -> CargoResult<ArtifactTarget> {
486514
Ok(match target {
487515
"target" => ArtifactTarget::BuildDependencyAssumeTarget,
488-
name => ArtifactTarget::Force(CompileKind::Target(CompileTarget::new(name)?)),
516+
name => ArtifactTarget::Force(CompileTarget::new(name)?),
489517
})
490518
}
491519

492520
pub fn to_compile_kind(&self) -> Option<CompileKind> {
493521
match self {
494522
ArtifactTarget::BuildDependencyAssumeTarget => None,
495-
ArtifactTarget::Force(kind) => Some(*kind),
523+
ArtifactTarget::Force(target) => Some(CompileKind::Target(*target)),
496524
}
497525
}
498526
}
@@ -507,6 +535,21 @@ pub enum ArtifactKind {
507535
Staticlib,
508536
}
509537

538+
impl ser::Serialize for ArtifactKind {
539+
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
540+
where
541+
S: ser::Serializer,
542+
{
543+
let out: Cow<'_, str> = match *self {
544+
ArtifactKind::AllBinaries => "bin".into(),
545+
ArtifactKind::Staticlib => "staticlib".into(),
546+
ArtifactKind::Cdylib => "cdylib".into(),
547+
ArtifactKind::SelectedBinary(name) => format!("bin:{}", name.as_str()).into(),
548+
};
549+
out.serialize(s)
550+
}
551+
}
552+
510553
impl fmt::Display for ArtifactKind {
511554
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
512555
f.write_str(match self {

src/cargo/core/resolver/resolve.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -300,31 +300,30 @@ unable to verify that `{0}` is the same as when the lockfile was generated
300300
from: PackageId,
301301
to: PackageId,
302302
to_target: &Target,
303-
) -> CargoResult<(String, Option<InternedString>)> {
303+
) -> CargoResult<(InternedString, Option<InternedString>)> {
304304
let empty_set: HashSet<Dependency> = HashSet::new();
305305
let deps = if from == to {
306306
&empty_set
307307
} else {
308308
self.dependencies_listed(from, to)
309309
};
310310

311-
let crate_name = to_target.crate_name();
312-
let mut names = deps.iter().map(|d| {
311+
let target_crate_name = || (to_target.crate_name(), None);
312+
let mut name_pairs = deps.iter().map(|d| {
313313
d.explicit_name_in_toml()
314-
.map(|s| s.as_str().replace("-", "_"))
315-
.unwrap_or_else(|| crate_name.clone())
314+
.map(|s| (s.as_str().replace("-", "_"), Some(s)))
315+
.unwrap_or_else(target_crate_name)
316316
});
317-
let name = names.next().unwrap_or_else(|| crate_name.clone());
318-
for n in names {
317+
let (extern_crate_name, dep_name) = name_pairs.next().unwrap_or_else(target_crate_name);
318+
for (n, _) in name_pairs {
319319
anyhow::ensure!(
320-
n == name,
320+
n == extern_crate_name,
321321
"the crate `{}` depends on crate `{}` multiple times with different names",
322322
from,
323323
to,
324324
);
325325
}
326-
let dep_name = deps.iter().filter_map(|d| d.explicit_name_in_toml()).next();
327-
Ok((name, dep_name))
326+
Ok((extern_crate_name.into(), dep_name))
328327
}
329328

330329
fn dependencies_listed(&self, from: PackageId, to: PackageId) -> &HashSet<Dependency> {

src/cargo/ops/cargo_output_metadata.rs

Lines changed: 105 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::core::compiler::{CompileKind, RustcTargetData};
2-
use crate::core::dependency::DepKind;
2+
use crate::core::dependency::{ArtifactKind, ArtifactTarget, DepKind};
33
use crate::core::package::SerializedPackage;
44
use crate::core::resolver::{features::CliFeatures, HasDevUnits, Resolve};
55
use crate::core::{Dependency, Package, PackageId, Workspace};
@@ -81,7 +81,7 @@ struct MetadataResolveNode {
8181

8282
#[derive(Serialize)]
8383
struct Dep {
84-
name: String,
84+
name: InternedString,
8585
pkg: PackageId,
8686
dep_kinds: Vec<DepKindInfo>,
8787
}
@@ -90,13 +90,24 @@ struct Dep {
9090
struct DepKindInfo {
9191
kind: DepKind,
9292
target: Option<Platform>,
93+
extern_name: String,
94+
#[serde(skip_serializing_if = "Option::is_none")]
95+
bin_name: Option<InternedString>,
96+
#[serde(skip_serializing_if = "Option::is_none")]
97+
artifact: Option<&'static str>,
98+
#[serde(skip_serializing_if = "Option::is_none")]
99+
compile_target: Option<InternedString>,
93100
}
94101

95102
impl From<&Dependency> for DepKindInfo {
96103
fn from(dep: &Dependency) -> DepKindInfo {
97104
DepKindInfo {
98105
kind: dep.kind(),
99106
target: dep.platform().cloned(),
107+
extern_name: dep.name_in_toml().replace('-', "_").into(),
108+
bin_name: None,
109+
artifact: None,
110+
compile_target: None,
100111
}
101112
}
102113
}
@@ -206,21 +217,35 @@ fn build_resolve_graph_r(
206217
}
207218
})
208219
.filter_map(|(dep_id, deps)| {
209-
let mut dep_kinds: Vec<_> = deps.iter().map(DepKindInfo::from).collect();
210-
dep_kinds.sort();
211-
package_map
212-
.get(&dep_id)
213-
.and_then(|pkg| pkg.targets().iter().find(|t| t.is_lib()))
214-
.and_then(|lib_target| {
215-
resolve
216-
.extern_crate_name_and_dep_name(pkg_id, dep_id, lib_target)
217-
.map(|(ext_crate_name, _)| ext_crate_name)
218-
.ok()
219-
})
220-
.map(|name| Dep {
221-
name,
222-
pkg: normalize_id(dep_id),
223-
dep_kinds,
220+
let dep_pkg = package_map.get(&dep_id);
221+
dep_pkg
222+
.and_then(
223+
|dep_pkg| match dep_pkg.targets().iter().find(|t| t.is_lib()) {
224+
Some(lib_target) => resolve
225+
.extern_crate_name_and_dep_name(pkg_id, dep_id, lib_target)
226+
.map(|(ext_crate_name, _)| ext_crate_name)
227+
.ok(),
228+
None => {
229+
// No traditional library is present which excludes bin-only artifacts.
230+
// If one is present, we emulate the naming that would happen in `extern_crate_name_…()`.
231+
deps.iter().find_map(|d| {
232+
d.artifact()
233+
.map(|_| d.name_in_toml().replace('-', "_").into())
234+
})
235+
}
236+
},
237+
)
238+
.map(|name| {
239+
let mut dep_kinds: Vec<_> = deps
240+
.iter()
241+
.flat_map(|dep| single_dep_kind_or_spread_artifact_kinds(dep_pkg, dep))
242+
.collect();
243+
dep_kinds.sort();
244+
Dep {
245+
name,
246+
pkg: normalize_id(dep_id),
247+
dep_kinds,
248+
}
224249
})
225250
})
226251
.collect();
@@ -244,3 +269,66 @@ fn build_resolve_graph_r(
244269
);
245270
}
246271
}
272+
273+
fn single_dep_kind_or_spread_artifact_kinds(
274+
dep_pkg: Option<&Package>,
275+
dep: &Dependency,
276+
) -> Vec<DepKindInfo> {
277+
fn fix_extern_name(dki: &mut DepKindInfo, bin_name: &str) {
278+
dki.extern_name = bin_name.replace('-', "_").into();
279+
}
280+
dep.artifact()
281+
.map(|artifact| {
282+
let mut has_all_binaries = false;
283+
let compile_target = artifact.target().map(|target| match target {
284+
ArtifactTarget::BuildDependencyAssumeTarget => "target".into(),
285+
ArtifactTarget::Force(target) => target.rustc_target().into(),
286+
});
287+
let mut dep_kinds: Vec<_> = artifact
288+
.kinds()
289+
.iter()
290+
.filter_map(|kind| {
291+
let mut dki = DepKindInfo::from(dep);
292+
dki.artifact = Some(
293+
match kind {
294+
ArtifactKind::Staticlib => "staticlib",
295+
ArtifactKind::Cdylib => "cdylib",
296+
ArtifactKind::AllBinaries => {
297+
// handled in second pass
298+
has_all_binaries = true;
299+
return None;
300+
}
301+
ArtifactKind::SelectedBinary(name) => {
302+
dki.bin_name = Some(*name);
303+
fix_extern_name(&mut dki, name);
304+
"bin"
305+
}
306+
}
307+
.into(),
308+
);
309+
dki.compile_target = compile_target;
310+
Some(dki)
311+
})
312+
.collect();
313+
if let Some(dep_pkg) = has_all_binaries.then(|| dep_pkg).flatten() {
314+
// Note that we silently ignore the binaries missed here if dep_pkg is None, which apparently can happen.
315+
// If some warnings should one day be printed for less surprising behaviour, also consider adding a warning to the
316+
// ignored error further above (see `….ok()`).
317+
dep_kinds.extend(dep_pkg.targets().iter().filter(|t| t.is_bin()).map(
318+
|bin_target| {
319+
let mut dki = DepKindInfo::from(dep);
320+
dki.artifact = "bin".into();
321+
dki.bin_name = Some(bin_target.name().into());
322+
fix_extern_name(&mut dki, bin_target.name());
323+
dki.compile_target = compile_target;
324+
dki
325+
},
326+
));
327+
};
328+
if artifact.is_lib() {
329+
dep_kinds.push(DepKindInfo::from(dep))
330+
}
331+
dep_kinds
332+
})
333+
.unwrap_or_else(|| vec![DepKindInfo::from(dep)])
334+
}

0 commit comments

Comments
 (0)