Link to versioned pre-built libraries with bazel

Viewed 283

Assume that a prec-compiled dependency is supplied by a vendor:

$ ls /opt/vendor/protobuf/lib
libprotobuf.so.3 -> libprotobuf.so.3.0.0
libprotobuf.so.3.0.0

To use this with Bazel, the following target can be created:

cc_import(
  name = "protobuf",
  shared_library = "lib/libprotobuf.3.0.0",
)

This way, a bazel-built application can link to the library, however, it fails to start:

error while loading shared libraries: libprotobuf.so.3: cannot open shared object file: no such file or directory

The root cause is that the actual so file has a custom SONAME field:

objdump -x libprotobuf.so.3.0.0|grep SONAME
  SONAME      libprotobuf.so.3

The loader will look for libprotobuf.so.3 (instead of 3.0.0), but will not find it in the sandbox, as we never told bazel about the symlink. The symlink is relative, specifying it in the cc_import target will yield to a similar error.

Is it possible to create a runnable binary with bazel that links to such a shared library that is supposed to be found via a symlink?

1 Answers

Setting the RPATH can be a workaround. The cc_import need to be wrapped by a cc_library:

cc_library(
  name = "protobuf",
  deps = [":protobuf_impl"],
  linkopts = ["-Wl,-rpath=/opt/vendor/protobuf/lib"],
)

cc_import(
  name = "protobuf_impl",
  shared_library = "lib/libprotobuf.3.0.0",
)

This will make the binary run, but assumes that "/opt/vendor/protobuf/lib" is present on every system (incl. remote execution), and the loader during runtime still escapes the sandbox. A clearer solution would be nice.

Related