Skip to content

Commit c604416

Browse files
committed
Auto merge of #7215 - ehuss:build-script-cleanup, r=alexcrichton
Clean up build script stuff and documentation. I often get lost trying to understand some of this build script stuff, so this is an attempt to make it a little easier to follow. Overview: - Remove `Context::build_script_overridden`. - Add `BuildContext::script_override` to query if something is overridden. - Do not bother to compute unit dependencies for overridden build scripts. This is the most risky change, since there are some subtle assumptions when connecting up the various build script maps. However, as best as I can reason through, it seems correct. The intent here is to avoid all the situations where it attempts to filter out these extra deps. - Rename `Context::build_state` to `Context::build_script_outputs` to try to be clearer about what it is. Similarly rename `BuildState` to `BuildScriptOutputs`. - Remove trivial 1-line function `load_build_deps`. - Add some documentation.
2 parents 462365a + bd31c08 commit c604416

File tree

9 files changed

+180
-141
lines changed

9 files changed

+180
-141
lines changed

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ mod target_info;
1616
pub use self::target_info::{FileFlavor, TargetInfo};
1717

1818
/// The build context, containing all information about a build task.
19+
///
20+
/// It is intended that this is mostly static information. Stuff that mutates
21+
/// during the build can be found in the parent `Context`. (I say mostly,
22+
/// because this has internal caching, but nothing that should be observable
23+
/// or require &mut.)
1924
pub struct BuildContext<'a, 'cfg> {
2025
/// The workspace the build is for.
2126
pub ws: &'a Workspace<'cfg>,
@@ -183,6 +188,17 @@ impl<'a, 'cfg> BuildContext<'a, 'cfg> {
183188
pub fn extra_args_for(&self, unit: &Unit<'a>) -> Option<&Vec<String>> {
184189
self.extra_compiler_args.get(unit)
185190
}
191+
192+
/// If a build script is overridden, this returns the `BuildOutput` to use.
193+
///
194+
/// `lib_name` is the `links` library name and `kind` is whether it is for
195+
/// Host or Target.
196+
pub fn script_override(&self, lib_name: &str, kind: Kind) -> Option<&BuildOutput> {
197+
match kind {
198+
Kind::Host => self.host_config.overrides.get(lib_name),
199+
Kind::Target => self.target_config.overrides.get(lib_name),
200+
}
201+
}
186202
}
187203

188204
/// Information required to build for a target.
@@ -192,7 +208,11 @@ pub struct TargetConfig {
192208
pub ar: Option<PathBuf>,
193209
/// The path of the linker for this target.
194210
pub linker: Option<PathBuf>,
195-
/// Special build options for any necessary input files (filename -> options).
211+
/// Build script override for the given library name.
212+
///
213+
/// Any package with a `links` value for the given library name will skip
214+
/// running its build script and instead use the given output from the
215+
/// config file.
196216
pub overrides: HashMap<String, BuildOutput>,
197217
}
198218

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

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::collections::{HashMap, HashSet};
33
use std::ffi::OsStr;
44
use std::fmt::Write;
55
use std::path::PathBuf;
6-
use std::sync::Arc;
6+
use std::sync::{Arc, Mutex};
77

88
use filetime::FileTime;
99
use jobserver::Client;
@@ -15,7 +15,7 @@ use crate::util::errors::{CargoResult, CargoResultExt};
1515
use crate::util::{internal, profile, Config};
1616

1717
use super::build_plan::BuildPlan;
18-
use super::custom_build::{self, BuildDeps, BuildScripts, BuildState};
18+
use super::custom_build::{self, BuildDeps, BuildScriptOutputs, BuildScripts};
1919
use super::fingerprint::Fingerprint;
2020
use super::job_queue::JobQueue;
2121
use super::layout::Layout;
@@ -28,21 +28,45 @@ mod compilation_files;
2828
use self::compilation_files::CompilationFiles;
2929
pub use self::compilation_files::{Metadata, OutputFile};
3030

31+
/// Collection of all the stuff that is needed to perform a build.
3132
pub struct Context<'a, 'cfg> {
33+
/// Mostly static information about the build task.
3234
pub bcx: &'a BuildContext<'a, 'cfg>,
35+
/// A large collection of information about the result of the entire compilation.
3336
pub compilation: Compilation<'cfg>,
34-
pub build_state: Arc<BuildState>,
35-
pub build_script_overridden: HashSet<(PackageId, Kind)>,
37+
/// Output from build scripts, updated after each build script runs.
38+
pub build_script_outputs: Arc<Mutex<BuildScriptOutputs>>,
39+
/// Dependencies (like rerun-if-changed) declared by a build script.
40+
/// This is *only* populated from the output from previous runs.
41+
/// If the build script hasn't ever been run, then it must be run.
3642
pub build_explicit_deps: HashMap<Unit<'a>, BuildDeps>,
43+
/// Fingerprints used to detect if a unit is out-of-date.
3744
pub fingerprints: HashMap<Unit<'a>, Arc<Fingerprint>>,
45+
/// Cache of file mtimes to reduce filesystem hits.
3846
pub mtime_cache: HashMap<PathBuf, FileTime>,
47+
/// A set used to track which units have been compiled.
48+
/// A unit may appear in the job graph multiple times as a dependency of
49+
/// multiple packages, but it only needs to run once.
3950
pub compiled: HashSet<Unit<'a>>,
51+
/// Linking information for each `Unit`.
52+
/// See `build_map` for details.
4053
pub build_scripts: HashMap<Unit<'a>, Arc<BuildScripts>>,
54+
/// Used to check the `links` field in the manifest is not duplicated and
55+
/// is used correctly.
4156
pub links: Links,
57+
/// Job server client to manage concurrency with other processes.
4258
pub jobserver: Client,
59+
/// "Primary" packages are the ones the user selected on the command-line
60+
/// with `-p` flags. If no flags are specified, then it is the defaults
61+
/// based on the current directory and the default workspace members.
4362
primary_packages: HashSet<PackageId>,
63+
/// The dependency graph of units to compile.
4464
unit_dependencies: HashMap<Unit<'a>, Vec<Unit<'a>>>,
65+
/// An abstraction of the files and directories that will be generated by
66+
/// the compilation. This is `None` until after `unit_dependencies` has
67+
/// been computed.
4568
files: Option<CompilationFiles<'a, 'cfg>>,
69+
/// Cache of packages, populated when they are downloaded.
4670
package_cache: HashMap<PackageId, &'a Package>,
4771

4872
/// A flag indicating whether pipelining is enabled for this compilation
@@ -82,16 +106,14 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
82106
Ok(Self {
83107
bcx,
84108
compilation: Compilation::new(bcx)?,
85-
build_state: Arc::new(BuildState::new(&bcx.host_config, &bcx.target_config)),
109+
build_script_outputs: Arc::new(Mutex::new(BuildScriptOutputs::default())),
86110
fingerprints: HashMap::new(),
87111
mtime_cache: HashMap::new(),
88112
compiled: HashSet::new(),
89113
build_scripts: HashMap::new(),
90114
build_explicit_deps: HashMap::new(),
91115
links: Links::new(),
92116
jobserver,
93-
build_script_overridden: HashSet::new(),
94-
95117
primary_packages: HashSet::new(),
96118
unit_dependencies: HashMap::new(),
97119
files: None,
@@ -228,7 +250,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
228250
super::output_depinfo(&mut self, unit)?;
229251
}
230252

231-
for (&(ref pkg, _), output) in self.build_state.outputs.lock().unwrap().iter() {
253+
for (&(ref pkg, _), output) in self.build_script_outputs.lock().unwrap().iter() {
232254
self.compilation
233255
.cfgs
234256
.entry(pkg.clone())
@@ -338,22 +360,6 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
338360
//
339361
// TODO: this ideally should be `-> &[Unit<'a>]`.
340362
pub fn dep_targets(&self, unit: &Unit<'a>) -> Vec<Unit<'a>> {
341-
// If this build script's execution has been overridden then we don't
342-
// actually depend on anything, we've reached the end of the dependency
343-
// chain as we've got all the info we're gonna get.
344-
//
345-
// Note there's a subtlety about this piece of code! The
346-
// `build_script_overridden` map here is populated in
347-
// `custom_build::build_map` which you need to call before inspecting
348-
// dependencies. However, that code itself calls this method and
349-
// gets a full pre-filtered set of dependencies. This is not super
350-
// obvious, and clear, but it does work at the moment.
351-
if unit.target.is_custom_build() {
352-
let key = (unit.pkg.package_id(), unit.kind);
353-
if self.build_script_overridden.contains(&key) {
354-
return Vec::new();
355-
}
356-
}
357363
self.unit_dependencies[unit].clone()
358364
}
359365

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,13 @@ fn compute_deps_custom_build<'a, 'cfg>(
258258
unit: &Unit<'a>,
259259
bcx: &BuildContext<'a, 'cfg>,
260260
) -> CargoResult<Vec<(Unit<'a>, UnitFor)>> {
261+
if let Some(links) = unit.pkg.manifest().links() {
262+
if bcx.script_override(links, unit.kind).is_some() {
263+
// Overridden build scripts don't have any dependencies.
264+
return Ok(Vec::new());
265+
}
266+
}
267+
261268
// When not overridden, then the dependencies to run a build script are:
262269
//
263270
// 1. Compiling the build script itself.

0 commit comments

Comments
 (0)