Skip to content

Commit ea09591

Browse files
committed
feat(compile-time-deps): Implement non compile time deps filtering
1 parent ea015a2 commit ea09591

File tree

9 files changed

+97
-44
lines changed

9 files changed

+97
-44
lines changed

src/cargo/core/compiler/build_config.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ pub struct BuildConfig {
5050
pub timing_outputs: Vec<TimingOutput>,
5151
/// Output SBOM precursor files.
5252
pub sbom: bool,
53+
/// Build compile time dependencies only, e.g., build scripts and proc macros
54+
pub compile_time_deps_only: bool,
5355
}
5456

5557
fn default_parallelism() -> CargoResult<u32> {
@@ -129,6 +131,7 @@ impl BuildConfig {
129131
future_incompat_report: false,
130132
timing_outputs: Vec::new(),
131133
sbom,
134+
compile_time_deps_only: false,
132135
})
133136
}
134137

src/cargo/core/compiler/build_runner/compilation_files.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,10 @@ impl<'a, 'gctx: 'a> CompilationFiles<'a, 'gctx> {
448448
bcx: &BuildContext<'a, 'gctx>,
449449
) -> CargoResult<Arc<Vec<OutputFile>>> {
450450
let ret = match unit.mode {
451+
_ if unit.skip_non_compile_time_dep => {
452+
// This skips compilations so no outputs
453+
vec![]
454+
}
451455
CompileMode::Doc => {
452456
let path = if bcx.build_config.intent.wants_doc_json_output() {
453457
self.out_dir(unit)

src/cargo/core/compiler/mod.rs

Lines changed: 48 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -180,50 +180,55 @@ fn compile<'gctx>(
180180
return Ok(());
181181
}
182182

183-
// Build up the work to be done to compile this unit, enqueuing it once
184-
// we've got everything constructed.
185-
fingerprint::prepare_init(build_runner, unit)?;
186-
187-
let job = if unit.mode.is_run_custom_build() {
188-
custom_build::prepare(build_runner, unit)?
189-
} else if unit.mode.is_doc_test() {
190-
// We run these targets later, so this is just a no-op for now.
191-
Job::new_fresh()
192-
} else if build_plan {
193-
Job::new_dirty(
194-
rustc(build_runner, unit, &exec.clone())?,
195-
DirtyReason::FreshBuild,
196-
)
197-
} else {
198-
let force = exec.force_rebuild(unit) || force_rebuild;
199-
let mut job = fingerprint::prepare_target(build_runner, unit, force)?;
200-
job.before(if job.freshness().is_dirty() {
201-
let work = if unit.mode.is_doc() || unit.mode.is_doc_scrape() {
202-
rustdoc(build_runner, unit)?
203-
} else {
204-
rustc(build_runner, unit, exec)?
205-
};
206-
work.then(link_targets(build_runner, unit, false)?)
183+
// If we are in `--compile-time-deps` and the given unit is not a compile time
184+
// dependency, skip compling the unit and jumps to dependencies, which still
185+
// have chances to be compile time dependencies
186+
if !unit.skip_non_compile_time_dep {
187+
// Build up the work to be done to compile this unit, enqueuing it once
188+
// we've got everything constructed.
189+
fingerprint::prepare_init(build_runner, unit)?;
190+
191+
let job = if unit.mode.is_run_custom_build() {
192+
custom_build::prepare(build_runner, unit)?
193+
} else if unit.mode.is_doc_test() {
194+
// We run these targets later, so this is just a no-op for now.
195+
Job::new_fresh()
196+
} else if build_plan {
197+
Job::new_dirty(
198+
rustc(build_runner, unit, &exec.clone())?,
199+
DirtyReason::FreshBuild,
200+
)
207201
} else {
208-
// We always replay the output cache,
209-
// since it might contain future-incompat-report messages
210-
let show_diagnostics = unit.show_warnings(bcx.gctx)
211-
&& build_runner.bcx.gctx.warning_handling()? != WarningHandling::Allow;
212-
let work = replay_output_cache(
213-
unit.pkg.package_id(),
214-
PathBuf::from(unit.pkg.manifest_path()),
215-
&unit.target,
216-
build_runner.files().message_cache_path(unit),
217-
build_runner.bcx.build_config.message_format,
218-
show_diagnostics,
219-
);
220-
// Need to link targets on both the dirty and fresh.
221-
work.then(link_targets(build_runner, unit, true)?)
222-
});
223-
224-
job
225-
};
226-
jobs.enqueue(build_runner, unit, job)?;
202+
let force = exec.force_rebuild(unit) || force_rebuild;
203+
let mut job = fingerprint::prepare_target(build_runner, unit, force)?;
204+
job.before(if job.freshness().is_dirty() {
205+
let work = if unit.mode.is_doc() || unit.mode.is_doc_scrape() {
206+
rustdoc(build_runner, unit)?
207+
} else {
208+
rustc(build_runner, unit, exec)?
209+
};
210+
work.then(link_targets(build_runner, unit, false)?)
211+
} else {
212+
// We always replay the output cache,
213+
// since it might contain future-incompat-report messages
214+
let show_diagnostics = unit.show_warnings(bcx.gctx)
215+
&& build_runner.bcx.gctx.warning_handling()? != WarningHandling::Allow;
216+
let work = replay_output_cache(
217+
unit.pkg.package_id(),
218+
PathBuf::from(unit.pkg.manifest_path()),
219+
&unit.target,
220+
build_runner.files().message_cache_path(unit),
221+
build_runner.bcx.build_config.message_format,
222+
show_diagnostics,
223+
);
224+
// Need to link targets on both the dirty and fresh.
225+
work.then(link_targets(build_runner, unit, true)?)
226+
});
227+
228+
job
229+
};
230+
jobs.enqueue(build_runner, unit, job)?;
231+
}
227232

228233
// Be sure to compile all dependencies of this target as well.
229234
let deps = Vec::from(build_runner.unit_deps(unit)); // Create vec due to mutable borrow.

src/cargo/core/compiler/standard_lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ fn generate_roots(
210210
/*dep_hash*/ 0,
211211
IsArtifact::No,
212212
None,
213+
false,
213214
));
214215
}
215216
}

src/cargo/core/compiler/unit.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,13 @@ pub struct UnitInner {
112112
///
113113
/// [`FeaturesFor::ArtifactDep`]: crate::core::resolver::features::FeaturesFor::ArtifactDep
114114
pub artifact_target_for_features: Option<CompileTarget>,
115+
116+
/// Skip compiling this unit because `--compile-time-deps` flag is set and
117+
/// this is not a compile time dependency.
118+
///
119+
/// Since dependencies of this unit might be compile time dependencies, we
120+
/// set this field instead of completely dropping out this unit from unit graph.
121+
pub skip_non_compile_time_dep: bool,
115122
}
116123

117124
impl UnitInner {
@@ -245,6 +252,7 @@ impl UnitInterner {
245252
dep_hash: u64,
246253
artifact: IsArtifact,
247254
artifact_target_for_features: Option<CompileTarget>,
255+
skip_non_compile_time_dep: bool,
248256
) -> Unit {
249257
let target = match (is_std, target.kind()) {
250258
// This is a horrible hack to support build-std. `libstd` declares
@@ -281,6 +289,7 @@ impl UnitInterner {
281289
dep_hash,
282290
artifact,
283291
artifact_target_for_features,
292+
skip_non_compile_time_dep,
284293
});
285294
Unit { inner }
286295
}

src/cargo/core/compiler/unit_dependencies.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,7 @@ fn new_unit_dep_with_profile(
866866
/*dep_hash*/ 0,
867867
artifact.map_or(IsArtifact::No, |_| IsArtifact::Yes),
868868
artifact_target,
869+
false,
869870
);
870871
Ok(UnitDep {
871872
unit,

src/cargo/core/manifest.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,11 @@ impl Target {
10791079
*self.kind() == TargetKind::CustomBuild
10801080
}
10811081

1082+
/// Returns `true` if it is a compile time depencencies, e.g., build script or proc macro
1083+
pub fn is_compile_time_dependency(&self) -> bool {
1084+
self.is_custom_build() || self.proc_macro()
1085+
}
1086+
10821087
/// Returns the arguments suitable for `--crate-type` to pass to rustc.
10831088
pub fn rustc_crate_types(&self) -> Vec<CrateType> {
10841089
self.kind().rustc_crate_types()

src/cargo/ops/cargo_compile/mod.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ pub fn create_bcx<'a, 'gctx>(
449449
&units,
450450
&scrape_units,
451451
host_kind_requested.then_some(explicit_host_kind),
452+
build_config.compile_time_deps_only,
452453
);
453454

454455
let mut extra_compiler_args = HashMap::new();
@@ -582,12 +583,16 @@ where `<compatible-ver>` is the latest version supporting rustc {rustc_version}"
582583
/// This is also responsible for adjusting the `debug` setting for host
583584
/// dependencies, turning off debug if the user has not explicitly enabled it,
584585
/// and the unit is not shared with a target unit.
586+
///
587+
/// This is also responsible for adjusting whether each unit should be compiled
588+
/// or not regarding `--compile-time-deps` flag.
585589
fn rebuild_unit_graph_shared(
586590
interner: &UnitInterner,
587591
unit_graph: UnitGraph,
588592
roots: &[Unit],
589593
scrape_units: &[Unit],
590594
to_host: Option<CompileKind>,
595+
compile_time_deps_only: bool,
591596
) -> (Vec<Unit>, Vec<Unit>, UnitGraph) {
592597
let mut result = UnitGraph::new();
593598
// Map of the old unit to the new unit, used to avoid recursing into units
@@ -602,8 +607,10 @@ fn rebuild_unit_graph_shared(
602607
&mut result,
603608
&unit_graph,
604609
root,
610+
true,
605611
false,
606612
to_host,
613+
compile_time_deps_only,
607614
)
608615
})
609616
.collect();
@@ -628,14 +635,21 @@ fn traverse_and_share(
628635
new_graph: &mut UnitGraph,
629636
unit_graph: &UnitGraph,
630637
unit: &Unit,
638+
unit_is_root: bool,
631639
unit_is_for_host: bool,
632640
to_host: Option<CompileKind>,
641+
compile_time_deps_only: bool,
633642
) -> Unit {
634643
if let Some(new_unit) = memo.get(unit) {
635644
// Already computed, no need to recompute.
636645
return new_unit.clone();
637646
}
638647
let mut dep_hash = StableHasher::new();
648+
let skip_non_compile_time_deps = compile_time_deps_only
649+
&& (!unit.target.is_compile_time_dependency() ||
650+
// Root unit is not a dependency unless other units are dependant
651+
// to it.
652+
unit_is_root);
639653
let new_deps: Vec<_> = unit_graph[unit]
640654
.iter()
641655
.map(|dep| {
@@ -645,8 +659,13 @@ fn traverse_and_share(
645659
new_graph,
646660
unit_graph,
647661
&dep.unit,
662+
false,
648663
dep.unit_for.is_for_host(),
649664
to_host,
665+
// If we should compile the current unit, we should also compile
666+
// its dependencies. And if not, we should compile compile time
667+
// dependencies only.
668+
skip_non_compile_time_deps,
650669
);
651670
new_dep_unit.hash(&mut dep_hash);
652671
UnitDep {
@@ -712,6 +731,7 @@ fn traverse_and_share(
712731
unit.dep_hash,
713732
unit.artifact,
714733
unit.artifact_target_for_features,
734+
unit.skip_non_compile_time_dep,
715735
);
716736

717737
// We can now turn the deferred value into its actual final value.
@@ -742,8 +762,11 @@ fn traverse_and_share(
742762
// Since `dep_hash` is now filled in, there's no need to specify the artifact target
743763
// for target-dependent feature resolution
744764
None,
765+
skip_non_compile_time_deps,
745766
);
746-
assert!(memo.insert(unit.clone(), new_unit.clone()).is_none());
767+
if !unit_is_root || !compile_time_deps_only {
768+
assert!(memo.insert(unit.clone(), new_unit.clone()).is_none());
769+
}
747770
new_graph.entry(new_unit.clone()).or_insert(new_deps);
748771
new_unit
749772
}
@@ -904,6 +927,7 @@ fn override_rustc_crate_types(
904927
unit.dep_hash,
905928
unit.artifact,
906929
unit.artifact_target_for_features,
930+
unit.skip_non_compile_time_dep,
907931
)
908932
};
909933
units[0] = match unit.target.kind() {

src/cargo/ops/cargo_compile/unit_generator.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ impl<'a> UnitGenerator<'a, '_> {
167167
/*dep_hash*/ 0,
168168
IsArtifact::No,
169169
None,
170+
false,
170171
)
171172
})
172173
.collect()

0 commit comments

Comments
 (0)