module LLVM.Internal.ObjectFile where

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

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 obj :: 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 :: FilePath -> IO ObjectFile
createObjectFile :: FilePath -> IO ObjectFile
createObjectFile path :: FilePath
path = (AnyContT IO ObjectFile
 -> (ObjectFile -> IO ObjectFile) -> IO ObjectFile)
-> (ObjectFile -> IO ObjectFile)
-> AnyContT IO ObjectFile
-> IO ObjectFile
forall a b c. (a -> b -> c) -> b -> a -> c
flip AnyContT IO ObjectFile
-> (ObjectFile -> IO ObjectFile) -> IO ObjectFile
forall (m :: * -> *) a. AnyContT m a -> forall r. (a -> m r) -> m r
runAnyContT ObjectFile -> IO ObjectFile
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 buf :: Ptr MemoryBuffer
buf <- Specification -> AnyContT IO (OwnerTransfered (Ptr MemoryBuffer))
forall (e :: * -> *) h c. EncodeM e h c => h -> e c
encodeM (FilePath -> Specification
File FilePath
path)
  Ptr ObjectFile
obj <- IO (Ptr ObjectFile) -> AnyContT IO (Ptr ObjectFile)
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 "LLVMCreateObjectFile returned a null pointer."
  ObjectFile -> AnyContT IO ObjectFile
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 :: FilePath -> (ObjectFile -> IO a) -> IO a
withObjectFile f :: 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 (FilePath -> IO ObjectFile
createObjectFile FilePath
f) ObjectFile -> IO ()
disposeObjectFile