From 3b75391f24b40dbd45ed57c39df3a03e203108f4 Mon Sep 17 00:00:00 2001 From: Lukasz Anforowicz Date: Tue, 15 Sep 2026 09:34:37 -0700 Subject: [PATCH] Allow linking `utf8_validity` alongside `protobuf` in cargo builds. `libprotobuf` has undefined references to `utf8_range_IsValid` and `utf8_range_ValidPrefix`, which are provided by `libutf8_validity`. Previously, `collect_protobuf_libs` only accepted the archive named `protobuf`. This change extends the allowlist to include `utf8_validity`. The discovery remains an explicit allowlist, because other archives in the protobuf install tree must not be linked together: * `utf8_range` defines the same symbols as `utf8_validity` and causes duplicate symbol errors (`LNK2005`). * `protobuf-lite` duplicates symbols from `protobuf`. * `protoc` and `upb` are not needed by Crubit. This change allows Chromium's `tools/rust/build_crubit.py` to remove the workaround that merged `libutf8_validity` into `libprotobuf`. PiperOrigin-RevId: 981873060 --- cargo/build/protobuf.rs | 43 ++++++++++++++++++++++++++++++++++++++--- docs/cpp/building.md | 4 +++- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/cargo/build/protobuf.rs b/cargo/build/protobuf.rs index 6d279fd85..e3fd67169 100644 --- a/cargo/build/protobuf.rs +++ b/cargo/build/protobuf.rs @@ -12,12 +12,49 @@ pub fn collect_protobuf_includes() -> Vec { paths::get_env_paths("PROTOBUF_INCLUDE_PATH") } +fn is_protobuf_lib(name: &str) -> bool { + // Protobuf's CMake build prefixes these archives with `lib` on every platform, + // including Windows, where `collect_static_libs` keeps the file stem as-is. + matches!(name.strip_prefix("lib").unwrap_or(name), "protobuf" | "utf8_validity") +} + /// Returns the paths to the protobuf libraries (to be used as a search path) and a /// list of libraries to be linked. +/// +/// This is an allowlist rather than "everything in the directory", because a protobuf +/// install tree holds several archives that must not be linked together: +/// +/// * `protobuf` is the library Crubit uses, and it has undefined references into +/// `utf8_validity`, so the two belong together. +/// * `utf8_range` is compiled from the same `utf8_range.c` as `utf8_validity` and +/// defines the same symbols, so linking both is a duplicate symbol error. +/// * `protobuf-lite` is a subset of `protobuf`, and would collide with it likewise. +/// * `protoc` and `upb` are not used by Crubit. pub fn collect_protobuf_libs() -> (Vec, Vec) { - paths::collect_static_libs("PROTOBUF_LIB_STATIC_PATH", |name| { - name.strip_prefix("lib").unwrap_or(name) == "protobuf" - }) + paths::collect_static_libs("PROTOBUF_LIB_STATIC_PATH", is_protobuf_lib) +} + +/// Unit tests for protobuf library allowlist matching. +/// +/// Note: These tests use standard `#[test]` rather than `googletest` because +/// `crubit_build` is a build helper crate built via Cargo. +#[cfg(test)] +mod tests { + use super::*; + + #[test] // allow_core_test (see mod tests doc comment) + fn test_is_protobuf_lib() { + assert!(is_protobuf_lib("protobuf")); + assert!(is_protobuf_lib("libprotobuf")); + assert!(is_protobuf_lib("utf8_validity")); + assert!(is_protobuf_lib("libutf8_validity")); + assert!(!is_protobuf_lib("utf8_range")); + assert!(!is_protobuf_lib("libutf8_range")); + assert!(!is_protobuf_lib("protobuf-lite")); + assert!(!is_protobuf_lib("libprotobuf-lite")); + assert!(!is_protobuf_lib("protoc")); + assert!(!is_protobuf_lib("upb")); + } } /// Locates pre-generated .pb.cc C++ source files corresponding to `proto_sources` diff --git a/docs/cpp/building.md b/docs/cpp/building.md index 2bf843da2..c88572030 100644 --- a/docs/cpp/building.md +++ b/docs/cpp/building.md @@ -94,7 +94,9 @@ export ABSL_INCLUDE_PATH=/path/to/absl/include/dir export ABSL_LIB_STATIC_PATH=/path/to/absl/libs ## This path contains google/protobuf/ dir with all the includes. export PROTOBUF_INCLUDE_PATH=/path/to/protobuf/include/dir -## This path contains libprotobuf.a +## This path contains libprotobuf.a and libutf8_validity.a. Other archives that a +## protobuf install tree holds (libutf8_range.a, libprotobuf-lite.a, libprotoc.a, +## libupb.a) are ignored; the first two would collide with the ones above. export PROTOBUF_LIB_STATIC_PATH=/path/to/protobuf/libs cargo build --bin rs_bindings_from_cc