【问题标题】:How to use a DLL in a Haskell project?如何在 Haskell 项目中使用 DLL?
【发布时间】:2015-09-20 23:05:29
【问题描述】:

我想在 Haskell 项目中使用外部库 RDFox

上下文:我正在使用 GHC 7.10 和 stack 处理 64 位的 Windows 和 Linux。 RDFox 是用 C++ 编写的。可以使用 Java 和 Python 包装器下载 RDFox 共享库(.dll、.so)。

目标:我想在我的 Haskell 项目中重用 RDFox (.dll, .so) 编译的库,所以我需要为 RDFox 创建一个 Haskell 包装器。

问题: 作为 Haskell 的新手,我很难知道从哪里开始。我找到了几个关于该主题的页面(来自 Haskell wiki 和 StackOverflow),但我并不清楚工作流程和配置。

问题:我想知道:

  1. 如何配置 stack 和 cabal 以使用外部库,在 Windows Linux 上构建(不同的机器,相同的存储库)。
  2. 如何配置 GHCi 以在此外部库上进行交互式测试。
  3. 将 Python 包装器翻译成 Haskell 是最好的方法吗?我想避免分析 RDFox C++ 代码。

【问题讨论】:

  • 首先您可能需要为 C++ api 创建一个 C 导出的包装器。
  • C++ 中的命名约定比 C 中复杂得多。我认为 FFI 不支持对非 extern-C 事物进行名称修改。
  • 如果您知道名称修改方案,您可以使用Win32 包中的System.Win32.DLLunix 包中的System.Posix.DynamicLinker。但是,两个平台之间的名称修改可能会有所不同,因此您必须做两次工作。如果你写一个 C 包装器,你只需要做一次。
  • 只要学会爱上 C++ 中的 extern "C"{}。
  • 您不需要创建任何 C 包装器。必要的extern "C" 已经到位(如果没有它,将很难创建 Python 包装器)。

标签: haskell shared-libraries ghc cabal haskell-stack


【解决方案1】:
  1. 您需要在.cabal 文件的executable 部分中使用extra-lib-dirsextra-libraries,如下所示:

    name:                 MyApp
    version:              0.1.0.0
    synopsis:
    homepage:
    author:               simon.bourne
    category:
    build-type:           Simple
    cabal-version:        >=1.10
    
    library
      exposed-modules:      HelloWorld
      build-depends:        base >= 4.7 && < 5
      hs-source-dirs:       src
      default-language:     Haskell2010
    
    executable MyApp
      main-is:              Main.hs
      extra-lib-dirs:       lib
      extra-libraries:      helloWorld
      build-depends:        base >= 4.7 && < 5,
                            MyApp
      hs-source-dirs:       app
    
    default-language: Haskell2010
    

    将您的 dll 和 .so 放入 lib。请注意,如果您在 linux 上使用静态库(.a 而不是 .so),则会遇到链接顺序问题。

    有关示例,请参阅 this。不要被名称所迷惑,因为它适用于 .so 文件。

  2. stack ghci 应该可以正常工作,前提是它可以找到您的库(Linux 上的LD_LIBRARY_PATH)。

  3. C API(在您的问题的 cmets 中提到)已经存在。您只需要编写 Haskell FFI 签名,例如:

    foreign import ccall safe "helloWorld" c_helloWorld :: IO ()
    

    我强烈建议使用safe ccalls,并且不要将函数包装在unsafePerformIO 中。

    如果您需要传递非不透明结构,您可能需要调查c2hshsc2hs,但我认为您不需要这样做。有关详细信息,请参阅此question

【讨论】:

    【解决方案2】:

    您需要为 C++ api 和 Haskell 包装器创建一个 C 导出的包装器到 FFI 到 C 导出的包装器。

    这里描述了 C# 和 Haskell 之间的编组: Calling Haskell from C#

    但它在 C++ 和 Haskell 之间的编组非常相似

    例如创建C++导出函数:

    extern "C" __declspec(dllexport) int __cdecl addFive(int number);
    
    extern "C" __declspec(dllexport) int __cdecl addFive(int number)
    {
        return number + 5;
    }
    

    在 Haskell 中你需要导入代码:

    foreign import ccall "addFive" addFive :: Int -> Int
    

    然后你可以在 Haskell 中使用 addFive 作为典型的 Haskell 函数

    对于复合数据类型(类和结构),您需要在 Haskell 中创建 C++ 数据类型模拟。然后您需要描述如何将数据类型从 C++ 编组到 Haskell 以及从 Haskell 编组到 C++。

    在 Haskell 中,这意味着您需要为您的数据类型创建 Storable 实例。

    【讨论】:

      【解决方案3】:

      this documentation的回答:

      ghc -c Adder.hs
      ghc -c StartEnd.c
      ghc -shared -o Adder.dll Adder.o Adder_stub.o StartEnd.o
      

      【讨论】:

      • 这是为了导出一个 haskell dll 用于其他语言。 OP 询问如何在 haskell 程序中使用从 C++ 导出的 dll。
      猜你喜欢
      • 1970-01-01
      • 2021-12-22
      • 2017-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-22
      • 2014-09-28
      • 1970-01-01
      相关资源
      最近更新 更多