packages feed

c2hsc 0.2.0 → 0.3.0

raw patch · 3 files changed

+277/−157 lines, 3 filesdep +cmdargs

Dependencies added: cmdargs

Files

Main.hs view
@@ -1,14 +1,17 @@+{-# LANGUAGE DeriveDataTypeable #-}+ module Main where  import           Control.Applicative import           Control.Monad hiding (sequence) import           Control.Monad.Trans.State import           Data.Char-import           Data.Foldable-import           Data.List hiding (concat)+import           Data.Foldable hiding (concat)+import           Data.List import qualified Data.Map as M import           Data.Maybe import           Data.Traversable+--import           Debug.Trace import           Language.C.Data.Ident import           Language.C.Data.InputStream import           Language.C.Data.Node@@ -19,6 +22,7 @@ import           Language.C.System.GCC import           Language.C.System.Preprocess import           Prelude hiding (concat, sequence)+import           System.Console.CmdArgs import           System.Directory import           System.Environment import           System.FilePath@@ -26,79 +30,128 @@ import           Text.PrettyPrint as P import           Text.StringTemplate +version :: String+version = "0.2.0"++copyright :: String+copyright = "2012"++c2hscSummary :: String+c2hscSummary = "c2hsc v" ++ version ++ ", (C) John Wiegley " ++ copyright++data C2HscOptions = C2HscOptions+    { gcc       :: FilePath+    , cppopts   :: String+    , prefix    :: String+    , useStdout :: Bool+    , verbose   :: Bool+    , debug     :: Bool+    , files     :: [FilePath] }+    deriving (Data, Typeable, Show, Eq)++c2hscOptions :: C2HscOptions+c2hscOptions = C2HscOptions+    { gcc       = def &= typFile+                  &= help "Specify explicit path to gcc or cpp"+    , cppopts   = def &= typ "OPTS"+                  &= help "Pass OPTS to the preprocessor"+    , prefix    = def &= typ "PREFIX"+                  &= help "Use PREFIX when naming modules"+    , useStdout = def &= name "stdout"+                  &= help "Send all output to stdout (for testing)"+    , verbose   = def &= name "v"+                  &= help "Report progress verbosely"+    , debug     = def &= name "D"+                  &= help "Report debug information"+    , files     = def &= args &= typFile } &=+    summary c2hscSummary &=+    program "c2hsc" &=+    help "Create an .hsc Bindings-DSL file from a C API header file"+ ------------------------------ IMPURE FUNCTIONS ------------------------------  -- Parsing of C headers begins with finding gcc so we can run the -- preprocessor.  main :: IO ()-main = do-  gccExe <- findExecutable "gcc"+main = getArgs >>= runArgs++runArgs :: [String] -> IO()+runArgs mainArgs = do+  opts <- withArgs (if null mainArgs then ["--help"] else mainArgs)+          (cmdArgs c2hscOptions)+  when (prefix opts == "") $+    error "Please specify a module prefix to use with --prefix"++  gccExe <- findExecutable $ case gcc opts of "" -> "gcc"; x -> x   case gccExe of-    Nothing      -> error "Cannot find 'gcc' executable on the PATH"-    Just gccPath -> getArgs >>= parseFile gccPath+    Nothing      -> error $ "Cannot find executable '" ++ gcc opts ++ "'"+    Just gccPath -> parseFile gccPath opts  -- Once gcc is found, setup to parse the C file by running the preprocessor. -- Then, identify the input file absolutely so we know which declarations to -- print out at the end. -parseFile :: FilePath -> [String] -> IO ()-parseFile gccPath args = do-  fileName <- canonicalizePath $ last args-  result   <- runPreprocessor (newGCC gccPath)-                              (rawCppArgs (tail . init $ args) fileName)-  case result of-    Left err     -> error $ "Failed to run cpp: " ++ show err-    Right stream -> do-      let HscOutput hscs helpercs _ =-            execState (parseCFile stream fileName (initPos fileName))-                      newHscState-      writeProducts (head args) fileName hscs helpercs+parseFile :: FilePath -> C2HscOptions -> IO ()+parseFile gccPath opts =+  for_ (files opts) $ \fileName -> do+    result <- runPreprocessor (newGCC gccPath)+                              (rawCppArgs [(cppopts opts)] fileName)+    case result of+      Left err     -> error $ "Failed to run cpp: " ++ show err+      Right stream -> do+        let HscOutput hscs helpercs _ =+              execState (parseCFile stream fileName (initPos fileName))+                        newHscState+        writeProducts opts fileName hscs helpercs  -- Write out the gathered data -writeProducts :: String -> FilePath -> [String] -> [String] -> IO ()-writeProducts libName fileName hscs helpercs = do+writeProducts :: C2HscOptions -> FilePath -> [String] -> [String] -> IO ()+writeProducts opts fileName hscs helpercs = do   let tmpl = unlines [ "#include <bindings.dsl.h>"                      , "#include <git2.h>"                      , "module $libName$.$cFileName$ where"                      , "#strict_import"                      , "" ]-      vars = [ ("libName",   libName)+      vars = [ ("libName",   prefix opts)              , ("cFileName", cap) ]       code = newSTMP tmpl       base = dropExtension . takeFileName $ fileName       cap  = capitalize base    let target = cap ++ ".hsc"-  handle <- openFile target WriteMode+  handle <- if useStdout opts+            then return System.IO.stdout+            else openFile target WriteMode    hPutStrLn handle $ toString $ setManyAttrib vars code    -- Sniff through the file again, but looking only for local #include's   contents <- readFile fileName-  let includes = filter ("#include \"" `isPrefixOf`) (lines contents)-+  let includes = filter ("#include \"" `isPrefixOf`) . lines $ contents   for_ includes $ \inc ->     hPutStrLn handle $ "import "-                    ++ libName ++ "."+                    ++ prefix opts ++ "."                     ++ (capitalize . takeWhile (/= '.') . drop 10 $ inc)    traverse_ (hPutStrLn handle) hscs -  hClose handle+  unless (useStdout opts) $ hClose handle   putStrLn $ "Wrote " ++ target    when (length helpercs > 0) $ do     let targetc = cap ++ ".hsc.helper.c"-    handlec <- openFile targetc WriteMode+    handlec <- if useStdout opts+               then return System.IO.stdout+               else openFile targetc WriteMode      hPutStrLn handlec "#include <bindings.cmacros.h>"     traverse_ (hPutStrLn handlec) includes     hPutStrLn handlec ""     traverse_ (hPutStrLn handlec) helpercs -    hClose handlec+    unless (useStdout opts) $ hClose handlec     putStrLn $ "Wrote " ++ targetc    where capitalize [] = []@@ -150,16 +203,13 @@   case parseC stream pos of     Left err -> error $ "Failed to compile: " ++ show err     Right (CTranslUnit decls _) -> generateHsc decls-   where     generateHsc :: [CExtDecl] -> Output ()     generateHsc = traverse_ (appendNode fileName)  declInFile :: FilePath -> CExtDecl -> Bool-declInFile fileName = (fileName ==) . infoFile . declInfo--infoFile :: NodeInfo -> String-infoFile = posFile . posOfNode+declInFile fileName =+  (== takeFileName fileName) . takeFileName . posFile . posOfNode . declInfo  declInfo :: CExtDecl -> NodeInfo declInfo (CDeclExt (CDecl _ _ info))       = info@@ -181,8 +231,8 @@ appendNode :: FilePath -> CExtDecl -> Output ()  appendNode fp dx@(CDeclExt (CDecl declSpecs items _)) =-  for_ items $ \(declrtr, _, _) -> do-    for_ (splitDecl declrtr) $ \(d, ddrs, name) ->+  for_ items $ \(declrtr, _, _) ->+    for_ (splitDecl declrtr) $ \(d, ddrs, nm) ->       case ddrs of         CFunDeclr (Right (_, _)) _ _ : _ ->           when (declInFile fp dx) $@@ -191,7 +241,7 @@         _ -> do           when (declInFile fp dx) $ do             appendHsc $ "{- " ++ P.render (pretty dx) ++ " -}"-            appendType declSpecs name+            appendType declSpecs nm            -- If the type is a typedef, record the equivalence so we can look           -- it up later@@ -203,36 +253,34 @@               dname <- declSpecTypeName declSpecs               case dname of                 "" -> return ()-                _  -> defineType name dname+                _  -> defineType nm dname             _ -> return ()    where splitDecl declrtr = do           -- Take advantage of the Maybe monad to save us some effort           d@(CDeclr ident ddrs _ _ _) <- declrtr-          (Ident name _ _)            <- ident-          return (d, ddrs, name)+          (Ident nm _ _)              <- ident+          return (d, ddrs, nm)  appendNode fp dx@(CFDefExt (CFunDef declSpecs declrtr _ _ _)) =   -- Assume functions defined in headers are inline functions   when (declInFile fp dx) $ do     appendFunc "#cinline" declSpecs declrtr -    case declrtr of-      (CDeclr ident ddrs _ _ _) ->-        for_ ident $ \(Ident name _ _) ->-          case head ddrs of-            (CFunDeclr (Right (decls, _)) _ _) -> do-              let argsList =-                    concat . intersperse ", " . map (P.render . pretty) $ decls-              retType <- derDeclrTypeName' True declSpecs (tail ddrs)-              if retType /= ""-                then appendHelper $ "BC_INLINE" ++ show (length decls)-                                 ++ "(" ++ name ++ ", " ++ argsList-                                 ++ ", " ++ retType ++ ")"-                else appendHelper $ "BC_INLINE" ++ show (length decls)-                                 ++ "VOID(" ++ name ++ ", " ++ argsList ++ ")"-            _ -> return ()+    let (CDeclr ident ddrs _ _ _) = declrtr +    for_ ident $ \(Ident nm _ _) ->+      case head ddrs of+        (CFunDeclr (Right (decls, _)) _ _) -> do+          retType <- derDeclrTypeName' True declSpecs (tail ddrs)+          funType <- applyDeclrs True retType ddrs+          if retType /= ""+            then appendHelper $ "BC_INLINE" ++ show (length decls)+                             ++ "(" ++ nm ++ ", " ++ funType ++ ")"+            else appendHelper $ "BC_INLINE" ++ show (length decls)+                             ++ "VOID(" ++ nm ++ ", " ++ funType ++ ")"+        _ -> return ()+ appendNode _ (CAsmExt _ _) = return ()  -- Print out a function as #ccall or #cinline.  The syntax is the same for@@ -242,25 +290,26 @@ appendFunc :: String -> [CDeclarationSpecifier a] -> CDeclarator a -> Output () appendFunc marker declSpecs (CDeclr ident ddrs _ _ _) = do   retType  <- derDeclrTypeName declSpecs (tail ddrs)-  argTypes <- sequence $ getArgTypes (head ddrs)+  argTypes <- (++) <$> (filter (/= "") <$> sequence (getArgTypes (head ddrs)))+                   <*> pure [ "IO (" ++ retType ++ ")" ]    let name' = nameFromIdent ident-      tmpl  = "$marker$ $name$ , $argTypes;separator=' -> '$ -> IO ($retType$)"+      tmpl  = "$marker$ $name$ , $argTypes;separator=' -> '$"       code  = newSTMP tmpl       -- I have to this separately since argTypes :: [String]       code' = setAttribute "argTypes" argTypes code       vars  = [ ("marker",  marker)-              , ("name",    name')-              , ("retType", retType) ]+              , ("name",    name') ]    appendHsc $ toString $ setManyAttrib vars code'    where+    getArgTypes :: CDerivedDeclarator a -> [Output String]     getArgTypes (CFunDeclr (Right (decls, _)) _ _) = map cdeclTypeName decls     getArgTypes _ = []      nameFromIdent :: Maybe Ident -> String-    nameFromIdent name = case name of+    nameFromIdent nm = case nm of       Just (Ident n _ _) -> n       _ -> "<no name>" @@ -285,14 +334,14 @@       appendHsc $ "#integral_t " ++ name'        for_ defs $ \ds ->-        for_ ds $ \((Ident name _ _), _) -> do-          appendHsc $ "#num " ++ name+        for_ ds $ \(Ident nm _ _, _) ->+          appendHsc $ "#num " ++ nm      appendType' _ = return ()      identName ident = case ident of                         Nothing -> declrName-                        Just (Ident name _ _) -> name+                        Just (Ident nm _ _) -> nm  -- The remainder of this file is some hairy code for turning various -- constructs into Bindings-DSL type names, such as turning "int ** foo" into@@ -303,32 +352,51 @@ cdeclName :: CDeclaration a -> Maybe String cdeclName (CDecl _ more _) =   case more of-    (Just (CDeclr (Just (Ident name _ _)) _ _ _ _), _, _) : _ -> Just name+    (Just (CDeclr (Just (Ident nm _ _)) _ _ _ _), _, _) : _ -> Just nm     _ -> Nothing  cdeclTypeName :: CDeclaration a -> Output String-cdeclTypeName (CDecl declSpecs more _) =+cdeclTypeName = cdeclTypeName' False++cdeclTypeName' :: Bool -> CDeclaration a -> Output String+cdeclTypeName' cStyle (CDecl declSpecs more _) =   case more of-    (Just x, _, _) : _ -> declrTypeName declSpecs x-    _                  -> declSpecTypeName declSpecs+    (Just x, _, _) : _ -> declrTypeName' cStyle declSpecs x+    _                  -> declSpecTypeName' cStyle declSpecs  declSpecTypeName :: [CDeclarationSpecifier a] -> Output String-declSpecTypeName = flip derDeclrTypeName []+declSpecTypeName = declSpecTypeName' False +declSpecTypeName' :: Bool -> [CDeclarationSpecifier a] -> Output String+declSpecTypeName' cStyle = flip (derDeclrTypeName' cStyle) []+ declrTypeName :: [CDeclarationSpecifier a] -> CDeclarator a -> Output String-declrTypeName declSpecs (CDeclr _ ddrs _ _ _) = derDeclrTypeName declSpecs ddrs+declrTypeName = declrTypeName' False +declrTypeName' :: Bool -> [CDeclarationSpecifier a] -> CDeclarator a+               -> Output String+declrTypeName' cStyle declSpecs (CDeclr _ ddrs _ _ _) =+  derDeclrTypeName' cStyle declSpecs ddrs+ derDeclrTypeName :: [CDeclarationSpecifier a] -> [CDerivedDeclarator a]                  -> Output String derDeclrTypeName = derDeclrTypeName' False  derDeclrTypeName' :: Bool -> [CDeclarationSpecifier a] -> [CDerivedDeclarator a]                   -> Output String-derDeclrTypeName' cStyle declSpecs ddrs =-  applyPointers <$> fullTypeName' None declSpecs <*> pure ddrs+derDeclrTypeName' cStyle declSpecs ddrs = do+  nm <- fullTypeName' None declSpecs+  applyDeclrs cStyle nm ddrs+   where     fullTypeName' :: Signedness -> [CDeclarationSpecifier a] -> Output String-    fullTypeName' _ []     = return ""+    fullTypeName' _ [] = return ""++    fullTypeName' _ (CTypeSpec (CSignedType _):[]) =+      if cStyle then return "signed" else return "CInt"+    fullTypeName' _ (CTypeSpec (CUnsigType _):[]) =+      if cStyle then return "unsigned" else return "CUInt"+     fullTypeName' s (x:xs) =       case x of         CTypeSpec (CSignedType _) -> fullTypeName' Signed xs@@ -336,28 +404,51 @@         CTypeSpec tspec           -> if cStyle                                      then cTypeName tspec s                                      else typeName tspec s-        _                         -> fullTypeName' s xs+        _ -> fullTypeName' s xs -    applyPointers :: String -> [CDerivedDeclarator a] -> String-    applyPointers baseType [] = baseType-    applyPointers baseType (x:[]) =-      case x of-        CPtrDeclr _ _ ->-          if cStyle-          then if baseType == ""-               then "void *"-               else baseType ++ " *"-          else if baseType == ""-               then "Ptr ()"-               else "Ptr " ++ baseType-        _ -> ""-    applyPointers baseType (x:xs) =-      case x of-        CPtrDeclr _ _ ->-          if cStyle-          then applyPointers baseType xs ++ " *"-          else "Ptr (" ++ applyPointers baseType xs ++ ")"-        _ -> ""+concatM :: (Monad f, Functor f) => [f [a]] -> f [a]+concatM xs = concat <$> sequence xs++applyDeclrs :: Bool -> String -> [CDerivedDeclarator a] -> Output String++applyDeclrs cStyle baseType (p@CPtrDeclr {}:f@CFunDeclr {}:ds)+  | cStyle    = applyDeclrs cStyle (baseType ++ " *") (f:ds)+  | otherwise = join $ applyDeclrs cStyle <$> applyDeclrs cStyle baseType [p]+                                          <*> pure (f:ds)++applyDeclrs cStyle baseType (CFunDeclr (Right (decls, _)) _ _:_)+  | cStyle = do+    let declNames = sequence $+                    map (cdeclTypeName' cStyle) decls ++ [pure baseType]+    intercalate ", " <$> (filter (/= "") <$> declNames)++  | otherwise = do+    let declNames = sequence $ map cdeclTypeName decls ++ [pure baseType]+    argTypes <- intercalate " -> " <$> (filter (/= "") <$> declNames)+    return $ "FunPtr (" ++ argTypes ++ ")"++applyDeclrs cStyle baseType (CPtrDeclr _ _:[])+  | cStyle && baseType == "" = return "void *"+  | cStyle                  = return $ baseType ++ "*"+  | baseType == ""          = return "Ptr ()"+  | baseType == "CChar"     = return "CString"+  | otherwise               = return $ "Ptr " ++ baseType++applyDeclrs cStyle baseType (CPtrDeclr _ _:xs)+  | cStyle    = concatM [ applyDeclrs cStyle baseType xs+                        , pure " *" ]+  | otherwise = concatM [ pure "Ptr ("+                        , applyDeclrs cStyle baseType xs+                        , pure ")" ]++applyDeclrs cStyle baseType (CArrDeclr {}:xs)+  | cStyle    = concatM [ applyDeclrs cStyle baseType xs+                        , pure "[]" ]+  | otherwise = concatM [ pure "Ptr ("+                        , applyDeclrs cStyle baseType xs+                        , pure ")" ]++applyDeclrs _ baseType _ = return baseType  -- Simple translation from C types to Foreign.C.Types types.  We represent -- Void as the empty string so that returning void becomes IO (), and passing@@ -365,39 +456,39 @@  typeName :: CTypeSpecifier a -> Signedness -> Output String -typeName (CVoidType _) _   = return $ ""-typeName (CFloatType _) _  = return $ "CFloat"-typeName (CDoubleType _) _ = return $ "CDouble"-typeName (CBoolType _) _   = return $ "CInt"+typeName (CVoidType _) _   = return ""+typeName (CFloatType _) _  = return "CFloat"+typeName (CDoubleType _) _ = return "CDouble"+typeName (CBoolType _) _   = return "CInt"  typeName (CCharType _) s   = case s of-                               Signed   -> return $ "CSChar"-                               Unsigned -> return $ "CUChar"-                               _        -> return $ "CChar"+                               Signed   -> return "CSChar"+                               Unsigned -> return "CUChar"+                               _        -> return "CChar" typeName (CShortType _) s  = case s of-                               Signed   -> return $ "CShort"-                               Unsigned -> return $ "CUShort"-                               _        -> return $ "CShort"+                               Signed   -> return "CShort"+                               Unsigned -> return "CUShort"+                               _        -> return "CShort" typeName (CIntType _) s    = case s of-                               Signed   -> return $ "CInt"-                               Unsigned -> return $ "CUInt"-                               _        -> return $ "CInt"+                               Signed   -> return "CInt"+                               Unsigned -> return "CUInt"+                               _        -> return "CInt" typeName (CLongType _) s   = case s of-                               Signed   -> return $ "CLong"-                               Unsigned -> return $ "CULong"-                               _        -> return $ "CLong"+                               Signed   -> return "CLong"+                               Unsigned -> return "CULong"+                               _        -> return "CLong" -typeName (CTypeDef (Ident name _ _) _) _ = do-  definition <- lookupType name-  return $ fromMaybe ("<" ++ name ++ ">") definition+typeName (CTypeDef (Ident nm _ _) _) _ = do+  definition <- lookupType nm+  return $ fromMaybe ("<" ++ nm ++ ">") definition -typeName (CComplexType _) _  = return $ ""-typeName (CSUType _ _) _     = return $ ""-typeName (CEnumType _ _) _   = return $ ""-typeName (CTypeOfExpr _ _) _ = return $ ""-typeName (CTypeOfType _ _) _ = return $ ""+typeName (CComplexType _) _  = return ""+typeName (CSUType _ _) _     = return ""+typeName (CEnumType _ _) _   = return ""+typeName (CTypeOfExpr _ _) _ = return ""+typeName (CTypeOfType _ _) _ = return "" -typeName _ _ = return $ ""+typeName _ _ = return ""  -- Translation from C back to C.  Needed because there's no good way to pretty -- print a function's return type (including pointers on the declarator) in@@ -405,40 +496,40 @@  cTypeName :: CTypeSpecifier a -> Signedness -> Output String -cTypeName (CVoidType _) _   = return $ ""-cTypeName (CFloatType _) _  = return $ "float"-cTypeName (CDoubleType _) _ = return $ "double"-cTypeName (CBoolType _) _   = return $ "int"+cTypeName (CVoidType _) _   = return ""+cTypeName (CFloatType _) _  = return "float"+cTypeName (CDoubleType _) _ = return "double"+cTypeName (CBoolType _) _   = return "int"  cTypeName (CCharType _) s   = case s of-                               Signed   -> return $ "signed char"-                               Unsigned -> return $ "unsigned char"-                               _        -> return $ "char"+                               Signed   -> return "signed char"+                               Unsigned -> return "unsigned char"+                               _        -> return "char" cTypeName (CShortType _) s  = case s of-                               Signed   -> return $ "signed short"-                               Unsigned -> return $ "unsigned short"-                               _        -> return $ "hort"+                               Signed   -> return "signed short"+                               Unsigned -> return "unsigned short"+                               _        -> return "hort" cTypeName (CIntType _) s    = case s of-                               Signed   -> return $ "signed int"-                               Unsigned -> return $ "unsigned int"-                               _        -> return $ "int"+                               Signed   -> return "signed int"+                               Unsigned -> return "unsigned int"+                               _        -> return "int" cTypeName (CLongType _) s   = case s of-                               Signed   -> return $ "signed long"-                               Unsigned -> return $ "unsigned long"-                               _        -> return $ "long"+                               Signed   -> return "signed long"+                               Unsigned -> return "unsigned long"+                               _        -> return "long" -cTypeName (CTypeDef (Ident name _ _) _) _ = do-  definition <- lookupType name-  return $ fromMaybe name definition+cTypeName (CTypeDef (Ident nm _ _) _) _ = do+  definition <- lookupType nm+  return $ fromMaybe nm definition -cTypeName (CComplexType _) _  = return $ ""-cTypeName (CSUType _ _) _     = return $ ""-cTypeName (CEnumType _ _) _   = return $ ""-cTypeName (CTypeOfExpr _ _) _ = return $ ""-cTypeName (CTypeOfType _ _) _ = return $ ""+cTypeName (CComplexType _) _  = return ""+cTypeName (CSUType _ _) _     = return ""+cTypeName (CEnumType _ _) _   = return ""+cTypeName (CTypeOfExpr _ _) _ = return ""+cTypeName (CTypeOfType _ _) _ = return "" -cTypeName _ _ = return $ ""+cTypeName _ _ = return "" --- parseFile "/usr/bin/gcc" ["-U__BLOCKS__", "/Users/johnw/src/hlibgit2/libgit2/include/git2/types.h"]+-- runArgs ["--prefix=C2Hsc.Smoke", "--cppopts=-U__BLOCKS__", "test/smoke.h"]  -- c2hsc.hs
README.md view
@@ -8,3 +8,22 @@ For example, in `hlibgit2` on the Mac I'm using:      c2hsc Bindings.Libgit2 -U__BLOCKS__ libgit2/include/git2/tree.h++Known issues:++ - Varargs functions do not translate+ - Arrays are not handled at all (use #array_field $name , $type)+ - Handle type synonyms+ - Unnamed enums are not being emitted+ - Inline helper generator outputs the wrong headers+ - Files named foo_bar should become FooBar+ - Global variables are not being emitted++Also, please note that this tool will never be 100% accurate.  It cannot+translate macros, or anything related to the preprocessor, for example.  It+often misses necessary `#include` files, and will get them wrong in any case+if preprocessor conditionals are involved.++The goal of `c2hsc` is to solve the hardest 80% of the problem of creating an+FFI library.  The remaining 20%, plus validation of the results, is an+exercise necessarily left to the user.
c2hsc.cabal view
@@ -1,6 +1,6 @@ Name: c2hsc -Version:  0.2.0+Version:  0.3.0 Synopsis: Convert C API header files to .hsc and .hsc.helper.c files  Description: Convert C API header files to .hsc and .hsc.helper.c files@@ -17,19 +17,29 @@ Extra-Source-Files: README.md  Executable c2hsc-    Main-is: Main.hs-    Ghc-options: -Wall+  Main-is: Main.hs+  Ghc-options: -Wall -    Build-depends: base >= 4 && < 5-                 , mtl-                 , containers-                 , transformers-                 , directory-                 , language-c-                 , HStringTemplate-                 , pretty-                 , filepath+  Build-depends: base >= 4 && < 5+               , mtl+               , containers+               , transformers+               , directory+               , language-c+               , HStringTemplate+               , pretty+               , filepath+               , cmdargs +--Test-suite smoke+--  Type: exitcode-stdio-1.0+--  Main-is: Smoke.hs+--  Hs-source-dirs: test+--  Build-depends: base >= 4 && < 5+--               , c2hsc+ Source-repository head-  type:     git-  location: https://github.com/jwiegley/c2hsc+  Type:     git+  Location: https://github.com/jwiegley/c2hsc++-- c2hsc.cabal ends here