如何减少Haskell DLL中的符号数?(“导出序数太大”)

Bjö*_*ter 10 dll haskell ghc

我正在Haskell中构建一个可在macOS和Windows上使用的DLL,并且后者有问题。具体来说,DLL中的符号数变得太大(“导出序数太大”):

Linking mydll.dll ...
C://Users//bjorn//AppData//Local//Programs//stack//i386-windows//ghc-8.6.5//mingw//bin/ld.exe: Error: export ordinal too large: 73799
collect2.exe: error: ld returned 1 exit status
`gcc.exe' failed in phase `Linker'. (Exit code: 1)
Run Code Online (Sandbox Code Playgroud)

这与https://gitlab.haskell.org/ghc/ghc/wikis/windows-dynamic-linking中描述的问题密切相关,该问题描述了我遇到的序数限制:

这样做的主要原因是PE规范中的限制,该规范将ordinal值(与导出符号关联的唯一数字/索引)使用16位int。这限制了我们可以导出到2^16-1 (~65k)符号的符号数量。

不幸的是,我缺乏@Phyx的专业知识,对于如何解决/解决我的案例问题有些困惑。

调查中

通过一些试验,我使用attoparsec替换了一些代码,据undefined我所知,该代码阻止了attoparsec(以及它的某些依赖项)被链接。这使符号的数量减少到60232(使用计数nm -g mydll.dll | wc -l)。这并不是说attoparsec是问题所在,而只是提供DLL如何随着依赖关系增长的示例。

符号

DLL的最终用户API由许多FFI foreign export ccall函数组成。作为一个例子,有功能/动作logStartedforeign export ccall logStarted :: IO ())。Grepping用于logStarted在输出nm -g我发现:

6b6910d0 D _FFI_logStarted_closure
6af817fc T _FFI_logStarted_info
6b6910d8 D _FFI_zdfstableZZC0ZZCmainZZCFFIZZClogStarted_closure
6af81810 T _FFI_zdfstableZZC0ZZCmainZZCFFIZZClogStarted_info
6b6910c0 D _FFI_zdfstableZZC0ZZCmainZZCFFIZZClogStarted1_closure
6af817c8 T _FFI_zdfstableZZC0ZZCmainZZCFFIZZClogStarted1_info
6b6910b0 D _FFI_zdfstableZZC0ZZCmainZZCFFIZZClogStarted2_closure
6af81780 T _FFI_zdfstableZZC0ZZCmainZZCFFIZZClogStarted2_info
6b76509e R _FFI_zdfstableZZC0ZZCmainZZCFFIZZClogStarted3_bytes
6b691098 D _FFI_zdfstableZZC0ZZCmainZZCFFIZZClogStarted4_closure
6af816d8 T _FFI_zdfstableZZC0ZZCmainZZCFFIZZClogStarted4_info
6af87522 T _logStarted
Run Code Online (Sandbox Code Playgroud)

当我唯一需要的符号是时,这是很多符号_logStarted。类似地,为链接到DLL的每个haskell函数定义了几个符号(无论它们来自哪个包,以及绝大多数当然不是最终用户API的一部分)。

我尝试了什么

  1. 传递--discard-allld(with ld-options: -Wl,--discard-all)可将符号数量减少约100个,因此并不是很有用。

  2. 使用(在https://gitlab.haskell.org/ghc/ghc/wikis/windows-dynamic-linking中提到)的--retain-symbols-file=api.txt选项。首先,这不是一个非常有吸引力的解决方案,因为我必须保持与FFI导出的一致性。无论如何,由于它(似乎)先组装DLL,然后组装条形符号,因此它不起作用。组装步骤仍然失败。(尝试时的结果相似。)ldapi.txt--strip-all

思想

我可以以某种方式要求ghc对要输出的符号进行更多限制吗?最后我要出口的是FFI出口

gen-dll用于构建GHC DLL 的工具可以帮助吗?似乎可以,但是我不确定哪种说法合适。

相关的,也许吗?

(解决方案盯着我吗?)

关于当前构建过程的注意事项

我正在使用foreign-libraryCabal文件中的堆栈和节构建DLL 。但是,当手动编译(使用ghc -o mydll.dll -shared -static [files])时,我得到相同的结果。如有必要(例如集成gen-dll到流程中),我将更改为手动构建脚本。

现在,我在32位Windows上构建,但也打算生成64位版本的DLL。