packages feed

inline-c 0.5.0.1 → 0.5.2.0

raw patch · 6 files changed

+380/−7 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

+ README.md view
@@ -0,0 +1,346 @@+# inline-c++[![Build Status](https://travis-ci.org/fpco/inline-c.svg)](https://travis-ci.org/fpco/inline-c)++`inline-c` lets you seamlessly call C libraries and embed+high-performance inline C code in Haskell modules. Haskell and C can+be freely intermixed in the same source file, and data passed to and+from code in either language with minimal overhead. No FFI required.++`inline-c` is Haskell's escape hatch (or one of) to the wild world of+legacy code and high-performance numerical and system libraries. It+has other uses too: you can also think of `inline-c` as to Haskell+what inline Assembly is to C — a convenient means to eke out a little+bit of extra performance in those rare cases where C still beats+Haskell.++Build instructions are reserved for the [last section](#how-to-build).+You'll need to compile the examples below and try them out.++## Getting started++Let's say we want to compute the cosine of a number using C from+Haskell. `inline-c` let's you write this function call inline, without+any need for a binding to the foreign function:++```+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}++import qualified Language.C.Inline as C++C.include "<math.h>"++main :: IO ()+main = do+  x <- [C.exp| double{ cos(1) } |]+  print x+```++`inline-c` leverages the [quasiquotation][ghc-manual-quasiquotation]+language extension implemented in GHC.+[Template Haskell][ghc-manual-template-haskell] is also required.+Importing the `Language.C.Inline` module brings in scope most required+Haskell definitions. `C.include "<math.h>"` brings into scope the+foreign function `cos()` that we wish to call. Finally, in the `main`+function, `[C.exp| double { cos(1) } |]` denotes an inline C expression+of type `double`. `cexp` stands for "C expression". It is a custom+quasiquoter provided by `inline-c`.++A `C.exp` quasiquotation always includes a type annotation for the+inline C expression. This annotation determines the type of the+quasiquotation in Haskell. Out of the box, `inline-c` knows how to map+many common C types to Haskell type. In this case,++```+[C.exp| double { cos(1) } |] :: IO CDouble+```++For pure C expression like these we also provide `C.pure`, which works+exactly the same but without the `IO`:++```+[C.pure| double { cos(1) } |] :: CDouble+```++Obviously extra care must be taken when using `C.pure`: the embedded C+code must be referentially transparent.++## Multiple statements++`inline-c` allows embedding arbitrary C code, not just expressions, in+the form of a sequence of statements, using the `c` quasiquoter:++```+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}++import qualified Language.C.Inline as C++C.include "<stdio.h>"++main :: IO ()+main = do+  x <- [C.block| int {+      // Read and sum 5 integers+      int i, sum = 0, tmp;+      for (i = 0; i < 5; i++) {+        scanf("%d ", &tmp);+        sum += tmp;+      }+      return sum;+    } |]+  print x+```++Just as with `C.exp`, we need a type annotation on the entire C block.+The annotation specifies the return type. That is, the type of the+expression in any return statement.++## Capturing Haskell variables -- parameter declaration++`inline-c` allows referring to Haskell variables inside C expressions+and code blocks. We do so by "anti-quoting" them.++Let's say that we wanted to parameterize the function we wrote above+by how many numbers we should read. We can do so by defining a Haskell+function whose parameter we can refer to from within C:++```+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}+import qualified Language.C.Inline as C+import           Foreign.C.Types++C.include "<stdio.h>"++-- | @readAndSum n@ reads @n@ numbers from standard input and returns+-- their sum.+readAndSum :: CInt -> IO CInt+readAndSum n  = [C.block| int {+    // Read and sum n integers+    int i, sum = 0, tmp;+    for (i = 0; i < $(int n); i++) {+      scanf("%d ", &tmp);+      sum += tmp;+    }+    return sum;+  } |]++main :: IO ()+main = do+  x <- readAndSum 5+  print x+```++Here, the Haskell variable `n` is captured right where we need it using+`$(int n)`.  Standard anti-quotation (we'll talk about additional ones+later) consists of a `$` followed by a C declaration in parenthesis.++For each anti-quotation, a variable with a matching type is expected in+the Haskell environment.  In this case `inline-c` expects a variable+named `n` of type `CInt`, which is the case.++## What can be captured and returned?++All C types correspond to exactly one Haskell type. Basic types (`int`,+`long`, `double`, `float`, etc.) get converted to their Haskell+equivalents `CInt`, `CLong`, `CDouble`, `CFloat`. Pointers and arrays+get converted to `Ptr`. Function pointers get converted to `FunPtr`.++`inline-c` can also handle user-defined structs and enums, provided that+they are instances of `Storable` and that you tell `inline-c` about them+using [contexts](#contexts).++## Contexts++Everything beyond the base functionality provided by `inline-c` is+specified in a structure that we call "`Context`".  From a user+perspective, if we want to use anything but the default context+(`C.baseCtx`), we must set the `C.Context` explicitly using the+`C.context` function.  The next two sections include several examples.++The `C.Context` allows to extend `inline-c` to support++* Custom C types beyond the basic ones;+* And [additional anti-quoters](#more-anti-quoters).++`C.Context`s can be composed using their `Monoid` instance.++Ideally a `C.Context` will be provided for each C library that should be+used with `inline-c`. The user can then combine multiple contexts+together if multiple libraries are to be used in the same program. See+the [`inline-c-nag` package](https://github.com/fpco/inline-c-nag) for+an example of using a `C.Context` tailored for a library.++For information regarding how to define `C.Context`s, see the+Haddock-generated API documentation for `Language.C.Inline.Context`.++## More anti-quoters++Besides the basic anti-quoter, which captures variables as they are,+some more anti-quoters are provided with additional functionality.  As+mentioned, `inline-c` can easily be extended with anti-quoters defined+by the user, using [contexts](#contexts).++### Vectors++The `vec-len` and `vec-ptr` anti-quoters in the `C.vecCtx` context let us+easily use [Haskell vectors](http://hackage.haskell.org/package/vector)+in C.  Continuing along the "summing" theme, we can write code that sums+Haskell vectors in C:++```+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}+import qualified Language.C.Inline as C+import qualified Data.Vector.Storable.Mutable as V+import           Data.Monoid ((<>))+import           Foreign.C.Types++-- To use the vector anti-quoters, we need the 'C.vecCtx' along with the+-- 'C.baseCtx'.+C.context (C.baseCtx <> C.vecCtx)++sumVec :: V.IOVector CDouble -> IO CDouble+sumVec vec = [C.block| double {+    double sum = 0;+    int i;+    for (i = 0; i < $vec-len:vec; i++) {+      sum += $vec-ptr:(double *vec)[i];+    }+    return sum+  } |]++main :: IO ()+main = do+  x <- sumVec =<< V.fromList [1,2,3]+  print x+```++The `vec-len` anti-quoter is used simply by specifying the vector we+want to get the length of (in our case, `vec`).  To use the `vec-ptr`+anti-quoter it is also required to specify the pointer type we want.+Since `vec` is a vector of `CDouble`s, we want a pointer to `double`s.++## ByteStrings++The `bs-len` and `bs-ptr` ant-quoters in the `C.bsCtx` context work+exactly the same as the `vec-len` and `vec-ptr` counterparts, but with+strict `ByteString`s.  The only difference is that it is no necessary to+specify the type of the pointer from C -- it is always going to be+`unsigned char *`:++```+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE QuasiQuotes #-}+import qualified Data.ByteString as BS+import           Data.Monoid ((<>))+import           Foreign.C.Types+import qualified Language.C.Inline as C++C.context (C.baseCtx <> C.bsCtx)++-- | Count the number of set bits in a 'BS.ByteString'.+countSetBits :: BS.ByteString -> IO CInt+countSetBits bs = [C.block|+    int {+      int i, bits = 0;+      for (i = 0; i < $bs-len:bs; i++) {+        unsigned char ch = $bs-ptr:bs[i];+        bits += (ch * 01001001001ULL & 042104210421ULL) % 017;+      }+      return bits;+    }+  |]+```++### Function pointers++Using the `fun` anti-quoter, present in the `C.funCtx` context, we can+easily turn Haskell function into function pointers.++```+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-}+import qualified Language.C.Inline as C++-- To use the function pointer anti-quoter, we need the 'C.funCtx along with+-- the 'C.baseCtx'.+C.context (C.baseCtx <> C.funCtx)++ackermann :: CLong -> CLong -> CLong+ackermann m n+  | m == 0 = n + 1+  | m > 0 && n == 0 = ackermann (m - 1) 1+  | otherwise = ackermann (m - 1) (ackermann m (n - 1))++main :: IO ()+main = do+  let ackermannIO m n = return $ ackermann m n+  let x = 3+  let y = 4+  z <- [C.exp| long{+      $fun:(int (*ackermannIO)(int, int))($(long x), $(long y))+    } |]+  print z+```++In this example, we capture a Haskell function of type `CLong -> CLong+-> IO CLong`, `ackermannIO`, to a function pointer in C, using the `fun`+anti-quoter.  Note how we need to specify the function pointer type when+we capture `ackermannIO`, using standard C declaration syntax.  Also+note that the `fun` anti-quoter works with `IO` functions, and so we+needed to modify `ackermann` to make it have the right type.++In general, when anti-quoting, if the type can be inferred (like in the+case of `vec-len`), only the Haskell identifier appears.  If it can't,+the target C type and the Haskell identifier are mentioned using C+declaration syntax.++## How to build++Each module that uses at least one of the `inline-c` functions gets a C+file associated to it, where the filename of said file will be the same+as the module but with a C extension.  This C file must be built after+the Haskell code and linked appropriately.  If you use cabal, all you+have to do is declare each associated C file in the `.cabal` file and+you are good.++For example we might have++```+executable foo+  main-is:             Main.hs, Foo.hs, Bar.hs+  hs-source-dirs:      src+  -- Here the corresponding C sources must be listed for every module+  -- that uses C code.  In this example, Main.hs and Bar.hs do, but+  -- Foo.hs does not.+  c-sources:           src/Main.c, src/Bar.c+  -- These flags will be passed to the C compiler+  cc-options:          -Wall -O2+  -- Libraries to link the code with.+  extra-libraries:     -lm+  ...+```++Note that currently `cabal repl` is not supported, because the C code is+not compiled and linked appropriately.  Type-checking will still be+performed, so `cabal repl` can still be used to develop.++See `sample-cabal-project` for a working example.++If we were to compile the above manually we could do:++```+$ ghc -c Main.hs+$ cc -c Main.c -o Main_c.o+$ ghc Foo.hs+$ ghc Bar.hs+$ cc -c Bar.c -o Bar_c.o+$ ghc Main.o Foo.o Bar.o Main_c.o Bar_c.o -lm -o Main+```++[ghc-manual-quasiquotation]:+https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/template-haskell.html#th-quasiquotation+[ghc-manual-template-haskell]: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/template-haskell.html
+ changelog.md view
@@ -0,0 +1,2 @@+- 0.5.2.0: Make `bs-ptr` use `char` instead of `unsigned char`.  See+  issue #16.
inline-c.cabal view
@@ -1,5 +1,5 @@ name:                inline-c-version:             0.5.0.1+version:             0.5.2.0 synopsis:            Write Haskell source files including C code inline. No FFI required. description:         See <https://github.com/fpco/inline-c/blob/master/README.md>. license:             MIT@@ -11,6 +11,7 @@ tested-with:         GHC == 7.8.4, GHC == 7.10.1 build-type:          Simple cabal-version:       >=1.10+Extra-Source-Files:  README.md, changelog.md  source-repository head   type:     git
src/Language/C/Inline/Context.hs view
@@ -52,7 +52,7 @@ import qualified Data.Vector.Storable as V import qualified Data.Vector.Storable.Mutable as VM import           Foreign.C.Types-import           Foreign.Ptr (Ptr, FunPtr, castPtr)+import           Foreign.Ptr (Ptr, FunPtr) import           Foreign.Storable (Storable) import qualified Language.Haskell.TH as TH import qualified Text.Parser.Token as Parser@@ -377,13 +377,13 @@   { aqParser = do       cId <- C.parseIdentifier       let s = C.unIdentifier cId-      return (s, C.Ptr [] (C.TypeSpecifier mempty (C.Char (Just C.Unsigned))), s)+      return (s, C.Ptr [] (C.TypeSpecifier mempty (C.Char Nothing)), s)   , aqMarshaller = \_purity _cTypes cTy cId -> do       case cTy of-        C.Ptr _ (C.TypeSpecifier _ (C.Char (Just C.Unsigned))) -> do-          hsTy <- [t| Ptr CUChar |]+        C.Ptr _ (C.TypeSpecifier _ (C.Char Nothing)) -> do+          hsTy <- [t| Ptr CChar |]           hsExp <- getHsVariable "bsCtx" cId-          hsExp' <- [| \cont -> BS.unsafeUseAsCString $(return hsExp) $ \ptr -> cont (castPtr ptr)  |]+          hsExp' <- [| \cont -> BS.unsafeUseAsCString $(return hsExp) $ \ptr -> cont ptr  |]           return (hsTy, hsExp')         _ ->           error "impossible: got type different from `unsigned char' (bsCtx)"
test/tests.c view
@@ -94,3 +94,15 @@        } ++int inline_c_14_17d13d6f2f87c2401476aaf41e06593689723baf(long bs_inline_c_0, char * bs_inline_c_1) {++          int i, bits = 0;+          for (i = 0; i < bs_inline_c_0; i++) {+            char ch = bs_inline_c_1[i];+            bits += (ch * 01001001001ULL & 042104210421ULL) % 017;+          }+          return bits;+        +}+
test/tests.hs view
@@ -19,7 +19,7 @@  import           Dummy -C.context (C.baseCtx <> C.funCtx <> C.vecCtx)+C.context (C.baseCtx <> C.funCtx <> C.vecCtx <> C.bsCtx)  C.include "<math.h>" C.include "<stdio.h>"@@ -156,3 +156,15 @@         return x;       } |]       sum' `Hspec.shouldBe` 3 * 10+    Hspec.it "bytestrings" $ do+      let bs = "foo"+      bits <- [C.block| int {+          int i, bits = 0;+          for (i = 0; i < $bs-len:bs; i++) {+            char ch = $bs-ptr:bs[i];+            bits += (ch * 01001001001ULL & 042104210421ULL) % 017;+          }+          return bits;+        } |]+      bits `Hspec.shouldBe` 16+