Search code examples
c++bazel

Link archive to shared library with Bazel


Using Bazel, I'd like to link a position independent static archive directly to a shared library (not to the application using the shared library). Something like:

g++ -shared mylib.cpp archive.a -o libmylib.so
g++ mybin.cpp -lmylib -o mybin

Rationale: RedHat packages libelf as a static archive, that has some otherwise public symbols (e.g: elf_errmsg) marked as hidden: the archive must be linked to the module using it (in this case, the shared library): linking to the application is too late.

I tried:

  • Wrapping the archive in a cc_import rule
  • Adding the rule to the deps of the cc_library: doesn't work, archive gets linked to the app
  • Adding the rule to the srcs of the cc_library: doesn't work, archive gets linked to the app
  • Adding the archive file directly to the linkopts of the cc_library: almost works, but the archive gets linked to both the library and the binaries depending on it.
  • Renaming the archive to .lo or .pic.lo: doesn't work, archive gets linked to the app with -Wl,wholearchive
  • Adding alwayslink = True to the cc_import: doesn't work, archive gets linked to the app with -Wl,wholearchive

Solution

  • Something like this should work for what you're trying to do:

    cc_binary(
        name = "libmylib.so",
        srcs = ["mylib.cpp", "archive.a"],
        linkshared = True,
    )
    
    cc_library(
        name = "mylib",
        srcs = ["libmylib.so"],
        hdrs = ["mylib.hpp"],
    )
    cc_binary(
        name = "mybin",
        srcs = ["mybin.cpp"],
        deps = [":mylib"],
    )
    

    You can build a shared library (which is done as cc_binary(linkshared = True); this bit may not seem entirely intuitive) from your source and the library archive.

    You can build a cc_library to use as a dependency of your other targets... and use that to build a cc_binary target.

    In theory if this was just one time/place thing, you could probably shorten it like this (but it's more of a minimal length example):

    cc_binary(
        name = "libmylib.so",
        srcs = ["mylib.cpp", "archive.a"],
        linkshared = True,
    )
    
    cc_binary(
        name = "mybin",
        srcs = ["mybin.cpp", "mylib.hpp", ":libmylib.so"],
    )