Auxio/musikr/src/main/jni/build.rs
Alexander Capehart 774b2a90bb
musikr: cleanup
2025-02-19 14:16:47 -07:00

158 lines
5.2 KiB
Rust

use cxx_build;
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::error::Error;
fn build_taglib(target: &str, working_dir: &Path) -> Result<PathBuf, Box<dyn Error>> {
let taglib_src_dir = working_dir.join("taglib");
let taglib_build_dir = taglib_src_dir.join("build");
let taglib_pkg_dir = taglib_src_dir.join("pkg");
let arch_build_dir = taglib_build_dir.join(&target);
let arch_pkg_dir = taglib_pkg_dir.join(&target);
// If lib/libtag.a exists, we don't need to build it
if arch_pkg_dir.join("lib/libtag.a").exists() {
return Ok(arch_pkg_dir);
}
// Prepare basic cmake arguments
let mut cmake_args = vec![
"-B".to_string(),
arch_build_dir.to_str().unwrap().to_string(),
"-DBUILD_SHARED_LIBS=OFF".to_string(),
"-DVISIBILITY_HIDDEN=ON".to_string(),
"-DBUILD_TESTING=OFF".to_string(),
"-DBUILD_EXAMPLES=OFF".to_string(),
"-DBUILD_BINDINGS=OFF".to_string(),
"-DWITH_ZLIB=OFF".to_string(),
"-DCMAKE_BUILD_TYPE=Release".to_string(),
"-DCMAKE_CXX_FLAGS=-fPIC".to_string(),
];
if target.contains("android") {
// Android target, we need to tack on the NDK toolchain file/args
let arch = if target == "x86_64-linux-android" {
"x86_64"
} else if target.contains("i686-linux-android") {
"x86"
} else if target.contains("aarch64-linux-android") {
"arm64-v8a"
} else if target.contains("armv7-linux-androideabi") {
"armeabi-v7a"
} else {
// should never happen
return Err(format!("Unsupported Android target: {}", target).into());
};
let clang_path = env::var("CLANG_PATH").expect("CLANG_PATH env var not set");
let toolchains_marker = "/toolchains";
let ndk_path = if let Some(pos) = clang_path.find(toolchains_marker) {
&clang_path[..pos]
} else {
return Err(format!("CLANG_PATH does not contain '{}'", toolchains_marker).into());
};
let ndk_toolchain = working_dir.join("android.toolchain.cmake");
cmake_args.extend(vec![
format!("-DANDROID_NDK_PATH={}", ndk_path),
format!("-DCMAKE_TOOLCHAIN_FILE={}", ndk_toolchain.to_str().unwrap()),
format!("-DANDROID_ABI={}", arch),
]);
}
// Configure step
let status = Command::new("cmake")
.args(&cmake_args)
.current_dir(&taglib_src_dir)
.status()?;
if !status.success() {
return Err(format!("cmake configure failed for target {}", target).into());
}
// Build step
let status = Command::new("cmake")
.arg("--build")
.arg(arch_build_dir.to_str().unwrap())
.arg("--config")
.arg("Release")
.arg(format!(
"-j{}",
std::thread::available_parallelism().unwrap().get()
))
.status()?;
if !status.success() {
return Err(format!("cmake build failed for target {}", target).into());
}
// Install step
let status = Command::new("cmake")
.arg("--install")
.arg(arch_build_dir.to_str().unwrap())
.arg("--config")
.arg("Release")
.arg("--prefix")
.arg(arch_pkg_dir.to_str().unwrap())
.arg("--strip")
.status()?;
if !status.success() {
return Err(format!("cmake install failed for arch {}", target).into());
}
Ok(arch_pkg_dir)
}
fn configure_cxx_bridge(target: &str) -> Result<(), Box<dyn Error>> {
let mut builder = cxx_build::bridge("src/taglib/bridge.rs");
builder
.file("shim/iostream_shim.cpp")
.file("shim/file_shim.cpp")
.file("shim/tk_shim.cpp")
.file("shim/picture_shim.cpp")
.file("shim/xiph_shim.cpp")
.file("shim/id3v1_shim.cpp")
.file("shim/id3v2_shim.cpp")
.file("shim/mp4_shim.cpp")
.include(format!("taglib/pkg/{}/include", target))
.include(".")
.flag_if_supported("-std=c++14");
if target.contains("android") {
builder
.cpp_link_stdlib("c++_static")
// Magic linker flags that statically link exception handling symbols
// to the library.
.flag("-fexceptions")
.flag("-funwind-tables");
}
builder.compile("taglib_cxx_bindings");
Ok(())
}
fn main() -> Result<(), Box<dyn Error>> {
let working_dir = env::current_dir()?;
let target = env::var("TARGET")?;
let working_dir = Path::new(&working_dir);
let arch_pkg_dir = build_taglib(&target, &working_dir)?;
println!(
"cargo:rustc-link-search=native={}/lib",
arch_pkg_dir.display()
);
println!("cargo:rustc-link-lib=static=tag");
println!("cargo:rerun-if-changed=taglib/");
configure_cxx_bridge(&target)?;
if target.contains("android") {
// Magic linker flags that statically link the C++ runtime
// and exception handling to the library.
println!("cargo:rustc-link-lib=static=c++_static");
println!("cargo:rustc-link-lib=static=c++abi");
println!("cargo:rustc-link-lib=unwind");
}
println!("cargo:rerun-if-changed=shim/");
Ok(())
}