Skip to content

Commit 028fe53

Browse files
committed
Merge branch 'stable'
2 parents fa9c76c + ae4720d commit 028fe53

File tree

4 files changed

+225
-97
lines changed

4 files changed

+225
-97
lines changed

doc/GUIDE.md

Lines changed: 0 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,103 +1091,6 @@ modified version of a dependency that hasn't yet been released upstream.
10911091
See [stack.yaml documentation](yaml_configuration.md#packages) for more
10921092
details.
10931093

1094-
## Haskell packages with C code
1095-
1096-
A Haskell package can include C source code. For example, consider a simple
1097-
one-package project named `c-example`, created by `stack new c-example` but with
1098-
these changes:
1099-
1100-
A C header file `my-library.h` added in new directory `include`:
1101-
~~~c
1102-
#ifndef MY_LIBRARY_HEADER
1103-
#define MY_LIBRARY_HEADER
1104-
int max(int, int);
1105-
#endif
1106-
~~~
1107-
1108-
A C source code file `my-library.c` added in new directory `c-source`:
1109-
~~~c
1110-
#include "my-library.h"
1111-
1112-
/* Function returning the larger of two integers */
1113-
int max(int x1, int x2) {
1114-
if (x1 > x2)
1115-
return x1;
1116-
else
1117-
return x2;
1118-
}
1119-
~~~
1120-
1121-
A different `src/Lib.hs` Haskell module, including a Haskell foreign import
1122-
declaration making use of the C `max` function:
1123-
~~~haskell
1124-
module Lib
1125-
( someFunc
1126-
, c_max
1127-
) where
1128-
1129-
someFunc :: IO ()
1130-
someFunc = putStrLn "someFunc"
1131-
1132-
foreign import ccall "max" c_max :: Int -> Int -> Int
1133-
~~~
1134-
1135-
A different `app/Main.hs` Haskell module, making use of the Haskell `c_max`
1136-
function now exported from module `Lib`:
1137-
~~~haskell
1138-
module Main ( main ) where
1139-
1140-
import Lib ( c_max, someFunc )
1141-
1142-
main :: IO ()
1143-
main = do
1144-
someFunc
1145-
print $ c_max 10 100
1146-
~~~
1147-
1148-
The package's `package.yaml` file (simplied), used to create the package's
1149-
Cabal file, might look like this:
1150-
~~~yaml
1151-
spec-version: 0.36.0
1152-
1153-
name: c-example
1154-
version: 0.1.0.0
1155-
1156-
# Hpack 0.36.1 and earlier does not support Cabal's 'includes' field
1157-
extra-source-files:
1158-
- include/my-library.h
1159-
1160-
dependencies:
1161-
- base >= 4.7 && < 5
1162-
1163-
library:
1164-
source-dirs: src
1165-
include-dirs: # Where to look for C header files?
1166-
- include
1167-
c-sources: # What C source code files to be compiled and linked?
1168-
- c-source/my-library.c
1169-
1170-
executables:
1171-
c-example-exe:
1172-
main: Main.hs
1173-
source-dirs: app
1174-
ghc-options:
1175-
- -threaded
1176-
- -rtsopts
1177-
- -with-rtsopts=-N
1178-
dependencies:
1179-
- c-example
1180-
~~~
1181-
1182-
The project's `stack.yaml` file only needs to identify a snapshot:
1183-
~~~yaml
1184-
snapshot: lts-22.26 # GHC 9.6.5
1185-
~~~
1186-
1187-
This example project can be built with Stack in the normal way (`stack build`),
1188-
and the built executable can then be executed in the Stack environment in the
1189-
normal way (`stack exec c-example-exe`).
1190-
11911094
## Flags and GHC options
11921095

11931096
There are two common ways to alter how a package will install: with Cabal flags

doc/haskell_and_c_code.md

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
<div class="hidden-warning"><a href="https://docs.haskellstack.org/"><img src="https://cdn.jsdelivr.net/gh/commercialhaskell/stack/doc/img/hidden-warning.svg"></a></div>
2+
3+
# Haskell and C code
4+
5+
## Haskell packages with C code
6+
7+
A Haskell package can include C source code. For example, consider a simple
8+
one-package Stack project named `c-example`, created by `stack new c-example`
9+
but with these changes:
10+
11+
A C header file `my-library.h` added in new directory `include`:
12+
~~~c
13+
#ifndef MY_LIBRARY_HEADER
14+
#define MY_LIBRARY_HEADER
15+
int max(int, int);
16+
#endif
17+
~~~
18+
19+
A C source code file `my-library.c` added in new directory `c-source`:
20+
~~~c
21+
#include "my-library.h"
22+
23+
/* Function returning the larger of two integers */
24+
int max(int x1, int x2) {
25+
if (x1 > x2)
26+
return x1;
27+
else
28+
return x2;
29+
}
30+
~~~
31+
32+
A different Haskell module in source file `src/Lib.hs`, including a Haskell
33+
foreign import declaration making use of the C `max` function:
34+
~~~haskell
35+
module Lib ( c_max ) where
36+
37+
foreign import ccall "max" c_max :: Int -> Int -> Int
38+
~~~
39+
40+
A different Haskell module in source file `app/Main.hs`, making use of the
41+
Haskell function `c_max` exported from module `Lib`:
42+
~~~haskell
43+
module Main ( main ) where
44+
45+
import Lib ( c_max )
46+
47+
main :: IO ()
48+
main = print $ c_max 10 100
49+
~~~
50+
51+
The package's `package.yaml` file (simplied), used to create the package's
52+
Cabal file, might look like this:
53+
~~~yaml
54+
spec-version: 0.36.0
55+
56+
name: c-example
57+
version: 0.1.0.0
58+
59+
extra-source-files:
60+
- include/my-library.h
61+
62+
dependencies:
63+
- base >= 4.7 && < 5
64+
65+
library:
66+
source-dirs: src
67+
include-dirs: # Where to look for C header files?
68+
- include
69+
c-sources: # What C source code files to be compiled and linked?
70+
- c-source/my-library.c
71+
72+
executables:
73+
c-example-exe:
74+
main: Main.hs
75+
source-dirs: app
76+
ghc-options:
77+
- -threaded
78+
- -rtsopts
79+
- -with-rtsopts=-N
80+
dependencies:
81+
- c-example
82+
~~~
83+
84+
The project's `stack.yaml` file only needs to identify a snapshot:
85+
~~~yaml
86+
snapshot: lts-22.26 # GHC 9.6.5
87+
~~~
88+
89+
This example project can be built with Stack in the normal way (`stack build`),
90+
and the built executable can then be executed in the Stack environment in the
91+
normal way (`stack exec c-example-exe`).
92+
93+
## Haskell packages with C `main` function
94+
95+
A Haskell package can include an executable which has a `main` function written
96+
in C. For example, consider a simple one-package Stack project named
97+
`c-example`, with:
98+
99+
A `package.yaml` describing a library and two executables, named `haskell-exe`
100+
and `c-exe`:
101+
102+
~~~yaml
103+
spec-version: 0.36.0
104+
105+
name: c-example
106+
version: 0.1.0.0
107+
108+
dependencies: base
109+
110+
library:
111+
source-dirs: src
112+
# The Lib_stub.h header must be put by GHC somewhere where Cabal can find it.
113+
# This tells GHC to put it in the autogen-stubs directory of the project
114+
# directory.
115+
ghc-options:
116+
- -stubdir autogen-stubs
117+
118+
executables:
119+
haskell-exe:
120+
main: Main.hs
121+
source-dirs: app
122+
ghc-options:
123+
- -threaded
124+
- -rtsopts
125+
- -with-rtsopts=-N
126+
dependencies: c-example
127+
c-exe:
128+
main: main.c
129+
source-dirs: c-app
130+
ghc-options: -no-hs-main
131+
# This specifies that directory autogen-stubs should be searched for header
132+
# files.
133+
include-dirs: autogen-stubs
134+
dependencies: c-example
135+
~~~
136+
137+
A Haskell module souce file named `Lib.hs` in directory `src`:
138+
~~~haskell
139+
module Lib
140+
( myMax -- Exported only for the use of the 'Haskell' executable
141+
) where
142+
143+
myMax :: Int -> Int -> Int
144+
myMax x1 x2 = if x1 > x2 then x1 else x2
145+
146+
foreign export ccall myMax :: Int -> Int -> Int
147+
~~~
148+
149+
A Haskell module source file named `Main.hs` in directory `app`:
150+
~~~haskell
151+
module Main ( main ) where
152+
153+
import Lib ( myMax )
154+
155+
main :: IO ()
156+
main = print $ myMax 10 100
157+
~~~
158+
159+
A C source file named `main.c` in directory `c-app`:
160+
~~~c
161+
// Based in part on
162+
// https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/ffi.html#using-your-own-main
163+
164+
#include <stdio.h> // Provides printf()
165+
166+
#include <HsFFI.h> // Provides hs_init() and hs_exit(). See the Haskell 2010
167+
// Report, 8.7.
168+
169+
// Parts specific to GHC
170+
#ifdef __GLASGOW_HASKELL__
171+
#include "Lib_stub.h" // Automatically generated by GHC, given use of
172+
// foreign export ... in module Lib.hs ...
173+
#endif
174+
175+
int main(int argc, char *argv[]) {
176+
// Initialises the Haskell system and provides it with the available command
177+
// line arguments
178+
hs_init(&argc, &argv);
179+
180+
// Use our foreign export from module Lib.hs ...
181+
printf("%lld\n", myMax(10,100));
182+
183+
// De-initialise the Haskell system
184+
hs_exit();
185+
return 0;
186+
}
187+
~~~
188+
189+
The `foreign export` declaration in Haskell module `Lib` will cause GHC to
190+
generate a 'stub' C header file named `Lib_stub.h`. The GHC option `-stubdir`
191+
will cause GHC to put that file in the specified directory (`autogen-stubs`, in
192+
this example).
193+
194+
!!! info
195+
196+
If GHC's `-stubdir` option is omitted, GHC will put the generated C header
197+
file together with the other build artefacts for the module. However, that
198+
location cannot be specified reliably using the `include-dirs` key.
199+
200+
That generated C header file will have content like:
201+
~~~c
202+
#include <HsFFI.h>
203+
#if defined(__cplusplus)
204+
extern "C" {
205+
#endif
206+
extern HsInt myMax(HsInt a1, HsInt a2);
207+
#if defined(__cplusplus)
208+
}
209+
#endif
210+
~~~
211+
212+
The `include-dirs` key will cause the specified directory (again,
213+
`autogen-stubs` in this example) to be searched for C header files.
214+
215+
The project's `stack.yaml` file only needs to identify a snapshot:
216+
~~~yaml
217+
snapshot: lts-22.26 # GHC 9.6.5
218+
~~~
219+
220+
This example project can be built with Stack in the normal way (`stack build`),
221+
and the built executables can then be executed in the Stack environment in the
222+
normal way (`stack exec haskell-exe` for the 'Haskell' executable and
223+
`stack exec c-exe` for the 'C' executable).

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ nav:
8989
- Azure CI: azure_ci.md
9090
- Lock files: lock_files.md
9191
- Stack work directories: stack_work.md
92+
- Haskell and C code: haskell_and_c_code.md
9293
- How Stack works (advanced):
9394
- Build overview: build_overview.md
9495
- Stack's code (advanced):

stack.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ extra-source-files:
5858
doc/glossary.md
5959
doc/GUIDE.md
6060
doc/GUIDE_advanced.md
61+
doc/haskell_and_c_code.md
6162
doc/hoogle_command.md
6263
doc/hpc_command.md
6364
doc/ide_command.md

0 commit comments

Comments
 (0)