From 3922df17e54fca74c4d29e126e5ab91919914f49 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Mon, 12 Apr 2021 19:14:32 +0300 Subject: [PATCH] Bundled protoc only if the interpreter exists Otherwise on systems such as NixOS the prost-build attempts to execute the bundled protoc, hits a very obscure error about file not existing and exits, without trying the other options (such as the protoc from path, if it exists there). --- prost-build/build.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/prost-build/build.rs b/prost-build/build.rs index 3ce4848b9..0902d3e40 100644 --- a/prost-build/build.rs +++ b/prost-build/build.rs @@ -35,13 +35,26 @@ fn env_protoc() -> Option { Some(protoc) } +/// We can only use a bundled protoc if the interpreter necessary to load the binary is available. +/// +/// The interpreter is specific to the binary and can be queried via e.g. `patchelf +/// --print-interpreter`, or via readelf, or similar. +fn is_interpreter(path: &'static str) -> bool { + // Here we'd check for it being executable and other things, but for now it being present is + // probably good enough. + std::fs::metadata(path).is_ok() +} + /// Returns the path to the bundled `protoc`, if it is available for the host platform. -#[cfg(not(target_env = "musl"))] fn bundled_protoc() -> Option { 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", + ("linux", "x86") if is_interpreter("/lib/ld-linux.so.2") => "protoc-linux-x86_32", + ("linux", "x86_64") if is_interpreter("/lib64/ld-linux-x86-64.so.2") => { + "protoc-linux-x86_64" + } + ("linux", "aarch64") if is_interpreter("/lib/ld-linux-aarch64.so.1") => { + "protoc-linux-aarch_64" + } ("macos", "x86_64") => "protoc-osx-x86_64", ("macos", "aarch64") => "protoc-osx-x86_64", // will be translated to aarch64 by Rosetta ("windows", _) => "protoc-win32.exe", @@ -51,14 +64,6 @@ fn bundled_protoc() -> Option { Some(bundle_path().join(protoc_bin_name)) } -/// `musl` build hosts do not have a bundled `protoc`. -/// -/// Note: this checks the target of the `prost-build` build.rs, which is ultimately the host architecture. -#[cfg(target_env = "musl")] -fn bundled_protoc() -> Option { - None -} - /// Returns the path to the `protoc` included on the `PATH`, if it exists. fn path_protoc() -> Option { which::which("protoc").ok()