Importing a known function from an already-compiled binary, using GHC's API or Hint
Asked Answered
B

2

5

I have a module Target, with a function Target.accessMe inside it. I compile this module in some way, then get rid of the source code.

Now, what series of arcane incantations must I do to make a different program dynamically import Target.accessMe? This program knows accessMe's type in advance. Also, consider the fact that the source code of Target is not available.

The plugins package manages to accomplish this, but seems to have serious issues with working on Windows. I've checked out plugins's source, but am having trouble understanding it.

I've tried using Hint, but can only find out how to evaluate code that I have the source for.

Thanks for any help!

Beitnes answered 2/4, 2011 at 4:22 Comment(0)
B
2

The answer to this question has been given to me elsewhere. The GHC API is capable of doing this. Here are two functions, one of which compiles Target.hs, while the other accesses Target.accessMe (and doesn't require the source code of the Target module to be there anymore).

import GHC
import DynFlags

compile :: String -> IO SuccessFlag
compile name = defaultRunGhc $ do
  dynflags <- getSessionDynFlags
  let dynflags' = dynflags -- You can change various options here.
  setSessionDynFlags dynflags'

  -- (name) can be "Target.hs", "Target", etc.
  target <- guessTarget name Nothing
  addTarget target
  load LoadAllTargets -- Runs something like "ghc --make".

That's a function that compiles a given module and returns whether compilation succeeded or not. It uses a defaultRunGhc helper function that is defined as:

import GHC.Paths (libdir)

defaultRunGhc :: Ghc a -> IO a
defaultRunGhc = defaultErrorHandler defaultDynFlags . runGhc (Just libdir)

And now a function for fetching a value from the compiled module. The module's source code need not be present at this point.

import Unsafe.Coerce (unsafeCoerce)

fetch :: String -> String -> IO Int -- Assumes we are fetching an Int value.
fetch name value = defaultRunGhc $ do
  -- Again, you can change various options in dynflags here, as above.
  dynflags <- getSessionDynFlags
  let m = mkModule (thisPackage dynflags) (mkModuleName name)
  setContext [] [(m, Nothing)] -- Use setContext [] [m] for GHC<7.

  fetched <- compileExpr (name ++ "." ++ value) -- Fetching "Target.accessMe".
  return (unsafeCoerce fetched :: Int)

And that's it!

Beitnes answered 12/4, 2011 at 6:43 Comment(2)
I tried this with ghc 7.0.3 and it didn't work. I get error: "Failed to load interface for Target':" if source of Target has been removed, or "attempting to use module main:Target' (./Target.hs) which is not loaded" if I leave the source there.Fencing
It should be noted that this does not match the latest version of the GHC API, which is described here: haskell.org/haskellwiki/GHC/As_a_libraryEccentric
C
0

The plugins package is problematic anyway. You might want to look at Hint instead.

Cyanate answered 2/4, 2011 at 4:24 Comment(3)
Thanks for the suggestion. I've heard of Hint, but how well does it compare with plugins when it comes to performance, which is very neccessary in this program? Can code executed with Hint be run as if it was compiled with optimization? Also, can Hint be used with already-compiled programs?Beitnes
You could say Hint is the successor to plugins. It's a friendlier wrapper around the GHC API, and can be used both to compile and execute code at runtime and load precompiled modules (this is necessary for an interpreter, as it's the only way to access the standard libraries). You would, I think, need to compile a stub to access it, though. If this is problematic, direct-plugins might be a better solution; I can't tell if it's known to work on Windows, though.Cyanate
I don't see anything in the hint API about "compile and execute code at runtime and load precompiled modules". All I see is interpret, and I can't figure out how to load precompiled modules--it always requires the modules to be installed or source.Fencing

© 2022 - 2024 — McMap. All rights reserved.