Skip to content

Commit bd5847d

Browse files
committed
Tidy up stack.yaml vs a Cabal file
1 parent 5a179be commit bd5847d

File tree

4 files changed

+90
-70
lines changed

4 files changed

+90
-70
lines changed

doc/faq.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ directory. None of this should affect any existing Haskell tools at all.
6767
Stack will use Cabal via `setup`.
6868

6969
For detail on the differences between a `stack.yaml` file and a Cabal file, see
70-
[stack.yaml vs Cabal package file](stack_yaml_vs_cabal_package_file.md).
70+
[stack.yaml vs a Cabal file](stack_yaml_vs_cabal_package_file.md).
7171

7272
## I need to use a different version of a package than what is provided by the LTS Haskell snapshot I'm using, what should I do?
7373

Lines changed: 87 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,110 @@
11
<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

3-
# stack.yaml vs Cabal package file
3+
# stack.yaml versus package.yaml versus a Cabal file
44

5-
Due to their apparent overlap, the purpose of the following three files can be
6-
unclear:
5+
What is the difference between a `stack.yaml` file, a `package.yaml` file and a
6+
Cabal file (named `<package_name>.cabal`)? This page aims to make that clear.
77

8-
* `stack.yaml`
9-
* A Cabal package file, e.g. `my-package.cabal`
10-
* `package.yaml`
8+
In short:
119

12-
The last two are easy to explain: `package.yaml` is a file format supported by
13-
[Hpack](https://github.com/sol/hpack#readme). It adds some niceties on top of
14-
Cabal. For example, Hpack has YAML syntax support and will automatically
15-
generate of `exposed-modules` lists. However, it's just a frontend to Cabal
16-
package files. So for this document, we're instead going to focus on the first
17-
two and try to answer:
10+
* `stack.yaml` contains project-level configuration for Stack, and may contain
11+
project-specific options and non-project-specific options.
1812

19-
_What's the difference between a `stack.yaml` file and a cabal package file?_
13+
* `package.yaml` contains a description of a package in the
14+
[Hpack](https://github.com/sol/hpack) format. Hpack, including Stack's
15+
built-in version, uses the file to create a Cabal file.
16+
17+
* a Cabal file also contains a description of a package, but in the format used
18+
by Cabal.
19+
20+
## package.yaml versus a Cabal file
21+
22+
Why two different formats to describe packages? Hpack is considered to have some
23+
advantages over the underlying Cabal format, which are explained its project
24+
repository. They include that the Hpack format supports YAML syntax and the
25+
automatic generation of the lists of `exposed-modules` used in the Cabal format.
26+
27+
The remainder of this page will focus on the difference between a `stack.yaml`
28+
file and a package description file.
2029

2130
## Package versus project
2231

23-
Cabal is a build system, which is used by Stack. Cabal defines the concept of a
24-
_package_. A package has:
32+
Stack is a build tool and it uses Cabal, a build system. Cabal defines the
33+
concept of a _package_. A package has:
2534

2635
* A name and version
27-
* 0 or 1 libraries
28-
* 0 or more executables
36+
* optionally, one library
37+
* optionally, one or more executables
2938
* A Cabal file (or, as mentioned above, an [Hpack](https://github.com/sol/hpack)
3039
`package.yaml` file that generates a Cabal file)
3140
* And a bunch more
3241

33-
The second to last bullet bears repeating: there's a 1-to-1 correspondence between
34-
packages and cabal files.
42+
There is a one-to-one correspondence between a package and a Cabal file.
3543

36-
Stack is a build tool that works on top of the Cabal build system, and defines
37-
a new concept called a _project_. A project has:
44+
Stack defines a new concept called a _project_. A project has:
3845

3946
* A _resolver_, which tells it about a snapshot (more on this later)
4047
* Extra dependencies on top of the snapshot
41-
* 0 or more local Cabal packages
48+
* Optionally, one or more local Cabal packages
4249
* Flag and GHC options configurations
4350
* And a bunch more Stack configuration
4451

45-
A source of confusion is that, often, you'll have a project that defines
46-
exactly one package you're working on, and in that situation it's unclear why,
47-
for example, you need to specify an extra depedency in both your `stack.yaml`
48-
_and_ cabal file. To explain, let's take a quick detour to talk about snapshots
52+
Often you will have a project that defines only one local Cabal package that you
53+
are working on. If you need to specify an extra dependency, a source of
54+
confusion can be why you need to specify it both in the `stack.yaml` file _and_
55+
in the Cabal file. To explain, let's take a quick detour to talk about snapshots
4956
and how Stack resolves dependencies.
5057

5158
## Resolvers and snapshots
5259

53-
Stack follows a rule that says, for any projects, there is precisely 1 version
54-
of each package available. Obviously there are _many_ versions of many
55-
different packages available in the world. But when resolving a `stack.yaml`
56-
file, Stack requires that you have chosen a specific version for each package
57-
available.
60+
Stack follows a rule that says, for any projects, there is precisely one version
61+
of each package available. Obviously, for many packages there are _many_
62+
versions available in the world. But when resolving a `stack.yaml` file, Stack
63+
requires that you have chosen a specific version for each package available.
5864

5965
The most common means by which this set of packages is defined is via a
60-
Stackage Snapshot. For example, if you go to the page
61-
<https://www.stackage.org/lts-10.2>, you will see a list of 2,666 packages at
62-
specific version numbers. When you then specify `resolver: lts-10.2`, you're
66+
snapshot provided by Stackage. For example, if you go to the page
67+
<https://www.stackage.org/lts-19.17>, you will see a list of 2,910 packages at
68+
specific version numbers. When you then specify `resolver: lts-19.17`, you're
6369
telling Stack to use those package versions in resolving dependencies down to
64-
concrete version numbers.
70+
specific versions of packages.
6571

66-
Sometimes a snapshot doesn't have all of the packages you want. Or you want a
67-
different version. Or you want to work on a local modification of a package. In
68-
all of those cases, you can add more configuration data to your `stack.yaml` to
69-
override the values it received from your `resolver` setting. At the end of the
70-
day, each of your projects will end up with some way of resolving a package
71-
name into a concrete version number.
72+
Sometimes a snapshot doesn't have all of the packages that you want. Or you want
73+
a different version of a package. Or you want to work on a local modification of
74+
a package. In all of those cases, you can add more configuration data to your
75+
`stack.yaml` file to override the values it received from your `resolver`
76+
setting. At the end of the day, each of your projects will end up with some way
77+
of resolving a package name into a specific version of that package.
7278

73-
## Why specify deps twice?
79+
## Why specify dependencies twice?
7480

75-
When you add something like this to your `stack.yaml` file:
81+
The package `acme-missiles` is not included in any Stackage snapshots. When you
82+
add something like this to your `stack.yaml` file:
7683

77-
```yaml
84+
~~~yaml
7885
extra-deps:
7986
- acme-missiles-0.3
80-
```
87+
~~~
8188

82-
What you're saying to Stack is: if at any point you find that you need to build
83-
the `acme-missiles` package, please use version `0.3`. You are _not_ saying
89+
what you're saying to Stack is: "if at any point you find that you need to build
90+
the `acme-missiles` package, please use version `0.3`". You are _not_ saying
8491
"please build `acme-missiles` now." You are also not saying "my package depends
8592
on `acme-missiles`." You are simply making it available should the need arise.
8693

87-
When you add `build-depends: acme-missiles` to your cabal file or
88-
`dependencies: [acme-missiles]` to your `package.yaml` file, you're saying
89-
"this package requires that `acme-missiles` be available." Since
94+
When you add to your `package.yaml` file:
95+
96+
~~~yaml
97+
dependencies:
98+
- acme-missiles
99+
~~~
100+
101+
or, alternatively, you add directly to your Cabal file:
102+
103+
~~~yaml
104+
build-depends: acme-missiles
105+
~~~
106+
107+
you're saying "this package requires that `acme-missiles` be available." Since
90108
`acme-missiles` doesn't appear in your snapshot, without also modifying your
91109
`stack.yaml` to mention it via `extra-deps`, Stack will complain about the
92110
dependency being unavailable.
@@ -98,43 +116,45 @@ somehow, you'd lose reproducibility. How would Stack know which version to use?
98116
It may elect to use the newest version, but if a new version is available in
99117
the future, will it automatically switch to that?
100118

101-
Stack's baseline philosophy is that build plans are always reproducible\*. The
119+
Stack's core philosophy is that build plans are always reproducible. The
102120
purpose of the `stack.yaml` file is to define an immutable set of packages. No
103121
matter when in time you use it, and no matter how many new release happen in
104122
the interim, the build plan generated should be the same.
105123

106-
\* There's at least one hole in this theory today, which is Hackage revisions.
107-
When you specify `extra-deps: [acme-missiles-0.3]`, it doesn't specify which
108-
revision of the cabal file to use, and Stack will just choose the latest. Stack
109-
version 1.6 added the ability to specify exact revisions of cabal files, but
110-
this isn't enforced as a requirement as it's so different from the way most
111-
people work with packages.
124+
(There is, however, at least one hole in this theory today, which is Hackage
125+
revisions. When you specify `extra-deps: [acme-missiles-0.3]`, it doesn't
126+
specify which revision of the Cabal file to use, and Stack will just choose the
127+
latest. Stack has the ability to specify exact revisions of Cabal files, but
128+
this isn't enforced as a requirement, because it is so different from the way
129+
most people work with packages.)
112130

113131
And now, how about the other side: why doesn't Stack automatically add
114-
`acme-missiles` to `build-depends` in your cabal file if you add it as an
115-
extra-dep? There are a surprising number reasons actually:
132+
`acme-missiles` to `build-depends` in your Cabal file if you add it as an
133+
extra-dep? There are a surprising number reasons for this:
116134

117-
* The cabal spec doesn't support anything like that
135+
* The Cabal specification doesn't support anything like that
118136
* There can be multiple packages in a project, and how do we know which package
119137
actually needs the dependency?
120138
* There can be multiple components (libraries, executable, etc) in a package,
121139
and how do we know which of those actually needs the dependency?
122-
* The dependency may only be conditionally needed, based on flags, OS, or
123-
architecture. As an extreme example, we wouldn't want a Linux-only package to
124-
be force-built on Windows.
140+
* The dependency may only be conditionally needed, based on flags, operating
141+
system, or architecture. As an extreme example, we wouldn't want a Linux-only
142+
package to be built by force on Windows.
125143

126144
While for simple use cases it seems like automatically adding dependencies from
127-
the cabal file to the `stack.yaml` file or vice-versa would be a good thing, it
145+
the Cabal file to the `stack.yaml` file or vice-versa would be a good thing, it
128146
breaks down immediately for any semi-difficult case. Therefore, Stack requires
129147
you to add it to both places.
130148

131-
And a final note, in case it wasn't clear. The example I gave above used
149+
And a final note, in case it wasn't clear. The example above used
132150
`acme-missiles`, which is not in Stackage snapshots. If, however, you want to
133151
depend on a package already present in the snapshot you've selected, there's no
134152
need to add it explicitly to your `stack.yaml` file: it's already there
135153
implicitly via the `resolver` setting. This is what you do the majority of the
136154
time, such as when you add `vector` or `mtl` as a `build-depends` value.
137155

138-
## Should I check in generated cabal files?
156+
## Should I check-in automatically generated Cabal files?
139157

140-
Yes, you should. This recommendation was changed in [issue #5210](https://github.com/commercialhaskell/stack/issues/5210), please see the discussion there.
158+
Yes, you should. This recommendation was changed in
159+
[issue #5210](https://github.com/commercialhaskell/stack/issues/5210). Please
160+
see the discussion there.

doc/yaml_configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ you're not sure how, open an issue labeled "question".
3232

3333
If you wish to understand the difference between a `stack.yaml` files and a
3434
Cabal file (named `<package_name>.cabal`), see
35-
[stack.yaml vs cabal package file](stack_yaml_vs_cabal_package_file.md).
35+
[stack.yaml vs a Cabal file](stack_yaml_vs_cabal_package_file.md).
3636

3737
## Project-specific configuration
3838

mkdocs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pages:
2020
- User guide: GUIDE.md
2121
- FAQ: faq.md
2222
- Configuration (project and global): yaml_configuration.md
23-
- stack.yaml vs cabal package files: stack_yaml_vs_cabal_package_file.md
23+
- stack.yaml vs a Cabal file: stack_yaml_vs_cabal_package_file.md
2424
- Build command: build_command.md
2525
- Stack and Visual Studio Code: Stack_and_VS_Code.md
2626
- Developing on Windows: developing_on_windows.md

0 commit comments

Comments
 (0)