Haskell动态库

Kai*_*aur 8 haskell compilation ghc

http://www.vex.net/~trebla/haskell/so.xhtml描述了如何编译共享库.

关于编译命令:

ghc -O2 -dynamic -shared -fPIC -o libEval.so Eval.hs hsbracket.c -lHSrts-ghc7.6.3
Run Code Online (Sandbox Code Playgroud)

它说:

(你能否省略-dynamic请求其他软件包的静态库?不是真的,它们不是用-fPIC生成的.特别是在x86_64上它是非法的.)

为什么会这样?如果没有libHS*依赖项,应该怎么做才能编译共享库?

Dun*_*tts 10

由于Kaiko私下与我联系以获得答案,不妨在此发布...

精简版

通过省略-dynamic,您将尝试获取所有静态.a库并将它们链接到一个大型.so文件中.那些.libs本身是在没有-fPIC的情况下构建的.最终在.so文件上的所有代码必须使用-fPIC构建(至少在ELF x86-64上).因此,在这种情况下链接会失败,因为-fPIC是必需的,但libs不是用-fPIC构建的.

长版

构建静态库和动态库的不同方法有一些不同:

  1. 它是作为.a存档还是.so(或.dll/.dynlib)对象构建的?
  2. 它是用-fPIC构建的,是否与位置无关的代码?
  3. 外部符号是否应位于同一DSO或外部DSO中?

原则上,这些东西的许多不同组合是有意义的,但实际上只使用了少数几种.

在Linux(ELF)上,​​有两种构建库的标准方法,完全静态和完全动态.在完全静态的方法中,上面问题1,2,3的答案是:.a存档,没有-fPIC,相同的DSO.在完全动态的方法中,答案是:.so lib,-fPIC,外部DSO.

现在你想要做的是与众不同.您希望将所有库构建为.a文件,但希望-fPIC和外部符号位于同一DSO中.这样就可以将所有这些库链接到一个巨大的共享库中.因此,关键的区别在于使用-fPIC,因为在ELF(特别是x86_64)上,最终在共享库中的代码必须使用-fPIC构建.

相比之下,在Windows上,GHC可以完全按照您的需要进行操作,将所有Haskell库(包括RTS等)链接到一个大型共享库(.dll)中.这是因为在Windows上(与ELF不同),位置无关的代码无关紧要.所以在Windows上,可以使用静态库并将它们链接到一个大的共享库中.

原则上,如果所有Haskell库都是静态构建但使用-fPIC,那么在Linux上也应该可以实现.这不是默认值,这就是为什么在Linux上不能省略-dynamic的直接原因.

因此原则上,可以尝试使用-fPIC标志从源重建ghc和核心库,然后查看它是否可以省略-dynamic并将所有内容链接到一个巨大的共享库中.


Kai*_*aur 4

是的,使用 -fPIC 进行编译会有所帮助。以下是如何做到这一点。

ghc-7.8.4/mk/build.mk:

 SRC_HC_OPTS     = -H64m -O 
 EXTRA_HC_OPTS   = -fPIC    
 SRC_CC_OPTS     = -fPIC -O 
 GhcStage1HcOpts = -fasm -O0
 GhcStage2HcOpts = -fasm -O0
 GhcLibHcOpts    = -fasm -O2
 GhcLibWays      = v dyn    
 DYNAMIC_GHC_PROGRAMS = YES 
 DYNAMIC_BY_DEFAULT   = NO  
 SplitObjs            = NO  
 HADDOCK_DOCS         = NO  
 BUILD_DOCBOOK_HTML   = NO  
 BUILD_DOCBOOK_PS     = NO  
 BUILD_DOCBOOK_PDF    = NO  
Run Code Online (Sandbox Code Playgroud)

当你编译 ghc 时:

export EXTRA_CONFIGURE_OPTS="--disable-library-profiling --enable-shared"
Run Code Online (Sandbox Code Playgroud)

要使用 -fPIC 构建 cabal 包,请使用:

cabal install --enable-shared --ghc-option=-fPIC text
Run Code Online (Sandbox Code Playgroud)

测试文件foo.hs(Data.Text 用于查看 cabal 包是否也有效):

import Foreign.C as C 
import Data.Text as T
import Data.Text.Foreign as T 
foreign export ccall   len :: CString -> IO CInt 
len t = C.peekCString t >>= return . CInt . fromIntegral . T.length . T.pack  
main = return ()
Run Code Online (Sandbox Code Playgroud)

动态构建:

ghc -dynamic --make foo.hs
Run Code Online (Sandbox Code Playgroud)

动态与静态混合构建(不确定是否需要 pthread,但它说明了如何添加动态链接):

ghc -fPIC -shared --make -o libfoo.so \
 -optl-Wl,-Bstatic -lHSrts -lCffi \
   -lHSbase-4.7.0.2 -lHSinteger-gmp-0.5.1.0 -lHSghc-prim-0.3.1.0 \
-optl-Wl,-Bdynamic -lpthread foo.hs
Run Code Online (Sandbox Code Playgroud)