google / hrepl

Interactive development for Bazel/Haskell rules
Apache License 2.0
47 stars 10 forks source link

User-specified static library could not be loaded (.../_solib_k8/.../libz.so) #9

Open aherrmann opened 4 years ago

aherrmann commented 4 years ago

hrepl fails to load targets that depend on certain types of dynamic libraries.

This can be reproduced on the rules_haskell repository with the following command:

$ nix-shell --run 'hrepl //tests/binary-with-indirect-sysdeps:hs-lib'
GHCi, version 8.6.5: http://www.haskell.org/ghc/  :? for help
<command line>: User-specified static library could not be loaded (/home/aj/.cache/bazel/_bazel_aj/021cc9f0bfc60754963d997427e7eb3e/execroot/rules_haskell/bazel-out/k8-fastbuild/bin/_solib_k8/_U@zlib.dev_S_S_Czlib___Uexternal_Snixpkgs_Uzlib_Slib/libz.so)
Loading static libraries is not supported in this configuration.
Try using a dynamic library instead.

Error running GHCi.

Using the --show-commands flag shows that GHCi is passed the following flags:

-lz -lz.so -lz.so.1.2

This seems to be the source of the issue and seems to be caused by the following line in hrepl: https://github.com/google/hrepl/blob/33f879eecd986c92ba67f31aec05e3d7f4fbc025/hrepl/Repl.hs#L239 That logic to obtain the library name from a file name fails on versioned libraries like libz.so.1.2.11, or on system libraries outside of Linux, e.g. libz.dylib.

The target //tests/binary-with-indirect-sysdeps:hs-lib depends on a libz that is provided by nixpkgs and comes in three shapes: libz.so libz.so.1 libz.so.1.2.11.

hrepl revision 33f879eecd986c92ba67f31aec05e3d7f4fbc025 rules_haskell revision b41234677c9381982aae98098fb473a5b733c945

judah commented 4 years ago

Thanks for the report. Would if work we just changed rules_haskell (in info.bzl:compile_info_output_groups) to remove any C libraries whose path doesn't end in ".so"? Does rules_haskell already make a similar distinction when figuring out the command-line for, say, linking a haskell_binary with linkstatic=False against libz? (I assume in that case it also only needs to only pass -lz.)

aherrmann commented 4 years ago

Would if work we just changed rules_haskell (in info.bzl:compile_info_output_groups) to remove any C libraries whose path doesn't end in ".so"?

That wouldn't work on other platforms, e.g. on Darwin, nixpkgs or system provided libraries would end on .dylib. Also, if one wants to use the transitive_cc_libs field to determine the required library files, then one will need all of them. Typically, libz.so.1.2.11 is the actual library file, libz.so is a symlink and is what ld finds when one passes -lz, libz.so.1 is another symlink and matches the SONAME of the library, so artifacts that dynamically link against libz will look for that file.

Does rules_haskell already make a similar distinction when figuring out the command-line [...]?

rules_haskell has logic to determine the library name based on a file name. It strips the lib prefix and the file extension where it considers all of .so.1.2.11 as the extension. We don't currently deduplicate the resulting linker flags, so we'll have -lz -lz -lz. AFAIK ld handles this fine, but if it's an issue one could deduplicate with something like map head . groups (to preserve linking order).

jamesthompson commented 4 years ago

@aherrmann I've just been bitten by this with rules_haskell on macOS trying to link against postgresql-libpq.

There it has a static library libpgcommon.a that it's trying to load and it's giving me the same error.

User-specified static library could not be loaded (external/nixpkgs_postgresql/lib/libpgcommon.a)
Loading static libraries is not supported in this configuration.
Try using a dynamic library instead.