Skip to content

Commit

Permalink
Bundled protoc only if the interpreter exists (#459)
Browse files Browse the repository at this point in the history
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).

Co-authored-by: Lucio Franco <luciofranco14@gmail.com>
  • Loading branch information
nagisa and LucioFranco committed Jul 6, 2021
1 parent fdc319c commit 5d93c55
Showing 1 changed file with 17 additions and 12 deletions.
29 changes: 17 additions & 12 deletions prost-build/build.rs
Expand Up @@ -35,13 +35,26 @@ fn env_protoc() -> Option<PathBuf> {
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<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",
("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",
Expand All @@ -51,14 +64,6 @@ fn bundled_protoc() -> Option<PathBuf> {
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<PathBuf> {
None
}

/// Returns the path to the `protoc` included on the `PATH`, if it exists.
fn path_protoc() -> Option<PathBuf> {
which::which("protoc").ok()
Expand Down

0 comments on commit 5d93c55

Please sign in to comment.