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 CcInfo provider for C library dependencies #663

Merged
merged 6 commits into from
Feb 4, 2019
Merged

Conversation

aherrmann
Copy link
Member

@aherrmann aherrmann commented Jan 29, 2019

Implements the cc_library dependency part of #593.

  • Extract information on C library dependencies from Bazel's builtin CcInfo provider. This allows to benefit from Bazel's central _solib directory which holds all dynamic C library dependencies, and thereby allows to reduce the amount of RUNPATH entries. This also allows to benefit from Bazel's builtin library name mangling without having to reimplement it in rules_haskell
  • Accordingly, this PR removes the C library name mangling implementation in rules_haskell.
  • Bazel only mangles names of dynamic library dependencies. If a library dependency is available as both static and dynamic library, then each will have a different "mangled" name. However, GHC expects both static and dynamic libraries to be available under the same name. The reason is that library dependencies have to be listed in the extra-libraries section of the package configuration file. To link the final binary statically, we only provide static archives at linking. However, for GHC's own linker (TemplateHaskell, REPL, etc.) we require dynamic libraries. Both have to match the entries in extra-libraries. We achieve this by manually mangling the static archives based on Baezl's builtin mangling if the static and dynamic library "mangled" names differ.
  • On MacOS GHC's builtin linker hard-codes the expectation that any dynamic library dependencies are .dylib files. However, Bazel produces .so files. To work around this issue we create symlinks to adapt any .so dependencies as .dylib dependencies. Note, that this is only required when interacting with GHC's builtin linker. I.e. for compilation, doctests, REPL. In particular, this is not required for the final linking. This is good news as it allows us to still benefit from Bazel's central _solib directory on MacOS.
  • Adds a regression test for indirect cc_library system library dependencies. Previously these did not work due to manual name mangling.

Copy link
Member

@mboes mboes left a comment

Choose a reason for hiding this comment

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

LGTM, but I'm a bit uncomfortable with the boilerplate around gathering transitive library dependencies. Could you try factoring that out a bit more? There's some platform-specific mangling going on there, that i'll be all too easy to miss after some refactoring in the future.

haskell/private/providers.bzl Outdated Show resolved Hide resolved
@mboes
Copy link
Member

mboes commented Jan 29, 2019

@guibou could you test this on your codebase before we merge?

@aherrmann
Copy link
Member Author

Not quite there, yet.

This seems to trigger segfaults in happy, when compiling with GHC > 8.2.2. Probably related to -fPIC behaviour.

@guibou
Copy link
Contributor

guibou commented Jan 30, 2019

@mboes tests are OK.

Copy link
Contributor

@guibou guibou left a comment

Choose a reason for hiding this comment

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

LGTM.

@aherrmann
Copy link
Member Author

I've looked into the happy segfault. This turns out to be an issue in Hazel. Hazel always links against the threaded runtime in cbits. Now that transitive C library dependencies are tracked properly by rules_haskell, this dependency ends up being forwarded into the happy binary. happy ends up being linked against both the threaded and non-thread rts and that causes the segfault at runtime.

A simple workaround in Hazel is to only include the rts headers into cbits targets, not the library.

I'll address @mboes 's comments, and then merge this PR, and fix the Hazel issue separately.

@aherrmann aherrmann force-pushed the cc_dependencies branch 2 times, most recently from bb1b9eb to cf431a8 Compare January 30, 2019 17:36
@Profpatsch
Copy link
Contributor

I’ll review tomorrow.

Copy link
Contributor

@Profpatsch Profpatsch left a comment

Choose a reason for hiding this comment

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

I love these changes!

There’s some extreme amounts of copy & paste in some places, which we should be able to get rid of.

haskell/doctest.bzl Show resolved Hide resolved
haskell/private/actions/link.bzl Outdated Show resolved Hide resolved
haskell/private/dependencies.bzl Show resolved Hide resolved
haskell/private/providers.bzl Outdated Show resolved Hide resolved
- Extract information on C library dependencies from Bazel's builtin
  CcInfo provider. This allows to benefit from Bazel's central `_solib`
  directory which holds all dynamic C library dependencies, and thereby
  allows to reduce the amount of RUNPATH entries. This also allows to
  benefit from Bazel's builtin library name mangling without having to
  reimplement it in rules_haskell
- Bazel only mangles names of dynamic library dependencies. If a library
  dependency is available as both static and dynamic library, then each
  will have a different name (`.artifact()`). However, GHC expects both
  static and dynamic libraries to be available under the same name.
  The reason is that library dependencies have to be listed in the
  extra-libraries section of the package configuration file. To link the
  final binary statically, we only provide static archives at linking.
  However, for GHC's own linker (TemplateHaskell, REPL, etc.) we require
  dynamic libraries. Both have to match the entries in extra-libraries.
  We achieve this by manually mangling the static archives based on
  Baezl's builtin mangling if the static and dynamic library names
  (`original_artifact()`) differ.
- On MacOS GHC's builtin linker hard-codes the expectation that any
  dynamic library dependencies are `.dylib` files. However, Bazel
  produces `.so` files, see [1]. To work around this issue we create
  symlinks to adapt any `.so` dependencies as `.dylib` dependencies.
  Note, that this is only required when interacting with GHC's builtin
  linker. I.e. for compilation, doctests, REPL. In particular, this is
  not required for the final linking. This is good news as it allows us
  to still benefit from Bazel's central `_solib` directory on MacOS.

[1]: https://stackoverflow.com/questions/2339679/what-are-the-differences-between-so-and-dylib-on-osx
Addressing PR review comments.

Reducing the risk of future refactorings introducing subtle bugs by
missing required steps in get_solibs_for_ghc_linker.
@aherrmann
Copy link
Member Author

Rebased and addressed all comments.

@aherrmann aherrmann dismissed Profpatsch’s stale review February 4, 2019 18:24

All change-requests addressed.

@aherrmann aherrmann merged commit e6094bf into master Feb 4, 2019
@aherrmann aherrmann deleted the cc_dependencies branch February 4, 2019 18:25
(cc_link_libs, _cc_solibs) = _link_dependencies(
hs,
dep_info,
True, # dynamic linking mode
Copy link
Contributor

@Profpatsch Profpatsch Feb 6, 2019

Choose a reason for hiding this comment

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

You can use named arguments in invocations in skylark, dynamic = True.

I strongly suggest we switch all calls to explicitly name arguments.

aherrmann added a commit that referenced this pull request Feb 6, 2019
To improve readability.

Addressing review comment #663 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants