module LLVM.Internal.ObjectFile where

import Control.Exception (bracket)
import Control.Monad.IO.Class
import Control.Monad.AnyCont
import Foreign.Ptr
import GHC.Stack

import LLVM.Prelude
import LLVM.Internal.Coding
import LLVM.Internal.MemoryBuffer
import qualified LLVM.Internal.FFI.LLVMCTypes as FFI
import qualified LLVM.Internal.FFI.ObjectFile as FFI

newtype ObjectFile = ObjectFile (Ptr FFI.ObjectFile)

-- | Dispose of an 'ObjectFile'.
disposeObjectFile :: ObjectFile -> IO ()
disposeObjectFile :: ObjectFile -> IO ()
disposeObjectFile (ObjectFile Ptr ObjectFile
obj) = Ptr ObjectFile -> IO ()
FFI.disposeObjectFile Ptr ObjectFile
obj

-- | Create a object file which can later be linked with the
-- 'LLVM.Internal.OrcJIT.LinkingLayer'.
--
-- Note that the file at `path` should already be a compiled object file i.e a
-- `.o` file. This does *not* compile source files.
createObjectFile :: HasCallStack => FilePath -> IO ObjectFile
createObjectFile :: HasCallStack => FilePath -> IO ObjectFile
createObjectFile FilePath
path = (ObjectFile -> IO ObjectFile)
-> AnyContT IO ObjectFile -> IO ObjectFile
forall a (m :: * -> *) r. (a -> m r) -> AnyContT m a -> m r
runAnyContT' ObjectFile -> IO ObjectFile
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (AnyContT IO ObjectFile -> IO ObjectFile)
-> AnyContT IO ObjectFile -> IO ObjectFile
forall a b. (a -> b) -> a -> b
$ do
  -- The ownership of the object file is transfered to the object
  -- file, so we need to make sure that we do not free it here.
  FFI.OwnerTransfered Ptr MemoryBuffer
buf <- Specification -> AnyContT IO (OwnerTransfered (Ptr MemoryBuffer))
forall (e :: * -> *) h c. (EncodeM e h c, HasCallStack) => h -> e c
encodeM (FilePath -> Specification
File FilePath
path)
  Ptr ObjectFile
obj <- IO (Ptr ObjectFile) -> AnyContT IO (Ptr ObjectFile)
forall a. IO a -> AnyContT IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Ptr ObjectFile) -> AnyContT IO (Ptr ObjectFile))
-> IO (Ptr ObjectFile) -> AnyContT IO (Ptr ObjectFile)
forall a b. (a -> b) -> a -> b
$ Ptr MemoryBuffer -> IO (Ptr ObjectFile)
FFI.createObjectFile Ptr MemoryBuffer
buf
  Bool -> AnyContT IO () -> AnyContT IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Ptr ObjectFile
obj Ptr ObjectFile -> Ptr ObjectFile -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr ObjectFile
forall a. Ptr a
nullPtr) (AnyContT IO () -> AnyContT IO ())
-> AnyContT IO () -> AnyContT IO ()
forall a b. (a -> b) -> a -> b
$ FilePath -> AnyContT IO ()
forall a. HasCallStack => FilePath -> a
error FilePath
"LLVMCreateObjectFile returned a null pointer."
  ObjectFile -> AnyContT IO ObjectFile
forall a. a -> AnyContT IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Ptr ObjectFile -> ObjectFile
ObjectFile Ptr ObjectFile
obj)

-- | @bracket@-style wrapper for `createObjectFile` and `disposeObjectFile`.
withObjectFile :: FilePath -> (ObjectFile -> IO a) -> IO a
withObjectFile :: forall a. FilePath -> (ObjectFile -> IO a) -> IO a
withObjectFile FilePath
f = IO ObjectFile
-> (ObjectFile -> IO ()) -> (ObjectFile -> IO a) -> IO a
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket (HasCallStack => FilePath -> IO ObjectFile
FilePath -> IO ObjectFile
createObjectFile FilePath
f) ObjectFile -> IO ()
disposeObjectFile