
# 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).