Skip to content

Commit

Permalink
core: find protobuf-src protoc binary dynamically
Browse files Browse the repository at this point in the history
  • Loading branch information
williballenthin committed Oct 30, 2024
1 parent e3f9ba8 commit 6530cde
Showing 1 changed file with 62 additions and 10 deletions.
72 changes: 62 additions & 10 deletions core/build.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,67 @@
use std::io::Result;
use std::{io::Result, ops::Not, path::PathBuf};

/// Figure out where the protoc executable from protobuf-src is, if available.
fn find_protoc() -> Option<PathBuf> {
// protobuf-src doesn't support Windows,
// so the external build environment must provide protoc.exe.
// https://github.com/MaterializeInc/rust-protobuf-native/issues/4
//
// Our setup approximates the changes here:
// https://github.com/CerebusOSS/ella/pull/14/files
//
// But there are some problems...
//
// We might want to use `if cfg!(not(target_os = "windows"))`
// to include protobuf-src on supported platforms,
// but this doesn't actually work correctly in a build.rs script,
// because the target is for the build.rs script, not the final program,
// which is important during cross compilation.
//
// So then we might want to use
// `if std::env::var_os("CARGO_CFG_WINDOWS").is_none()` and we can,
// but we can't conditionally compile code within the block,
// such as conditionally reference protobuf-src.
//
// So instead, we look around the build directory for the protoc file
// :evilgrin:
//
// This requires that protobuf-src is listed in the build-dependencies
// and that it gets built before this script, which seems to be true.

// like: .../lancelot/target/debug/build/lancelot-f70fef48d1b50e7f/out
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR not present");
let out_dir = PathBuf::from(out_dir);

// like: .../lancelot/target/debug/build
let build_dir = &out_dir.parent().unwrap().parent().unwrap();

for entry in std::fs::read_dir(build_dir).ok()? {

Check failure on line 38 in core/build.rs

View workflow job for this annotation

GitHub Actions / test

unnecessary `if let` since only the `Ok` variant of the iterator element is used
if let Ok(entry) = entry {
if entry.file_name().to_string_lossy().starts_with("protobuf-src-").not() {
continue;
}

let mut path = entry.path();
path.push("out");
path.push("bin");
path.push("protoc");

if matches!(std::fs::exists(&path), Ok(true)) {
return Some(path);
}
}
}

None
}

fn main() -> Result<()> {
if std::env::var_os("CARGO_CFG_WINDOWS").is_none() {
// protobuf-src doesn't support Windows,
// so the external build environment must provide protoc.exe.
// https://github.com/MaterializeInc/rust-protobuf-native/issues/4
//
// Our setup approximates the changes here:
// https://github.com/CerebusOSS/ella/pull/14/files
std::env::set_var("PROTOC", protobuf_src::protoc());
std::env::set_var("PROTOC_INCLUDE", protobuf_src::include());
if let Some(protoc) = find_protoc() {
std::env::set_var("PROTOC", &*protoc.to_string_lossy());
} else if std::env::var_os("CARGO_CFG_WINDOWS").is_none() {
panic!("expected to find protoc for non-Windows target")
} else {
// on Windows, external environment is expected to provide protoc.
}

// this may fail on windows if protoc.exe is not present.
Expand Down

0 comments on commit 6530cde

Please sign in to comment.