# Haskell and C code ## Haskell packages with C code A Haskell package can include C source code. For example, consider a simple one-package Stack project named `c-example`, created by `stack new c-example` but with these changes: A C header file `my-library.h` added in new directory `include`: ~~~c #ifndef MY_LIBRARY_HEADER #define MY_LIBRARY_HEADER int max(int, int); #endif ~~~ A C source code file `my-library.c` added in new directory `c-source`: ~~~c #include "my-library.h" /* Function returning the larger of two integers */ int max(int x1, int x2) { if (x1 > x2) return x1; else return x2; } ~~~ A different Haskell module in source file `src/Lib.hs`, including a Haskell foreign import declaration making use of the C `max` function: ~~~haskell module Lib ( c_max ) where foreign import ccall "max" c_max :: Int -> Int -> Int ~~~ A different Haskell module in source file `app/Main.hs`, making use of the Haskell function `c_max` exported from module `Lib`: ~~~haskell module Main ( main ) where import Lib ( c_max ) main :: IO () main = print $ c_max 10 100 ~~~ The package's `package.yaml` file (simplied), used to create the package's Cabal file, might look like this: ~~~yaml spec-version: 0.36.0 name: c-example version: 0.1.0.0 extra-source-files: - include/my-library.h dependencies: - base >= 4.7 && < 5 library: source-dirs: src include-dirs: # Where to look for C header files? - include c-sources: # What C source code files to be compiled and linked? - c-source/my-library.c executables: c-example-exe: main: Main.hs source-dirs: app ghc-options: - -threaded - -rtsopts - -with-rtsopts=-N dependencies: - c-example ~~~ The project's `stack.yaml` file only needs to identify a snapshot: ~~~yaml snapshot: lts-24.37 # GHC 9.10.3 ~~~ This example project can be built with Stack in the normal way (`stack build`), and the built executable can then be executed in the Stack environment in the normal way (`stack exec c-example-exe`). ## Haskell packages with C `main` function A Haskell package can include an executable which has a `main` function written in C. For example, consider a simple one-package Stack project named `c-example`, with: A `package.yaml` describing a library and two executables, named `haskell-exe` and `c-exe`: ~~~yaml spec-version: 0.36.0 name: c-example version: 0.1.0.0 dependencies: base library: source-dirs: src # The Lib_stub.h header must be put by GHC somewhere where Cabal can find it. # This tells GHC to put it in the autogen-stubs directory of the project # directory. ghc-options: - -stubdir autogen-stubs executables: haskell-exe: main: Main.hs source-dirs: app ghc-options: - -threaded - -rtsopts - -with-rtsopts=-N dependencies: c-example c-exe: main: main.c source-dirs: c-app ghc-options: -no-hs-main # This specifies that directory autogen-stubs should be searched for header # files. include-dirs: autogen-stubs dependencies: c-example ~~~ !!! warning `Cabal-3.12.0.0`, a boot package of GHC 9.10.1, ignores `source-dirs` when the `main` file is not a Haskell source code file. This was a regression and fixed in subsequent versions of Cabal (the library). A Haskell module souce file named `Lib.hs` in directory `src`: ~~~haskell module Lib ( myMax -- Exported only for the use of the 'Haskell' executable ) where myMax :: Int -> Int -> Int myMax x1 x2 = if x1 > x2 then x1 else x2 foreign export ccall myMax :: Int -> Int -> Int ~~~ A Haskell module source file named `Main.hs` in directory `app`: ~~~haskell module Main ( main ) where import Lib ( myMax ) main :: IO () main = print $ myMax 10 100 ~~~ A C source file named `main.c` in directory `c-app`: ~~~c // Based in part on // https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/ffi.html#using-your-own-main #include // Provides printf() #include // Provides hs_init() and hs_exit(). See the Haskell 2010 // Report, 8.7. // Parts specific to GHC #ifdef __GLASGOW_HASKELL__ #include "Lib_stub.h" // Automatically generated by GHC, given use of // foreign export ... in module Lib.hs ... #endif int main(int argc, char *argv[]) { // Initialises the Haskell system and provides it with the available command // line arguments hs_init(&argc, &argv); // Use our foreign export from module Lib.hs ... printf("%lld\n", myMax(10,100)); // De-initialise the Haskell system hs_exit(); return 0; } ~~~ The `foreign export` declaration in Haskell module `Lib` will cause GHC to generate a 'stub' C header file named `Lib_stub.h`. The GHC option `-stubdir` will cause GHC to put that file in the specified directory (`autogen-stubs`, in this example). !!! info If GHC's `-stubdir` option is omitted, GHC will put the generated C header file together with the other build artefacts for the module. However, that location cannot be specified reliably using the `include-dirs` key. That generated C header file will have content like: ~~~c #include #if defined(__cplusplus) extern "C" { #endif extern HsInt myMax(HsInt a1, HsInt a2); #if defined(__cplusplus) } #endif ~~~ The `include-dirs` key will cause the specified directory (again, `autogen-stubs` in this example) to be searched for C header files. The project's `stack.yaml` file only needs to identify a snapshot: ~~~yaml snapshot: lts-24.37 # GHC 9.10.3 ~~~ This example project can be built with Stack in the normal way (`stack build`), and the built executables can then be executed in the Stack environment in the normal way (`stack exec haskell-exe` for the 'Haskell' executable and `stack exec c-exe` for the 'C' executable).