Skip to content

protobuf.dev bottles ship with unresolved abseil symbols (consumer link surface broken) #13105

Description

@tannevaled

Symptom

Any pantry recipe that transitively links libprotobuf.so (so far observed: android-tools in #13068) fails the final ld step with hundreds of unresolved references to abseil templated functions:

ld: /opt/protobuf.dev/v35.0.0/lib/libprotobuf.so.35.0.0:
    undefined reference to `absl::lts_20250127::log_internal::LogMessage::operator<<<long, …>(…)`

Both protobuf 25.x and 35.0.0 bottles show the same pattern, and the absl::lts_<DATE>:: namespace in the unresolved symbols differs from the abseil currently published by pantry's resolver. Pinning the consumer's abseil.io: ^20250127 (or even =20250127.0.0) doesn't fix it — the template instantiations in libabsl_log_internal_message.so.2501.0.0 differ even within the same LTS line.

Root cause

projects/protobuf.dev/package.yml acknowledges this directly with a FIXME and a build-time workaround:

dependencies:
  # this is a bit of a hack, since they need their built version at link time
  # but the built version *has* to drift :/
  abseil.io: '*'

build:
  dependencies:
    abseil.io: ^20250127 # FIXME: how? it links to e.g. libabsl_bad_any_cast_impl.so.2308.0.0
  env:
    linux:
      # likely needs bumping to an unreleased abseil.io version
      # ld.lld: error: undefined reference due to --no-allow-shlib-undefined:
      #   absl::lts_20240116::log_internal::LogMessage::operator<<<int, 0>(int const&)
      LDFLAGS: $LDFLAGS -Wl,--allow-shlib-undefined

In other words protobuf's own bottle is built with --allow-shlib-undefined, so its libprotobuf.so ships with unresolved abseil refs baked in. Consumers then have to either:

  1. Also pass -Wl,--allow-shlib-undefined (my current workaround on new(android-tools): standalone adb / fastboot / mkbootimg #13068) — fragile, the binary may still fail to load at runtime depending on what abseil is in RUNPATH.
  2. Statically link everything (cargo / Bazel / vcpkg do this) — defeats pantry's bottle model.
  3. Coincidentally have the same abseil at consumer link time that protobuf was built against — the lockstep approach arch uses (upgpkg: rebuild abseil-cpp + protobuf on every abseil bump).

Suggested fixes (in increasing order of structural change)

  1. Re-bottle protobuf against current abseil. No recipe change needed — just bump pkgrel / re-trigger CI. Buys time until next abseil drift, then re-bottle again. Matches what arch does.
  2. Add a CI policy in pantry: when abseil's bottle changes major LTS namespace, automatically trigger rebuilds of every consumer (protobuf, grpc, etc.). This is the proper "lockstep" approach.
  3. Bundle abseil inside libprotobuf.so. Protobuf upstream provides -Dprotobuf_ABSL_PROVIDER=module which statically links abseil into protobuf. Larger bottle but eliminates the ABI drift entirely. Used by Bazel/conan/vcpkg.

Where this surfaces in practice

  • new(android-tools): standalone adb / fastboot / mkbootimg #13068 (android-tools) — every iteration of the final adb / fastboot link bombs on these symbols. Workaround pushed to that PR's branch; not a real fix.
  • Likely affects any new C++ recipe that uses protobuf at link time. Things like envoy, grpc, opentelemetry, gnu radio etc. are all candidates.

Happy to send a PR for option 1 (re-bottle) if a maintainer says "yes" — would just need a trivial commit on projects/protobuf.dev/package.yml to bump version metadata and let CI re-run.

cc'ing nobody in particular — wanted to make this surface-visible since the FIXME is buried in a comment.

🤖 Surfaced while working on #13068.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions