Quite frankly this is a strange claim; in what way is the native .cabal
format unfriendly? In fact, if anything I’d recommend against Stack’s “friendly” format; see e.g. [Haskell-community] Standard package file format
As for reproducible builds, this is not exclusive to Stack; it may surprise people, but Cabal supported “reproducible builds” since around Cabal 1.18 (released in 2013); it’s something you tend to need when you use Haskell professionally; and if you want to extend the reproducibility beyond the Haskell layer, augmenting Cabal with NixOS is currently the most principled solution I know of.
Moreover, I’d like to offer a more comprehensive answer to OP (taken from cabal.rst · GitHub):
The Cabal/Stack Disambiguation Guide
One of the most frequently asked Haskell beginner questions in recent
years is:
“Stack or cabal?”
I will helpfully not answer this question. Instead I will hope to
eliminate the confusion that many of the askers seem to have about the
various different things named “cabal” and how they relate to each other
and stack.
So, how many things named “cabal” do we have? We have:
-
CABAL (the spec)
CABAL is the Common Architecture for Building Applications &
Libraries. It’s a specification for defining how Haskell
applications and libraries should be built, defining dependencies,
etc.
-
.cabal
(the file format)
The file format used to write down the aforementioned definitions
for a specific package.
-
Cabal (the library)
The library implementing the above specification and file format.
-
cabal
(the executable)
The cabal
executable, more accurately named cabal-install
, is a
commandline tool that uses Cabal (the library) to resolve
dependencies from Hackage and build packages.
How does Stack relate to all this CABAL stuff?
Stack is a replacement for cabal-install
, i.e. the cabal
executable.
The stack
commandline tool, like cabal-install
is a tool that uses
Cabal (the library) to resolve dependencies and build packages. The main
difference between cabal-install
and stack
is how they resolve
dependencies.
So, what do cabal-install
and stack
do differently?
cabal-install
looks at the declared version ranges of a package in the
.cabal
file and using the available versions on Hackage it computes a
build plan satisfying the version constraints, then compiles using this
build plan.
stack
on the other hand uses “resolvers”. A resolver is a snapshot of
various package versions on Stackage and dependencies are resolved by
“just use the exact version specified by the resolver”.
It is possible to make stack
resolve things dynamically as
cabal-install
and vice versa, you can create snapshots (freeze files)
using cabal-install
to accomplish what stack
does.
So which tool should I use?
Honestly, at this point I don’t think there is much difference, use
whichever tool best fits your workflow. The only real strong opinion I
have is that you should avoid Stack’s (optional) use of hpack
at all
costs.
hpack
is a tool that generates .cabal
files from package.yaml
. In
the past there were some (in my personal opinion, weak) reasons for
using package.yaml
, but those are nowadays possible in .cabal
too.
package.yaml
does not support all CABAL features and requires all your
potential users to install extra tooling. The .cabal
format is
understood by both cabal-install
and stack
without extra tools, so
everyone can just use/contribute with their preferred tools.