tôi cần phải có một cái gì đó giống nhưHaskell, GHC 8: tự động tải/mô-đun nhập khẩu
-- Main.hs
module Main where
main :: IO()
main = do
<import Plugin>
print Plugin.computation
Với Plugin như
-- Plugin.hs
module Plugin where
computation :: Int
computation = 4
Tuy nhiên, tôi cần các plugin được biên dịch cùng với các ứng dụng chính . Chúng cần được triển khai cùng nhau. Chỉ việc nhập (không phải biên dịch) của mô-đun sẽ diễn ra tự động.
Tôi tìm thấy Dynamically loading compiled Haskell module - GHC 7.6 trên đường đi và nó hoạt động tốt với GHC 8.0.2 ngoại trừ việc nó yêu cầu tệp nguồn của plugin nằm trong thư mục làm việc hiện tại khi thực thi ứng dụng.
Sửa (07.12.2017)
Có thể tải một mô-đun từ một String thay vì một tập tin bằng cách sử dụng API GHC? http://hackage.haskell.org/package/ghc-8.2.1/docs/GHC.html#t:Target cho thấy rằng nó có thể, nhưng tài liệu có nhiều lỗ và tôi không thể tìm thấy một cách để thực sự làm điều này. Nếu điều này có thể được thực hiện, tôi có thể sử dụng file-embed để bao gồm tệp nguồn plugin vào nhị phân đã biên dịch. Ví dụ:
module Main where
-- Dynamic loading of modules
import GHC
import GHC.Paths (libdir)
import DynFlags
import Unsafe.Coerce
import Data.Time.Clock (getCurrentTime)
import StringBuffer
pluginModuleNameStr :: String
pluginModuleNameStr = "MyPlugin"
pluginSourceStr :: String
pluginSourceStr = unlines
[ "module MyPlugin where"
, "computation :: Int"
, "computation = 4"
]
pluginModuleName :: ModuleName
pluginModuleName = mkModuleName pluginModuleNameStr
pluginSource :: StringBuffer
pluginSource = stringToStringBuffer pluginSourceStr
main :: IO()
main = do
currentTime <- getCurrentTime
defaultErrorHandler defaultFatalMessager defaultFlushOut $ do
result <- runGhc (Just libdir) $ do
dflags <- getSessionDynFlags
setSessionDynFlags dflags
let target = Target { targetId = TargetModule $ pluginModuleName
, targetAllowObjCode = True
, targetContents = Just (pluginSource
, currentTime
)
}
setTargets [target]
r <- load LoadAllTargets
case r of
Failed -> error "Compilation failed"
Succeeded -> do
setContext [IIDecl $ simpleImportDecl pluginModuleName]
result <- compileExpr ("MyPlugin.computation")
let result' = unsafeCoerce result :: Int
return result'
print result
này, tuy nhiên, kết quả trong
<command-line>: panic! (the 'impossible' happened)
(GHC version 8.0.2 for x86_64-apple-darwin):
module ‘MyPlugin’ is a package module
Sửa (08.12.2017)
tôi có thể biên dịch "cắm" trực tiếp vào nhị phân thức bằng cách viết nguồn vào một tập tin tạm thời và sau đó tải nó như trong bài liên kết (Dynamically loading compiled Haskell module - GHC 7.6). Tuy nhiên, điều này không chơi tốt nếu nhập khẩu Plugin gói từ Hackage:
module Main where
import Control.Monad.IO.Class (liftIO)
import DynFlags
import GHC
import GHC.Paths (libdir)
import System.Directory (getTemporaryDirectory, removePathForcibly)
import Unsafe.Coerce (unsafeCoerce)
pluginModuleNameStr :: String
pluginModuleNameStr = "MyPlugin"
pluginSourceStr :: String
pluginSourceStr = unlines
[ "module MyPlugin where"
, "import Data.Aeson"
, "computation :: Int"
, "computation = 4"
]
writeTempFile :: IO FilePath
writeTempFile = do
dir <- getTemporaryDirectory
let file = dir ++ "/" ++ pluginModuleNameStr ++ ".hs"
writeFile file pluginSourceStr
return file
main :: IO()
main = do
moduleFile <- writeTempFile
defaultErrorHandler defaultFatalMessager defaultFlushOut $ do
result <- runGhc (Just libdir) $ do
dflags <- getSessionDynFlags
setSessionDynFlags dflags
target <- guessTarget moduleFile Nothing
setTargets [target]
r <- load LoadAllTargets
liftIO $ removePathForcibly moduleFile
case r of
Failed -> error "Compilation failed"
Succeeded -> do
setContext [IIDecl $ simpleImportDecl $ mkModuleName pluginModuleNameStr]
result <- compileExpr "MyPlugin.computation"
let result' = unsafeCoerce result :: Int
return result'
print result
Có cách nào để tải các gói khi, ví dụ, MyPlugin
chứa các tuyên bố import Data.Aeson
? Nếu tôi thêm nó vào chuỗi plugin, nó không thành công với
/var/folders/t2/hp9y8x6s6rs7zg21hdzvhbf40000gn/T/MyPlugin.hs:2:1: error:
Failed to load interface for ‘Data.Aeson’
Perhaps you meant Data.Version (from base-4.9.1.0)
Use -v to see a list of the files searched for.
haskell-loader-exe: panic! (the 'impossible' happened)
(GHC version 8.0.2 for x86_64-apple-darwin):
Compilation failed
CallStack (from HasCallStack):
error, called at app/Main.hs:40:19 in main:Main
Lý do yêu cầu của tôi là hỗ trợ cơ sở dữ liệu: Chúng tôi sử dụng liên tục để truy cập cơ sở dữ liệu và nhập khẩu năng động là cần thiết để hỗ trợ nhiều cơ sở dữ liệu (MySQL , PostgreSQL và SQLite) trong khi vẫn cho phép người dùng cuối chỉ cài đặt một trong ba máy chủ cơ sở dữ liệu (với các từ khác: không yêu cầu người dùng cài đặt tất cả chúng nếu họ chỉ sử dụng, ví dụ, PostgreSQL). Mô-đun cụ thể cho cơ sở dữ liệu chỉ nên được tải khi người dùng thực sự định cấu hình ứng dụng chính để sử dụng mô-đun đó.
Nếu tôi không import Database.Persist.MySQL
, thì ứng dụng sẽ không yêu cầu cài đặt MySQL. Nếu không, ứng dụng sẽ không thành công, ví dụ:
dyld: Library not loaded:
/usr/local/opt/mysql/lib/libmysqlclient.20.dylib
trên macOS.
Tôi có cảm giác rằng đây có thể là trường hợp sử dụng cho ghc [backpack] (https://plv.mpi-sws.org/backpack/), nhưng không thể chắc chắn vì tôi chưa sử dụng nhưng bản thân tôi. Ngoài ra nó chỉ có sẵn trên ghc-8.2 –
Cảm ơn, nhưng tôi không chắc liệu chúng tôi có thể nâng cấp dự án lên GHC 8.2 vào thời điểm này hay không. Ngoài ra, chúng tôi sử dụng Stack, không tương thích với ba lô tại thời điểm này (mặc dù họ đang làm việc trên nó). – eugenk
Tôi đã chỉnh sửa bài đăng để hiển thị cách tiếp cận hiện tại của mình. – eugenk