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

Link C libraries statically if possible on linkstatic = True binaries #587

Merged
merged 7 commits into from
Jan 18, 2019

Conversation

aherrmann
Copy link
Member

Closes #580

Changes rules_haskell to prefer linking C library dependencies statically over dynamically on Haskell binary targets with linkstatic = True.

GHC's default behaviour (following from the linker's behaviour) is to prefer dynamic libraries over static libraries for C library dependencies, even when linking statically against Haskell libraries.

With this change only static versions of C library dependencies are passed as inputs to the linking action - unless no static library is available. This forces the linker to link against static versions of C library dependencies.

Adds a regression test for #580.

So these can be used in other `.bzl` files.
I.e. when building a Haskell binary with `linkstatic = True`, then link
statically against Haskell and C library dependencies where possible.

GHC's default behaviour (following from the linker's behaviour) is to
prefer dynamic libraries over static libraries for C library
dependencies, even when linking statically against Haskell libraries.

By only passing static library versions (unless on static library is
available) of C library dependencies as inputs to the linking action,
the linker has no choice but to link statically.

Closes #580
Test that a Haskell binary compiled with `linkstatic = True`, will only
link to static library dependencies (where available), and that a
Haskell binary compiled with `linkstatic = False`, will link all its
library dependencies dynamically (where available).

The test cases assume that for each library dependency both a dynamic
and a static version are available, i.e. the default of `linkstatic =
False` for library dependencies.

Uses `haskell_test` in place of `haskell_binary` to ensure that the
resulting binaries can be executed without any runtime linker errors.
@mboes
Copy link
Member

mboes commented Jan 17, 2019

What do the CC rules do here? If you cc_import something that has both a dynamic and static version, is the static version preferred in the default "mostly static" mode?

@mboes
Copy link
Member

mboes commented Jan 17, 2019

I think I have my answer in example 5 of this section: https://docs.bazel.build/versions/master/be/c-cpp.html#cc_import.

So this PR is ultimately bringing us in line with the CC semantics for linkstatic?

@aherrmann
Copy link
Member Author

@mboes

So this PR is ultimately bringing us in line with the CC semantics for linkstatic?

Yes, haskell_binary and haskell_test will prefer static linking over dynamic linking for C library dependencies when a static library is available.

dbg mode enforces static linking in which case the test case for dynamic
linking will fail.
`objdump` is not available on the MacOS build. Furthermore, on MacOS
only direct library dependencies are listed under the shared library
dependencies. Also, on MacOS the dynamic library dependency listed in
the binary's header uses the library ID instead of the mangled library
path as on Linux.

This changes and simplifies the binary-linkstatic-flag tests to work on
both Linux and MacOS seemlessly.

First, we turn the indirect C library dependency into a direct
dependency.

Second, instead of checking for shared library dependencies, we directly
check for the `value` and `*HsLib_value_closure` symbols. In a
statically linked binary both those symbols will be defined directly in
the binary. In a dynamically linked binary both symbols will be listed
as undefined. The `nm` tool is available on both the Linux and MacOS
builds and can list all undefined symbols in the binary.
@aherrmann aherrmann merged commit 3e5e413 into master Jan 18, 2019
@aherrmann aherrmann deleted the static-cbits branch January 18, 2019 11:56
binary="$1"
mode="$2"
if [[ $mode = dbg ]]; then
# Skip test in debug builds. Debug mode forces static linking.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice trick!

@aherrmann aherrmann mentioned this pull request Jan 28, 2019
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.

3 participants