mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-25 11:14:46 +00:00
feat(compile-time-deps): Implement non compile time deps filtering
This commit is contained in:
parent
d253d12122
commit
5b178a8d05
@ -50,6 +50,8 @@ pub struct BuildConfig {
|
||||
pub timing_outputs: Vec<TimingOutput>,
|
||||
/// Output SBOM precursor files.
|
||||
pub sbom: bool,
|
||||
/// Build compile time dependencies only, e.g., build scripts and proc macros
|
||||
pub compile_time_deps_only: bool,
|
||||
}
|
||||
|
||||
fn default_parallelism() -> CargoResult<u32> {
|
||||
@ -129,6 +131,7 @@ impl BuildConfig {
|
||||
future_incompat_report: false,
|
||||
timing_outputs: Vec::new(),
|
||||
sbom,
|
||||
compile_time_deps_only: false,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -448,6 +448,10 @@ impl<'a, 'gctx: 'a> CompilationFiles<'a, 'gctx> {
|
||||
bcx: &BuildContext<'a, 'gctx>,
|
||||
) -> CargoResult<Arc<Vec<OutputFile>>> {
|
||||
let ret = match unit.mode {
|
||||
_ if unit.skip_non_compile_time_dep => {
|
||||
// This skips compilations so no outputs
|
||||
vec![]
|
||||
}
|
||||
CompileMode::Doc => {
|
||||
let path = if bcx.build_config.intent.wants_doc_json_output() {
|
||||
self.out_dir(unit)
|
||||
|
@ -180,50 +180,55 @@ fn compile<'gctx>(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Build up the work to be done to compile this unit, enqueuing it once
|
||||
// we've got everything constructed.
|
||||
fingerprint::prepare_init(build_runner, unit)?;
|
||||
// If we are in `--compile-time-deps` and the given unit is not a compile time
|
||||
// dependency, skip compling the unit and jumps to dependencies, which still
|
||||
// have chances to be compile time dependencies
|
||||
if !unit.skip_non_compile_time_dep {
|
||||
// Build up the work to be done to compile this unit, enqueuing it once
|
||||
// we've got everything constructed.
|
||||
fingerprint::prepare_init(build_runner, unit)?;
|
||||
|
||||
let job = if unit.mode.is_run_custom_build() {
|
||||
custom_build::prepare(build_runner, unit)?
|
||||
} else if unit.mode.is_doc_test() {
|
||||
// We run these targets later, so this is just a no-op for now.
|
||||
Job::new_fresh()
|
||||
} else if build_plan {
|
||||
Job::new_dirty(
|
||||
rustc(build_runner, unit, &exec.clone())?,
|
||||
DirtyReason::FreshBuild,
|
||||
)
|
||||
} else {
|
||||
let force = exec.force_rebuild(unit) || force_rebuild;
|
||||
let mut job = fingerprint::prepare_target(build_runner, unit, force)?;
|
||||
job.before(if job.freshness().is_dirty() {
|
||||
let work = if unit.mode.is_doc() || unit.mode.is_doc_scrape() {
|
||||
rustdoc(build_runner, unit)?
|
||||
} else {
|
||||
rustc(build_runner, unit, exec)?
|
||||
};
|
||||
work.then(link_targets(build_runner, unit, false)?)
|
||||
let job = if unit.mode.is_run_custom_build() {
|
||||
custom_build::prepare(build_runner, unit)?
|
||||
} else if unit.mode.is_doc_test() {
|
||||
// We run these targets later, so this is just a no-op for now.
|
||||
Job::new_fresh()
|
||||
} else if build_plan {
|
||||
Job::new_dirty(
|
||||
rustc(build_runner, unit, &exec.clone())?,
|
||||
DirtyReason::FreshBuild,
|
||||
)
|
||||
} else {
|
||||
// We always replay the output cache,
|
||||
// since it might contain future-incompat-report messages
|
||||
let show_diagnostics = unit.show_warnings(bcx.gctx)
|
||||
&& build_runner.bcx.gctx.warning_handling()? != WarningHandling::Allow;
|
||||
let work = replay_output_cache(
|
||||
unit.pkg.package_id(),
|
||||
PathBuf::from(unit.pkg.manifest_path()),
|
||||
&unit.target,
|
||||
build_runner.files().message_cache_path(unit),
|
||||
build_runner.bcx.build_config.message_format,
|
||||
show_diagnostics,
|
||||
);
|
||||
// Need to link targets on both the dirty and fresh.
|
||||
work.then(link_targets(build_runner, unit, true)?)
|
||||
});
|
||||
let force = exec.force_rebuild(unit) || force_rebuild;
|
||||
let mut job = fingerprint::prepare_target(build_runner, unit, force)?;
|
||||
job.before(if job.freshness().is_dirty() {
|
||||
let work = if unit.mode.is_doc() || unit.mode.is_doc_scrape() {
|
||||
rustdoc(build_runner, unit)?
|
||||
} else {
|
||||
rustc(build_runner, unit, exec)?
|
||||
};
|
||||
work.then(link_targets(build_runner, unit, false)?)
|
||||
} else {
|
||||
// We always replay the output cache,
|
||||
// since it might contain future-incompat-report messages
|
||||
let show_diagnostics = unit.show_warnings(bcx.gctx)
|
||||
&& build_runner.bcx.gctx.warning_handling()? != WarningHandling::Allow;
|
||||
let work = replay_output_cache(
|
||||
unit.pkg.package_id(),
|
||||
PathBuf::from(unit.pkg.manifest_path()),
|
||||
&unit.target,
|
||||
build_runner.files().message_cache_path(unit),
|
||||
build_runner.bcx.build_config.message_format,
|
||||
show_diagnostics,
|
||||
);
|
||||
// Need to link targets on both the dirty and fresh.
|
||||
work.then(link_targets(build_runner, unit, true)?)
|
||||
});
|
||||
|
||||
job
|
||||
};
|
||||
jobs.enqueue(build_runner, unit, job)?;
|
||||
job
|
||||
};
|
||||
jobs.enqueue(build_runner, unit, job)?;
|
||||
}
|
||||
|
||||
// Be sure to compile all dependencies of this target as well.
|
||||
let deps = Vec::from(build_runner.unit_deps(unit)); // Create vec due to mutable borrow.
|
||||
|
@ -210,6 +210,7 @@ fn generate_roots(
|
||||
/*dep_hash*/ 0,
|
||||
IsArtifact::No,
|
||||
None,
|
||||
false,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -112,6 +112,13 @@ pub struct UnitInner {
|
||||
///
|
||||
/// [`FeaturesFor::ArtifactDep`]: crate::core::resolver::features::FeaturesFor::ArtifactDep
|
||||
pub artifact_target_for_features: Option<CompileTarget>,
|
||||
|
||||
/// Skip compiling this unit because `--compile-time-deps` flag is set and
|
||||
/// this is not a compile time dependency.
|
||||
///
|
||||
/// Since dependencies of this unit might be compile time dependencies, we
|
||||
/// set this field instead of completely dropping out this unit from unit graph.
|
||||
pub skip_non_compile_time_dep: bool,
|
||||
}
|
||||
|
||||
impl UnitInner {
|
||||
@ -245,6 +252,7 @@ impl UnitInterner {
|
||||
dep_hash: u64,
|
||||
artifact: IsArtifact,
|
||||
artifact_target_for_features: Option<CompileTarget>,
|
||||
skip_non_compile_time_dep: bool,
|
||||
) -> Unit {
|
||||
let target = match (is_std, target.kind()) {
|
||||
// This is a horrible hack to support build-std. `libstd` declares
|
||||
@ -281,6 +289,7 @@ impl UnitInterner {
|
||||
dep_hash,
|
||||
artifact,
|
||||
artifact_target_for_features,
|
||||
skip_non_compile_time_dep,
|
||||
});
|
||||
Unit { inner }
|
||||
}
|
||||
|
@ -866,6 +866,7 @@ fn new_unit_dep_with_profile(
|
||||
/*dep_hash*/ 0,
|
||||
artifact.map_or(IsArtifact::No, |_| IsArtifact::Yes),
|
||||
artifact_target,
|
||||
false,
|
||||
);
|
||||
Ok(UnitDep {
|
||||
unit,
|
||||
|
@ -1079,6 +1079,11 @@ impl Target {
|
||||
*self.kind() == TargetKind::CustomBuild
|
||||
}
|
||||
|
||||
/// Returns `true` if it is a compile time depencencies, e.g., build script or proc macro
|
||||
pub fn is_compile_time_dependency(&self) -> bool {
|
||||
self.is_custom_build() || self.proc_macro()
|
||||
}
|
||||
|
||||
/// Returns the arguments suitable for `--crate-type` to pass to rustc.
|
||||
pub fn rustc_crate_types(&self) -> Vec<CrateType> {
|
||||
self.kind().rustc_crate_types()
|
||||
|
@ -449,6 +449,7 @@ pub fn create_bcx<'a, 'gctx>(
|
||||
&units,
|
||||
&scrape_units,
|
||||
host_kind_requested.then_some(explicit_host_kind),
|
||||
build_config.compile_time_deps_only,
|
||||
);
|
||||
|
||||
let mut extra_compiler_args = HashMap::new();
|
||||
@ -582,12 +583,16 @@ where `<compatible-ver>` is the latest version supporting rustc {rustc_version}"
|
||||
/// This is also responsible for adjusting the `debug` setting for host
|
||||
/// dependencies, turning off debug if the user has not explicitly enabled it,
|
||||
/// and the unit is not shared with a target unit.
|
||||
///
|
||||
/// This is also responsible for adjusting whether each unit should be compiled
|
||||
/// or not regarding `--compile-time-deps` flag.
|
||||
fn rebuild_unit_graph_shared(
|
||||
interner: &UnitInterner,
|
||||
unit_graph: UnitGraph,
|
||||
roots: &[Unit],
|
||||
scrape_units: &[Unit],
|
||||
to_host: Option<CompileKind>,
|
||||
compile_time_deps_only: bool,
|
||||
) -> (Vec<Unit>, Vec<Unit>, UnitGraph) {
|
||||
let mut result = UnitGraph::new();
|
||||
// Map of the old unit to the new unit, used to avoid recursing into units
|
||||
@ -602,8 +607,10 @@ fn rebuild_unit_graph_shared(
|
||||
&mut result,
|
||||
&unit_graph,
|
||||
root,
|
||||
true,
|
||||
false,
|
||||
to_host,
|
||||
compile_time_deps_only,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
@ -628,14 +635,21 @@ fn traverse_and_share(
|
||||
new_graph: &mut UnitGraph,
|
||||
unit_graph: &UnitGraph,
|
||||
unit: &Unit,
|
||||
unit_is_root: bool,
|
||||
unit_is_for_host: bool,
|
||||
to_host: Option<CompileKind>,
|
||||
compile_time_deps_only: bool,
|
||||
) -> Unit {
|
||||
if let Some(new_unit) = memo.get(unit) {
|
||||
// Already computed, no need to recompute.
|
||||
return new_unit.clone();
|
||||
}
|
||||
let mut dep_hash = StableHasher::new();
|
||||
let skip_non_compile_time_deps = compile_time_deps_only
|
||||
&& (!unit.target.is_compile_time_dependency() ||
|
||||
// Root unit is not a dependency unless other units are dependant
|
||||
// to it.
|
||||
unit_is_root);
|
||||
let new_deps: Vec<_> = unit_graph[unit]
|
||||
.iter()
|
||||
.map(|dep| {
|
||||
@ -645,8 +659,13 @@ fn traverse_and_share(
|
||||
new_graph,
|
||||
unit_graph,
|
||||
&dep.unit,
|
||||
false,
|
||||
dep.unit_for.is_for_host(),
|
||||
to_host,
|
||||
// If we should compile the current unit, we should also compile
|
||||
// its dependencies. And if not, we should compile compile time
|
||||
// dependencies only.
|
||||
skip_non_compile_time_deps,
|
||||
);
|
||||
new_dep_unit.hash(&mut dep_hash);
|
||||
UnitDep {
|
||||
@ -712,6 +731,7 @@ fn traverse_and_share(
|
||||
unit.dep_hash,
|
||||
unit.artifact,
|
||||
unit.artifact_target_for_features,
|
||||
unit.skip_non_compile_time_dep,
|
||||
);
|
||||
|
||||
// We can now turn the deferred value into its actual final value.
|
||||
@ -742,8 +762,11 @@ fn traverse_and_share(
|
||||
// Since `dep_hash` is now filled in, there's no need to specify the artifact target
|
||||
// for target-dependent feature resolution
|
||||
None,
|
||||
skip_non_compile_time_deps,
|
||||
);
|
||||
assert!(memo.insert(unit.clone(), new_unit.clone()).is_none());
|
||||
if !unit_is_root || !compile_time_deps_only {
|
||||
assert!(memo.insert(unit.clone(), new_unit.clone()).is_none());
|
||||
}
|
||||
new_graph.entry(new_unit.clone()).or_insert(new_deps);
|
||||
new_unit
|
||||
}
|
||||
@ -904,6 +927,7 @@ fn override_rustc_crate_types(
|
||||
unit.dep_hash,
|
||||
unit.artifact,
|
||||
unit.artifact_target_for_features,
|
||||
unit.skip_non_compile_time_dep,
|
||||
)
|
||||
};
|
||||
units[0] = match unit.target.kind() {
|
||||
|
@ -167,6 +167,7 @@ impl<'a> UnitGenerator<'a, '_> {
|
||||
/*dep_hash*/ 0,
|
||||
IsArtifact::No,
|
||||
None,
|
||||
false,
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
|
Loading…
x
Reference in New Issue
Block a user