use crate::{
build::{
BuildOptions, Builder, CargoBuildProfile, OutputCallback, all_successful, failed_targets,
resolve_build_profile,
},
cargo::Cargo,
cli::{CliError, Result},
commands::{
generate::{GenerateOptions, GenerateTarget, run_generate_with_output},
pack::PackDartOptions,
},
config::Config,
pack::{PackError, print_cargo_line, resolve_build_cargo_args},
reporter::{Reporter, Step},
};
fn build_dart_targets(
config: &Config,
release: bool,
build_cargo_args: &[String],
step: &Step,
) -> Result<()> {
let on_output: Option<OutputCallback> = if step.is_verbose() {
Some(Box::new(|line: &str| print_cargo_line(line)))
} else {
None
};
let build_options = BuildOptions {
release,
package: Some(config.library_name().to_string()),
cargo_args: build_cargo_args.to_vec(),
env: Vec::new(),
on_output,
};
let builder = Builder::new(config, build_options);
let results = builder.build_targets(&config.dart_targets())?;
if all_successful(&results) {
return Ok(());
}
let failed = failed_targets(&results);
Err(CliError::Pack(PackError::BuildFailed { targets: failed }))
}
pub(crate) fn pack_dart(
config: &Config,
options: PackDartOptions,
reporter: &Reporter,
) -> Result<()> {
if !config.is_dart_enabled() {
return Err(CliError::CommandFailed {
command: "targets.dart.enabled = false".to_string(),
status: None,
});
}
reporter.section("☕", "Packing Dart");
let build_cargo_args = resolve_build_cargo_args(config, &options.execution.cargo_args);
let build_profile = resolve_build_profile(options.execution.release, &build_cargo_args);
if !options.execution.no_build {
let step = reporter.step("Building Rust cdylib");
build_dart_targets(
config,
matches!(build_profile, CargoBuildProfile::Release),
&build_cargo_args,
&step,
)?;
step.finish_success();
}
if options.execution.regenerate {
let step = reporter.step("Generating Dart bindings");
run_generate_with_output(
config,
GenerateOptions {
target: GenerateTarget::Dart,
output: Some(config.dart_output()),
experimental: options.experimental,
ir: false,
cargo_args: build_cargo_args.clone(),
},
)?;
step.finish_success();
}
let step = reporter.step("Packaging native libraries");
let cargo = Cargo::current(&build_cargo_args)?;
let metadata = cargo.metadata()?;
let cargo_manifest_path = cargo.manifest_path()?;
let package_selector =
cargo.effective_package_selector(config, &metadata, &cargo_manifest_path);
let libraries = metadata.resolve_built_libraries_for_targets(
&cargo_manifest_path,
build_profile.output_directory_name(),
&config.crate_artifact_name(),
package_selector.as_deref(),
&config.dart_targets(),
)?;
let package_dir = config.dart_output().join(&config.package.name);
let native_libs_dir = package_dir.join("native");
std::fs::create_dir_all(&native_libs_dir).map_err(|source| {
CliError::CreateDirectoryFailed {
path: native_libs_dir.clone(),
source,
}
})?;
for l in libraries {
let native_lib_triple_dir = native_libs_dir.join(l.target.triple());
std::fs::create_dir_all(&native_lib_triple_dir).map_err(|source| {
CliError::CreateDirectoryFailed {
path: native_lib_triple_dir.clone(),
source,
}
})?;
let native_lib_filepath =
native_lib_triple_dir.join(l.path.file_name().expect("file shouldn't terminate in .."));
std::fs::copy(&l.path, &native_lib_filepath).map_err(|source| CliError::CopyFailed {
from: l.path,
to: native_lib_filepath,
source,
})?;
}
step.finish_success();
reporter.finish();
Ok(())
}