use std::{env, path::PathBuf, str::FromStr}; fn main() { build_butck_ffi(); #[cfg(target_os = "windows")] build_win32_gui(); #[cfg(target_family = "unix")] build_gtk_gui(); } fn build_butck_ffi() { // Check if cbindgen is installed let cbindgen_check = std::process::Command::new("cbindgen") .arg("--version") .output(); if let Err(e) = cbindgen_check { if e.kind() == std::io::ErrorKind::NotFound { eprintln!("Error: cbindgen is not installed. Please install it with:"); eprintln!(" cargo install cbindgen"); std::process::exit(1); } else { eprintln!("Error: Failed to check cbindgen installation: {}", e); std::process::exit(1); } } let target_dir = get_target_dir(); // Try to run cbindgen to generate C bindings // > cbindgen --config cbindgen.toml ffi --output ffi/.temp/jvlib.h --quiet let output = std::process::Command::new("cbindgen") .args([ "--config", "cbindgen.toml", ".", "--output", &format!("{}/lib_butck.h", target_dir.display()), "--quiet", ]) .output(); match output { Ok(output) if output.status.success() => { // Successfully generated bindings } Ok(_) => { eprintln!("cbindgen failed to generate bindings"); } Err(e) if e.kind() == std::io::ErrorKind::NotFound => { eprintln!("cbindgen not found, skipping C binding generation"); } Err(e) => { eprintln!("Failed to run cbindgen: {}", e); } } } #[allow(dead_code)] fn build_win32_gui() { use std::fs; use std::path::Path; use std::process::Command; const EXE_NAME: &str = "butckg.exe"; let crate_root = env!("CARGO_MANIFEST_DIR"); let build_script = Path::new(crate_root).join("gui\\win32\\scripts\\build.ps1"); let status = Command::new("powershell") .arg("-ExecutionPolicy") .arg("Bypass") .arg("-File") .arg(&build_script) .status() .expect("Failed to execute build script"); if !status.success() { panic!("Build script failed with exit code: {:?}", status.code()); } let exe_path = Path::new(crate_root) .join("gui\\win32\\build\\bin") .join(EXE_NAME); if exe_path.exists() { let target_dir = get_target_dir(); let dest_path = target_dir.join(EXE_NAME); if let Err(e) = fs::copy(&exe_path, &dest_path) { panic!("Failed to copy executable to build directory: {}", e); } } else { panic!("Executable not found at: {:?}", exe_path); } } #[allow(dead_code)] fn build_gtk_gui() { use std::fs; use std::path::Path; use std::process::Command; const EXE_NAME: &str = "butckg"; let crate_root = env!("CARGO_MANIFEST_DIR"); let build_script = Path::new(crate_root).join("gui/gtk/cbuild.sh"); // Check if build script exists if !build_script.exists() { println!("GTK GUI build script not found, skipping GTK build"); return; } // Check if GTK development files are available let gtk_check = Command::new("pkg-config") .arg("--exists") .arg("gtk+-3.0") .status(); if let Ok(status) = gtk_check { if !status.success() { println!("GTK3 development files not found, skipping GTK build"); println!("Please install GTK3 development packages:"); println!(" Ubuntu/Debian: sudo apt-get install libgtk-3-dev"); println!(" Fedora: sudo dnf install gtk3-devel"); println!(" Arch: sudo pacman -S gtk3"); return; } } else { println!("Failed to check GTK3 installation, skipping GTK build"); return; } // Make build script executable #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; if let Ok(metadata) = fs::metadata(&build_script) { let mut perms = metadata.permissions(); perms.set_mode(0o755); fs::set_permissions(&build_script, perms).ok(); } } // Run build script let status = Command::new("bash") .arg(&build_script) .arg("build") .status() .expect("Failed to execute GTK build script"); if !status.success() { panic!( "GTK build script failed with exit code: {:?}", status.code() ); } let exe_path = Path::new(crate_root) .join("gui/gtk/build/bin") .join(EXE_NAME); if exe_path.exists() { let target_dir = get_target_dir(); let dest_path = target_dir.join(EXE_NAME); if let Err(e) = fs::copy(&exe_path, &dest_path) { panic!("Failed to copy GTK executable to build directory: {}", e); } } else { panic!("GTK executable not found at: {:?}", exe_path); } } fn get_target_dir() -> PathBuf { let out_dir = std::env::var("OUT_DIR").unwrap(); let out_dir_path = PathBuf::from_str(&out_dir).unwrap(); out_dir_path .parent() .unwrap() .parent() .unwrap() .parent() .unwrap() .to_path_buf() }