use std::env;
use std::path::PathBuf;
fn bundle_path() -> PathBuf {
env::current_dir()
.unwrap()
.join("third-party")
.join("protobuf")
}
fn env_protoc() -> Option<PathBuf> {
let protoc = match env::var_os("PROTOC") {
Some(path) => PathBuf::from(path),
None => return None,
};
if !protoc.exists() {
panic!(
"PROTOC environment variable points to non-existent file ({:?})",
protoc
);
}
Some(protoc)
}
fn bundled_protoc() -> Option<PathBuf> {
let protoc_bin_name = match (env::consts::OS, env::consts::ARCH) {
("linux", "x86") => "protoc-linux-x86_32",
("linux", "x86_64") => "protoc-linux-x86_64",
("linux", "aarch64") => "protoc-linux-aarch_64",
("macos", "x86_64") => "protoc-osx-x86_64",
("windows", _) => "protoc-win32.exe",
_ => return None,
};
Some(bundle_path().join(protoc_bin_name))
}
fn path_protoc() -> Option<PathBuf> {
which::which("protoc").ok()
}
fn env_protoc_include() -> Option<PathBuf> {
let protoc_include = match env::var_os("PROTOC_INCLUDE") {
Some(path) => PathBuf::from(path),
None => return None,
};
if !protoc_include.exists() {
panic!(
"PROTOC_INCLUDE environment variable points to non-existent directory ({:?})",
protoc_include
);
}
if !protoc_include.is_dir() {
panic!(
"PROTOC_INCLUDE environment variable points to a non-directory file ({:?})",
protoc_include
);
}
Some(protoc_include)
}
fn bundled_protoc_include() -> PathBuf {
bundle_path().join("include")
}
fn main() {
let protoc = env_protoc()
.or_else(bundled_protoc)
.or_else(path_protoc)
.expect(
"Failed to find the protoc binary. The PROTOC environment variable is not set, \
there is no bundled protoc for this platform, and protoc is not in the PATH",
);
let protoc_include = env_protoc_include().unwrap_or_else(bundled_protoc_include);
println!("cargo:rustc-env=PROTOC={}", protoc.display());
println!(
"cargo:rustc-env=PROTOC_INCLUDE={}",
protoc_include.display()
);
println!("cargo:rerun-if-env-changed=PROTOC");
println!("cargo:rerun-if-env-changed=PROTOC_INCLUDE");
}