| // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. |
| |
| use std::env; |
| use std::env::VarError; |
| use std::fs; |
| use std::io::Read; |
| use std::path::{Path, PathBuf}; |
| use walkdir::WalkDir; |
| |
| // Platform-Specific Instructions: Regenerating gRPC Bindings for Windows |
| |
| // If you need to manually update the 'android/grpc-bindings.rs' file on Windows, |
| // follow these steps: |
| |
| // 1. LLVM Setup |
| // - Download and install the pre-built LLVM binaries from: |
| // https://releases.llvm.org/download.html |
| // - Update the `LIBCLANG_PATH` environment variable to point to the 'bin' |
| // directory within your LLVM installation. (e.g., `C:\Program Files\LLVM\bin`) |
| |
| // 2. Environment Configuration |
| // - Set the `GRPCIO_SYS_GRPC_INCLUDE_PATH` environment variable to the |
| // location of your gRPC 'include' directory. |
| |
| // 3. Building the Bindings |
| // - Run the following Cargo command to regenerate the bindings: |
| // `cargo build --features _gen-bindings` |
| |
| include!("../link-deps.rs"); |
| |
| fn get_env(name: &str) -> Option<String> { |
| println!("cargo:rerun-if-env-changed={name}"); |
| match env::var(name) { |
| Ok(s) => Some(s), |
| Err(VarError::NotPresent) => None, |
| Err(VarError::NotUnicode(s)) => { |
| panic!("unrecognize env var of {name}: {:?}", s.to_string_lossy()); |
| } |
| } |
| } |
| |
| // Generate the bindings to grpc C-core. |
| // Try to disable the generation of platform-related bindings. |
| #[cfg(any( |
| feature = "_gen-bindings", |
| not(all( |
| any(target_os = "linux", target_os = "macos"), |
| any(target_arch = "x86_64", target_arch = "aarch64") |
| )) |
| ))] |
| fn bindgen_grpc(file_path: &Path) { |
| // create a config to generate binding file |
| let mut config = bindgen::Builder::default(); |
| if cfg!(feature = "_secure") { |
| config = config.clang_arg("-DGRPC_SYS_SECURE"); |
| } |
| |
| if get_env("CARGO_CFG_TARGET_OS").map_or(false, |s| s == "windows") { |
| config = config.clang_arg("-D _WIN32_WINNT=0x600"); |
| } |
| |
| // Search header files with API interface |
| let mut headers = Vec::new(); |
| for result in WalkDir::new(Path::new("./grpc/include")) { |
| let dent = result.expect("Error happened when search headers"); |
| if !dent.file_type().is_file() { |
| continue; |
| } |
| let mut file = fs::File::open(dent.path()).expect("couldn't open headers"); |
| let mut buf = String::new(); |
| file.read_to_string(&mut buf) |
| .expect("Coundn't read header content"); |
| if buf.contains("GRPCAPI") || buf.contains("GPRAPI") { |
| headers.push(String::from(dent.path().to_str().unwrap())); |
| } |
| } |
| |
| // To control the order of bindings |
| headers.sort(); |
| for path in headers { |
| config = config.header(path); |
| } |
| |
| println!("cargo:rerun-if-env-changed=TEST_BIND"); |
| let gen_tests = env::var("TEST_BIND").map_or(false, |s| s == "1"); |
| |
| let cfg = config |
| .header("grpc_wrap.cc") |
| .clang_arg("-xc++") |
| .clang_arg("-I./grpc/include") |
| .clang_arg("-std=c++11") |
| .rustfmt_bindings(true) |
| .impl_debug(true) |
| .size_t_is_usize(true) |
| .disable_header_comment() |
| .allowlist_function(r"\bgrpc_.*") |
| .allowlist_function(r"\bgpr_.*") |
| .allowlist_function(r"\bgrpcwrap_.*") |
| .allowlist_var(r"\bGRPC_.*") |
| .allowlist_type(r"\bgrpc_.*") |
| .allowlist_type(r"\bgpr_.*") |
| .allowlist_type(r"\bgrpcwrap_.*") |
| .allowlist_type(r"\bcensus_context.*") |
| .allowlist_type(r"\bverify_peer_options.*") |
| // Block all system headers. |
| .blocklist_file(r"^/.*") |
| .blocklist_function(r"\bgpr_mu_.*") |
| .blocklist_function(r"\bgpr_cv_.*") |
| .blocklist_function(r"\bgpr_once_.*") |
| .blocklist_type(r"gpr_mu") |
| .blocklist_type(r"gpr_cv") |
| .blocklist_type(r"gpr_once") |
| .constified_enum_module(r"grpc_status_code") |
| .layout_tests(gen_tests) |
| .default_enum_style(bindgen::EnumVariation::Rust { |
| non_exhaustive: false, |
| }); |
| println!("running {}", cfg.command_line_flags().join(" ")); |
| cfg.generate() |
| .expect("Unable to generate grpc bindings") |
| .write_to_file(file_path) |
| .expect("Couldn't write bindings!"); |
| } |
| |
| // Determine if need to update bindings. Supported platforms do not |
| // need to be updated by default unless the _gen-bindings feature is specified. |
| fn config_binding_path() { |
| let target = env::var("TARGET").unwrap(); |
| let file_path: PathBuf = match target.as_str() { |
| "x86_64-unknown-linux-gnu" |
| | "x86_64-unknown-linux-musl" |
| | "aarch64-unknown-linux-musl" |
| | "aarch64-unknown-linux-gnu" |
| | "x86_64-apple-darwin" |
| | "aarch64-apple-darwin" => { |
| // Cargo treats nonexistent files changed, so we only emit the rerun-if-changed |
| // directive when we expect the target-specific pre-generated binding file to be |
| // present. |
| println!("cargo:rerun-if-changed=bindings/bindings.rs"); |
| |
| PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) |
| .join("bindings") |
| .join("bindings.rs") |
| } |
| _ => PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) |
| .join("android") |
| .join("grpc-bindings.rs"), |
| }; |
| #[cfg(feature = "_gen-bindings")] |
| { |
| // On some system (like Windows), stack size of main thread may |
| // be too small. |
| let f = file_path.clone(); |
| std::thread::Builder::new() |
| .stack_size(8 * 1024 * 1024) |
| .name("bindgen_grpc".to_string()) |
| .spawn(move || bindgen_grpc(&f)) |
| .unwrap() |
| .join() |
| .unwrap(); |
| } |
| |
| println!( |
| "cargo:rustc-env=BINDING_PATH={}", |
| file_path.to_str().unwrap() |
| ); |
| } |
| |
| fn main() { |
| println!("cargo:rerun-if-changed=grpc_wrap.cc"); |
| println!("cargo:rerun-if-changed=grpc"); |
| |
| // create a builder to compile grpc_wrap.cc |
| let mut cc = cc::Build::new(); |
| |
| if get_env("CARGO_CFG_TARGET_OS").map_or(false, |s| s == "windows") { |
| // At lease vista |
| cc.define("_WIN32_WINNT", Some("0x600")); |
| } |
| |
| let mut include_paths: Vec<PathBuf> = Vec::new(); |
| let include_path = get_env("GRPCIO_SYS_GRPC_INCLUDE_PATH"); |
| if include_path.is_none() { |
| panic!("$GRPCIO_SYS_GRPC_INCLUDE_PATH is not set"); |
| } |
| include_paths.push(include_path.unwrap().into()); |
| for inc_path in include_paths { |
| cc.include(inc_path); |
| } |
| |
| cc.cpp(true); |
| cc.file("grpc_wrap.cc"); |
| cc.warnings_into_errors(true); |
| cc.compile("libgrpc_wrap.a"); |
| |
| config_binding_path(); |
| } |