从Haskell动态加载.o对象时函数解析错误

时间:2018-09-09 14:34:55

标签: haskell

我正在编写一个我想要模块化架构的工具。我的意思是,用户可以在启动时写下要加载的模块列表,而我的工具将为我加载相应的.o

这是到目前为止我设法编写的代码:

module Core where

import           Data.Monoid                  ((<>))
import           Data.Text                    (pack, unpack)
import           System.Directory             (getHomeDirectory)
import           System.Plugins.DynamicLoader

loadPlugins :: [Text] -> IO ()
loadPlugins plugins = do
  home <- getHomeDirectory
  -- addDLL "/home/tchoutri/.stack/programs/x86_64-linux/ghc-tinfo6-8.4.3/lib/ghc-8.4.3/base-4.11.1.0/libHSbase-4.11.1.0-ghc8.4.3.so"
  let paths = fmap (\x -> (pack home) <> "/.local/lib/polynot/polynot-" <> x <> ".o") plugins
  forM_ paths $ \path -> load path
 where
    load path = do
      m <- loadModuleFromPath (unpack path) (Just $ unpack path)
      resolveFunctions
      loadFunction m "runPlugin"

此刻我要加载的插件非常简单:

{-# LANGUAGE OverloadedStrings #-}

module Polynot.Plugin.Twitter where

runPlugin :: IO ()
runPlugin = putStrLn "[Twitter] 'sup"

它是用stack ghc -- --make -dynamic -fPIC -O3 twitter.hs编译的。然后在polynot-twitter.o中将其重命名为~/.local/lib/polynot/

编译顺利,当我运行stack exec -- polynot时,出现此错误:

polynot: user error (Unable to get qualified name from: /home/tchoutri/.local/lib/polynot/polynot-twitter.o)

谷歌快速搜索显示,此错误的唯一实例出现在源代码中。 :/

此外,我使用的是git版本的dynamic-loader。

(我可能会误以为我选择了模块化体系结构,我完全接受。如果您有更好的方法可以使用,则可以对此发表评论:)

1 个答案:

答案 0 :(得分:1)

我无法复制您的错误。我得到一个Prelude.head: empty list异常。

但是,我的猜测是它与dynamic-loader中的功能有关,期望从匹配模块层次结构的层次目录结构中加载模块。

简而言之,如果我将插件存储在:

~/.local/lib/polynot/Polynot/Plugin/Twitter.o

并像这样使用loadModule

loadModule "Polynot.Plugin.Twitter" 
           (Just "/home/buhr/.local/lib/polynot") (Just "o")

那对我来说还可以。

我使用的Main.hs是以下内容:

{-# LANGUAGE OverloadedStrings #-}

import           Control.Monad                (forM_)
import           Data.Monoid                  ((<>))
import           Data.Text                    (pack, unpack, Text)
import           System.Directory             (getHomeDirectory)
import           System.Plugins.DynamicLoader

loadPlugins :: [Text] -> IO ()
loadPlugins plugins = do
  home <- getHomeDirectory
  let basedir = (pack home) <> "/.local/lib/polynot"
  forM_ plugins (load basedir)
 where
    load dir plugin = do
      m <- loadModule (unpack plugin) (Just $ unpack dir) (Just "o")
      resolveFunctions
      entry <- loadFunction m "runPlugin"
      entry

main = do
  putStrLn "starting!"
  loadPlugins ["Polynot.Plugin.Twitter"]
  putStrLn "done!"