Haskell ebuild maintaining tips
*******************************
Check `Gentoo devmanual `_ for general
guidance on ebuild writing. This doc is about haskell-specific aspects of it.
Slot operator dependencies
==========================
Haskell packages use slot operator dependencies: `dev-haskell/foo:=`
(or `dev-haskell/foo:${slotname}=` to force rebuild of a package every
time `dev-haskell/foo` updates. It requires `EAPI=5` and upper.
The rebuild is needed as GHC haskell ABI is very precise(or fragile :):
package changes ABI every time package's version, interface hashes
(`.hi` files) or dependency packages change.
The `:=` is not enough to make sure system does not get into a broken state.
Consider an example: user has 3 packages installed depending on one another:
.. code-block::
darcs:RDEPEND="text:=" SLOT=0/${PV}
text:RDEPEND="binary:=" SLOT=0/${PV}
binary:RDEPEND="" SLOT=0/${PV}
Suppose binary will get an update: `binary-0` -> `binary-1`. That
will trigger a subslot rebuild for `text`. As a result ABI will be
changed for packages `binary` and `text`. `text` package won't change
it's subslot as there was no new `text` ebuild. Thus `darcs` package
will be left in broken state.
There is no easy fix for it. We need something that transitively
can flag ABI as changed: `feature request `_.
Upper bounds
============
Haskell upstreams usually adhere to `Package versioning policy `_
and guard upper bounds of used dependencies in their packages.
.. code-block:: haskell
-- somewhere in cheapskate.cabal
library
hs-source-dirs: .
build-depends: base >=4.4 && <5,
containers >=0.4 && <0.6,
mtl >=2.1 && <2.3,
text >= 0.9 && < 1.3,
blaze-html >=0.6 && < 0.10,
xss-sanitize >= 0.3 && < 0.4,
data-default >= 0.5 && < 0.7,
That means once you have added (say) `data-default-0.7` to the tree
those package will not be able to use it and will try to keep
older version installed for users of `cheapskate`.
It causes portage show warnings during upgrade at best and cryptic
slot conflicts at worst:
.. code-block::
!!! Multiple package instances within a single package slot have been pulled
!!! into the dependency graph, resulting in a slot conflict:
dev-haskell/data-default:0
(dev-haskell/data-default-0.7.0:0/0.7.0::haskell, ebuild scheduled for merge) pulled in by
>=dev-haskell/data-default-0.6.0:=[profile?] required by (dev-haskell/bcrypt-0.0.9:0/0.0.9::haskell, ebuild scheduled for merge)
^^ ^^^^^
(dev-haskell/data-default-0.5.3:0/0.5.3::haskell, installed) pulled in by
dev-haskell/data-default:0/0.5.3=[profile] required by (dev-haskell/gravatar-0.8.0:0/0.8.0::haskell, installed)
^^^^^^^^^
dev-haskell/data-default:0/0.5.3=[profile] required by (dev-haskell/keter-1.4.3.1-r1:0/1.4.3.1::haskell, installed)
^^^^^^^^^
= 0.5 && < 0.7' 'data-default >= 0.5'
}
Don't forget to revbump an ebuild after you change RDEPENDs.
Otherwise package manager will not try to update installed package
and will keep old upper bound.
.. code-block:: bash
$ git mv cheapskate-0.1.0.5.ebuild cheapskate-0.1.0.5-r1.ebuild
Validating upper bounds are consistent
======================================
When you add major version of a package (like the
``dev-haskell/data-default-0.7`` example above) chances are high that
quite a few ebulds in overlay still rely on older version and still
contain `` **network-3.0**).
It is tempting to put each incompatible library into it's own **SLOT**
(say, SLOT="2.8/${PV}" and SLOT="3.0/${PV}") and allow libraries to be
installed in parallel.
Unfortunately it usually does not work. The problem with
slotting is that each reverse dependency could only be
built against one of slots available at the same time
(not both at the same time).
Diamond-style dependencies can't be satisfied if different branches
of dependencies use different slots.
Example build failure on **recaptcha** package:
Warning:
This package indirectly depends on multiple versions of the same package. This is very likely to cause a compile failure.
package HTTP (HTTP-4000.3.14-AEcNM29soen35eXUQLVKbP) requires network-2.5.0.0-29nVNbJNyFb6jv23r63a7a
package recaptcha (recaptcha-0.1.0.4) requires network-3.0.1.1-Cv4xwaYSk3qLs0kTRkld1f
Network/Captcha/ReCaptcha.hs:74:31: error:
• Couldn't match expected type ‘network-2.5.0.0:Network.URI.URI’
with actual type ‘URI’
NB: ‘URI’
is defined in ‘Network.URI’ in package ‘network-uri-2.6.3.0’
‘network-2.5.0.0:Network.URI.URI’
is defined in ‘Network.URI’ in package ‘network-2.5.0.0’
Note: here **Network.URI.URI** type is not consistent across different
packages it comes from and type checker can't resolve them.
The only sure way to avoid this kind of library mix is to install only
one version of any library at a time. For API breaking changes is usually
involves a bit of upstream porting work to a new version.
Note: **cabal install** does not usually encounter this problem as it
rebuilds every dependency anew each time something changes in the dependency
graph.