in tools/hakari/src/hakari.rs [622:729]
fn build(builder: HakariBuilder<'g>) -> Self {
let graph = *builder.graph;
let mut computed_map_build = ComputedMapBuild::new(&builder);
let platform_specs: Vec<_> = builder
.platforms
.iter()
.map(|platform| PlatformSpec::Platform(platform.clone()))
.collect();
let unify_target_host = builder.unify_target_host.to_impl(graph);
// Collect all the dependencies that need to be unified, by platform and build type.
let mut map_build: OutputMapBuild<'g> = OutputMapBuild::new(graph);
map_build.insert_all(
computed_map_build.iter(),
builder.output_single_feature,
unify_target_host,
);
if !builder.output_single_feature {
// Adding packages might cause different feature sets for some dependencies. Simulate
// further builds with the given target and host features, and use that to add in any
// extra features that need to be considered.
loop {
let mut add_extra = HashSet::new();
for (output_key, features) in map_build.iter_feature_sets() {
let initials_platform = match output_key.build_platform {
BuildPlatform::Target => InitialsPlatform::Standard,
BuildPlatform::Host => InitialsPlatform::Host,
};
let mut cargo_opts = CargoOptions::new();
let platform_spec = match output_key.platform_idx {
Some(idx) => platform_specs[idx].clone(),
None => PlatformSpec::Always,
};
// Third-party dependencies are built without including dev.
cargo_opts
.set_include_dev(false)
.set_initials_platform(initials_platform)
.set_platform(platform_spec)
.set_resolver(builder.resolver)
.add_omitted_packages(computed_map_build.excludes.iter());
let cargo_set = features
.into_cargo_set(&cargo_opts)
.expect("into_cargo_set processed successfully");
// Check the features for the cargo set to see if any further dependencies were
// built with a different result and weren't included in the hakari map
// originally.
for &(build_platform, feature_set) in cargo_set.all_features().iter() {
for feature_list in
feature_set.packages_with_features(DependencyDirection::Forward)
{
let dep = feature_list.package();
let dep_id = dep.id();
let v_mut = computed_map_build
.get_mut(output_key.platform_idx, dep_id)
.expect("full value should be present");
// Is it already present in the output?
let new_key = OutputKey {
platform_idx: output_key.platform_idx,
build_platform,
};
if map_build.is_inserted(new_key, dep_id) {
continue;
}
let this_list: BTreeSet<_> = feature_list.named_features().collect();
let already_present = v_mut.contains(build_platform, &this_list);
if !already_present {
// The feature list added by this dependency is non-unique.
v_mut.mark_fixed_up(build_platform, this_list);
add_extra.insert((output_key.platform_idx, dep_id));
}
}
}
}
if add_extra.is_empty() {
break;
}
map_build.insert_all(
add_extra.iter().map(|&(platform_idx, dep_id)| {
let v = computed_map_build
.get(platform_idx, dep_id)
.expect("full value should be present");
(platform_idx, dep_id, v)
}),
builder.output_single_feature,
unify_target_host,
);
}
}
let computed_map = computed_map_build.computed_map;
let output_map = map_build.finish(&builder.final_excludes);
Self {
builder,
output_map,
computed_map,
}
}