I have an existing Haskell function that uses the GHC API to dynamically load compiled code from a module. It is based on the code from the blog post Dynamic Compilation and Loading of Modules in Haskell.
The code works fine in GHC 7.0, but had to be slightly modified to compile in GHC 7.2, because the GHC API changed.
The code now throws a runtime error in GHC 7.2:
mkTopLevEnv: not a home module (module name):(function name)
The code is
evalfuncLoadFFI String moduleName,
String externalFuncName,
String internalFuncName = do
result <- liftIO $ defaultRunGhc $ do
dynflags <- GHC.getSessionDynFlags
_ <- GHC.setSessionDynFlags dynflags
m <- GHC.findModule (GHC.mkModuleName moduleName) Nothing
--------------------------------------------------------
-- The following code works fine in GHC 7.0.4:
--
-- GHC.setContext [] [(m, Nothing)]
--
-- This new code attempts to set context to the module,
-- but throws an error in GHC 7.2:
--
(_,oi) <- GHC.getContext
GHC.setContext [m] oi
--------------------------------------------------------
fetched <- GHC.compileExpr (moduleName ++ "." ++ externalFuncName)
return (Unsafe.Coerce.unsafeCoerce fetched :: [LispVal] -> IOThrowsError LispVal)
defineVar env internalFuncName (IOFunc result)
For reference, the full code is available online in FFI.hs (github.com).
Does anyone have any idea how to fix or work around this problem?
Also, could this be caused by the new Safe Haskell changes in GHC 7.2, or is it just due to modifications to the GHC API?
The current module context is reserved for modules that are currently being compiled, i.e. when you specify modules in the context, they must explicitly not be external.
Instead, you should specify the wanted module as an import, in the second argument of setContext
. This can be done like so:
GHC.setContext []
-- import qualified Module
[ (GHC.simpleImportDecl . GHC.mkModuleName $ moduleName)
{ GHC.ideclQualified = True
}
-- -- import qualified Data.Dynamic
-- , (GHC.simpleImportDecl . GHC.mkModuleName $ "Data.Dynamic")
-- { GHC.ideclQualified = True
-- }
]
fetched <- GHC.compileExpr $ moduleName ++ "." ++ externalFuncName
return . unsafeCoerce $ fetched
-- or:
-- fetched <- GHC.dynCompileExpr $ moduleName ++ "." ++ externalFuncName
-- return . fromDynamic (error "Illegal type cast") $ fetched
PS: it might be a good idea to use GHC.dynCompileExpr
instead, so that you can avoid the unsafeCoerce
. You must add a qualified import for Data.Dynamic
in the context for it to work, but a Data.Dynamic.Dynamic
value is generally nicer to work with, since you can handle type errors more gracefully. I've added the code for that as comments in the above code.
And here is the syntax for GHC 7.4.1:
GHC.setContext
-- import qualified Module
[ GHC.IIDecl $
(GHC.simpleImportDecl . GHC.mkModuleName $ moduleName)
{GHC.ideclQualified = True}
]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With