haskell / cabal

Official upstream development repository for Cabal and cabal-install
https://haskell.org/cabal
Other
1.57k stars 676 forks source link

Hide cbits symbols via visibility attribute or compiler flag? #9991

Open endgame opened 1 week ago

endgame commented 1 week ago

Describe the feature request When compiling cbits-style code (code that's designed for foreign import only by its containing library), it would be nice if there was some official/automatic way to restrict the symbol visibility of the compiled bundled C code.

AIUI, there are a couple of ways to do this:

  1. Set an attribute on the definitions. This is __attribute__((visibility)) on GCC >=4. I think Clang supports the same syntax and has done so for a long time. Still, it would be nice if we could signal (via #define?) that it's supported, so the code could still work with older compilers (assuming they're supported by GHC). GCC >=5 and at least Clang >=3.6 support the preprocessor symbol __has_attribute(foo), but I don't know if MSVC does, or if GHC even supports MSVC.
  2. Pass -fvisibility=hidden on the command line to set the default visibility and then change it where needed via __attribute__.

In my own C library projects, I only do "visibility stuff" if both №1 and №2 are available (i.e., most of the time on modern systems). When it's available, I set -fvisibility=hidden and then put (a macro that expands to) __attribute__((visibility("default"))) on the public interface. For cbits-type stuff, there shouldn't be a public interface, so we should just be able to hide everything that's foreign imported, as it would only be referenced by the Haskell functions in the same Dynamic Shared Object (DSO).

Note that this isn't a complete solution to the problem, as AIUI static libraries can't do visibility stuff. So you do still risk symbol clashes there (or the linker just picking one, maybe?).

Additional context crypton-0.30 renamed some of its foreign imports to prevent a symbol clash during linking. This is exactly the "old woe" mentioned by the linked GCC wiki page.

I saw someone on irc://irc.libera.chat/reflex-frp just yesterday having problems with cryptonite (I have advised him to switch to crypton) and libsodium using the same symbols:

7:04 AM  Oh no!  I almost had my iOS build, but in the very last build step - frontend-static-aarch64-ios-0.1 - I get 'ld: 6 duplicate symbols for architecture arm64'
7:07 AM  Via different dependencies, I have two cryptography libraries, 'cryptonite' for Haskell and 'libsodium' for C.  Linking them together statically clashes.
7:14 AM  All 6 duplicates stem from 'blake2b-ref.o'
9:04 AM  I don't think we use blake anywhere in our app.  Going to local-fork either cryptonite or libsodium and rip blake2-ref out.  Or does anyone here know like, a linker option to make them coexist?
9:04 AM  or so?
hacklschorsch commented 1 week ago

Thanks @endgame !