Skip to content

[WIP] bazel: Allow to link third party libraries dynamically#4585

Closed
vadorovsky wants to merge 1 commit intoenvoyproxy:masterfrom
vadorovsky:dynamic-linking
Closed

[WIP] bazel: Allow to link third party libraries dynamically#4585
vadorovsky wants to merge 1 commit intoenvoyproxy:masterfrom
vadorovsky:dynamic-linking

Conversation

@vadorovsky
Copy link
Copy Markdown
Contributor

Description:
Provide an option --define dynamic_linking=enabled which allows
to link third-party libraries dynamically.

An another change is using glob function to resolve library
paths. Some Linux distributions use /usr/lib64 directory instead
of /usr/lib (if system is 64-bit). To fix build on them, the
wildard expression like thirdparty/lib*/name_of_library.a needs
to be used.

Risk Level: Low
Testing: None, but some CI tests in future could be added
Docs Changes: Option described in bazel/README.md
Release Notes: n/a

Signed-off-by: Michal Rostecki mrostecki@suse.de

Copy link
Copy Markdown
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems reasonable to enable as opt-in, thanks.

Comment thread source/common/json/BUILD Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't have to push this out to individual BUILD files; can't we hide the details inside envoy_build_system.bzl, in the envoy_cc_library definition?

Comment thread ci/prebuilt/BUILD Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is dynamic linking really orthogonal to both OS and CPU architecture?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It definitely should work the same for those libraries on Linux, *BSD and OS X. Do we support any other platforms?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And handling different CPU architectures on RPM-based distros (which use /usr/lib64 dir instead of /usr/lib for 64-bit systems) is the reason why I decided to use glob there.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you comment on how you expect the dynamic libraries to be distributed? As things stand, once you do a dynamic link, the .so artifacts that you rely on live in the Bazel cache. How would a user be expected to bundle them up for distribution? Or, is the idea that the user installs these libraries from completely independent sources always (as is generally the case for dynamic deps)? In the latter case, maybe spell this out in the docs.

Copy link
Copy Markdown
Contributor Author

@vadorovsky vadorovsky Oct 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last question is correct. I expect dynamic libraries just to be in /usr/lib(64) in form of .so files, which usually means installing those libraries from packages (like libevent-dev or libevent-devel, depends on distrubition) or from manual compilation (./configure --disable-static --enable-shared && make && make install). But as you mentioned in the last question, they might come from completely independent sources.

I will write it as a comment and in README.

My main motivation behind this PR is that I would like to package Envoy in openSUSE. We already ship all libraries needed by Envoy only as shared libraries. Generally we don't accept shipping static libraries unless we have really good reasons for doing so.

@vadorovsky vadorovsky changed the title bazel: Allow to link third party libraries dynamically [WIP] bazel: Allow to link third party libraries dynamically Oct 4, 2018
Comment thread bazel/envoy_build_system.bzl Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you factor this pattern out into a macro? I think if it's just a single return select(...) that Skylark is able to compose this.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would still argue that version numbers etc. don't belong in general BUILD files. Ideally we capture this kind of detail alongside the repository_locations.bzl or somewhere else confined to bazel/ directory.

Copy link
Copy Markdown
Contributor Author

@vadorovsky vadorovsky Oct 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have even better idea. Since libluajit version may vary in different distributions, it might be reasonable to use pkg-config for outputing proper flags. Like i.e.:

$ pkg-config --libs luajit
-lluajit-5.1

or

$ pkg-config --libs libevent_pthreads
-pthread -levent_pthreads -levent

I will try to write some macro or function for that in bazel/ dir.

Copy link
Copy Markdown
Member

@htuch htuch Oct 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, trying to hide this sounds nice, but using pkg-config is kind of non-hermetic, so that might be hard to fit into the Bazel model. I'd like to loop our resident Bazel expert @jmillikin-stripe into this discussion and also @irengrig from the Bazel development team who has been working on better integration with external build systems.

From a distribution perspective (i.e. SUSE) perspective, you probably don't even want to be using the version of LuaJIT that Envoy is pulling down from GitHub, you probably want to point at the existing installation in /usr/lib. This would involve setting up these external dependencies yourself in your WORKSPACE. I.e. before calling envoy_dependencies(), you already establish what //external:luajit and use the skip_targets arg.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bazel allow toolchains to rely on system installed libararies, so if you want to use headers/libraries from /usr, you may just need to generate your own https://github.com/envoyproxy/envoy/blob/master/ci/prebuilt/BUILD file with correct path.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@htuch Yes, being able LuaJIT and the other dependencies available in /usr/lib would be great.

@lizan OK, so I get that relying on system installed libraries is possible. Can you point me to some documentation or give some advice how should I generate my own BUILD file? Where exactly (in which directory) should I put this file?

Sorry for asking that basic questions, but using Google and looking at the documentation didn't make that clear for me and I feel lost.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lizan And another question. Is there something wrong with my attempt of changing ci/prebuilt/BUILD in this PR? third_party/... means /usr/... in practice, so I already teached this file to look for .so files in /usr/lib*.

Comment thread ci/prebuilt/BUILD Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you comment on how you expect the dynamic libraries to be distributed? As things stand, once you do a dynamic link, the .so artifacts that you rely on live in the Bazel cache. How would a user be expected to bundle them up for distribution? Or, is the idea that the user installs these libraries from completely independent sources always (as is generally the case for dynamic deps)? In the latter case, maybe spell this out in the docs.

@htuch
Copy link
Copy Markdown
Member

htuch commented Oct 4, 2018

@mrostecki The mac CI job looks genuinely broken, can you take a look?

Provide an option `--define dynamic_linking=enabled` which allows
to link third-party libraries dynamically.

An another change is using `glob` function to resolve library
paths. Some Linux distributions use /usr/lib64 directory instead
of /usr/lib (if system is 64-bit). To fix build on them, the
wildard expression like `thirdparty/lib*/name_of_library.a` needs
to be used.

Risk Level: Low
Testing: None, but some CI tests in future could be added
Docs Changes: Option described in bazel/README.md
Release Notes: n/a

Signed-off-by: Michal Rostecki <mrostecki@suse.de>
@vadorovsky
Copy link
Copy Markdown
Contributor Author

@htuch I added macros, I still need to investigate the CI failure on mac and add more info to docs. I will do that on Monday.

@stale
Copy link
Copy Markdown

stale Bot commented Oct 15, 2018

This pull request has been automatically marked as stale because it has not had activity in the last 7 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions!

@stale stale Bot added the stale stalebot believes this issue/PR has not been touched recently label Oct 15, 2018
@vadorovsky
Copy link
Copy Markdown
Contributor Author

vadorovsky commented Oct 17, 2018

I'm trying to make Envoy build working there:

https://build.opensuse.org/package/show/home:mrostecki/envoy

It's not building successfully yet, but almost...

And here are my patches:

https://build.opensuse.org/package/view_file/home:mrostecki/envoy/bazel-link-third-party-libraries-dynamically.patch?expand=1
https://build.opensuse.org/package/view_file/home:mrostecki/envoy/bazel-allow-to-distdir-all-dependencies.patch?expand=1

So, the motivation behind my work there is that:

  • openSUSE is not accepting static linking of libraries, we only allow dynamic linking (with very few exceptions, and yeah, there is probably no option that Envoy and its deps will become one of them)
  • OBS (Open Build System, the software which is behind build.opensuse.org) doesn't have Internet connection during package builds. We do that on purpose - we want to have all tarballs and code which we want to build before executing the build. In our thinking, downloading stuff during build means that build is not reproducible.

For now, libraries from ci/prebuilt/BUILD are dynamically linked, but all repos from bazel/repositories_locations.bzl are still bundled. I'm using --distdir option from Bazel to use previously fetched tarballs. But I would really like to avoid bundling dependencies and:

  • link dynamically C/C++ libraries defined in bazel/ too
  • use Python dependencies from the system
  • use Go compiler from the system

Sorry if it sounds a little bit harsh, that's not my intention. I know that our (SUSE vs Envoy upstream developers) philosophies about building and distributing software differ a lot. And what I'm trying to do is to reach some agreement.

We prefer dynamic linking of dependencies, because if there is some bug or security vulnerability, we want to apply the fix once for the whole Linux distribution. Sometimes we would like to do that downstream (it means - apply some patches before they are accepted upstream, or cherry-pick some commit before it's released, i.e. to fix customer's environment). Bundling libraries for each piece of software means that we need to care about applying fixes and upgrades multiple times and tracking that kind of activity is really painful.

For now I'm closing this pull request. It cannot be merged in the current shape.

I will let you know (especially @lizan, thanks for all your help and guidance!) how my efforts of packaging Envoy go. At the point when I will have fully working package and I will ensure that I dynamically linked as much as possible, I will tell you. And then we can start discussing about upstreaming that (or whether it even makes sense to upstream that).

@vadorovsky vadorovsky closed this Oct 17, 2018
@htuch
Copy link
Copy Markdown
Member

htuch commented Oct 17, 2018

@mrostecki Over time we expect our external dependency handling story to improve, based on work that @irengrig is doing to allow Bazel to natively support external cmake builds. At that time, we should see convergence of the different build approaches that currently exist in Envoy for external deps (see https://github.com/envoyproxy/envoy/blob/master/bazel/EXTERNAL_DEPS.md).

We don't really like the situation any more than you do; it is what it is because we wanted to have Bazel reasonably work with our OSS dependencies after the cmake migration and native support was lacking.

@lizan
Copy link
Copy Markdown
Member

lizan commented Oct 18, 2018

@mrostecki Glad to see you make some progress, but yeah I know the situation around dependency management is not great today.

OBS (Open Build System, the software which is behind build.opensuse.org) doesn't have Internet connection during package builds. We do that on purpose - we want to have all tarballs and code which we want to build before executing the build. In our thinking, downloading stuff during build means that build is not reproducible.

This is great, particularly I like your patch to specify all sha256 sums to used with --distdir. I think we can consider about using it in our CI too, perhaps with CircleCI cache (@htuch WDYT?). If you have time, would you mind make a PR out of that patch?

link dynamically C/C++ libraries defined in bazel/ too

You should be able to do this with similar techniques you did with //ci/prebuilt/BUILD for some of them. For example, tclap, spdlog. Though some of them are header only so I'm not sure how much gain you would get.

use Python dependencies from the system
use Go compiler from the system

Those are build time dependency only. What's your policy about them?

We prefer dynamic linking of dependencies, because if there is some bug or security vulnerability, we want to apply the fix once for the whole Linux distribution. Sometimes we would like to do that downstream (it means - apply some patches before they are accepted upstream, or cherry-pick some commit before it's released, i.e. to fix customer's environment). Bundling libraries for each piece of software means that we need to care about applying fixes and upgrades multiple times and tracking that kind of activity is really painful.

I understand this philosophical difference between us and distribution maintainers. Note that to make this work the library would be maintaining ABI compatibility. For example BoringSSL that Envoy bundles doesn't guarantee any ABI compatibility.

Anyway, let me know if you have any progress or any question.

@vadorovsky
Copy link
Copy Markdown
Contributor Author

@htuch Glad to hear about the ongoing work on external cmake bulds. I will keep an eye on it.

@lizan

This is great, particularly I like your patch to specify all sha256 sums to used with --distdir. I think we can consider about using it in our CI too, perhaps with CircleCI cache (@htuch WDYT?). If you have time, would you mind make a PR out of that patch?

Sure, I wil ltry to sumit a PR today.

You should be able to do this with similar techniques you did with //ci/prebuilt/BUILD for some of them. For example, tclap, spdlog. Though some of them are header only so I'm not sure how much gain you would get.

Even if some dependencies are header only, I still would like to use *-devel packages for them. Which seems to be doable in the way I did in //ci/prebuilt/BUILD, so it should be fine.

Those are build time dependency only. What's your policy about them?

If possible, I would like to still use buld time dependencies from system. Especially, I would like to not bundle Go. Bundling Python dependencies for build only maybe will be acceptable for us, but still, I will try to not bundle them if possible.

I understand this philosophical difference between us and distribution maintainers. Note that to make this work the library would be maintaining ABI compatibility.

Yes, I'm aware of that.

For example BoringSSL that Envoy bundles doesn't guarantee any ABI compatibility.

Actually, we will make an expection (hopefully the only one) for BoringSSL and bundle it. So we are fine with using --distdir for BoringSSL even in our packaging. That's because BoringSSL installed in the system would conflict with OpenSSL.

@vadorovsky
Copy link
Copy Markdown
Contributor Author

PR about --distdir #4779

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale stalebot believes this issue/PR has not been touched recently

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants