简体   繁体   中英

Can't load a Haskell dll on Windows

I often create some DLLs with Haskell that I load in R, and this works very well.

But I have some code dealing with the xlsx library, I can compile it to a DLL without issue, but when I load the DLL in R, this totally crashes the R session. However this occurs on Windows only, there's no issue on Linux.

I managed to find a minimal example and there's something weird. This is my minimal example:

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

If I compile this code to a DLL, loading this DLL in R crashes the R session on Windows. There's no such issue if I remove the test function. However the test function is not even exported (with foreign export ) and it is not called by the other functions, isn't it weird ? If I don't export this function and if I don't use it, why the DLL deals with this function ?

And more importantly, why the R session crashes when I load the DLL, and how to fix that ?

Edit

I have a more minimal example now. This works:

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

And this crashes:

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

It looks like Windows has a problem with ^? .

Edit 2

No crash with this equivalent code:

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 has a problem with ^? ixSheet ^? ixSheet . Now let me try on my real example...

I don't have a solution ( edit: I have one, see below ) but I can say this is due to the limit of number of exported symbols.

When I compile the code

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

and I inspect the DLL with DependencyWalker , I see there are 48318 exported symbols. That's acceptable.

But for the other code:

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

the generated DLL reaches the maximal number of exported symbols: there are 65535=2^16-1 exported symbols. This DLL is "truncated".

Edit: A possible solution !

A possible solution consists in using a def file. In a file MyDef.def , list the functions you want to export, eg funexport and HsStart , like this:

EXPORTS
 funexport
 HsStart

and add MyDef.def at the end of the command line you use to compile:

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

I have just tested this solution and it works. However this is the first time I test it, so I would not guarantee yet. I'm also surprised that ghc does not automatically do that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM