Skip to content

Commit 96a2c7d

Browse files
committed
Auto merge of #5722 - alexcrichton:beta-next, r=alexcrichton
[beta] Partially revert dep changes in #5651 This is a beta backport of #5711
2 parents cb019b6 + bb9ff3d commit 96a2c7d

File tree

3 files changed

+128
-39
lines changed

3 files changed

+128
-39
lines changed

src/cargo/core/compiler/context/unit_dependencies.rs

Lines changed: 99 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,16 @@ use super::{BuildContext, CompileMode, Kind, Unit};
1919
use core::dependency::Kind as DepKind;
2020
use core::profiles::ProfileFor;
2121
use core::{Package, Target};
22-
use std::collections::HashMap;
22+
use std::collections::{HashMap, HashSet};
2323
use CargoResult;
2424

2525
pub fn build_unit_dependencies<'a, 'cfg>(
2626
roots: &[Unit<'a>],
2727
bcx: &BuildContext<'a, 'cfg>,
28-
mut deps: &mut HashMap<Unit<'a>, Vec<Unit<'a>>>,
28+
deps: &mut HashMap<Unit<'a>, Vec<Unit<'a>>>,
2929
) -> CargoResult<()> {
30+
assert!(deps.len() == 0, "can only build unit deps once");
31+
3032
for unit in roots.iter() {
3133
// Dependencies of tests/benches should not have `panic` set.
3234
// We check the global test mode to see if we are running in `cargo
@@ -39,33 +41,35 @@ pub fn build_unit_dependencies<'a, 'cfg>(
3941
} else {
4042
ProfileFor::Any
4143
};
42-
deps_of(unit, bcx, &mut deps, profile_for)?;
44+
deps_of(unit, bcx, deps, profile_for)?;
4345
}
4446

47+
connect_run_custom_build_deps(bcx, deps);
48+
4549
Ok(())
4650
}
4751

48-
fn deps_of<'a, 'b, 'cfg>(
52+
fn deps_of<'a, 'cfg>(
4953
unit: &Unit<'a>,
5054
bcx: &BuildContext<'a, 'cfg>,
51-
deps: &'b mut HashMap<Unit<'a>, Vec<Unit<'a>>>,
55+
deps: &mut HashMap<Unit<'a>, Vec<Unit<'a>>>,
5256
profile_for: ProfileFor,
53-
) -> CargoResult<&'b [Unit<'a>]> {
57+
) -> CargoResult<()> {
5458
// Currently the `deps` map does not include `profile_for`. This should
5559
// be safe for now. `TestDependency` only exists to clear the `panic`
5660
// flag, and you'll never ask for a `unit` with `panic` set as a
5761
// `TestDependency`. `CustomBuild` should also be fine since if the
5862
// requested unit's settings are the same as `Any`, `CustomBuild` can't
5963
// affect anything else in the hierarchy.
6064
if !deps.contains_key(unit) {
61-
let unit_deps = compute_deps(unit, bcx, deps, profile_for)?;
65+
let unit_deps = compute_deps(unit, bcx, profile_for)?;
6266
let to_insert: Vec<_> = unit_deps.iter().map(|&(unit, _)| unit).collect();
6367
deps.insert(*unit, to_insert);
6468
for (unit, profile_for) in unit_deps {
6569
deps_of(&unit, bcx, deps, profile_for)?;
6670
}
6771
}
68-
Ok(deps[unit].as_ref())
72+
Ok(())
6973
}
7074

7175
/// For a package, return all targets which are registered as dependencies
@@ -75,11 +79,10 @@ fn deps_of<'a, 'b, 'cfg>(
7579
fn compute_deps<'a, 'b, 'cfg>(
7680
unit: &Unit<'a>,
7781
bcx: &BuildContext<'a, 'cfg>,
78-
deps: &'b mut HashMap<Unit<'a>, Vec<Unit<'a>>>,
7982
profile_for: ProfileFor,
8083
) -> CargoResult<Vec<(Unit<'a>, ProfileFor)>> {
8184
if unit.mode.is_run_custom_build() {
82-
return compute_deps_custom_build(unit, bcx, deps);
85+
return compute_deps_custom_build(unit, bcx);
8386
} else if unit.mode.is_doc() && !unit.mode.is_any_test() {
8487
// Note: This does not include Doctest.
8588
return compute_deps_doc(unit, bcx);
@@ -192,39 +195,27 @@ fn compute_deps<'a, 'b, 'cfg>(
192195
fn compute_deps_custom_build<'a, 'cfg>(
193196
unit: &Unit<'a>,
194197
bcx: &BuildContext<'a, 'cfg>,
195-
deps: &mut HashMap<Unit<'a>, Vec<Unit<'a>>>,
196198
) -> CargoResult<Vec<(Unit<'a>, ProfileFor)>> {
197199
// When not overridden, then the dependencies to run a build script are:
198200
//
199201
// 1. Compiling the build script itself
200202
// 2. For each immediate dependency of our package which has a `links`
201203
// key, the execution of that build script.
202-
let deps = deps
203-
.iter()
204-
.find(|(key, _deps)| key.pkg == unit.pkg && !key.target.is_custom_build())
205-
.expect("can't find package deps")
206-
.1;
207-
Ok(deps.iter()
208-
.filter_map(|unit| {
209-
if !unit.target.linkable() || unit.pkg.manifest().links().is_none() {
210-
return None;
211-
}
212-
dep_build_script(unit, bcx)
213-
})
214-
.chain(Some((
215-
new_unit(
216-
bcx,
217-
unit.pkg,
218-
unit.target,
219-
ProfileFor::CustomBuild,
220-
Kind::Host, // build scripts always compiled for the host
221-
CompileMode::Build,
222-
),
223-
// All dependencies of this unit should use profiles for custom
224-
// builds.
225-
ProfileFor::CustomBuild,
226-
)))
227-
.collect())
204+
//
205+
// We don't have a great way of handling (2) here right now so this is
206+
// deferred until after the graph of all unit dependencies has been
207+
// constructed.
208+
let unit = new_unit(
209+
bcx,
210+
unit.pkg,
211+
unit.target,
212+
ProfileFor::CustomBuild,
213+
Kind::Host, // build scripts always compiled for the host
214+
CompileMode::Build,
215+
);
216+
// All dependencies of this unit should use profiles for custom
217+
// builds.
218+
Ok(vec![(unit, ProfileFor::CustomBuild)])
228219
}
229220

230221
/// Returns the dependencies necessary to document a package
@@ -369,3 +360,74 @@ fn new_unit<'a>(
369360
mode,
370361
}
371362
}
363+
364+
/// Fill in missing dependencies for units of the `RunCustomBuild`
365+
///
366+
/// As mentioned above in `compute_deps_custom_build` each build script
367+
/// execution has two dependencies. The first is compiling the build script
368+
/// itself (already added) and the second is that all crates the package of the
369+
/// build script depends on with `links` keys, their build script execution. (a
370+
/// bit confusing eh?)
371+
///
372+
/// Here we take the entire `deps` map and add more dependencies from execution
373+
/// of one build script to execution of another build script.
374+
fn connect_run_custom_build_deps<'a>(
375+
bcx: &BuildContext,
376+
deps: &mut HashMap<Unit<'a>, Vec<Unit<'a>>>,
377+
) {
378+
let mut new_deps = Vec::new();
379+
380+
{
381+
// First up build a reverse dependency map. This is a mapping of all
382+
// `RunCustomBuild` known steps to the unit which depends on them. For
383+
// example a library might depend on a build script, so this map will
384+
// have the build script as the key and the library would be in the
385+
// value's set.
386+
let mut reverse_deps = HashMap::new();
387+
for (unit, deps) in deps.iter() {
388+
for dep in deps {
389+
if dep.mode == CompileMode::RunCustomBuild {
390+
reverse_deps.entry(dep)
391+
.or_insert(HashSet::new())
392+
.insert(unit);
393+
}
394+
}
395+
}
396+
397+
// And next we take a look at all build scripts executions listed in the
398+
// dependency map. Our job here is to take everything that depends on
399+
// this build script (from our reverse map above) and look at the other
400+
// package dependencies of these parents.
401+
//
402+
// If we depend on a linkable target and the build script mentions
403+
// `links`, then we depend on that package's build script! Here we use
404+
// `dep_build_script` to manufacture an appropriate build script unit to
405+
// depend on.
406+
for unit in deps.keys().filter(|k| k.mode == CompileMode::RunCustomBuild) {
407+
let reverse_deps = match reverse_deps.get(unit) {
408+
Some(set) => set,
409+
None => continue,
410+
};
411+
412+
let to_add = reverse_deps
413+
.iter()
414+
.flat_map(|reverse_dep| deps[reverse_dep].iter())
415+
.filter(|other| {
416+
other.pkg != unit.pkg &&
417+
other.target.linkable() &&
418+
other.pkg.manifest().links().is_some()
419+
})
420+
.filter_map(|other| dep_build_script(other, bcx).map(|p| p.0))
421+
.collect::<HashSet<_>>();
422+
423+
if !to_add.is_empty() {
424+
new_deps.push((*unit, to_add));
425+
}
426+
}
427+
}
428+
429+
// And finally, add in all the missing dependencies!
430+
for (unit, new_deps) in new_deps {
431+
deps.get_mut(&unit).unwrap().extend(new_deps);
432+
}
433+
}

tests/testsuite/build_script.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3080,9 +3080,11 @@ fn panic_abort_with_build_scripts() {
30803080
execs().with_status(0),
30813081
);
30823082

3083+
p.root().join("target").rm_rf();
3084+
30833085
assert_that(
3084-
p.cargo("test --release"),
3085-
execs().with_status(0)
3086+
p.cargo("test --release -v"),
3087+
execs().with_status(0).with_stderr_does_not_contain("[..]panic[..]"),
30863088
);
30873089
}
30883090

tests/testsuite/test.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4138,3 +4138,28 @@ fn json_artifact_includes_test_flag() {
41384138
),
41394139
);
41404140
}
4141+
4142+
#[test]
4143+
fn test_build_script_links() {
4144+
let p = project("foo")
4145+
.file(
4146+
"Cargo.toml",
4147+
r#"
4148+
[package]
4149+
name = "foo"
4150+
version = "0.0.1"
4151+
links = 'something'
4152+
4153+
[lib]
4154+
test = false
4155+
"#,
4156+
)
4157+
.file("build.rs", "fn main() {}")
4158+
.file("src/lib.rs", "")
4159+
.build();
4160+
4161+
assert_that(
4162+
p.cargo("test --no-run"),
4163+
execs().with_status(0),
4164+
);
4165+
}

0 commit comments

Comments
 (0)