作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我已经阅读了 Haskell 中的插件,但我无法找到一种令人满意的方式来实现我的目的(最好在生产环境中使用)。
我的插件系统目标是:
module SharedTypes (PluginInterface (..)) where
data PluginInterface =
PluginInterface { pluginName :: String
, runPlugin :: Int -> Int }
一些插件列表
-- ~/plugins/plugin{Nth}.?? (with N=1..)
module Plugin{Nth}( getPlugin ) where
import SharedTypes
getPlugin :: PluginInterface
getPlugin = PluginInterface "{Nth}th plugin" $ \x -> {Nth} * x
应用/服务
...
loadPlugins :: FilePath -> IO [PluginInterface]
loadPlugins = undefined
...
我认为使用动态编译链接库(将每个
Plugin{Nth}
编译为共享库)可以工作(作为 FFI)但是
getPlugin
功能点)ghc 7.10
的完整运行示例
module SharedTypes (
PluginInterface (..)
) where
data PluginInterface =
PluginInterface { pluginName :: String
, runPlugin :: Int -> Int
}
插件1.hs
module Plugin1 (
getPlugin
) where
import SharedTypes
getPlugin :: PluginInterface
getPlugin = PluginInterface "Plugin1" $ \x -> 1 * x
插件2.hs
module Plugin2 (
getPlugin
) where
import SharedTypes
getPlugin :: PluginInterface
getPlugin = PluginInterface "Plugin2" $ \x -> 2 * x
app.hs
import SharedTypes
import System.Plugins.DynamicLoader
import System.Directory
import Data.Maybe
import Control.Applicative
import Data.List
import System.FilePath
import Control.Monad
loadPlugins :: FilePath -> IO [PluginInterface]
loadPlugins path = getDirectoryContents path >>= mapM loadPlugin . filter (".plugin" `isSuffixOf`)
where loadPlugin file = do
m <- loadModuleFromPath (combine path file) -- absolute path
(Just path) -- base of qualified name (or you'll get not found)
resolveFunctions
getPlugin <- loadFunction m "getPlugin"
return getPlugin
main = do
-- and others used by plugins
addDLL "/usr/lib/ghc-7.10.1/base_I5BErHzyOm07EBNpKBEeUv/libHSbase-4.8.0.0-I5BErHzyOm07EBNpKBEeUv-ghc7.10.1.so"
loadModuleFromPath "/srv/despierto/home/josejuan/Projects/Solveet/PluginSystem/SharedTypes.o" Nothing
plugins <- loadPlugins "/srv/despierto/home/josejuan/Projects/Solveet/PluginSystem/plugins"
forM_ plugins $ \plugin -> do
putStrLn $ "Plugin name: " ++ pluginName plugin
putStrLn $ " Run := " ++ show (runPlugin plugin 34)
编译执行
[josejuan@centella PluginSystem]$ ghc --make -dynamic -fPIC -O3 Plugin1.hs
[1 of 2] Compiling SharedTypes ( SharedTypes.hs, SharedTypes.o )
[2 of 2] Compiling Plugin1 ( Plugin1.hs, Plugin1.o )
[josejuan@centella PluginSystem]$ ghc --make -dynamic -fPIC -O3 Plugin2.hs
[2 of 2] Compiling Plugin2 ( Plugin2.hs, Plugin2.o )
[josejuan@centella PluginSystem]$ mv Plugin1.o plugins/Plugin1.plugin
[josejuan@centella PluginSystem]$ mv Plugin2.o plugins/Plugin2.plugin
[josejuan@centella PluginSystem]$ ghc --make -dynamic -fPIC -O3 app.hs
[2 of 2] Compiling Main ( app.hs, app.o )
Linking app ...
[josejuan@centella PluginSystem]$ ./app
Plugin name: Plugin1
Run := 34
Plugin name: Plugin2
Run := 68
最佳答案
有the dynamic-loader package ,它允许您将额外的目标文件或共享库加载到您的进程中。 (Hackage 上的版本不适用于 7.10,但当前的 version on GitHub does 。)
有了这个,你可以这样做:
import System.Plugins.DynamicLoader
import System.Directory
loadPlugins :: FilePath -> IO [PluginInterface]
loadPlugins path = do
files <- getDirectoryContents path
mapM (\plugin_path -> do
m <- loadModuleFromPath (path ++ "/" ++ plugin_path) (Just path)
resolveFunctions
plugin <- loadFunction m "getPlugin"
return plugin) files
PluginInterface
数据类型并尝试加载使用旧版本编译的插件,您的应用程序将崩溃。您必须希望
getPlugin
函数的类型为
PluginInterface
,没有检查。最后,如果插件来自不受信任的来源,它可以执行任何操作,即使您尝试调用的函数在 Haskel 中应该是纯函数。
关于haskell - 开箱即用的 Haskell 插件系统,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30681954/
当我开始我的 openbox session 时,我需要这样的东西: firefox -p Profile 1 #Open in workspace 4 firefox -p profile 2 #O
我是一名优秀的程序员,十分优秀!