无法在Windows

时间:2017-09-27 13:15:56

标签: r haskell dll

我经常使用Haskell创建一些我在R中加载的DLL,这非常有用。

但我有一些处理xlsx库的代码,我可以将它编译成DLL而没有问题,但是当我在R中加载DLL时,这完全崩溃了R会话。但是这只发生在Windows上,Linux上没有问题。

我设法找到一个最小的例子,有一些奇怪的东西。这是我的最小例子:

{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE OverloadedStrings #-}

module TestDLL where
import Codec.Xlsx
import Control.Lens
import qualified Data.ByteString.Lazy as L
import Foreign
import Foreign.C
import Foreign.C.String (peekCString, newCString)

test :: IO ()
test = do
  bs <- L.readFile "report.xlsx"
  let value = toXlsx bs ^? ixSheet "List1" .
              ixCell (3,2) . cellValue . _Just
  putStrLn $ "Cell B3 contains " ++ show value

... some elementary functions here ...

如果我将此代码编译为DLL,则在R中加载此DLL会导致Windows上的R会话崩溃。如果删除test函数,则不存在此类问题。但是test函数甚至没有导出(使用foreign export)并且其他函数没有调用它,这不是很奇怪吗?如果我不导出此函数,如果我不使用它,为什么DLL处理这个函数?

更重要的是,为什么在加载DLL时R会话崩溃,以及如何解决这个问题?

修改

我现在有一个更小的例子。这有效:

test :: IO Xlsx
test = do
  bs <- L.readFile "report.xlsx"
  return $ toXlsx bs 

这崩溃了:

test :: IO (Maybe Worksheet)
test = do
  bs <- L.readFile "report.xlsx"
  return $ toXlsx bs ^? ixSheet "List1"

看起来Windows有^?的问题。

编辑2

使用此等效代码不会崩溃:

test :: IO (Maybe Worksheet)
test = do
  bs <- L.readFile "report.xlsx"
  let xlsx = toXlsx bs
  let sheets = _xlSheets xlsx
  let mapping = DM.fromList sheets
  return $ DM.lookup "List1" mapping

Windows遇到^? ixSheet问题。现在让我试试我的真实例子......

1 个答案:

答案 0 :(得分:1)

我没有解决方案(编辑:我有一个,见下文),但我可以说这是由于导出符号数量的限制。

编译代码时

test :: IO (Maybe Worksheet)
test = do
  bs <- L.readFile "report.xlsx"
  let xlsx = toXlsx bs
  let sheets = _xlSheets xlsx
  let mapping = DM.fromList sheets
  return $ DM.lookup "List1" mapping

我用DependencyWalker检查DLL,我看到有48318个导出的符号。这是可以接受的。

但是对于其他代码:

test :: IO (Maybe Worksheet)
test = do
  bs <- L.readFile "report.xlsx"
  return $ toXlsx bs ^? ixSheet "List1" 

生成的DLL达到导出符号的最大数量:65535 = 2 ^ 16-1个导出符号。此DLL被“截断”。

编辑:可能的解决方案!

可能的解决方案是使用def文件。在文件MyDef.def中,列出要导出的功能,例如funexportHsStart,如下所示:

EXPORTS
 funexport
 HsStart

并在用于编译的命令行末尾添加MyDef.def

ghc -shared foo.hs StartEnd.c -o foo.dll MyDef.def

我刚刚测试了这个解决方案,但它确实有效。然而,这是我第一次测试它,所以我不能保证。我也很惊讶ghc不会自动执行此操作。