diff --git a/.changeset/add_cpp_bindgen_command.md b/.changeset/add_cpp_bindgen_command.md new file mode 100644 index 000000000..3764ec6f3 --- /dev/null +++ b/.changeset/add_cpp_bindgen_command.md @@ -0,0 +1,5 @@ +--- +livekit-ffi: patch +--- + +Add a workspace-owned command for generating C++ bindings from `livekit-ffi` with the pinned LiveKit UniFFI C++ generator. diff --git a/tools/bindgens/Cargo.toml b/tools/bindgens/Cargo.toml index 592a91066..978fea2b1 100644 --- a/tools/bindgens/Cargo.toml +++ b/tools/bindgens/Cargo.toml @@ -7,9 +7,8 @@ repository.workspace = true description = "Foreign-binding generator CLIs for the LiveKit Rust crates" publish = false -# Tooling crate: each bin is a code-generation CLI shared across the workspace's -# uniffi-exposing crates (livekit-ffi, livekit-uniffi, ...). It has no library -# target — the bindgens read metadata from an already-compiled cdylib via -# `--library`, so they never depend on the crates they generate for. +# Tooling crate: each bin is a code-generation CLI shared across the workspace. +# The bindgens read metadata from an already-compiled cdylib via `--library`, so +# they never depend on the crates they generate for. [dependencies] uniffi = { workspace = true, features = ["cli"] } diff --git a/tools/bindgens/src/bin/uniffi-bindgen-cpp.rs b/tools/bindgens/src/bin/uniffi-bindgen-cpp.rs new file mode 100644 index 000000000..19950551d --- /dev/null +++ b/tools/bindgens/src/bin/uniffi-bindgen-cpp.rs @@ -0,0 +1,85 @@ +// Copyright 2026 LiveKit, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! The pinned UniFFI C++ bindgen CLI used by LiveKit SDK consumers. +//! +//! The C++ generator is a binary-only crate, so this workspace command installs +//! the pinned revision into the workspace target directory and forwards all +//! arguments to it. Generate C++ bindings from `livekit-ffi`, for example: +//! `cargo run -p bindgens --bin uniffi-bindgen-cpp -- \ +//! --library target/debug/liblivekit_ffi.dylib --out-dir ` + +use std::{ + env, + path::{Path, PathBuf}, + process::{Command, ExitCode}, +}; + +const REPOSITORY: &str = "https://github.com/alan-george-lk/uniffi-bindgen-cpp.git"; +const REVISION: &str = "7d54c1c56e0e4c46772ef4c2b5be3cb26396cbdb"; + +fn main() -> ExitCode { + match run() { + Ok(code) => code, + Err(error) => { + eprintln!("uniffi-bindgen-cpp: {error}"); + ExitCode::FAILURE + } + } +} + +fn run() -> Result { + let install_root = install_root(); + let executable = + install_root.join("bin").join(format!("uniffi-bindgen-cpp{}", env::consts::EXE_SUFFIX)); + + if !executable.is_file() { + install(&install_root)?; + } + + let status = Command::new(&executable) + .args(env::args_os().skip(1)) + .status() + .map_err(|error| format!("failed to run {}: {error}", executable.display()))?; + + match status.code() { + Some(code) if (0..=u8::MAX as i32).contains(&code) => Ok(ExitCode::from(code as u8)), + Some(code) => Err(format!("generator exited with unsupported status {code}")), + None => Err("generator terminated without an exit status".to_owned()), + } +} + +fn install_root() -> PathBuf { + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("../..") + .join("target") + .join("uniffi-bindgen-cpp") + .join(REVISION) +} + +fn install(install_root: &Path) -> Result<(), String> { + let cargo = env::var_os("CARGO").unwrap_or_else(|| "cargo".into()); + let status = Command::new(cargo) + .args(["install", "--locked", "--git", REPOSITORY, "--rev", REVISION, "--root"]) + .arg(install_root) + .arg("uniffi-bindgen-cpp") + .status() + .map_err(|error| format!("failed to install pinned C++ generator: {error}"))?; + + if status.success() { + Ok(()) + } else { + Err(format!("installing pinned C++ generator failed with {status}")) + } +}