Skip to content

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

@tannevaled

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions