libffi-0.2.1/0000755000000000000000000000000007346545000011136 5ustar0000000000000000libffi-0.2.1/CHANGELOG.md0000644000000000000000000000242007346545000012745 0ustar0000000000000000## 0.2.1 [2022.09.24] * Add `sizeAndAlignmentOfCType` to `Foreign.LibFFI.Base`, which can be used to retrieve the size and alignment of a `CType`. ## 0.2 [2022.08.11] * The `libffi` library now uses `bracket` internally and should now be exception-safe. * There is a now a `ghc-bundled-libffi` `cabal` flag that makes this library statically link against GHC's bundled copy of `libffi` rather than attempt to link against the system `libffi`. On the vast majority of GHCs, this is the most reasonable option, as linking against the system `libffi` is inherently fragile. As a result, `+ghc-bundled-libffi` is now the defalut setting. See the [`README`](https://github.com/remiturk/libffi/blob/master/README.md#notes-on-ghcs-bundling-of-libffi) for more discussion on this point. * The definition of `Arg` has changed: ```diff -newtype Arg = Arg { unArg :: IO (Ptr CType, Ptr CValue, IO ()) } +newtype Arg = Arg { unArg :: forall a. (Ptr CType -> Ptr CValue -> IO a) -> IO a } ``` * The definition of `RetType` has changed: ```diff -data RetType a = RetType (Ptr CType) ((Ptr CValue -> IO ()) -> IO a) +newtype RetType a = RetType { unRetType :: (Ptr CType -> Ptr CValue -> IO ()) -> IO a } ``` ## 0.1 [2009.03.17] * Initial release. libffi-0.2.1/Foreign/0000755000000000000000000000000007346545000012527 5ustar0000000000000000libffi-0.2.1/Foreign/LibFFI.hs0000644000000000000000000000131307346545000014114 0ustar0000000000000000{- | This is the only module that normal users should need to import. As an example, allocate 1GB of memory, zero it, and crash: @ import System.Posix.DynamicLinker import Foreign.Ptr import Foreign.LibFFI main = do malloc <- dlsym Default \"malloc\" memset <- dlsym Default \"memset\" p <- callFFI malloc (retPtr retVoid) [argCSize (2^30)] callFFI memset (retPtr retVoid) [argPtr p, argCInt 0, argCSize (2^30)] callFFI memset (retPtr retVoid) [argPtr nullPtr, argCInt 0, argCSize 1] @ -} module Foreign.LibFFI (Arg ,RetType ,callFFI ,withRetType ,module Foreign.LibFFI.Types ) where import Foreign.LibFFI.Base import Foreign.LibFFI.Types libffi-0.2.1/Foreign/LibFFI/0000755000000000000000000000000007346545000013562 5ustar0000000000000000libffi-0.2.1/Foreign/LibFFI/Base.hs0000644000000000000000000000667607346545000015007 0ustar0000000000000000{-# LANGUAGE Rank2Types #-} {- | This module defines the basic libffi machinery. You will need this to create support for new ffi types. -} module Foreign.LibFFI.Base where import Control.Monad import Control.Exception import Foreign.Ptr import Foreign.Storable import Foreign.Marshal import Foreign.LibFFI.Internal import Foreign.LibFFI.FFITypes newtype Arg = Arg { unArg :: forall a. (Ptr CType -> Ptr CValue -> IO a) -> IO a } customPointerArg :: (a -> IO (Ptr b)) -> (Ptr b -> IO ()) -> a -> Arg customPointerArg newA freeA a = Arg $ \withArg -> bracket (newA a) freeA $ \p -> with p $ \pp -> withArg ffi_type_pointer (castPtr pp) mkStorableArg :: Storable a => Ptr CType -> a -> Arg mkStorableArg cType a = Arg $ \withArg -> with a $ \p -> withArg cType (castPtr p) newtype RetType a = RetType { unRetType :: (Ptr CType -> Ptr CValue -> IO ()) -> IO a } instance Functor RetType where fmap f = withRetType (return . f) withRetType :: (a -> IO b) -> RetType a -> RetType b withRetType f (RetType withPoke) = RetType $ withPoke >=> f mkStorableRetType :: Storable a => Ptr CType -> RetType a mkStorableRetType cType = RetType $ \write -> alloca $ \cValue -> write cType (castPtr cValue) >> peek cValue newStorableStructArgRet :: Storable a => [Ptr CType] -> IO (a -> Arg, RetType a, IO ()) newStorableStructArgRet cTypes = do (cType, freeit) <- newStructCType cTypes return (mkStorableArg cType, mkStorableRetType cType, freeit) newStructCType :: [Ptr CType] -> IO (Ptr CType, IO ()) newStructCType cTypes = do ffi_type <- mallocBytes sizeOf_ffi_type elements <- newArray0 nullPtr cTypes init_ffi_type ffi_type elements return (ffi_type, free ffi_type >> free elements) sizeAndAlignmentOfCType :: Ptr CType -> IO (Int, Int) sizeAndAlignmentOfCType cType = do (size, alignment) <- ffi_type_size_and_alignment cType if size /= 0 && alignment /= 0 then return (fromIntegral size, fromIntegral alignment) else do -- The type's size and alignment haven't been initialized -- so we force it with a call to `ffi_prep_cif`. status <- allocaBytes sizeOf_cif $ \cif -> ffi_prep_cif cif ffi_default_abi 0 cType nullPtr unless (status == ffi_ok) $ error "sizeAndAlignmentOfCType: ffi_prep_cif failed" (size, alignment) <- ffi_type_size_and_alignment cType return (fromIntegral size, fromIntegral alignment) callFFI :: FunPtr a -> RetType b -> [Arg] -> IO b callFFI funPtr (RetType actRet) args = allocaBytes sizeOf_cif $ \cif -> allocaArray n $ \cTypesPtr -> allocaArray n $ \cValuesPtr -> let doCall = actRet $ \cRetType cRetValue -> do status <- ffi_prep_cif cif ffi_default_abi (fromIntegral n) cRetType cTypesPtr unless (status == ffi_ok) $ error "callFFI: ffi_prep_cif failed" ffi_call cif funPtr cRetValue cValuesPtr addArg (i, Arg actArg) goArgs = actArg $ \cType cValue -> do pokeElemOff cTypesPtr i cType pokeElemOff cValuesPtr i cValue goArgs in foldr addArg doCall $ zip [0..] args where n = length args libffi-0.2.1/Foreign/LibFFI/FFITypes.hs0000644000000000000000000000660407346545000015555 0ustar0000000000000000{-# LANGUAGE ForeignFunctionInterface #-} {- | The pointers exported and used by the C libffi describing basic ffi types. -} module Foreign.LibFFI.FFITypes where import Data.Int import Data.Word import Foreign.C.Types import Foreign.Ptr import Foreign.Storable import Foreign.LibFFI.Internal foreign import ccall unsafe "&" ffi_type_void :: Ptr CType foreign import ccall unsafe "&" ffi_type_sint8 :: Ptr CType foreign import ccall unsafe "&" ffi_type_uint8 :: Ptr CType foreign import ccall unsafe "&" ffi_type_uint16 :: Ptr CType foreign import ccall unsafe "&" ffi_type_sint16 :: Ptr CType foreign import ccall unsafe "&" ffi_type_uint32 :: Ptr CType foreign import ccall unsafe "&" ffi_type_sint32 :: Ptr CType foreign import ccall unsafe "&" ffi_type_uint64 :: Ptr CType foreign import ccall unsafe "&" ffi_type_sint64 :: Ptr CType foreign import ccall unsafe "&" ffi_type_float :: Ptr CType foreign import ccall unsafe "&" ffi_type_double :: Ptr CType foreign import ccall unsafe "&" ffi_type_pointer :: Ptr CType ffi_type_uchar :: Ptr CType ffi_type_uchar = ffi_type_uint8 ffi_type_schar :: Ptr CType ffi_type_schar = ffi_type_sint8 ffi_type_wchar :: Ptr CType ffi_type_wchar = case sizeOf (undefined :: CWchar) of 2 -> ffi_type_sint16 4 -> ffi_type_sint32 8 -> ffi_type_sint64 _ -> error "ffi_type_wchar of unsupported size" ffi_type_size :: Ptr CType ffi_type_size = case sizeOf (undefined :: CSize) of 4 -> ffi_type_uint32 8 -> ffi_type_uint64 _ -> error "ffi_type_size of unsupported size" ffi_type_time :: Ptr CType ffi_type_time = case sizeOf (undefined :: CTime) of 4 -> ffi_type_sint32 8 -> ffi_type_sint64 _ -> error "ffi_type_time of unsupported size" ffi_type_uint :: Ptr CType ffi_type_uint = case sizeOf (undefined :: CUInt) of 4 -> ffi_type_uint32 8 -> ffi_type_uint64 _ -> error "ffi_type_uint of unsupported size" ffi_type_sint :: Ptr CType ffi_type_sint = case sizeOf (undefined :: CInt) of 4 -> ffi_type_sint32 8 -> ffi_type_sint64 _ -> error "ffi_type_sint of unsupported size" ffi_type_ulong :: Ptr CType ffi_type_ulong = case sizeOf (undefined :: CULong) of 4 -> ffi_type_uint32 8 -> ffi_type_uint64 _ -> error "ffi_type_ulong of unsupported size" ffi_type_slong :: Ptr CType ffi_type_slong = case sizeOf (undefined :: CLong) of 4 -> ffi_type_sint32 8 -> ffi_type_sint64 _ -> error "ffi_type_slong of unsupported size" ffi_type_hs_int :: Ptr CType ffi_type_hs_int = case sizeOf (undefined :: Int) of 4 -> ffi_type_sint32 8 -> ffi_type_sint64 _ -> error "ffi_type_hs_int: unsupported sizeOf (_ :: Int)" ffi_type_hs_word :: Ptr CType ffi_type_hs_word = case sizeOf (undefined :: Word) of 4 -> ffi_type_uint32 8 -> ffi_type_uint64 _ -> error "ffi_type_hs_word: unsupported sizeOf (_ :: Word)" libffi-0.2.1/Foreign/LibFFI/Internal.hsc0000644000000000000000000000261107346545000016035 0ustar0000000000000000{-# LANGUAGE ForeignFunctionInterface, EmptyDataDecls #-} {- | The internals of the C library libffi -} module Foreign.LibFFI.Internal where #include import Data.Int import Data.Word import Foreign.C.Types import Foreign.Ptr import Foreign.Storable data CValue data CType data CIF type C_ffi_status = (#type ffi_status) type C_ffi_abi = (#type ffi_abi) ffi_default_abi :: C_ffi_abi ffi_default_abi = #const FFI_DEFAULT_ABI ffi_ok :: C_ffi_status ffi_ok = #const FFI_OK sizeOf_cif :: Int sizeOf_cif = #size ffi_cif sizeOf_ffi_type :: Int sizeOf_ffi_type = #size ffi_type init_ffi_type :: Ptr CType -> Ptr (Ptr CType) -> IO () init_ffi_type cType cTypes = do (#poke ffi_type, size) cType (0 :: CSize) (#poke ffi_type, alignment) cType (0 :: CUShort) (#poke ffi_type, type) cType ((#const FFI_TYPE_STRUCT) :: CUShort) (#poke ffi_type, elements) cType cTypes ffi_type_size_and_alignment :: Ptr CType -> IO (CSize, CUShort) ffi_type_size_and_alignment cType = do size <- (#peek ffi_type, size) cType alignment <- (#peek ffi_type, alignment) cType return (size, alignment) foreign import ccall safe ffi_prep_cif :: Ptr CIF -> C_ffi_abi -> CUInt -> Ptr CType -> Ptr (Ptr CType) -> IO C_ffi_status foreign import ccall safe ffi_call :: Ptr CIF -> FunPtr a -> Ptr CValue -> Ptr (Ptr CValue) -> IO () libffi-0.2.1/Foreign/LibFFI/Types.hs0000644000000000000000000001413207346545000015223 0ustar0000000000000000-- | Arguments and return types module Foreign.LibFFI.Types ( -- * Arguments -- ** Integral types argCInt, argCUInt, argCLong, argCULong, argInt8, argInt16, argInt32, argInt64, argWord8, argWord16, argWord32, argWord64, -- ** Floating point types argCFloat, argCDouble, -- ** Various other C types argCSize, argCTime, argCChar, argCUChar, argCWchar, argPtr, argFunPtr, -- ** Strings argString, argByteString, argConstByteString, -- * Return types -- ** Integral types retVoid, retCInt, retCUInt, retCLong, retCULong, retInt8, retInt16, retInt32, retInt64, retWord8, retWord16, retWord32, retWord64, -- ** Floating point types retCFloat, retCDouble, -- ** Various other C types retCSize, retCTime, retCChar, retCUChar, retCWchar, retPtr, retFunPtr, -- ** Strings retCString, retString, retByteString, retMallocByteString ) where import Control.Monad import Data.List import Data.Char import Data.Int import Data.Word import Foreign.C.Types import Foreign.Ptr import Foreign.Storable import Foreign.C.String import Foreign.Marshal import qualified Data.ByteString as BS import qualified Data.ByteString.Unsafe as BSU import Foreign.LibFFI.Base import Foreign.LibFFI.FFITypes argCInt :: CInt -> Arg argCInt = mkStorableArg ffi_type_sint argCUInt :: CUInt -> Arg argCUInt = mkStorableArg ffi_type_uint argCLong :: CLong -> Arg argCLong = mkStorableArg ffi_type_slong argCULong :: CULong -> Arg argCULong = mkStorableArg ffi_type_ulong -- | Note that on e.g. x86_64, Int \/= CInt argInt8 :: Int8 -> Arg argInt8 = mkStorableArg ffi_type_sint8 argInt16 :: Int16 -> Arg argInt16 = mkStorableArg ffi_type_sint16 argInt32 :: Int32 -> Arg argInt32 = mkStorableArg ffi_type_sint32 argInt64 :: Int64 -> Arg argInt64 = mkStorableArg ffi_type_sint64 argWord8 :: Word8 -> Arg argWord8 = mkStorableArg ffi_type_uint8 argWord16 :: Word16 -> Arg argWord16 = mkStorableArg ffi_type_uint16 argWord32 :: Word32 -> Arg argWord32 = mkStorableArg ffi_type_uint32 argWord64 :: Word64 -> Arg argWord64 = mkStorableArg ffi_type_uint64 argCFloat :: CFloat -> Arg argCFloat = mkStorableArg ffi_type_float argCDouble :: CDouble -> Arg argCDouble = mkStorableArg ffi_type_double argCSize :: CSize -> Arg argCSize = mkStorableArg ffi_type_size argCTime :: CTime -> Arg argCTime = mkStorableArg ffi_type_size argCChar :: CChar -> Arg argCChar = mkStorableArg ffi_type_schar argCUChar :: CUChar -> Arg argCUChar = mkStorableArg ffi_type_uchar argCWchar :: CWchar -> Arg argCWchar = mkStorableArg ffi_type_wchar argPtr :: Ptr a -> Arg argPtr = mkStorableArg ffi_type_pointer argFunPtr :: FunPtr a -> Arg argFunPtr = mkStorableArg ffi_type_pointer {- | The string argument is passed to C as a char * pointer, which is freed afterwards. The argument should not contain zero-bytes. -} argString :: String -> Arg argString = customPointerArg newCString free -- | Like argString, but for ByteString's. argByteString :: BS.ByteString -> Arg argByteString = customPointerArg (flip BS.useAsCString return) (const $ return ()) -- | Like argByteString, but changing the string from C breaks referential transparency. argConstByteString :: BS.ByteString -> Arg argConstByteString = customPointerArg (flip BSU.unsafeUseAsCString return) (const $ return ()) retVoid :: RetType () retVoid = RetType (\write -> write ffi_type_void nullPtr >> return ()) retCInt :: RetType CInt retCInt = mkStorableRetType ffi_type_sint retCUInt :: RetType CUInt retCUInt = mkStorableRetType ffi_type_uint retCLong :: RetType CLong retCLong = mkStorableRetType ffi_type_slong retCULong :: RetType CULong retCULong = mkStorableRetType ffi_type_ulong retInt8 :: RetType Int8 retInt8 = mkStorableRetType ffi_type_sint8 retInt16 :: RetType Int16 retInt16 = mkStorableRetType ffi_type_sint16 retInt32 :: RetType Int32 retInt32 = mkStorableRetType ffi_type_sint32 retInt64 :: RetType Int64 retInt64 = mkStorableRetType ffi_type_sint64 retWord8 :: RetType Word8 retWord8 = mkStorableRetType ffi_type_uint8 retWord16 :: RetType Word16 retWord16 = mkStorableRetType ffi_type_uint16 retWord32 :: RetType Word32 retWord32 = mkStorableRetType ffi_type_uint32 retWord64 :: RetType Word64 retWord64 = mkStorableRetType ffi_type_uint64 retCFloat :: RetType CFloat retCFloat = mkStorableRetType ffi_type_float retCDouble :: RetType CDouble retCDouble = mkStorableRetType ffi_type_double retCSize :: RetType CSize retCSize = mkStorableRetType ffi_type_size retCTime :: RetType CTime retCTime = mkStorableRetType ffi_type_time retCChar :: RetType CChar retCChar = mkStorableRetType ffi_type_schar retCUChar :: RetType CUChar retCUChar = mkStorableRetType ffi_type_uchar retCWchar :: RetType CWchar retCWchar = mkStorableRetType ffi_type_wchar retFunPtr :: RetType a -> RetType (FunPtr a) retFunPtr _ = mkStorableRetType ffi_type_pointer retPtr :: RetType a -> RetType (Ptr a) retPtr _ = mkStorableRetType ffi_type_pointer retCString :: RetType CString retCString = retPtr retCChar {- | Peek a String out of the returned char *. The char * is not freed. -} retString :: RetType String retString = withRetType peekCString (retPtr retCChar) {- | Like retString, but for ByteString's -} retByteString :: RetType BS.ByteString retByteString = withRetType BS.packCString (retPtr retCChar) {- | Make a ByteString out of the returned char *. The char * will be free(3)ed when the ByteString is garbage collected. -} retMallocByteString :: RetType BS.ByteString retMallocByteString = withRetType BSU.unsafePackMallocCString (retPtr retCChar) libffi-0.2.1/LICENSE0000644000000000000000000000244607346545000012151 0ustar0000000000000000Copyright (c) 2008, Remi Turk All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. libffi-0.2.1/README.md0000644000000000000000000001133407346545000012417 0ustar0000000000000000# `libffi` [![Hackage](https://img.shields.io/hackage/v/libffi.svg)][Hackage: libffi] [![Hackage Dependencies](https://img.shields.io/hackage-deps/v/libffi.svg)](http://packdeps.haskellers.com/reverse/libffi) [![Haskell Programming Language](https://img.shields.io/badge/language-Haskell-blue.svg)][Haskell.org] [![BSD3 License](http://img.shields.io/badge/license-BSD3-brightgreen.svg)][tl;dr Legal: BSD3] [![Linux build](https://github.com/remiturk/libffi/workflows/Haskell-CI/badge.svg)](https://github.com/remiturk/libffi/actions?query=workflow%3AHaskell-CI) [Hackage: libffi]: http://hackage.haskell.org/package/libffi "libffi package on Hackage" [Haskell.org]: http://www.haskell.org "The Haskell Programming Language" [tl;dr Legal: BSD3]: https://tldrlegal.com/license/bsd-3-clause-license-%28revised%29 "BSD 3-Clause License (Revised)" A binding to `libffi`, allowing C functions of types only known at runtime to be called from Haskell. # Notes on GHC's bundling of `libffi` This library makes a somewhat unusual choice: by default, it does not explicitly declare a dependency against the `libffi` C library. This is because most binary distributions of GHC—that is, GHCs configured without the `--with-system-libffi` option—bundle their own copies of `libffi`. One of these copies is statically linked, and another of these copies is dynamically linked. Moreover, whenever GHC compiles an executable, it will always pass the necessary flags to link against its static copy of `libffi`, as the GHC runtime system depends on it. When GHC bundles its own copies of `libffi`, if you were to declare, say, an `extra-libraries: ffi` dependency, then it would not behave in the way that you would expect. This is because: 1. The linker flags to link against GHC's static copy of `libffi` always come first in the final linking step when compiling an executable. As a result, declaring an `extra-libraries: ffi` dependency won't make much of a difference, since GHC will always statically link against its own copy of `libffi` anyway due to the order of linker flags. 2. Moreover, declaring an `extra-libraries: ffi` dependency can have the unfortunate side effect of declaring an _unused_ dynamic dependency against `libffi`. Even worse is the fact that the version of dynamically linked `libffi` that comes with your operating system may differ from the version of dynamically linked `libffi` that GHC bundles. When the version numbers differ, this can lead to the compiled executable failing at runtime with mysterious errors such as: ``` error while loading shared libraries: libffi.so.7: cannot open shared object file: No such file or directory ``` For more information on this point, see [GHC#15397](https://gitlab.haskell.org/ghc/ghc/-/issues/15397). Observation (2) means that when GHC is configured with `--with-system-libffi`, it is inherently fragile to use `extra-libraries: ffi`. This is an unfortunate situation, but there is not much that one can do about this short of fixing GHC#15397 upstream. A workaround would be to configure GHC with `--with-system-libffi`, but practically speaking, the vast majority of GHC binary distributions do not configure this way. This includes all versions of GHC that `ghcup` distributes, so unless we want to exclude most GHC users, we need some kind of workaround for this issue. Our workaround is to rely on observation (1). That is, because GHC always passes flags to the linker to link against its own static copy of `libffi`, we can always assume that GHC will handle the `libffi` dependency for us. As a result, the default behavior for this library is to enable the `+ghc-bundled-libffi` flag, which means that the library will not declare an external dependency on `libffi` at all. This is rather unusual, but then again, GHC bundling its own copies of `libffi` is also unusual. (To our knowledge, this is the _only_ C library that GHC bundles in this fashion.) We have tested out `+ghc-bundled-libffi` on Windows, macOS, and Linux, and it works as expected. If you encounter any linking oddities with `+ghc-bundled-libffi`, please file an issue. It is worth re-emphasizing that `+ghc-bundled-libffi` will only work if you are using a binary distribution of GHC that was not configured with the `--with-system-libffi` option. If you _are_ using such a GHC, then you will need to use `-ghc-bundle-libffi` (note the minus sign) to disable the flag and link against your operating system's copy of `libffi`. Unfortunately, `cabal` does not provide a way to detect whether GHC was configured with `--with-system-libffi` or not, so the burden is on users to enable or disable `ghc-bundle-libffi` as appropriate. libffi-0.2.1/Setup.hs0000644000000000000000000000006007346545000012566 0ustar0000000000000000import Distribution.Simple main = defaultMain libffi-0.2.1/libffi.cabal0000644000000000000000000000527107346545000013362 0ustar0000000000000000Name: libffi cabal-version: >= 1.10 Version: 0.2.1 Description: A binding to libffi, allowing C functions of types only known at runtime to be called from Haskell. License: BSD3 License-file: LICENSE Copyright: Remi Turk 2008-2009 Author: Remi Turk Maintainer: remi.turk@gmail.com Homepage: http://haskell.org/haskellwiki/Library/libffi Stability: alpha Synopsis: A binding to libffi Tested-With: GHC == 7.0.4 , GHC == 7.2.2 , GHC == 7.4.2 , GHC == 7.6.3 , GHC == 7.8.4 , GHC == 7.10.3 , GHC == 8.0.2 , GHC == 8.2.2 , GHC == 8.4.4 , GHC == 8.6.5 , GHC == 8.8.4 , GHC == 8.10.7 , GHC == 9.0.2 , GHC == 9.2.2 extra-source-files: CHANGELOG.md, README.md Build-Type: Simple Category: Foreign flag ghc-bundled-libffi description: When GHC is configured without @--with-system-libffi@, it will bundle its own copies of @libffi@, one of them statically linked and the other dynamically linked. This flag will force linking against the static copy of @libffi@ that GHC bundles. This avoids a GHC bug (https://gitlab.haskell.org/ghc/ghc/-/issues/15397) that can arise when the linker confuses the system's dynamic @libffi@ with GHC's own dynamic @libffi@. Note that this flag only works when GHC is configured without the @--with-system-libffi@ option. This is the case for most GHC binary distributions, such as those provided by @ghcup@. If you are using a GHC that was configured with @--with-system-libffi@, however, you will need to disable this option and link against the system's version of @libffi@ instead. default: True source-repository head type: git location: https://github.com/remiturk/libffi library build-depends: base >= 3 && < 5, bytestring exposed-modules: Foreign.LibFFI, Foreign.LibFFI.Base, Foreign.LibFFI.Types, Foreign.LibFFI.FFITypes, Foreign.LibFFI.Internal if !flag(ghc-bundled-libffi) pkgconfig-depends: libffi default-language: Haskell2010