Skip to content

Commit b62890c

Browse files
committed
Update 'building your project'
1 parent 53d1795 commit b62890c

File tree

1 file changed

+142
-72
lines changed

1 file changed

+142
-72
lines changed

doc/tutorial/building_your_project.md

Lines changed: 142 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
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>
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>
22

33
# 2. Building your project
44

5-
The `build` command is the heart and soul of Stack. It is the engine that powers
6-
building your code, testing it, getting dependencies, and more. Quite a bit of
7-
the remainder of this guide will cover more advanced `build` functions and
8-
features, such as building test and Haddocks at the same time, or constantly
9-
rebuilding blocking on file changes.
5+
The [`stack build`](../commands/build_command.md) command is the heart of Stack.
6+
It is the engine that powers building your code, testing it, getting
7+
dependencies, and more. Much of the remainder of this getting started guide will
8+
cover its features.
109

1110
!!! note
1211

@@ -16,61 +15,95 @@ rebuilding blocking on file changes.
1615

1716
## Adding dependencies
1817

19-
Let's say we decide to modify our `helloworld` source a bit to use a new
20-
library, perhaps the ubiquitous `text` package. In `src/Lib.hs`, we can, for
21-
example add:
18+
A Haskell package often depends on code exposed by other Haskell packages.
19+
20+
Let's say we decide to modify our existing `helloworld` package source code to
21+
use a new library, the one provided by the
22+
[`text`](https://hackage.haskell.org/package/text) package.
23+
24+
We can modify `src/Lib.hs` so that its contents are as follows (click
25+
:material-plus-circle: to learn more):
2226

2327
~~~haskell
24-
{-# LANGUAGE OverloadedStrings #-}
28+
{-# LANGUAGE OverloadedStrings #-} -- (1)!
29+
2530
module Lib
2631
( someFunc
2732
) where
2833

29-
import qualified Data.Text.IO as T
34+
import qualified Data.Text.IO as T -- (2)!
3035

3136
someFunc :: IO ()
32-
someFunc = T.putStrLn "someFunc"
37+
someFunc = T.putStrLn "someFunc" --(3)!
3338
~~~
3439

35-
When we try to build this, things don't go as expected:
40+
1. Enables overloaded string literals. String literals now have type
41+
`(IsString a) => a`.
42+
43+
2. The module is exposed by the library of the `text` package.
44+
45+
3. `Data.Text.IO.putStrLn :: Text -> IO ()`.
46+
47+
If we command:
3648

3749
~~~text
3850
stack build
39-
# build failure output (abridged for clarity) ...
40-
src\Lib.hs:6:1: error:
51+
~~~
52+
53+
Stack will report error [S-7282] during the build:
54+
55+
~~~text
56+
...
57+
Building library for helloworld-0.1.0.0..
58+
[1 of 2] Compiling Lib [Source file changed]
59+
60+
src\Lib.hs:7:1: error:
4161
Could not load module ‘Data.Text.IO’
42-
It is a member of the hidden package ‘text-1.2.5.0’.
62+
It is a member of the hidden package ‘text-2.0.2’.
4363
Perhaps you need to add ‘text’ to the build-depends in your .cabal file.
4464
Use -v (or `:set -v` in ghci) to see a list of the files searched for.
4565
|
46-
6 | import qualified Data.Text.IO as T
66+
7 | import qualified Data.Text.IO as T
4767
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
68+
69+
Error: [S-7282]
70+
Stack failed to execute the build plan.
71+
72+
While executing the build plan, Stack encountered the error:
73+
74+
[S-7011]
75+
While building package helloworld-0.1.0.0 (scroll up to its section to see the error) using:
76+
...
77+
Process exited with code: ExitFailure 1
4878
~~~
4979

50-
This means that the package containing the module in question is not available.
51-
To tell Stack to use [text](https://hackage.haskell.org/package/text), you need
52-
to add it to your `package.yaml` file — specifically in your `dependencies`
53-
section, like this:
80+
The error `Could not load module ...` means that the package exposing the module
81+
in question is not available.
82+
83+
To tell Stack that the `text` package is a dependency of the `helloworld`
84+
package, you need to update the package description file (`package.yaml`).
85+
Specifically, you need to add `text` under the `dependencies` key, like this:
5486

5587
~~~yaml
5688
dependencies:
5789
- base >= 4.7 && < 5
58-
- text # added here
90+
- text # added
5991
~~~
6092

61-
Now if we rerun `stack build`, we should get a successful result. Command:
93+
Now, if we command again:
6294

6395
~~~text
6496
stack build
65-
# build output ...
6697
~~~
6798

68-
This output means that the `text` package was downloaded, configured, built, and
99+
we should get a successful result.
100+
101+
The output means that the `text` package was downloaded, configured, built, and
69102
locally installed. Once that was done, we moved on to building our project
70103
package (`helloworld`). At no point did we need to ask Stack to build
71104
dependencies — it does so automatically.
72105

73-
### Listing Dependencies
106+
## Listing dependencies
74107

75108
Let's have Stack add a few more dependencies to our project. First, we'll
76109
include two new packages in the `dependencies` section for our library in our
@@ -80,44 +113,48 @@ include two new packages in the `dependencies` section for our library in our
80113
dependencies:
81114
- base >= 4.7 && < 5
82115
- text
83-
- filepath
84-
- containers
116+
- filepath # added
117+
- containers # added
85118
~~~
86119

87-
After adding these two dependencies, we can again run `stack build` to have them
88-
installed. Command:
120+
After adding these two dependencies, we can again command:
89121

90122
~~~text
91123
stack build
92-
# build output ...
93124
~~~
94125

95-
Finally, to find out which versions of these libraries Stack installed, we can
96-
ask Stack to `ls dependencies`. Command:
126+
to have them downloaded, configured, built, and locally installed.
127+
128+
To find out which versions of these packages Stack installed, we can command:
97129

98130
~~~text
99131
stack ls dependencies
100-
# dependency output ...
101132
~~~
102133

103-
### extra-deps
134+
## Packages not in the snapshot
135+
136+
The packages `text`, `filepath` and `containers` have something in common: they
137+
are all provided with GHC (referred to as GHC boot packages).
104138

105-
Let's try a more off-the-beaten-track package: the joke
106-
[acme-missiles](http://www.stackage.org/package/acme-missiles) package. Our
107-
source code is simple:
139+
Let's try a dependency on a more off-the-beaten-track package: the joke
140+
[acme-missiles](http://www.stackage.org/package/acme-missiles) package.
141+
142+
We can further modify `src/Lib.hs` so that its contents are as follows:
108143

109144
~~~haskell
110145
module Lib
111146
( someFunc
112147
) where
113148

114-
import Acme.Missiles
149+
import Acme.Missiles ( launchMissiles )
115150

116151
someFunc :: IO ()
117152
someFunc = launchMissiles
118153
~~~
119154

120-
Again, we add this new dependency to the `package.yaml` file like this:
155+
As before, to tell Stack that the `acme-missiles` package is a dependency of the
156+
`helloworld` package, we can update the package description file
157+
(`package.yaml`). The relevant part of the file now looks like this:
121158

122159
~~~yaml
123160
dependencies:
@@ -128,47 +165,80 @@ dependencies:
128165
- acme-missiles # added
129166
~~~
130167

131-
However, rerunning `stack build` shows us the following error message. Command:
168+
If we command:
132169

133170
~~~text
134171
stack build
135-
# build failure output ...
136172
~~~
137173

138-
It says that it was unable to construct the build plan.
174+
Stack will report error [S-4804]:
175+
176+
~~~text
177+
Error: [S-4804]
178+
Stack failed to construct a build plan.
179+
180+
While constructing the build plan, Stack encountered the following errors. The
181+
'Stack configuration' refers to the set of package versions specified by the
182+
snapshot (after any dropped packages, or pruned GHC boot packages; if a boot
183+
package is replaced, Stack prunes all other such packages that depend on it) and
184+
any extra-deps:
185+
186+
In the dependencies for helloworld-0.1.0.0:
187+
* acme-missiles needed, but no version is in the Stack configuration (latest
188+
matching version is 0.3).
189+
The above is/are needed since helloworld is a build target.
190+
191+
Some different approaches to resolving some or all of this:
192+
193+
* Recommended action: try adding the following to your extra-deps in
194+
...\helloworld\stack.yaml (project-level configuration):
195+
196+
- acme-missiles-0.3@sha256:2ba66a092a32593880a87fb00f3213762d7bca65a687d45965778deb8694c5d1,613
197+
~~~
198+
199+
It says that Stack was unable to construct the build plan.
139200

140201
This brings us to the next major topic in using Stack.
141202

142-
## Curated package sets
203+
## Extending snapshots
204+
205+
A snapshot specifies a version of GHC and a set of package versions.
143206

144207
Remember above when `stack new` selected some
145208
[LTS snapshot](https://github.com/commercialhaskell/lts-haskell#readme) for us?
146209
That defined our build plan and available packages. When we tried using the
147210
`text` package, it just worked, because it was part of the LTS *package set*.
148211

149-
We've specified the `acme-missiles` package in the `package.yaml` file (see
150-
above), but `acme-missiles` is not part of that LTS package set, so building
212+
We have updated the description of the `helloworld` package (in `package.yaml`)
213+
to specify that it depends on the `acme-missiles` package, but `acme-missiles`
214+
is not a member of the set of packages specified by the snapshot. So building
151215
failed.
152216

153-
To add `acme-missiles` to the available packages, we'll use the `extra-deps` key
154-
in the `stack.yaml` file. That key defines extra packages, not present in the
155-
snapshot, that will be needed as dependencies. You can add this like so:
217+
To add a version of `acme-missiles` to the available package versions, we'll use
218+
the `extra-deps` key in Stack's project-level configuration file (`stack.yaml`).
219+
That key defines extra package versions, not present in the snapshot, that will
220+
be needed as dependencies. You can add this like so:
156221

157222
~~~yaml
158223
extra-deps:
159224
- acme-missiles-0.3 # not in the LTS snapshot
160225
~~~
161226

162-
Now `stack build` will succeed.
227+
Now, if we command again:
228+
229+
~~~text
230+
stack build
231+
~~~
232+
233+
we should get a successful result.
163234

164-
With that out of the way, let's dig a little bit more into these package sets,
165-
also known as *snapshots*. We mentioned the LTS snapshots, and you can get quite
166-
a bit of information about it at
235+
With that out of the way, let's dig a little bit more into these snapshots. We
236+
mentioned the LTS snapshots, and you can get information about it at
167237
[https://www.stackage.org/lts](https://www.stackage.org/lts), including:
168238

169-
* The appropriate value (`lts-22.13`, as is currently the latest LTS)
239+
* The appropriate value (`lts-22.30`, as is currently the latest LTS)
170240
* The GHC version used
171-
* A full list of all packages available in this snapshot
241+
* A full list of all packages versions available in this snapshot
172242
* The ability to perform a Hoogle search on the packages in this snapshot
173243
* A [list of all modules](https://www.stackage.org/lts/docs) in a snapshot,
174244
which can be useful when trying to determine which package to add to your
@@ -182,7 +252,7 @@ about them on the
182252
If you're not sure which to use, start with LTS Haskell (which Stack will lean
183253
towards by default as well).
184254

185-
## Snapshots and changing your compiler version
255+
## Available snapshots
186256

187257
Let's explore package sets a bit further. Instead of `lts-22.13`, let's change
188258
our `stack.yaml` file to use the
@@ -217,22 +287,6 @@ on the command line and not in your `stack.yaml` file is that using them:
217287
2. Produces unreliable results (since a build run today may proceed differently
218288
tomorrow because of changes outside of your control)
219289

220-
### Changing GHC versions
221-
222-
Finally, let's try using an older LTS snapshot. We'll use the newest 21.x
223-
snapshot with the command:
224-
225-
~~~text
226-
stack --snapshot lts-21 build
227-
# build output ...
228-
~~~
229-
230-
This succeeds, automatically installing the necessary GHC along the way. So, we
231-
see that different LTS versions use different GHC versions and Stack can handle
232-
that.
233-
234-
### Other snapshot values
235-
236290
We've mentioned `nightly-YYYY-MM-DD` and `lts-X.Y` values for the snapshot.
237291
There are actually other options available, and the list will grow over time.
238292
At the time of writing:
@@ -243,6 +297,22 @@ At the time of writing:
243297
The most up-to-date information can always be found in the
244298
[stack.yaml documentation](../configure/yaml/project.md#snapshot).
245299

300+
## Snapshots and GHC versions
301+
302+
As mentioned, a snapshot specifies a version of GHC as well as a set of package
303+
versions.
304+
305+
Let's try using an older LTS snapshot. We'll use the newest 21.x snapshot with
306+
the command:
307+
308+
~~~text
309+
stack --snapshot lts-21 build
310+
~~~
311+
312+
This succeeds, automatically installing the necessary GHC along the way. So, we
313+
see that different LTS versions use different GHC versions and Stack can handle
314+
that.
315+
246316
## Cleaning your project
247317

248318
You can clean up build artifacts for your project using the `stack clean` and

0 commit comments

Comments
 (0)