use std::process::Command;
fn main() {
#[cfg(target_os = "windows")]
{
let mut res = winres::WindowsResource::new();
res.set_icon("assets/icon.ico");
res.set("ProductName", "Transmutation");
res.set(
"FileDescription",
"High-performance document conversion engine for AI/LLM embeddings",
);
res.set("CompanyName", "HiveLLM Team");
res.set("LegalCopyright", "Copyright (c) 2025 HiveLLM Team");
res.set("OriginalFilename", "transmutation.exe");
if let Err(e) = res.compile() {
eprintln!("Warning: Failed to compile Windows resources: {e}");
}
}
check_external_dependencies();
#[cfg(feature = "docling-ffi")]
{
println!("cargo:rerun-if-changed=cpp/docling_ffi.cpp");
println!("cargo:rerun-if-changed=cpp/docling_ffi.h");
println!("cargo:rerun-if-changed=cpp/CMakeLists.txt");
#[cfg(target_os = "windows")]
{
use std::path::Path;
let arch = if cfg!(target_arch = "x86_64") {
"x86"
} else {
"ARM"
};
let build_dir = format!("build_windows_{arch}");
let lib_path_str = format!("{build_dir}/Release/docling_ffi.lib");
let libs_path_str = format!("libs/docling-ffi-windows_{arch}.lib");
let lib_path = Path::new(&lib_path_str);
let libs_path = Path::new(&libs_path_str);
if !lib_path.exists() && !libs_path.exists() {
eprintln!("========================================");
eprintln!("ERROR: docling_ffi.lib not found!");
eprintln!("========================================");
eprintln!("Please run: .\\build_cpp.ps1");
eprintln!("This will build the C++ library for Windows.");
eprintln!("Or use WSL for full functionality:");
eprintln!(
" wsl -d Ubuntu-24.04 -- bash -c 'cd /mnt/f/Node/hivellm/transmutation && ./build_cpp.sh'"
);
eprintln!("========================================");
panic!("C++ library not built");
}
println!("cargo:rustc-link-search=native=libs");
println!("cargo:rustc-link-search=native={build_dir}/Release");
println!(
"cargo:rustc-link-search=native=docling-parse/build_windows_{arch}_docling/Release"
);
println!("cargo:rustc-link-lib=dylib=docling_ffi");
let dll_libs_path = format!("libs/docling-ffi-windows_{arch}.dll");
let dll_build_path = format!("{build_dir}/Release/docling_ffi.dll");
let dll_src_str = if Path::new(&dll_libs_path).exists() {
dll_libs_path
} else {
dll_build_path
};
let dll_src = Path::new(&dll_src_str);
let target_dir = std::env::var("OUT_DIR").unwrap();
let dll_dst = Path::new(&target_dir).join("../../../docling_ffi.dll");
if dll_src.exists() {
let _ = std::fs::copy(dll_src, dll_dst);
}
}
#[cfg(target_os = "linux")]
{
let arch = if cfg!(target_arch = "x86_64") {
"x86"
} else if cfg!(target_arch = "aarch64") {
"ARM"
} else {
"x86"
};
let build_dir = format!("build_linux_{arch}");
println!("cargo:rustc-link-search=native=libs"); println!("cargo:rustc-link-search=native={build_dir}");
println!("cargo:rustc-link-search=native=cpp/build"); println!("cargo:rustc-link-search=native=docling-parse/build_linux_{arch}_docling");
println!("cargo:rustc-link-lib=dylib=docling_ffi");
println!("cargo:rustc-link-arg=-Wl,-rpath,$ORIGIN");
println!("cargo:rustc-link-arg=-Wl,-rpath,$ORIGIN/../libs");
println!("cargo:rustc-link-arg=-Wl,-rpath,$ORIGIN/../{build_dir}");
}
#[cfg(target_os = "macos")]
{
let arch = if cfg!(target_arch = "x86_64") {
"x86"
} else if cfg!(target_arch = "aarch64") {
"ARM"
} else {
"ARM"
}; let build_dir = format!("build_macos_{arch}");
println!("cargo:rustc-link-search=native=libs");
println!("cargo:rustc-link-search=native={build_dir}");
println!("cargo:rustc-link-search=native=cpp/build"); println!("cargo:rustc-link-search=native=docling-parse/build_macos_{arch}_docling");
println!("cargo:rustc-link-lib=dylib=docling_ffi");
println!("cargo:rustc-link-arg=-Wl,-rpath,@loader_path");
println!("cargo:rustc-link-arg=-Wl,-rpath,@loader_path/../libs");
println!("cargo:rustc-link-arg=-Wl,-rpath,@loader_path/../{build_dir}");
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
{
println!("cargo:rustc-link-lib=dylib=stdc++");
}
}
}
fn check_external_dependencies() {
#[allow(unused_mut)]
let mut warnings: Vec<(&str, &str, String)> = Vec::new();
#[cfg(feature = "pdf-to-image")]
{
if !command_exists("pdftoppm") {
warnings.push((
"pdftoppm (poppler-utils)",
"PDF → Image conversion",
get_install_command("poppler-utils"),
));
}
}
#[cfg(all(feature = "office", feature = "pdf-to-image"))]
{
if !command_exists("libreoffice") && !command_exists("soffice") {
warnings.push((
"LibreOffice",
"DOCX/PPTX → Image conversion",
get_install_command("libreoffice"),
));
}
}
#[cfg(feature = "tesseract")]
{
if !command_exists("tesseract") {
warnings.push((
"Tesseract OCR",
"Image → Text (OCR)",
get_install_command("tesseract"),
));
}
}
#[cfg(any(feature = "audio", feature = "video"))]
{
if !command_exists("ffmpeg") {
warnings.push((
"FFmpeg",
"Audio/Video processing",
get_install_command("ffmpeg"),
));
}
}
if !warnings.is_empty() {
eprintln!();
eprintln!("╔════════════════════════════════════════════════════════════╗");
eprintln!("║ ⚠️ Optional External Dependencies Missing ║");
eprintln!("╚════════════════════════════════════════════════════════════╝");
eprintln!();
eprintln!("Transmutation will compile, but some features won't work:");
eprintln!();
for (tool, feature, install_cmd) in &warnings {
eprintln!(" ❌ {tool}: {feature}");
eprintln!(" Install: {install_cmd}");
}
eprintln!();
eprintln!("📖 For detailed installation instructions:");
eprintln!(" https://github.com/yourusername/transmutation/blob/main/install/README.md");
eprintln!();
eprintln!("💡 Quick install (all dependencies):");
eprintln!("{}", get_quick_install_all());
eprintln!();
}
}
#[allow(dead_code)]
fn command_exists(cmd: &str) -> bool {
Command::new(if cfg!(target_os = "windows") {
"where"
} else {
"which"
})
.arg(cmd)
.output()
.map(|output| output.status.success())
.unwrap_or(false)
}
#[allow(dead_code)]
fn get_install_command(tool: &str) -> String {
#[cfg(target_os = "linux")]
{
match tool {
"poppler-utils" => "sudo apt-get install poppler-utils".to_string(),
"libreoffice" => "sudo apt-get install libreoffice".to_string(),
"tesseract" => "sudo apt-get install tesseract-ocr".to_string(),
"ffmpeg" => "sudo apt-get install ffmpeg".to_string(),
_ => format!("sudo apt-get install {tool}"),
}
}
#[cfg(target_os = "macos")]
{
match tool {
"poppler-utils" => "brew install poppler".to_string(),
"libreoffice" => "brew install --cask libreoffice".to_string(),
"tesseract" => "brew install tesseract".to_string(),
"ffmpeg" => "brew install ffmpeg".to_string(),
_ => format!("brew install {tool}"),
}
}
#[cfg(target_os = "windows")]
{
match tool {
"poppler-utils" => "choco install poppler".to_string(),
"libreoffice" => "choco install libreoffice".to_string(),
"tesseract" => "choco install tesseract".to_string(),
"ffmpeg" => "choco install ffmpeg".to_string(),
_ => format!("choco install {tool}"),
}
}
}
fn get_quick_install_all() -> &'static str {
#[cfg(target_os = "linux")]
{
" ./install/install-deps-linux.sh"
}
#[cfg(target_os = "macos")]
{
" ./install/install-deps-macos.sh"
}
#[cfg(target_os = "windows")]
{
" .\\install\\install-deps-windows.ps1 (or .bat)"
}
}