为何必须从共享库而非静态链接调用hs_init函数?
问题根源:多RTS实例的隔离
这个问题的核心在于动态共享库和主程序加载了两个完全独立的GHC RTS(运行时系统)实例,它们的运行状态完全隔离,导致初始化状态无法共享。下面拆解两种调用方式的本质差异:
1. 定义_LIB_INIT:调用共享库内的hs_init
当你通过dlsym从libAdd.so获取并调用hs_init时,你初始化的是共享库自身绑定的动态RTS实例:
- 编译
libAdd.so时使用了-dynamic参数,这意味着共享库会链接动态版本的GHC RTS(即libHSrts-ghc8.2.2.so)。 hs_add作为共享库导出的函数,它的执行逻辑完全依赖这个共享库绑定的RTS实例,而你调用的hs_init正好完成了该实例的初始化,所以整个流程能正常运行。
2. 移除_LIB_INIT:调用静态链接的hs_init
当你直接调用hs_init时,这个函数属于主程序静态链接的RTS实例:
- 你的C程序用
ghc --make -no-hs-main编译时,默认会静态链接GHC RTS(主程序与该静态RTS绑定为一个整体)。 - 但动态加载的
libAdd.so是独立模块,它自身链接了动态RTS,和主程序的静态RTS是完全分离的两个运行环境。 - 你初始化了主程序的RTS,但
hs_add依赖的共享库RTS实例并未被初始化,因此会抛出RTS is not initialised的错误。
补充:如何让两者共享RTS?
如果想让主程序的hs_init能作用于共享库,需要让两者使用同一个RTS实例,可行方案包括:
- 编译共享库时移除
-dynamic参数,改用静态链接RTS(注意可能存在兼容性限制); - 主程序也改为动态链接RTS,且确保共享库与主程序使用同一版本的RTS。
内容的提问来源于stack exchange,提问作者Ed Behn
相关产品推荐
相关产品推荐

