Skip to content

Commit

Permalink
Support target setting for non-build dependencies
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Byron committed Feb 18, 2022
1 parent 6dc0705 commit 3a65f7c
Show file tree
Hide file tree
Showing 9 changed files with 1,235 additions and 78 deletions.
11 changes: 6 additions & 5 deletions src/cargo/core/compiler/build_context/target_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -760,11 +760,12 @@ impl<'cfg> RustcTargetData<'cfg> {
.default_kind()
.into_iter()
.chain(p.manifest().forced_kind())
.into_iter()
.chain(p.manifest().dependencies().iter().filter_map(|d| {
d.artifact()
.and_then(|a| a.target().and_then(|t| t.to_compile_kind()))
}))
.chain(
p.manifest()
.dependencies()
.iter()
.filter_map(|d| d.artifact()?.target()?.to_compile_kind()),
)
}));
for kind in all_kinds {
if let CompileKind::Target(target) = kind {
Expand Down
26 changes: 15 additions & 11 deletions src/cargo/core/compiler/unit_dependencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,13 +290,14 @@ fn compute_deps(

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

let lib = package_lib(dep_pkg, has_artifact, artifact_lib);
let lib = match lib {
Expand Down Expand Up @@ -459,7 +460,13 @@ fn calc_artifact_deps(
unit,
unit_for,
state,
unit.kind,
artifact
.target()
.and_then(|t| match t {
ArtifactTarget::BuildDependencyAssumeTarget => None,
ArtifactTarget::Force(kind) => Some(CompileKind::Target(kind)),
})
.unwrap_or(unit.kind),
artifact_pkg,
dep,
)?);
Expand Down Expand Up @@ -533,7 +540,7 @@ fn compute_deps_custom_build(

fn build_artifact_requirements_to_units(
parent: &Unit,
root_unit_compile_kind: CompileKind,
root_unit_compile_target: CompileKind,
artifact_deps: Vec<(PackageId, &HashSet<Dependency>)>,
state: &State<'_, '_>,
) -> CargoResult<Vec<UnitDep>> {
Expand All @@ -553,8 +560,8 @@ fn build_artifact_requirements_to_units(
.expect("artifact dep")
.target()
.map(|kind| match kind {
ArtifactTarget::Force(kind) => kind,
ArtifactTarget::BuildDependencyAssumeTarget => root_unit_compile_kind,
ArtifactTarget::Force(target) => CompileKind::Target(target),
ArtifactTarget::BuildDependencyAssumeTarget => root_unit_compile_target,
})
.unwrap_or(CompileKind::Host),
artifact_pkg,
Expand All @@ -576,7 +583,6 @@ fn artifact_targets_to_unit_deps(
let ret = match_artifacts_kind_with_targets(parent, dep, artifact_pkg.targets())?
.into_iter()
.flat_map(|target| {
// TODO(ST): handle target="target", there isn't even a test for that yet
// We split target libraries into individual units, even though rustc is able to produce multiple
// kinds in an single invocation for the sole reason that each artifact kind has its own output directory,
// something we can't easily teach rustc for now.
Expand Down Expand Up @@ -904,13 +910,11 @@ fn new_unit_dep_with_profile(
profile: Profile,
artifact: bool,
) -> CargoResult<UnitDep> {
// TODO: consider making extern_crate_name return InternedString?
let (extern_crate_name, dep_name) = state.resolve().extern_crate_name_and_dep_name(
parent.pkg.package_id(),
pkg.package_id(),
target,
)?;
let extern_crate_name = InternedString::new(&extern_crate_name);
let public = state
.resolve()
.is_public_dep(parent.pkg.package_id(), pkg.package_id());
Expand Down
49 changes: 46 additions & 3 deletions src/cargo/core/dependency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use log::trace;
use semver::VersionReq;
use serde::ser;
use serde::Serialize;
use std::borrow::Cow;
use std::fmt;
use std::path::PathBuf;
use std::rc::Rc;
Expand Down Expand Up @@ -62,6 +63,8 @@ struct SerializedDependency<'a> {
optional: bool,
uses_default_features: bool,
features: &'a [InternedString],
#[serde(skip_serializing_if = "Option::is_none")]
artifact: Option<&'a Artifact>,
target: Option<&'a Platform>,
/// The registry URL this dependency is from.
/// If None, then it comes from the default registry (crates.io).
Expand Down Expand Up @@ -90,6 +93,7 @@ impl ser::Serialize for Dependency {
rename: self.explicit_name_in_toml().map(|s| s.as_str()),
registry: registry_id.as_ref().map(|sid| sid.url().as_str()),
path: self.source_id().local_path(),
artifact: self.artifact(),
}
.serialize(s)
}
Expand Down Expand Up @@ -438,6 +442,30 @@ pub struct Artifact {
target: Option<ArtifactTarget>,
}

#[derive(Serialize)]
pub struct SerializedArtifact<'a> {
kinds: &'a [ArtifactKind],
lib: bool,
target: Option<&'a str>,
}

impl ser::Serialize for Artifact {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
SerializedArtifact {
kinds: self.kinds(),
lib: self.is_lib,
target: self.target.as_ref().map(|t| match t {
ArtifactTarget::BuildDependencyAssumeTarget => "target",
ArtifactTarget::Force(target) => target.rustc_target(),
}),
}
.serialize(s)
}
}

impl Artifact {
pub(crate) fn parse(
artifacts: &StringOrVec,
Expand Down Expand Up @@ -478,21 +506,21 @@ pub enum ArtifactTarget {
BuildDependencyAssumeTarget,
/// Then name of the platform triple, like `x86_64-apple-darwin`, that this artifact will be always be build for, no matter
/// if it is a build, normal or dev dependency.
Force(CompileKind),
Force(CompileTarget),
}

impl ArtifactTarget {
pub fn parse(target: &str) -> CargoResult<ArtifactTarget> {
Ok(match target {
"target" => ArtifactTarget::BuildDependencyAssumeTarget,
name => ArtifactTarget::Force(CompileKind::Target(CompileTarget::new(name)?)),
name => ArtifactTarget::Force(CompileTarget::new(name)?),
})
}

pub fn to_compile_kind(&self) -> Option<CompileKind> {
match self {
ArtifactTarget::BuildDependencyAssumeTarget => None,
ArtifactTarget::Force(kind) => Some(*kind),
ArtifactTarget::Force(target) => Some(CompileKind::Target(*target)),
}
}
}
Expand All @@ -507,6 +535,21 @@ pub enum ArtifactKind {
Staticlib,
}

impl ser::Serialize for ArtifactKind {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
let out: Cow<'_, str> = match *self {
ArtifactKind::AllBinaries => "bin".into(),
ArtifactKind::Staticlib => "staticlib".into(),
ArtifactKind::Cdylib => "cdylib".into(),
ArtifactKind::SelectedBinary(name) => format!("bin:{}", name.as_str()).into(),
};
out.serialize(s)
}
}

impl fmt::Display for ArtifactKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Expand Down
19 changes: 9 additions & 10 deletions src/cargo/core/resolver/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,31 +300,30 @@ unable to verify that `{0}` is the same as when the lockfile was generated
from: PackageId,
to: PackageId,
to_target: &Target,
) -> CargoResult<(String, Option<InternedString>)> {
) -> CargoResult<(InternedString, Option<InternedString>)> {
let empty_set: HashSet<Dependency> = HashSet::new();
let deps = if from == to {
&empty_set
} else {
self.dependencies_listed(from, to)
};

let crate_name = to_target.crate_name();
let mut names = deps.iter().map(|d| {
let target_crate_name = || (to_target.crate_name(), None);
let mut name_pairs = deps.iter().map(|d| {
d.explicit_name_in_toml()
.map(|s| s.as_str().replace("-", "_"))
.unwrap_or_else(|| crate_name.clone())
.map(|s| (s.as_str().replace("-", "_"), Some(s)))
.unwrap_or_else(target_crate_name)
});
let name = names.next().unwrap_or_else(|| crate_name.clone());
for n in names {
let (extern_crate_name, dep_name) = name_pairs.next().unwrap_or_else(target_crate_name);
for (n, _) in name_pairs {
anyhow::ensure!(
n == name,
n == extern_crate_name,
"the crate `{}` depends on crate `{}` multiple times with different names",
from,
to,
);
}
let dep_name = deps.iter().filter_map(|d| d.explicit_name_in_toml()).next();
Ok((name, dep_name))
Ok((extern_crate_name.into(), dep_name))
}

fn dependencies_listed(&self, from: PackageId, to: PackageId) -> &HashSet<Dependency> {
Expand Down
122 changes: 105 additions & 17 deletions src/cargo/ops/cargo_output_metadata.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::core::compiler::{CompileKind, RustcTargetData};
use crate::core::dependency::DepKind;
use crate::core::dependency::{ArtifactKind, ArtifactTarget, DepKind};
use crate::core::package::SerializedPackage;
use crate::core::resolver::{features::CliFeatures, HasDevUnits, Resolve};
use crate::core::{Dependency, Package, PackageId, Workspace};
Expand Down Expand Up @@ -81,7 +81,7 @@ struct MetadataResolveNode {

#[derive(Serialize)]
struct Dep {
name: String,
name: InternedString,
pkg: PackageId,
dep_kinds: Vec<DepKindInfo>,
}
Expand All @@ -90,13 +90,24 @@ struct Dep {
struct DepKindInfo {
kind: DepKind,
target: Option<Platform>,
extern_name: String,
#[serde(skip_serializing_if = "Option::is_none")]
bin_name: Option<InternedString>,
#[serde(skip_serializing_if = "Option::is_none")]
artifact: Option<&'static str>,
#[serde(skip_serializing_if = "Option::is_none")]
compile_target: Option<InternedString>,
}

impl From<&Dependency> for DepKindInfo {
fn from(dep: &Dependency) -> DepKindInfo {
DepKindInfo {
kind: dep.kind(),
target: dep.platform().cloned(),
extern_name: dep.name_in_toml().replace('-', "_").into(),
bin_name: None,
artifact: None,
compile_target: None,
}
}
}
Expand Down Expand Up @@ -206,21 +217,35 @@ fn build_resolve_graph_r(
}
})
.filter_map(|(dep_id, deps)| {
let mut dep_kinds: Vec<_> = deps.iter().map(DepKindInfo::from).collect();
dep_kinds.sort();
package_map
.get(&dep_id)
.and_then(|pkg| pkg.targets().iter().find(|t| t.is_lib()))
.and_then(|lib_target| {
resolve
.extern_crate_name_and_dep_name(pkg_id, dep_id, lib_target)
.map(|(ext_crate_name, _)| ext_crate_name)
.ok()
})
.map(|name| Dep {
name,
pkg: normalize_id(dep_id),
dep_kinds,
let dep_pkg = package_map.get(&dep_id);
dep_pkg
.and_then(
|dep_pkg| match dep_pkg.targets().iter().find(|t| t.is_lib()) {
Some(lib_target) => resolve
.extern_crate_name_and_dep_name(pkg_id, dep_id, lib_target)
.map(|(ext_crate_name, _)| ext_crate_name)
.ok(),
None => {
// No traditional library is present which excludes bin-only artifacts.
// If one is present, we emulate the naming that would happen in `extern_crate_name_…()`.
deps.iter().find_map(|d| {
d.artifact()
.map(|_| d.name_in_toml().replace('-', "_").into())
})
}
},
)
.map(|name| {
let mut dep_kinds: Vec<_> = deps
.iter()
.flat_map(|dep| single_dep_kind_or_spread_artifact_kinds(dep_pkg, dep))
.collect();
dep_kinds.sort();
Dep {
name,
pkg: normalize_id(dep_id),
dep_kinds,
}
})
})
.collect();
Expand All @@ -244,3 +269,66 @@ fn build_resolve_graph_r(
);
}
}

fn single_dep_kind_or_spread_artifact_kinds(
dep_pkg: Option<&Package>,
dep: &Dependency,
) -> Vec<DepKindInfo> {
fn fix_extern_name(dki: &mut DepKindInfo, bin_name: &str) {
dki.extern_name = bin_name.replace('-', "_").into();
}
dep.artifact()
.map(|artifact| {
let mut has_all_binaries = false;
let compile_target = artifact.target().map(|target| match target {
ArtifactTarget::BuildDependencyAssumeTarget => "target".into(),
ArtifactTarget::Force(target) => target.rustc_target().into(),
});
let mut dep_kinds: Vec<_> = artifact
.kinds()
.iter()
.filter_map(|kind| {
let mut dki = DepKindInfo::from(dep);
dki.artifact = Some(
match kind {
ArtifactKind::Staticlib => "staticlib",
ArtifactKind::Cdylib => "cdylib",
ArtifactKind::AllBinaries => {
// handled in second pass
has_all_binaries = true;
return None;
}
ArtifactKind::SelectedBinary(name) => {
dki.bin_name = Some(*name);
fix_extern_name(&mut dki, name);
"bin"
}
}
.into(),
);
dki.compile_target = compile_target;
Some(dki)
})
.collect();
if let Some(dep_pkg) = has_all_binaries.then(|| dep_pkg).flatten() {
// Note that we silently ignore the binaries missed here if dep_pkg is None, which apparently can happen.
// If some warnings should one day be printed for less surprising behaviour, also consider adding a warning to the
// ignored error further above (see `….ok()`).
dep_kinds.extend(dep_pkg.targets().iter().filter(|t| t.is_bin()).map(
|bin_target| {
let mut dki = DepKindInfo::from(dep);
dki.artifact = "bin".into();
dki.bin_name = Some(bin_target.name().into());
fix_extern_name(&mut dki, bin_target.name());
dki.compile_target = compile_target;
dki
},
));
};
if artifact.is_lib() {
dep_kinds.push(DepKindInfo::from(dep))
}
dep_kinds
})
.unwrap_or_else(|| vec![DepKindInfo::from(dep)])
}

0 comments on commit 3a65f7c

Please sign in to comment.