From 909fa564bc3b7f14cb4fcdb283f40be95a218ca3 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 11 Dec 2024 16:55:25 +0000 Subject: [PATCH] chore(ffi): avoid hardcoding clang version Update the workaround for https://github.com/rust-lang/rust/issues/109717 to avoid hardcoding the clang version; instead, run `clang -dumpversion` to figure it out. While we're there, use the `CC_x86_64-linux-android` env var, which should point to clang, rather than relying on `ANDROID_NDK_HOME` to be set. --- bindings/matrix-sdk-crypto-ffi/build.rs | 53 +++++++++++++++++-------- bindings/matrix-sdk-ffi/build.rs | 53 +++++++++++++++++-------- 2 files changed, 72 insertions(+), 34 deletions(-) diff --git a/bindings/matrix-sdk-crypto-ffi/build.rs b/bindings/matrix-sdk-crypto-ffi/build.rs index e66920150e3..14f2d11e10b 100644 --- a/bindings/matrix-sdk-crypto-ffi/build.rs +++ b/bindings/matrix-sdk-crypto-ffi/build.rs @@ -1,10 +1,10 @@ -use std::{env, error::Error}; +use std::{env, error::Error, path::PathBuf, process::Command}; use vergen::EmitBuilder; /// Adds a temporary workaround for an issue with the Rust compiler and Android /// in x86_64 devices: https://github.com/rust-lang/rust/issues/109717. -/// The workaround comes from: https://github.com/mozilla/application-services/pull/5442 +/// The workaround is based on: https://github.com/mozilla/application-services/pull/5442 /// /// IMPORTANT: if you modify this, make sure to modify /// [../matrix-sdk-ffi/build.rs] too! @@ -12,26 +12,45 @@ fn setup_x86_64_android_workaround() { let target_os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS not set"); let target_arch = env::var("CARGO_CFG_TARGET_ARCH").expect("CARGO_CFG_TARGET_ARCH not set"); if target_arch == "x86_64" && target_os == "android" { - let android_ndk_home = env::var("ANDROID_NDK_HOME").expect("ANDROID_NDK_HOME not set"); - let build_os = match env::consts::OS { - "linux" => "linux", - "macos" => "darwin", - "windows" => "windows", - _ => panic!( - "Unsupported OS. You must use either Linux, MacOS or Windows to build the crate." - ), - }; - const DEFAULT_CLANG_VERSION: &str = "18"; - let clang_version = - env::var("NDK_CLANG_VERSION").unwrap_or_else(|_| DEFAULT_CLANG_VERSION.to_owned()); - let linux_x86_64_lib_dir = format!( - "toolchains/llvm/prebuilt/{build_os}-x86_64/lib/clang/{clang_version}/lib/linux/" + // Configure rust to statically link against the `libclang_rt.builtins` supplied + // with clang. + + // cargo-ndk sets CC_x86_64-linux-android to the path to `clang`, within the + // Android NDK. + let clang_path = PathBuf::from( + env::var("CC_x86_64-linux-android").expect("CC_x86_64-linux-android not set"), ); - println!("cargo:rustc-link-search={android_ndk_home}/{linux_x86_64_lib_dir}"); + + // clang_path should now look something like + // `.../sdk/ndk/28.0.12674087/toolchains/llvm/prebuilt/linux-x86_64/bin/clang`. + // We strip `/bin/clang` from the end to get the toolchain path. + let toolchain_path = clang_path + .ancestors() + .nth(2) + .expect("could not find NDK toolchain path") + .to_str() + .expect("NDK toolchain path is not valid UTF-8"); + + let clang_version = get_clang_major_version(&clang_path); + + println!("cargo:rustc-link-search={toolchain_path}/lib/clang/{clang_version}/lib/linux/"); println!("cargo:rustc-link-lib=static=clang_rt.builtins-x86_64-android"); } } +/// Run the clang binary at `clang_path`, and return its major version number +fn get_clang_major_version(clang_path: &PathBuf) -> String { + let clang_output = + Command::new(clang_path).arg("-dumpversion").output().expect("failed to start clang"); + + if !clang_output.status.success() { + panic!("failed to run clang: {}", String::from_utf8_lossy(&clang_output.stderr)); + } + + let clang_version = String::from_utf8(clang_output.stdout).expect("clang output is not utf8"); + clang_version.split('.').next().expect("could not parse clang output").to_owned() +} + fn main() -> Result<(), Box> { setup_x86_64_android_workaround(); diff --git a/bindings/matrix-sdk-ffi/build.rs b/bindings/matrix-sdk-ffi/build.rs index 30a6b178a9f..2605a8fe514 100644 --- a/bindings/matrix-sdk-ffi/build.rs +++ b/bindings/matrix-sdk-ffi/build.rs @@ -1,10 +1,10 @@ -use std::{env, error::Error}; +use std::{env, error::Error, path::PathBuf, process::Command}; use vergen::EmitBuilder; /// Adds a temporary workaround for an issue with the Rust compiler and Android /// in x86_64 devices: https://github.com/rust-lang/rust/issues/109717. -/// The workaround comes from: https://github.com/mozilla/application-services/pull/5442 +/// The workaround is based on: https://github.com/mozilla/application-services/pull/5442 /// /// IMPORTANT: if you modify this, make sure to modify /// [../matrix-sdk-crypto-ffi/build.rs] too! @@ -12,26 +12,45 @@ fn setup_x86_64_android_workaround() { let target_os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS not set"); let target_arch = env::var("CARGO_CFG_TARGET_ARCH").expect("CARGO_CFG_TARGET_ARCH not set"); if target_arch == "x86_64" && target_os == "android" { - let android_ndk_home = env::var("ANDROID_NDK_HOME").expect("ANDROID_NDK_HOME not set"); - let build_os = match env::consts::OS { - "linux" => "linux", - "macos" => "darwin", - "windows" => "windows", - _ => panic!( - "Unsupported OS. You must use either Linux, MacOS or Windows to build the crate." - ), - }; - const DEFAULT_CLANG_VERSION: &str = "18"; - let clang_version = - env::var("NDK_CLANG_VERSION").unwrap_or_else(|_| DEFAULT_CLANG_VERSION.to_owned()); - let linux_x86_64_lib_dir = format!( - "toolchains/llvm/prebuilt/{build_os}-x86_64/lib/clang/{clang_version}/lib/linux/" + // Configure rust to statically link against the `libclang_rt.builtins` supplied + // with clang. + + // cargo-ndk sets CC_x86_64-linux-android to the path to `clang`, within the + // Android NDK. + let clang_path = PathBuf::from( + env::var("CC_x86_64-linux-android").expect("CC_x86_64-linux-android not set"), ); - println!("cargo:rustc-link-search={android_ndk_home}/{linux_x86_64_lib_dir}"); + + // clang_path should now look something like + // `.../sdk/ndk/28.0.12674087/toolchains/llvm/prebuilt/linux-x86_64/bin/clang`. + // We strip `/bin/clang` from the end to get the toolchain path. + let toolchain_path = clang_path + .ancestors() + .nth(2) + .expect("could not find NDK toolchain path") + .to_str() + .expect("NDK toolchain path is not valid UTF-8"); + + let clang_version = get_clang_major_version(&clang_path); + + println!("cargo:rustc-link-search={toolchain_path}/lib/clang/{clang_version}/lib/linux/"); println!("cargo:rustc-link-lib=static=clang_rt.builtins-x86_64-android"); } } +/// Run the clang binary at `clang_path`, and return its major version number +fn get_clang_major_version(clang_path: &PathBuf) -> String { + let clang_output = + Command::new(clang_path).arg("-dumpversion").output().expect("failed to start clang"); + + if !clang_output.status.success() { + panic!("failed to run clang: {}", String::from_utf8_lossy(&clang_output.stderr)); + } + + let clang_version = String::from_utf8(clang_output.stdout).expect("clang output is not utf8"); + clang_version.split('.').next().expect("could not parse clang output").to_owned() +} + fn main() -> Result<(), Box> { setup_x86_64_android_workaround(); uniffi::generate_scaffolding("./src/api.udl").expect("Building the UDL file failed");