diff options
author | Jeff Vander Stoep <jeffv@google.com> | 2020-10-14 15:35:59 +0200 |
---|---|---|
committer | Jeff Vander Stoep <jeffv@google.com> | 2020-10-14 15:44:30 +0200 |
commit | 3adfea8b276f06db63ae4182233560537aca2ffb (patch) | |
tree | a543e650c0d9b57239020605562e73d35f9db409 /build.rs | |
parent | e028ffbabf8620351ce637bb48a8bb539c753c38 (diff) | |
download | grpcio-sys-3adfea8b276f06db63ae4182233560537aca2ffb.tar.gz |
Import grpcio-sys 0.6.0
And add metadata files using the following command:
get_rust_pkg.py --add3prf -v grpcio-sys-0.6.0 -o grpcio-sys
Use LICENSE file from parent grpcio crate. Add README.android
as requested during security review.
Test: None
Change-Id: Ib5f5c2af6f51d50c536cc4b6979666d480a57041
Diffstat (limited to 'build.rs')
-rw-r--r-- | build.rs | 407 |
1 files changed, 407 insertions, 0 deletions
diff --git a/build.rs b/build.rs new file mode 100644 index 00000000..b5f34eab --- /dev/null +++ b/build.rs @@ -0,0 +1,407 @@ +// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. + +use std::env::VarError; +use std::io::prelude::*; +use std::io::BufReader; +use std::path::{Path, PathBuf}; +use std::{env, fs, io}; + +use cmake::Config as CmakeConfig; +use pkg_config::{Config as PkgConfig, Library}; +use walkdir::WalkDir; + +const GRPC_VERSION: &str = "1.29.1"; + +fn probe_library(library: &str, cargo_metadata: bool) -> Library { + match PkgConfig::new() + .atleast_version(GRPC_VERSION) + .cargo_metadata(cargo_metadata) + .probe(library) + { + Ok(lib) => lib, + Err(e) => panic!("can't find library {} via pkg-config: {:?}", library, e), + } +} + +fn prepare_grpc() { + let mut modules = vec![ + "grpc", + "grpc/third_party/cares/cares", + "grpc/third_party/address_sorting", + "grpc/third_party/abseil-cpp", + ]; + + if cfg!(feature = "secure") && !cfg!(feature = "openssl") { + modules.push("grpc/third_party/boringssl-with-bazel"); + } + + for module in modules { + if is_directory_empty(module).unwrap_or(true) { + panic!( + "Can't find module {}. You need to run `git submodule \ + update --init --recursive` first to build the project.", + module + ); + } + } +} + +fn is_directory_empty<P: AsRef<Path>>(p: P) -> Result<bool, io::Error> { + let mut entries = fs::read_dir(p)?; + Ok(entries.next().is_none()) +} + +fn trim_start<'a>(s: &'a str, prefix: &str) -> Option<&'a str> { + if s.starts_with(prefix) { + Some(s.trim_start_matches(prefix)) + } else { + None + } +} + +fn build_grpc(cc: &mut cc::Build, library: &str) { + prepare_grpc(); + + let mut third_party = vec![ + "cares/cares/lib", + "abseil-cpp/absl/strings", + "abseil-cpp/absl/time", + "abseil-cpp/absl/base", + "abseil-cpp/absl/types", + "abseil-cpp/absl/numeric", + ]; + + let dst = { + let mut config = CmakeConfig::new("grpc"); + + if get_env("CARGO_CFG_TARGET_OS").map_or(false, |s| s == "macos") { + config.cxxflag("-stdlib=libc++"); + } + + // Ensure CoreFoundation be found in macos or ios + if get_env("CARGO_CFG_TARGET_OS").map_or(false, |s| s == "macos") + || get_env("CARGO_CFG_TARGET_OS").map_or(false, |s| s == "ios") + { + println!("cargo:rustc-link-lib=framework=CoreFoundation"); + } + + if env::var("CARGO_CFG_TARGET_ENV").unwrap() == "musl" { + config.define("CMAKE_CXX_COMPILER", "g++"); + } + + // Cross-compile support for iOS + match env::var("TARGET").unwrap().as_str() { + "aarch64-apple-ios" => { + config + .define("CMAKE_OSX_SYSROOT", "iphoneos") + .define("CMAKE_OSX_ARCHITECTURES", "arm64"); + } + "armv7-apple-ios" => { + config + .define("CMAKE_OSX_SYSROOT", "iphoneos") + .define("CMAKE_OSX_ARCHITECTURES", "armv7"); + } + "armv7s-apple-ios" => { + config + .define("CMAKE_OSX_SYSROOT", "iphoneos") + .define("CMAKE_OSX_ARCHITECTURES", "armv7s"); + } + "i386-apple-ios" => { + config + .define("CMAKE_OSX_SYSROOT", "iphonesimulator") + .define("CMAKE_OSX_ARCHITECTURES", "i386"); + } + "x86_64-apple-ios" => { + config + .define("CMAKE_OSX_SYSROOT", "iphonesimulator") + .define("CMAKE_OSX_ARCHITECTURES", "x86_64"); + } + _ => {} + }; + + // Allow overriding of the target passed to cmake + // (needed for Android crosscompile) + if let Ok(val) = env::var("CMAKE_TARGET_OVERRIDE") { + config.target(&val); + } + + // We don't need to generate install targets. + config.define("gRPC_INSTALL", "false"); + // We don't need to build csharp target. + config.define("gRPC_BUILD_CSHARP_EXT", "false"); + // We don't need to build codegen target. + config.define("gRPC_BUILD_CODEGEN", "false"); + // We don't need to build benchmarks. + config.define("gRPC_BENCHMARK_PROVIDER", "none"); + if cfg!(feature = "openssl") { + config.define("gRPC_SSL_PROVIDER", "package"); + if cfg!(feature = "openssl-vendored") { + config.register_dep("openssl"); + } + } else if cfg!(feature = "secure") { + third_party.extend_from_slice(&["boringssl-with-bazel"]); + } + if cfg!(feature = "no-omit-frame-pointer") { + config + .cflag("-fno-omit-frame-pointer") + .cxxflag("-fno-omit-frame-pointer"); + } + // Uses zlib from libz-sys. + setup_libz(&mut config); + config.build_target(library).uses_cxx11().build() + }; + + let build_dir = format!("{}/build", dst.display()); + if get_env("CARGO_CFG_TARGET_OS").map_or(false, |s| s == "windows") { + let profile = match &*env::var("PROFILE").unwrap() { + "bench" | "release" => "Release", + _ => "Debug", + }; + println!("cargo:rustc-link-search=native={}/{}", build_dir, profile); + for path in third_party { + println!( + "cargo:rustc-link-search=native={}/third_party/{}/{}", + build_dir, path, profile + ); + } + } else { + println!("cargo:rustc-link-search=native={}", build_dir); + for path in third_party { + println!( + "cargo:rustc-link-search=native={}/third_party/{}", + build_dir, path, + ); + } + } + + // link libz + println!("cargo:rustc-link-lib=static=z"); + // link cares + println!("cargo:rustc-link-lib=static=cares"); + // link address_sorting + println!("cargo:rustc-link-lib=static=address_sorting"); + // link absl/base + println!("cargo:rustc-link-lib=static=absl_base"); + println!("cargo:rustc-link-lib=static=absl_raw_logging_internal"); + println!("cargo:rustc-link-lib=static=absl_dynamic_annotations"); + println!("cargo:rustc-link-lib=static=absl_throw_delegate"); + println!("cargo:rustc-link-lib=static=absl_log_severity"); + println!("cargo:rustc-link-lib=static=absl_spinlock_wait"); + // link absl/strings + println!("cargo:rustc-link-lib=static=absl_strings"); + println!("cargo:rustc-link-lib=static=absl_strings_internal"); + println!("cargo:rustc-link-lib=static=absl_str_format_internal"); + // link absl/time + println!("cargo:rustc-link-lib=static=absl_civil_time"); + println!("cargo:rustc-link-lib=static=absl_time_zone"); + println!("cargo:rustc-link-lib=static=absl_time"); + // link absl/types + println!("cargo:rustc-link-lib=static=absl_bad_optional_access"); + // link absl/numeric + println!("cargo:rustc-link-lib=static=absl_int128"); + // link grpc related lib + println!("cargo:rustc-link-lib=static=gpr"); + println!("cargo:rustc-link-lib=static=upb"); + println!("cargo:rustc-link-lib=static={}", library); + + if cfg!(feature = "secure") { + if cfg!(feature = "openssl") && !cfg!(feature = "openssl-vendored") { + figure_ssl_path(&build_dir); + } else { + println!("cargo:rustc-link-lib=static=ssl"); + println!("cargo:rustc-link-lib=static=crypto"); + } + } + + cc.include("grpc/include"); +} + +fn figure_ssl_path(build_dir: &str) { + let path = format!("{}/CMakeCache.txt", build_dir); + let f = BufReader::new(std::fs::File::open(&path).unwrap()); + let mut cnt = 0; + for l in f.lines() { + let l = l.unwrap(); + let t = trim_start(&l, "OPENSSL_CRYPTO_LIBRARY:FILEPATH=") + .or_else(|| trim_start(&l, "OPENSSL_SSL_LIBRARY:FILEPATH=")); + if let Some(s) = t { + let path = Path::new(s); + println!( + "cargo:rustc-link-search=native={}", + path.parent().unwrap().display() + ); + cnt += 1; + } + } + if cnt != 2 { + panic!( + "CMake cache invalid, file {} contains {} ssl keys!", + path, cnt + ); + } + println!("cargo:rustc-link-lib=ssl"); + println!("cargo:rustc-link-lib=crypto"); +} + +fn setup_libz(config: &mut CmakeConfig) { + config.define("gRPC_ZLIB_PROVIDER", "package"); + config.register_dep("Z"); + // cmake script expect libz.a being under ${DEP_Z_ROOT}/lib, but libz-sys crate put it + // under ${DEP_Z_ROOT}/build. Append the path to CMAKE_PREFIX_PATH to get around it. + let zlib_root = env::var("DEP_Z_ROOT").unwrap(); + let prefix_path = if let Ok(prefix_path) = env::var("CMAKE_PREFIX_PATH") { + format!("{};{}/build", prefix_path, zlib_root) + } else { + format!("{}/build", zlib_root) + }; + // To avoid linking system library, set lib path explicitly. + println!("cargo:rustc-link-search=native={}/build", zlib_root); + println!("cargo:rustc-link-search=native={}/lib", zlib_root); + env::set_var("CMAKE_PREFIX_PATH", prefix_path); +} + +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. +fn bindgen_grpc(mut config: bindgen::Builder, file_path: &PathBuf) { + // 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); + } + + 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) + .whitelist_function(r"\bgrpc_.*") + .whitelist_function(r"\bgpr_.*") + .whitelist_function(r"\bgrpcwrap_.*") + .whitelist_var(r"\bGRPC_.*") + .whitelist_type(r"\bgrpc_.*") + .whitelist_type(r"\bgpr_.*") + .whitelist_type(r"\bgrpcwrap_.*") + .whitelist_type(r"\bcensus_context.*") + .whitelist_type(r"\bverify_peer_options.*") + .blacklist_type(r"(__)?pthread.*") + .blacklist_function(r"\bgpr_mu_.*") + .blacklist_function(r"\bgpr_cv_.*") + .blacklist_function(r"\bgpr_once_.*") + .blacklist_type(r"gpr_mu") + .blacklist_type(r"gpr_cv") + .blacklist_type(r"gpr_once") + .constified_enum_module(r"grpc_status_code") + .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 UPDATE_BIND is specified. +// Other platforms use bindgen to generate the bindings every time. +fn config_binding_path(config: bindgen::Builder) { + let file_path: PathBuf; + let target = env::var("TARGET").unwrap(); + match target.as_str() { + "x86_64-unknown-linux-gnu" | "aarch64-unknown-linux-gnu" => { + // 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", &target); + + file_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) + .join("bindings") + .join(format!("{}-bindings.rs", &target)); + if env::var("UPDATE_BIND").map(|s| s == "1").unwrap_or(false) { + bindgen_grpc(config, &file_path); + } + } + _ => { + file_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("grpc-bindings.rs"); + bindgen_grpc(config, &file_path); + } + }; + 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"); + println!("cargo:rerun-if-env-changed=UPDATE_BIND"); + + // create a builder to compile grpc_wrap.cc + let mut cc = cc::Build::new(); + // create a config to generate binding file + let mut bind_config = bindgen::Builder::default(); + + let library = if cfg!(feature = "secure") { + cc.define("GRPC_SYS_SECURE", None); + bind_config = bind_config.clang_arg("-DGRPC_SYS_SECURE"); + "grpc" + } else { + "grpc_unsecure" + }; + + if get_env("CARGO_CFG_TARGET_OS").map_or(false, |s| s == "windows") { + // At lease vista + cc.define("_WIN32_WINNT", Some("0x600")); + bind_config = bind_config.clang_arg("-D _WIN32_WINNT=0x600"); + } + + if get_env("GRPCIO_SYS_USE_PKG_CONFIG").map_or(false, |s| s == "1") { + // Print cargo metadata. + let lib_core = probe_library(library, true); + for inc_path in lib_core.include_paths { + cc.include(inc_path); + } + } else { + build_grpc(&mut cc, library); + } + + cc.cpp(true); + if !cfg!(target_env = "msvc") { + cc.flag("-std=c++11"); + } + cc.file("grpc_wrap.cc"); + cc.warnings_into_errors(true); + cc.compile("libgrpc_wrap.a"); + + config_binding_path(bind_config); +} |