use std::path::Path;
use anyhow::{Context, Result};
use tempfile::TempDir;
use tracing::info;
use crate::codegen::{generate_build_rs, generate_cargo_toml, generate_lib_rs};
use crate::config::BuildConfig;
pub fn build(cfg: &BuildConfig, output_dir: &str) -> Result<()> {
let mut resolved = cfg.clone();
if let Some(path) = &resolved.build.folk_ext_path {
let abs = std::fs::canonicalize(path)
.with_context(|| format!("resolve folk_ext_path: {path}"))?;
resolved.build.folk_ext_path = Some(abs.display().to_string());
}
if let Some(path) = &resolved.build.folk_api_path {
let abs = std::fs::canonicalize(path)
.with_context(|| format!("resolve folk_api_path: {path}"))?;
resolved.build.folk_api_path = Some(abs.display().to_string());
}
for plugin in &mut resolved.plugin {
if let Some(path) = &plugin.path {
let abs = std::fs::canonicalize(path)
.with_context(|| format!("resolve plugin path: {path}"))?;
plugin.path = Some(abs.display().to_string());
}
}
let tmp = TempDir::new().context("create temp dir")?;
let tmp_path = tmp.path();
std::fs::create_dir_all(tmp_path.join("src"))?;
std::fs::write(tmp_path.join("Cargo.toml"), generate_cargo_toml(&resolved))?;
std::fs::write(tmp_path.join("src/lib.rs"), generate_lib_rs(&resolved))?;
std::fs::write(tmp_path.join("build.rs"), generate_build_rs())?;
info!(dir = %tmp_path.display(), "compiling PHP extension");
let status = std::process::Command::new("cargo")
.args(["build", "--release"])
.current_dir(tmp_path)
.status()
.context("run cargo")?;
if !status.success() {
anyhow::bail!("cargo build failed with status {status}");
}
let lib_name = &cfg.build.output;
let ext = if cfg!(target_os = "macos") {
"dylib"
} else {
"so"
};
let src = tmp_path
.join("target/release")
.join(format!("lib{lib_name}.{ext}"));
let dst = Path::new(output_dir).join(format!("{lib_name}.{ext}"));
std::fs::copy(&src, &dst)
.with_context(|| format!("copy {} → {}", src.display(), dst.display()))?;
info!(output = %dst.display(), "extension ready");
Ok(())
}