2017-09-27 67 views
3

我經常創建一些帶有加載到R中的Haskell的DLL,這很好。無法在Windows上加載Haskell dll

但我有一些與xlsx庫有關的代碼,我可以將它編譯成一個沒有問題的DLL,但是當我在R中加載DLL時,這會完全崩潰R會話。然而,這隻發生在Windows上,在Linux上沒有問題。

我設法找到一個最小的例子,有一些奇怪的。這是我的小例子:如果我編譯這段代碼的DLL,裝載在讀該DLL崩潰在Windows R對話

{-# 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 ... 

。如果我刪除test函數,則不存在這樣的問題。然而test函數甚至沒有被導出(使用foreign export),並且它不被其他函數調用,是不是很奇怪?如果我不導出這個函數,並且如果我不使用它,爲什麼DLL處理這個函數?

更重要的是,爲什麼R會話在我加載DLL時崩潰,以及如何解決這個問題?

編輯

我現在有一個更小例子。這工作:

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

我沒有解決方案(編輯:我有一個,請參閱下面的)但我可以說這是由於導出符號的數量限制。

當我編譯代碼

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不會自動做到這一點。

+0

不是一個Haskell用戶,但這看起來很瘋狂的行爲。這也看起來相關:https://ghc.haskell.org/trac/ghc/ticket/5987 –

+0

是的,這很奇怪。最後,使用'MyDef.def',我只有兩個導出的符號,並且該DLL可以工作。我想知道爲什麼GHC出口> 65535無用的符號。 –

+0

這並不奇怪,如果你想一想。函數應用程序在GHC中的工作方式意味着它需要一個信息表和一個關於它實現的每個函數的閉包。這意味着,如果你有一個Haskell dll引用另一個Haskell dll(例如當GHC和cabal使用動態方式),我們需要信息和閉包可用。也許一個標誌,表明該DLL不會被用作導入將是有益的,我會添加一個筆記。然而,什麼是錯誤是我們重新導出從其他包導入的功能。我會考慮修復GHC 8.4。 – Phyx