Rust: update protobuf_codegen crate to rely on separately installed protoc

I also added a check to ensure that `protoc --version` matches the protobuf
runtime version. The minitable generator plugin version should also match, but
unfortunately we can't easily check this today because it does not provide a
way to check its version.

PiperOrigin-RevId: 705944904
pull/19620/head
Adam Cozzette 2 months ago committed by Copybara-Service
parent 45ee584e6c
commit 2559176061
  1. 15
      rust/BUILD
  2. 2
      rust/release_crates/BUILD
  3. 6
      rust/release_crates/cargo_test.sh
  4. 1
      rust/release_crates/protobuf_codegen/BUILD
  5. 5
      rust/release_crates/protobuf_codegen/Cargo-template.toml
  6. 127
      rust/release_crates/protobuf_codegen/src/lib.rs
  7. 2
      upb_generator/minitable/BUILD

@ -291,18 +291,3 @@ pkg_filegroup(
prefix = "libupb", prefix = "libupb",
visibility = ["//rust/release_crates:__subpackages__"], visibility = ["//rust/release_crates:__subpackages__"],
) )
# Bundle only the linux-x86_64 protoc for testing.
pkg_cross_compiled_binaries(
name = "vendored_protocs_test",
cpus = [
"linux-x86_64",
],
prefix = "bin",
tags = ["manual"],
targets = [
"//upb_generator/minitable:protoc-gen-upb_minitable",
"//:protoc",
],
visibility = ["//rust/release_crates:__subpackages__"],
)

@ -8,6 +8,8 @@ sh_binary(
"//rust/release_crates/protobuf:protobuf_crate", "//rust/release_crates/protobuf:protobuf_crate",
"//rust/release_crates/protobuf_codegen:protobuf_codegen_crate", "//rust/release_crates/protobuf_codegen:protobuf_codegen_crate",
"//rust/release_crates/protobuf_example:protobuf_example_crate", "//rust/release_crates/protobuf_example:protobuf_example_crate",
"//src/google/protobuf/compiler:protoc",
"//upb_generator/minitable:protoc-gen-upb_minitable",
], ],
tags = ["manual"], tags = ["manual"],
deps = ["@bazel_tools//tools/bash/runfiles"], deps = ["@bazel_tools//tools/bash/runfiles"],

@ -56,7 +56,11 @@ mkdir $EXAMPLE_ROOT
EXAMPLE_TAR=$(rlocation com_google_protobuf/rust/release_crates/protobuf_example/protobuf_example_crate.tar) EXAMPLE_TAR=$(rlocation com_google_protobuf/rust/release_crates/protobuf_example/protobuf_example_crate.tar)
echo "Expanding protobuf_example crate tar" echo "Expanding protobuf_example crate tar"
tar -xvf $EXAMPLE_TAR -C $EXAMPLE_ROOT tar -xvf $EXAMPLE_TAR -C $EXAMPLE_ROOT
# Put the Bazel-built protoc and plugin at the beginning of $PATH
PATH=$(dirname $(rlocation com_google_protobuf/protoc)):$PATH
PATH=$(dirname $(rlocation com_google_protobuf/upb_generator/minitable/protoc-gen-upb_minitable)):$PATH
cd $CRATE_ROOT cd $CRATE_ROOT
CARGO_HOME=$CARGO_HOME cargo test CARGO_HOME=$CARGO_HOME cargo test

@ -7,7 +7,6 @@ pkg_tar(
srcs = [ srcs = [
":protobuf_codegen_files", ":protobuf_codegen_files",
"//:LICENSE", "//:LICENSE",
"//rust:vendored_protocs_test",
], ],
tags = ["manual"], tags = ["manual"],
visibility = ["//rust:__subpackages__"], visibility = ["//rust:__subpackages__"],

@ -9,4 +9,7 @@ rust-version = "1.74"
[dependencies] [dependencies]
cc = "1.1.6" cc = "1.1.6"
[dev-dependencies]
googletest = "0.12.0"

@ -4,20 +4,49 @@ use std::path::{Path, PathBuf};
pub struct CodeGen { pub struct CodeGen {
inputs: Vec<PathBuf>, inputs: Vec<PathBuf>,
output_dir: PathBuf, output_dir: PathBuf,
protoc_path: Option<PathBuf>,
protoc_gen_upb_minitable_path: Option<PathBuf>,
includes: Vec<PathBuf>, includes: Vec<PathBuf>,
} }
const VERSION: &str = env!("CARGO_PKG_VERSION"); const VERSION: &str = env!("CARGO_PKG_VERSION");
// Given the output of "protoc --version", returns a shortened version string
// suitable for comparing against the protobuf crate version.
//
// The output of protoc --version looks something like "libprotoc XX.Y",
// optionally followed by "-dev" or "-rcN". We want to strip the "-dev" suffix
// if present and return something like "30.0" or "30.0-rc1".
fn protoc_version(protoc_output: &str) -> String {
let mut s = protoc_output.strip_prefix("libprotoc ").unwrap().to_string();
let first_dash = s.find("-dev");
if let Some(i) = first_dash {
s.truncate(i);
}
s
}
// Given a crate version string, returns just the part of it suitable for
// comparing against the protoc version. The crate version is of the form
// "X.Y.Z" with an optional suffix starting with a dash. We want to drop the
// major version ("X.") and only keep the suffix if it starts with "-rc".
fn expected_protoc_version(cargo_version: &str) -> String {
let mut s = cargo_version.to_string();
let is_release_candidate = s.find("-rc") != None;
if !is_release_candidate {
if let Some(i) = s.find('-') {
s.truncate(i);
}
}
let mut v: Vec<&str> = s.split('.').collect();
assert_eq!(v.len(), 3);
v.remove(0);
v.join(".")
}
impl CodeGen { impl CodeGen {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
inputs: Vec::new(), inputs: Vec::new(),
output_dir: PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("protobuf_generated"), output_dir: PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("protobuf_generated"),
protoc_path: None,
protoc_gen_upb_minitable_path: None,
includes: Vec::new(), includes: Vec::new(),
} }
} }
@ -37,20 +66,6 @@ impl CodeGen {
self self
} }
pub fn protoc_path(&mut self, protoc_path: impl AsRef<Path>) -> &mut Self {
self.protoc_path = Some(protoc_path.as_ref().to_owned());
self
}
pub fn protoc_gen_upb_minitable_path(
&mut self,
protoc_gen_upb_minitable_path: impl AsRef<Path>,
) -> &mut Self {
self.protoc_gen_upb_minitable_path =
Some(protoc_gen_upb_minitable_path.as_ref().to_owned());
self
}
pub fn include(&mut self, include: impl AsRef<Path>) -> &mut Self { pub fn include(&mut self, include: impl AsRef<Path>) -> &mut Self {
self.includes.push(include.as_ref().to_owned()); self.includes.push(include.as_ref().to_owned());
self self
@ -92,12 +107,22 @@ impl CodeGen {
); );
} }
let protoc_path = if let Some(path) = &self.protoc_path { let mut version_cmd = std::process::Command::new("protoc");
path.clone() let output = version_cmd
} else { .arg("--version")
protoc_path().expect("To be a supported platform") .output()
}; .map_err(|e| format!("failed to run protoc --version: {}", e))?;
let mut cmd = std::process::Command::new(protoc_path);
let protoc_version = protoc_version(&String::from_utf8(output.stdout).unwrap());
let expected_protoc_version = expected_protoc_version(VERSION);
if protoc_version != expected_protoc_version {
panic!(
"Expected protoc version {} but found {}",
expected_protoc_version, protoc_version
);
}
let mut cmd = std::process::Command::new("protoc");
for input in &self.inputs { for input in &self.inputs {
cmd.arg(input); cmd.arg(input);
} }
@ -105,12 +130,6 @@ impl CodeGen {
// Attempt to make the directory if it doesn't exist // Attempt to make the directory if it doesn't exist
let _ = std::fs::create_dir(&self.output_dir); let _ = std::fs::create_dir(&self.output_dir);
} }
let protoc_gen_upb_minitable_path = if let Some(path) = &self.protoc_gen_upb_minitable_path
{
path.clone()
} else {
protoc_gen_upb_minitable_path().expect("To be a supported platform")
};
for include in &self.includes { for include in &self.includes {
println!("cargo:rerun-if-changed={}", include.display()); println!("cargo:rerun-if-changed={}", include.display());
@ -118,10 +137,6 @@ impl CodeGen {
cmd.arg(format!("--rust_out={}", self.output_dir.display())) cmd.arg(format!("--rust_out={}", self.output_dir.display()))
.arg("--rust_opt=experimental-codegen=enabled,kernel=upb") .arg("--rust_opt=experimental-codegen=enabled,kernel=upb")
.arg(format!(
"--plugin=protoc-gen-upb_minitable={}",
protoc_gen_upb_minitable_path.display()
))
.arg(format!("--upb_minitable_out={}", self.output_dir.display())); .arg(format!("--upb_minitable_out={}", self.output_dir.display()));
for include in &self.includes { for include in &self.includes {
cmd.arg(format!("--proto_path={}", include.display())); cmd.arg(format!("--proto_path={}", include.display()));
@ -162,32 +177,24 @@ impl CodeGen {
} }
} }
fn get_path_for_arch() -> Option<PathBuf> { #[cfg(test)]
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); mod tests {
path.push("bin"); use super::*;
match (std::env::consts::OS, std::env::consts::ARCH) { use googletest::prelude::*;
("macos", "x86_64") => path.push("osx-x86_64"),
("macos", "aarch64") => path.push("osx-aarch_64"),
("linux", "aarch64") => path.push("linux-aarch_64"),
("linux", "powerpc64") => path.push("linux-ppcle_64"),
("linux", "s390x") => path.push("linux-s390_64"),
("linux", "x86") => path.push("linux-x86_32"),
("linux", "x86_64") => path.push("linux-x86_64"),
("windows", "x86") => path.push("win32"),
("windows", "x86_64") => path.push("win64"),
_ => return None,
};
Some(path)
}
pub fn protoc_path() -> Option<PathBuf> { #[googletest::test]
let mut path = get_path_for_arch()?; fn test_protoc_version() {
path.push("protoc"); assert_eq!(protoc_version("libprotoc 30.0"), "30.0");
Some(path) assert_eq!(protoc_version("libprotoc 30.0-dev"), "30.0");
} assert_eq!(protoc_version("libprotoc 30.0-rc1"), "30.0-rc1");
}
pub fn protoc_gen_upb_minitable_path() -> Option<PathBuf> { #[googletest::test]
let mut path = get_path_for_arch()?; fn test_expected_protoc_version() {
path.push("protoc-gen-upb_minitable"); assert_eq!(expected_protoc_version("4.30.0"), "30.0");
Some(path) assert_eq!(expected_protoc_version("4.30.0-alpha"), "30.0");
assert_eq!(expected_protoc_version("4.30.0-beta"), "30.0");
assert_eq!(expected_protoc_version("4.30.0-pre"), "30.0");
assert_eq!(expected_protoc_version("4.30.0-rc1"), "30.0-rc1");
}
} }

@ -93,7 +93,7 @@ bootstrap_cc_binary(
visibility = [ visibility = [
"//editions/codegen_tests:__pkg__", "//editions/codegen_tests:__pkg__",
"//net/proto2/contrib/protoc_explorer:__pkg__", "//net/proto2/contrib/protoc_explorer:__pkg__",
"//rust:__pkg__", "//rust:__subpackages__",
"//third_party/prototiller/transformer:__pkg__", "//third_party/prototiller/transformer:__pkg__",
], ],
) )

Loading…
Cancel
Save