haskell / haskell/cabal

Hide cbits symbols via visibility attribute or compiler flag?

Open
#9,991 1 comment 1 reaction 0 assignees View on GitHub
type: enhancement
Dominant language
Haskell
Stars
1.7k
Forks
750
Avg merge
4d 3h
Merged PRs (30d)
28

Description

**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](https://gcc.gnu.org/wiki/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))`](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-visibility-function-attribute) 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 import`ed, 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](https://github.com/kazu-yamamoto/crypton/pull/10) 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?

Contributor guide

Open the contributing guide

Research direction

The issue names no files or tests; start by tracing Cabal's cbits compilation path and how foreign imports are linked. Compare GCC and Clang visibility support with the static-library limitation described here, and define done as an agreed, portable mechanism for restricting bundled C symbols.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, haskell
Domain
build-system
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.