diff --git a/crates/openshell-core/build.rs b/crates/openshell-core/build.rs index d3b078941..c5e97a7ea 100644 --- a/crates/openshell-core/build.rs +++ b/crates/openshell-core/build.rs @@ -9,10 +9,18 @@ mod build_version; const PROTO_REL: &str = "../../proto"; fn main() -> Result<(), Box> { - // Preserve the vendored include-tree guarantee even when the caller has - // PROTOC_INCLUDE set: prost validates that ambient path independently of - // explicit includes. Re-enter with a child-only environment override. - if env::var_os("PROTOC_INCLUDE").is_some() { + // A caller-supplied PROTOC (for example a distro package's system + // compiler) is used as-is and prost resolves its own includes. Without it, + // use the vendored compiler and include tree. + println!("cargo:rerun-if-env-changed=PROTOC"); + println!("cargo:rerun-if-env-changed=PROTOC_INCLUDE"); + let use_vendored_protoc = env::var_os("PROTOC").is_none(); + + // In vendored mode, preserve the vendored include-tree guarantee even when + // the caller has PROTOC_INCLUDE set: prost validates that ambient path + // independently of explicit includes. Re-enter with a child-only + // environment override. + if use_vendored_protoc && env::var_os("PROTOC_INCLUDE").is_some() { let status = std::process::Command::new(env::current_exe()?) .env_remove("PROTOC_INCLUDE") .status()?; @@ -40,10 +48,15 @@ fn main() -> Result<(), Box> { // Re-run when anything under proto/ changes (including newly added .proto files). println!("cargo:rerun-if-changed={PROTO_REL}"); // Configure the vendored compiler and well-known includes without changing - // the build process environment. + // the build process environment. With a caller-supplied PROTOC, leave both + // to prost. let mut proto_config = tonic_prost_build::Config::new(); - proto_config.protoc_executable(protoc_bin_vendored::protoc_bin_path()?); - let proto_include = protoc_bin_vendored::include_path()?; + let proto_include = if use_vendored_protoc { + proto_config.protoc_executable(protoc_bin_vendored::protoc_bin_path()?); + Some(protoc_bin_vendored::include_path()?) + } else { + None + }; let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?); let proto_root = manifest_dir.join(PROTO_REL); @@ -53,6 +66,8 @@ fn main() -> Result<(), Box> { let out_dir = PathBuf::from(env::var("OUT_DIR")?); let descriptor_path = out_dir.join("openshell_descriptor.bin"); + let mut include_dirs = vec![proto_root]; + include_dirs.extend(proto_include); // Configure tonic/prost protobuf code generation. tonic_prost_build::configure() @@ -62,7 +77,7 @@ fn main() -> Result<(), Box> { // Emit a binary FileDescriptorSet so the server can enumerate every // RPC at runtime (used by the per-handler auth exhaustiveness test). .file_descriptor_set_path(&descriptor_path) - .compile_with_config(proto_config, &proto_files, &[proto_root, proto_include])?; + .compile_with_config(proto_config, &proto_files, &include_dirs)?; println!( "cargo:rustc-env=OPENSHELL_DESCRIPTOR_PATH={}", diff --git a/crates/openshell-sandbox-backend/build.rs b/crates/openshell-sandbox-backend/build.rs index bdffd02b1..a807cefb2 100644 --- a/crates/openshell-sandbox-backend/build.rs +++ b/crates/openshell-sandbox-backend/build.rs @@ -2,10 +2,18 @@ // SPDX-License-Identifier: Apache-2.0 fn main() -> Result<(), Box> { - // Preserve the vendored include-tree guarantee even when the caller has - // PROTOC_INCLUDE set: prost validates that ambient path independently of - // explicit includes. Re-enter with a child-only environment override. - if std::env::var_os("PROTOC_INCLUDE").is_some() { + // A caller-supplied PROTOC (for example a distro package's system + // compiler) is used as-is and prost resolves its own includes. Without it, + // use the vendored compiler and include tree. + println!("cargo:rerun-if-env-changed=PROTOC"); + println!("cargo:rerun-if-env-changed=PROTOC_INCLUDE"); + let use_vendored_protoc = std::env::var_os("PROTOC").is_none(); + + // In vendored mode, preserve the vendored include-tree guarantee even when + // the caller has PROTOC_INCLUDE set: prost validates that ambient path + // independently of explicit includes. Re-enter with a child-only + // environment override. + if use_vendored_protoc && std::env::var_os("PROTOC_INCLUDE").is_some() { let status = std::process::Command::new(std::env::current_exe()?) .env_remove("PROTOC_INCLUDE") .status()?; @@ -18,10 +26,17 @@ fn main() -> Result<(), Box> { println!("cargo:rerun-if-changed=proto/openshell_sandbox.proto"); // Configure the vendored compiler and well-known includes without changing - // the build process environment. + // the build process environment. With a caller-supplied PROTOC, leave both + // to prost. let mut proto_config = tonic_prost_build::Config::new(); - proto_config.protoc_executable(protoc_bin_vendored::protoc_bin_path()?); - let proto_include = protoc_bin_vendored::include_path()?; + let proto_include = if use_vendored_protoc { + proto_config.protoc_executable(protoc_bin_vendored::protoc_bin_path()?); + Some(protoc_bin_vendored::include_path()?) + } else { + None + }; + let mut include_dirs = vec![std::path::PathBuf::from("proto")]; + include_dirs.extend(proto_include); tonic_prost_build::configure() .build_server(true) @@ -29,7 +44,7 @@ fn main() -> Result<(), Box> { .compile_with_config( proto_config, &[std::path::PathBuf::from("proto/openshell_sandbox.proto")], - &[std::path::PathBuf::from("proto"), proto_include], + &include_dirs, )?; Ok(()) } diff --git a/crates/openshell-server/build.rs b/crates/openshell-server/build.rs index 1ddffb2a4..c061cb0b6 100644 --- a/crates/openshell-server/build.rs +++ b/crates/openshell-server/build.rs @@ -5,10 +5,18 @@ use std::env; use std::path::PathBuf; fn main() -> Result<(), Box> { - // Preserve the vendored include-tree guarantee even when the caller has - // PROTOC_INCLUDE set: prost validates that ambient path independently of - // explicit includes. Re-enter with a child-only environment override. - if env::var_os("PROTOC_INCLUDE").is_some() { + // A caller-supplied PROTOC (for example a distro package's system + // compiler) is used as-is and prost resolves its own includes. Without it, + // use the vendored compiler and include tree. + println!("cargo:rerun-if-env-changed=PROTOC"); + println!("cargo:rerun-if-env-changed=PROTOC_INCLUDE"); + let use_vendored_protoc = env::var_os("PROTOC").is_none(); + + // In vendored mode, preserve the vendored include-tree guarantee even when + // the caller has PROTOC_INCLUDE set: prost validates that ambient path + // independently of explicit includes. Re-enter with a child-only + // environment override. + if use_vendored_protoc && env::var_os("PROTOC_INCLUDE").is_some() { let status = std::process::Command::new(env::current_exe()?) .env_remove("PROTOC_INCLUDE") .status()?; @@ -37,12 +45,19 @@ fn main() -> Result<(), Box> { } // Configure the vendored compiler and well-known includes without changing - // the build process environment. + // the build process environment. With a caller-supplied PROTOC, leave both + // to prost. let mut proto_config = tonic_prost_build::Config::new(); - proto_config.protoc_executable(protoc_bin_vendored::protoc_bin_path()?); - let proto_include = protoc_bin_vendored::include_path()?; + let proto_include = if use_vendored_protoc { + proto_config.protoc_executable(protoc_bin_vendored::protoc_bin_path()?); + Some(protoc_bin_vendored::include_path()?) + } else { + None + }; let descriptor_path = PathBuf::from(env::var("OUT_DIR")?).join("storage_descriptor.bin"); + let mut include_dirs = vec![storage_proto_dir, public_proto_dir]; + include_dirs.extend(proto_include); tonic_prost_build::configure() .build_server(false) .build_client(false) @@ -56,11 +71,7 @@ fn main() -> Result<(), Box> { "::openshell_core::proto::sandbox::v1", ) .file_descriptor_set_path(&descriptor_path) - .compile_with_config( - proto_config, - &[storage_proto], - &[storage_proto_dir, public_proto_dir, proto_include], - )?; + .compile_with_config(proto_config, &[storage_proto], &include_dirs)?; Ok(()) }