Lightningbeam/lightningbeam-ui/lightningbeam-editor/build.rs

207 lines
6.7 KiB
Rust

use std::env;
use std::fs;
use std::path::PathBuf;
fn main() {
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
// Copy factory instrument presets next to the binary (works on all platforms)
bundle_factory_presets();
if target_os == "windows" {
bundle_windows_dlls();
}
if target_os != "linux" {
return;
}
// Skip bundling if using static FFmpeg linking
if env::var("PKG_CONFIG_ALL_STATIC").is_ok() || env::var("FFMPEG_STATIC").is_ok() {
println!("cargo:warning=Skipping FFmpeg library bundling (static linking enabled)");
return;
}
// Get the output directory
let out_dir = env::var("OUT_DIR").unwrap();
let target_dir = PathBuf::from(&out_dir)
.parent().unwrap()
.parent().unwrap()
.parent().unwrap()
.to_path_buf();
// Create lib directory in target
let lib_dir = target_dir.join("lib");
fs::create_dir_all(&lib_dir).ok();
println!("cargo:warning=Bundling FFmpeg libraries to {:?}", lib_dir);
// List of FFmpeg 8.x libraries to bundle
let ffmpeg_libs = [
"libavcodec.so.62",
"libavdevice.so.62",
"libavfilter.so.11",
"libavformat.so.62",
"libavutil.so.60",
"libpostproc.so.57", // Actually version 57 in Ubuntu 24.04
"libswresample.so.6", // Actually version 6
"libswscale.so.9",
];
let lib_search_paths = [
"/usr/lib/x86_64-linux-gnu",
"/usr/lib64",
"/usr/lib",
];
// Copy FFmpeg libraries
for lib_name in &ffmpeg_libs {
copy_library(lib_name, &lib_search_paths, &lib_dir);
}
// Also bundle all FFmpeg codec dependencies to avoid version mismatches
let codec_libs = [
// Codec libraries
"libaom.so.3", "libdav1d.so.7", "librav1e.so.0", "libSvtAv1Enc.so.1",
"libvpx.so.9", "libx264.so.164", "libx265.so.199",
"libopus.so.0", "libvorbis.so.0", "libvorbisenc.so.2", "libmp3lame.so.0",
"libtheora.so.0", "libtheoraenc.so.1", "libtheoradec.so.1",
"libtwolame.so.0", "libspeex.so.1", "libshine.so.3",
"libwebp.so.7", "libwebpmux.so.3", "libjxl.so.0.7", "libjxl_threads.so.0.7",
// Container/protocol libraries
"librabbitmq.so.4", "librist.so.4", "libsrt-gnutls.so.1.5", "libzmq.so.5",
"libbluray.so.2", "libdvdnav.so.4", "libdvdread.so.8",
// Other dependencies
"libaribb24.so.0", "libcodec2.so.1.2", "libgsm.so.1",
"libopencore-amrnb.so.0", "libopencore-amrwb.so.0",
"libvo-amrwbenc.so.0", "libfdk-aac.so.2", "libilbc.so.3",
"libopenjp2.so.7", "libsnappy.so.1", "libvvenc.so.1.12",
];
for lib_name in &codec_libs {
copy_library(lib_name, &lib_search_paths, &lib_dir);
}
// Set rpath to look in ./lib and $ORIGIN/lib
println!("cargo:rustc-link-arg=-Wl,-rpath,$ORIGIN/lib");
println!("cargo:rustc-link-arg=-Wl,-rpath,{}", lib_dir.display());
}
fn bundle_windows_dlls() {
let ffmpeg_dir = match env::var("FFMPEG_DIR") {
Ok(dir) => PathBuf::from(dir),
Err(_) => return,
};
let bin_dir = ffmpeg_dir.join("bin");
if !bin_dir.exists() {
println!("cargo:warning=FFMPEG_DIR/bin not found, skipping DLL bundling");
return;
}
let out_dir = env::var("OUT_DIR").unwrap();
let target_dir = PathBuf::from(&out_dir)
.parent().unwrap()
.parent().unwrap()
.parent().unwrap()
.to_path_buf();
let dlls = [
"avcodec-62.dll",
"avdevice-62.dll",
"avfilter-11.dll",
"avformat-62.dll",
"avutil-60.dll",
"swresample-6.dll",
"swscale-9.dll",
];
for dll in &dlls {
let src = bin_dir.join(dll);
let dst = target_dir.join(dll);
if src.exists() {
if let Err(e) = fs::copy(&src, &dst) {
println!("cargo:warning=Failed to copy {}: {}", dll, e);
}
} else {
println!("cargo:warning=FFmpeg DLL not found: {}", src.display());
}
}
println!("cargo:warning=Bundled FFmpeg DLLs to {}", target_dir.display());
}
/// Copy factory instrument presets into target dir so they're next to the binary.
/// This makes them available for:
/// - Portable/AppImage builds (preset browser checks <exe>/presets/)
/// - Windows builds (same)
/// - cargo-deb/rpm packaging (assets reference target/release/presets/)
fn bundle_factory_presets() {
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let instruments_src = manifest_dir.join("../../src/assets/instruments");
let out_dir = env::var("OUT_DIR").unwrap();
let target_dir = PathBuf::from(&out_dir)
.parent().unwrap()
.parent().unwrap()
.parent().unwrap()
.to_path_buf();
let presets_dst = target_dir.join("presets");
if !instruments_src.exists() {
println!("cargo:warning=Factory instruments not found at {:?}, skipping", instruments_src);
return;
}
// Re-run if instruments change
println!("cargo:rerun-if-changed={}", instruments_src.display());
if let Err(e) = copy_dir_recursive(&instruments_src, &presets_dst) {
println!("cargo:warning=Failed to copy factory presets: {}", e);
}
}
/// Recursively copy a directory tree, preserving structure.
/// Only copies .json and .mp3 files (skips README.md, etc.)
fn copy_dir_recursive(src: &std::path::Path, dst: &std::path::Path) -> std::io::Result<()> {
fs::create_dir_all(dst)?;
for entry in fs::read_dir(src)? {
let entry = entry?;
let src_path = entry.path();
let dst_path = dst.join(entry.file_name());
if src_path.is_dir() {
copy_dir_recursive(&src_path, &dst_path)?;
} else if let Some(ext) = src_path.extension() {
let ext = ext.to_string_lossy().to_lowercase();
if ext == "json" || ext == "mp3" {
fs::copy(&src_path, &dst_path)?;
}
}
}
Ok(())
}
fn copy_library(lib_name: &str, search_paths: &[&str], lib_dir: &PathBuf) {
let mut copied = false;
for search_path in search_paths {
let src = PathBuf::from(search_path).join(lib_name);
if src.exists() {
let dst = lib_dir.join(lib_name);
if let Err(e) = fs::copy(&src, &dst) {
println!("cargo:warning=Failed to copy {}: {}", lib_name, e);
} else {
copied = true;
break;
}
}
}
if !copied {
// Don't warn for optional libraries
if !lib_name.contains("shine") && !lib_name.contains("fdk-aac") {
println!("cargo:warning=Could not find {} (optional)", lib_name);
}
}
}