use std::fs;
use crate::commands::emit::emit_wasm_module;
use crate::commands::require_project_root;
use crate::commands::verify::run_verification;
use crate::project::build::{self, BuildConfig, BuildError, CargoFailureKind};
use crate::project::manifest::Manifest;
use crate::ui::{self, CliError};
pub(crate) fn friendly_build_error(e: BuildError) -> Box<dyn std::error::Error> {
match e {
BuildError::Cargo(ref failure) => {
let hint = match failure.kind {
CargoFailureKind::DependencyResolution => {
"check the crate name and version in your `## Requires` block"
}
CargoFailureKind::GeneratedCode => {
"please report this at https://github.com/Brahmastra-Labs/logicaffeine/issues"
}
};
CliError::with_hint(e.to_string(), hint).into()
}
BuildError::Toolchain(_) => CliError::with_hint(
e.to_string(),
"install Rust from https://rustup.rs — or use `largo run --interpret` / `largo build --emit wasm`, which need no Rust toolchain",
)
.into(),
other => Box::new(other),
}
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn cmd_build(
release: bool,
verify: bool,
license: Option<String>,
lib: bool,
target: Option<String>,
native_functions: bool,
emit: Option<String>,
) -> Result<(), Box<dyn std::error::Error>> {
let project_root = require_project_root()?;
if verify {
run_verification(&project_root, license.as_deref())?;
}
if let Some(kind) = emit.as_deref() {
match kind {
"wasm" => return emit_wasm_module(&project_root, false),
"wasm-linked" => return emit_wasm_module(&project_root, true),
_ => return Err(format!("unknown --emit target '{kind}' (expected 'wasm' or 'wasm-linked')").into()),
}
}
let config = BuildConfig {
project_dir: project_root.clone(),
release,
lib_mode: lib,
target,
};
let result = build::build(config).map_err(friendly_build_error)?;
let mode = if release { "release" } else { "debug" };
ui::info(format!("Built {} [{}]", result.binary_path.display(), mode));
if native_functions {
build_native_function_bundle(&project_root)?;
}
Ok(())
}
pub(crate) fn build_native_function_bundle(
project_root: &std::path::Path,
) -> Result<(), Box<dyn std::error::Error>> {
let manifest = Manifest::load(project_root)?;
let entry_path = project_root.join(&manifest.package.entry);
let source = fs::read_to_string(&entry_path)?;
let bundle_dir = project_root.join(".logos-native");
let built = logicaffeine_compile::compile::build_native_bundle(&source, &bundle_dir)
.map_err(|e| format!("native bundle build failed: {e:?}"))?;
if built.is_empty() {
println!("No `is exported for native` functions to bundle.");
} else {
println!("Bundled {} native function(s) into {}:", built.len(), bundle_dir.display());
for (name, so) in &built {
println!(" {name} -> {}", so.display());
}
}
Ok(())
}