in src/buckify.rs [149:469]
fn generate_target_rules<'scope>(
context: &'scope RuleContext<'scope>,
pkg: &'scope Manifest,
tgt: &'scope ManifestTarget,
) -> Result<(Vec<Rule>, Vec<&'scope Manifest>)> {
let RuleContext {
config,
paths,
index,
..
} = context;
log::info!("Generating rules for package {} target {}", pkg, tgt.name);
let fixups = Fixups::new(config, paths, index, pkg, tgt)?;
if fixups.omit_target() {
return Ok((vec![], vec![]));
}
log::debug!("pkg {} target {} fixups {:#?}", pkg, tgt.name, fixups);
let rootmod = relative_path(&paths.third_party_dir, &tgt.src_path);
let edition = tgt.edition.unwrap_or(pkg.edition);
let licenses: BTreeSet<_> = fixups
.manifestwalk(&config.license_patterns, iter::empty::<&str>(), false)?
.chain(
pkg.license_file
.as_ref()
.map(|file| relative_path(&paths.third_party_dir, pkg.manifest_dir()).join(file))
.into_iter(),
)
.collect();
let global_rustc_flags = config.rustc_flags.clone();
let global_platform_rustc_flags = config.platform_rustc_flags.clone();
let srcdir = relative_path(pkg.manifest_dir(), tgt.src_path.parent().unwrap());
// Get a list of the most obvious sources for the crate. This is either a list of
// filename, or a list of globs.
// If we're configured to get precise sources and we're using 2018+ edition source, then
// parse the crate to see what files are actually used.
let mut srcs = if config.precise_srcs && edition >= Edition::Rust2018 {
match srcfiles::crate_srcfiles(&tgt.src_path) {
Ok(srcs) => {
let srcs = srcs
.into_iter()
.map(|src| normalize_dotdot(&src.path))
.collect::<Vec<_>>();
log::debug!("crate_srcfiles returned {:#?}", srcs);
srcs
}
Err(err) => {
log::info!("crate_srcfiles failed: {}", err);
vec![]
}
}
} else {
vec![]
};
if srcs.is_empty() {
// If that didn't work out, get srcs the globby way
srcs = vec![tgt.src_path.parent().unwrap().join("**/*.rs")]
}
// Platform-specific rule bits which are common to all platforms
let mut base = PlatformRustCommon {
rustc_flags: global_rustc_flags.clone(),
..Default::default()
};
// Per platform rule bits
let mut perplat: BTreeMap<PlatformName, PlatformRustCommon> = BTreeMap::new();
// global_platform_rustc_flags is already in terms of PlatformName, do we can just add them in.
for (plat, flags) in global_platform_rustc_flags {
perplat.entry(plat).or_default().rustc_flags.extend(flags)
}
unzip_platform(
&config,
&mut base,
&mut perplat,
|rule, flags| {
log::debug!("pkg {} target {}: adding flags {:?}", pkg, tgt.name, flags);
rule.rustc_flags.extend(flags)
},
fixups.compute_cmdline(),
)
.context("rustc_flags")?;
unzip_platform(
&config,
&mut base,
&mut perplat,
|rule, srcs| {
log::debug!("pkg {} target {}: adding srcs {:?}", pkg, tgt.name, srcs);
rule.srcs.extend(srcs)
},
fixups.compute_srcs(srcs)?,
)
.context("srcs")?;
unzip_platform(
&config,
&mut base,
&mut perplat,
|rule, map| {
log::debug!(
"pkg {} target {}: adding mapped_srcs(gen_srcs) {:?}",
pkg,
tgt.name,
map
);
let targets = map
.into_iter()
.map(|(rule, path)| (rule.target().to_string(), path));
rule.mapped_srcs.extend(targets);
},
fixups.compute_gen_srcs(&srcdir),
)
.context("mapped_srcs(gen_srcs)")?;
unzip_platform(
&config,
&mut base,
&mut perplat,
|rule, map| {
log::debug!(
"pkg {} target {}: adding mapped_srcs(paths) {:?}",
pkg,
tgt.name,
map
);
let paths = map
.into_iter()
.map(|(from, to)| (from.display().to_string(), to));
rule.mapped_srcs.extend(paths);
},
fixups.compute_mapped_srcs()?,
)
.context("mapped_srcs(paths)")?;
unzip_platform(
&config,
&mut base,
&mut perplat,
|rule, features| {
log::debug!(
"pkg {} target {}: adding features {:?}",
pkg,
tgt.name,
features
);
rule.features.extend(features);
},
fixups.compute_features(),
)
.context("features")?;
unzip_platform(
&config,
&mut base,
&mut perplat,
|rule, env| {
log::debug!("pkg {} target {}: adding env {:?}", pkg, tgt.name, env);
rule.env.extend(env);
},
fixups.compute_env(),
)
.context("env")?;
// Compute set of dependencies any rule we generate here will need. They will only
// be emitted if we actually emit some rules below.
let mut dep_pkgs = Vec::new();
for (deppkg, dep, alias) in fixups.compute_deps()? {
if dep.has_platform() {
// If this is a platform-specific dependency, find the
// matching supported platform(s) and insert it into the appropriate
// dependency.
// If the name is DEFAULT_PLATFORM then just put it in the normal generic deps
for (name, platform) in &config.platform {
let is_default = name.is_default();
log::debug!(
"pkg {} target {} dep {:?} platform ({}, {:?}) filter {:?}",
pkg,
tgt.name,
dep,
name,
platform,
dep.filter(platform)
);
if dep.filter(platform)? {
let dep = dep.clone();
if let Some(alias) = alias.clone() {
if is_default {
// Just use normal deps
base.named_deps.insert(alias, dep);
} else {
perplat
.entry(name.clone())
.or_default()
.named_deps
.insert(alias, dep);
}
} else {
if is_default {
// Normal deps
base.deps.insert(dep);
} else {
perplat.entry(name.clone()).or_default().deps.insert(dep);
}
}
dep_pkgs.extend(deppkg);
}
}
} else {
// Otherwise this is not platform-specific and can go into the
// generic dependencies.
if let Some(alias) = alias {
base.named_deps.insert(alias, dep);
} else {
base.deps.insert(dep);
}
dep_pkgs.extend(deppkg);
}
}
// "link_style" only really applies to binaries, so maintain separate binary base & perplat
let mut bin_base = base.clone();
let mut bin_perplat = perplat.clone();
unzip_platform(
&config,
&mut bin_base,
&mut bin_perplat,
|rule, link_style| {
log::debug!("pkg {} target {}: link_style {}", pkg, tgt.name, link_style);
rule.link_style = Some(link_style);
},
fixups.compute_link_style(),
)
.context("link_style")?;
// Standalone binary - binary for a package always takes the package's library as a dependency
// if there is one
if let Some(true) = pkg.dependency_target().map(ManifestTarget::kind_lib) {
bin_base.deps.insert(RuleRef::local(index.rule_name(pkg)));
}
// Generate rules appropriate to each kind of crate we want to support
let rules: Vec<Rule> = if (tgt.kind_lib() && tgt.crate_lib())
|| (tgt.kind_proc_macro() && tgt.crate_proc_macro())
|| (tgt.kind_cdylib() && tgt.crate_cdylib())
{
// Library or procmacro
vec![Rule::Library(RustLibrary {
common: RustCommon {
common: Common {
name: index.rule_name(pkg),
public: index.is_public(pkg),
licenses,
},
krate: tgt.name.replace('-', "_"),
rootmod,
edition,
base,
platform: perplat,
},
proc_macro: tgt.crate_proc_macro(),
dlopen_enable: tgt.kind_cdylib() && fixups.python_ext().is_none(),
python_ext: fixups.python_ext().map(str::to_string),
})]
} else if tgt.crate_bin() && tgt.kind_custom_build() {
// Build script
let buildscript = RustBinary {
common: RustCommon {
common: Common {
name: format!("{}-{}", pkg, tgt.name),
public: false,
licenses: Default::default(),
},
krate: tgt.name.replace('-', "_"),
rootmod,
edition,
base: PlatformRustCommon {
// don't use fixed ones because it will be a cyclic dependency
rustc_flags: global_rustc_flags,
..base
},
platform: perplat,
},
};
fixups.emit_buildscript_rules(buildscript, &config)?
} else if tgt.kind_bin() && tgt.crate_bin() && index.is_public(pkg) {
vec![Rule::Binary(RustBinary {
common: RustCommon {
common: Common {
name: format!("{}-{}", index.rule_name(pkg), tgt.name),
public: index.is_public(pkg),
licenses,
},
krate: tgt.name.replace('-', "_"),
rootmod,
edition,
base: bin_base,
platform: bin_perplat,
},
})]
} else {
// Ignore everything else for now.
log::info!("pkg {} target {} Skipping {:?}", pkg, tgt.name, tgt.kind());
vec![]
};
Ok((rules, dep_pkgs))
}