Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use cc_import on shared libraries with dependencies #24477

Open
wudisheng opened this issue Nov 25, 2024 · 0 comments
Open

Use cc_import on shared libraries with dependencies #24477

wudisheng opened this issue Nov 25, 2024 · 0 comments
Labels

Comments

@wudisheng
Copy link

wudisheng commented Nov 25, 2024

Description of the bug:

There are a few third-party pre-compiled shared libraries in our use case, we place them inside our workspace and use cc_import to import them. Some of them depend on others, for example, libX.so depends on libY.so, so in our BUILD there are targets like below and it was working fine.

cc_import(
    name = "imp-X",
    shared_library = "3rd/libX.so",
    deps = [":imp-Y"],  # NOTE: `libX.so` depends on `libY.so`.

cc_import(
    name = "imp-Y",
    shared_library = "3rd/libY.so",
)

cc_binary(
    name = "main",
    # ...
    deps = [
        # ...
        ":imp-X",  # NOTE: `main` depends on `libX.so` directly.
    ],
)

However, recently we made some changes in main's sources, and it starts to use something provided by libY.so directly, so the deps of main becomes [":imp-X", ":imp-Y"], but we found it not working as expected because there are some symbol resolution ordering issues between libX.so and libY.so ---- when main directly uses certain functions in libY.so, in order to make things correct, libY.so must come before libX.so in DT_NEEDED section of main.

But, because of topological sorting on dependencies done by Bazel, libY.so is always coming after libX.so, and we can not let imp-Y depends on imp-X which would form a circular dependency issue.

We had several attempts to workaround this, but nothing ideal found.

  • Create imp-Y2 as a copy of imp-Y and use it instead of imp-Y in main's deps.
cc_import(
    name = "imp-Y2",
    shared_library = "3rd/libY.so",
    deps = [":imp-X"],
)

This works for now but is apparently not a good solution, and it actually stores two copies of libY.so in the deployment runfiles (after dereferenced copying). Also, libY.so doesn't have to depend on libX.so, and we have other cc_binary using only libY.so, a global replacement would like to introduce unnecessary dependencies to some of them.

  • Rewrite imp-X as a tricky pair like below.
cc_import(
  name = "imp-X-only",
  shared_library = "3rd/libX.so",
)

cc_import(
  name = "imp-X",
  shared_library = "3rd/libY.so",
  deps = [":imp-X-only"],
)

But this doesn't work (or being too complicated) when there is another libZ.so having the same issue like libY.so, and also suffers multiple copies problem like above. Moreover, it smells too insane that imp-X's direct library is libY.so.

  • Try to make a dummy shared library which links to libX.so, and use it instead (relying on ELF loader's Breadth-First Search behavior to make libY.so load before libX.so).
cc_binary(
    name = "thin-X",
    deps = [":imp-X"],
    linkshared = True,
)

cc_import(
    name = "imp-thin-X",
    shared_library = ":thin-X",
    # ... (many attempts on combinations of options).
)

But we haven't found a way to use "imp-thin-X" with libX.so put into main's runfiles (in mangled subdirectory) and not in main's DT_NEEDED. Do we really have a way to put a .so into the mangled subdirectory in runfiles (and link with correct RPATH or RUNPATH) but not actually link the .so?

Any suggested alternatives on the situation I mentioned above?

Thanks!

Which category does this issue belong to?

C++ Rules

What's the simplest, easiest way to reproduce this bug? Please provide a minimal example if possible.

As described above.

Which operating system are you running Bazel on?

Ubuntu 22.04

What is the output of bazel info release?

6.3.2

If bazel info release returns development version or (@non-git), tell us how you built Bazel.

No response

What's the output of git remote get-url origin; git rev-parse HEAD ?

No response

If this is a regression, please try to identify the Bazel commit where the bug was introduced with bazelisk --bisect.

No response

Have you found anything relevant by searching the web?

No clear hit.

Any other information, logs, or outputs that you want to share?

No response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants