diff --git a/Cargo.lock b/Cargo.lock index 6eadf89bc..ea91d0c0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1721,12 +1721,12 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-targets 0.52.0", + "windows-link", ] [[package]] @@ -1854,6 +1854,7 @@ dependencies = [ "imgproc", "jni", "lazy_static", + "libloading", "livekit", "livekit-api", "livekit-protocol", diff --git a/livekit-ffi/Cargo.toml b/livekit-ffi/Cargo.toml index 1dd3be0b9..4d3d5d779 100644 --- a/livekit-ffi/Cargo.toml +++ b/livekit-ffi/Cargo.toml @@ -45,6 +45,7 @@ prost-build = "0.14.1" webrtc-sys-build = { workspace = true } [dev-dependencies] +libloading = "0.8.9" livekit-api = { workspace = true } [lib] diff --git a/livekit-ffi/build.rs b/livekit-ffi/build.rs index b8add70f2..96eb735a3 100644 --- a/livekit-ffi/build.rs +++ b/livekit-ffi/build.rs @@ -12,7 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{env, path::Path}; +use std::{ + env, + path::{Path, PathBuf}, +}; const PROTO_SRC_DIR: &str = "protocol"; @@ -23,6 +26,7 @@ fn main() { download_webrtc(); copy_webrtc_license(); configure_linker(); + get_lib_path(); generate_protobuf(); } @@ -61,6 +65,30 @@ fn configure_linker() { } } +/// Get the path of the built library in the target directory, used for integration testing. +fn get_lib_path() { + let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap()); + let target_dir = out_dir.ancestors().nth(4).expect("Failed to find target directory"); + + let build_profile = env::var("PROFILE").unwrap(); + let output_dir = target_dir.join(build_profile); + + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + let lib_extension = match target_os.as_str() { + "windows" => "dll", + "linux" | "android" => "so", + "macos" => "dylib", + "ios" => "a", + _ => { + panic!("Unsupported target, {}", target_os); + } + }; + let crate_name = env::var("CARGO_PKG_NAME").unwrap(); + let lib_name = format!("lib{}.{}", crate_name.replace("-", "_"), lib_extension); + let lib_path = output_dir.join(lib_name); + println!("cargo::rustc-env=FFI_LIB_PATH={}", lib_path.display()); +} + fn generate_protobuf() { let paths: Vec<_> = std::fs::read_dir(PROTO_SRC_DIR) .expect("Failed to read protobuf source directory") diff --git a/livekit-ffi/tests/lib_load_test.rs b/livekit-ffi/tests/lib_load_test.rs new file mode 100644 index 000000000..e34c1e665 --- /dev/null +++ b/livekit-ffi/tests/lib_load_test.rs @@ -0,0 +1,39 @@ +use libloading::{Library, Symbol}; +use std::{path::Path, process::Command}; + +const FFI_LIB_PATH: &str = env!("FFI_LIB_PATH"); // Set by build.rs + +const EXPECTED_SYMBOLS: &[&str] = &[ + "livekit_ffi_initialize", + "livekit_ffi_request", + "livekit_ffi_drop_handle", + "livekit_ffi_dispose", +]; + +#[test] +fn lib_load_test() { + println!("Library path: {}", FFI_LIB_PATH); + build_lib_if_required(); + unsafe { + let lib = Library::new(FFI_LIB_PATH).expect("Unable to load library"); + for symbol in EXPECTED_SYMBOLS { + let _loaded_symbol: Symbol u32> = + lib.get(symbol.as_bytes()).expect(&format!("Missing symbol: {}", symbol)); + } + } +} + +fn build_lib_if_required() { + let path = Path::new(FFI_LIB_PATH); + if !path.try_exists().unwrap() { + println!("Library not found, building…"); + let status = Command::new("cargo") + .args(&["build", "--lib"]) + .status() + .expect("Failed to run cargo build for test"); + + if !status.success() || !path.try_exists().unwrap() { + panic!("Failed to build lib to run test"); + } + } +}