1
0
mirror of https://git.FreeBSD.org/doc.git synced 2026-06-02 19:35:07 +00:00

Porter Handbook: Update documentation on porting Haskell programs.

Reviewed by: fernape, pauamma

Differential Revision: https://reviews.freebsd.org/D36090
This commit is contained in:
Gleb Popov
2022-08-09 16:09:26 +03:00
parent b4f6caf9a9
commit 08dd1185b4
2 changed files with 168 additions and 39 deletions
@@ -965,8 +965,8 @@ Refer to crossref:uses[uses-cabal,`cabal`] for a list of variables that can be s
.Creating a Port for a Hackage-hosted Haskell Application
[example]
====
When preparing a Haskell Cabal port, the package:devel/hs-cabal-install[] program is required, so make sure it is installed beforehand.
First we need to define common ports variables that allows cabal-install to fetch the package distribution file:
When preparing a Haskell Cabal port, package:devel/hs-cabal-install[] and package:ports-mgmt/hs-cabal2tuple[] programs are required, so make sure they are installed beforehand.
First we need to define common ports variables that allow cabal-install to fetch the package distribution file:
[.programlisting]
....
@@ -982,7 +982,7 @@ USES= cabal
.include <bsd.port.mk>
....
This minimal Makefile allows us to fetch the distribution file:
This minimal Makefile fetches the distribution file with the `cabal-extract` helper target:
[source,shell]
....
@@ -995,49 +995,34 @@ Downloaded ShellCheck-0.6.0
Unpacking to ShellCheck-0.6.0/
....
Now we have ShellCheck.cabal package description file, which allows us to fetch all package's dependencies, including transitive ones:
Now that we have ShellCheck.cabal package description file under `${WRKSRC}`, we can use `cabal-configure` to generate the build plan:
[source,shell]
....
% make cabal-extract-deps
% make cabal-configure
[...]
Resolving dependencies...
Downloading base-orphans-0.8.2
Downloaded base-orphans-0.8.2
Downloading primitive-0.7.0.0
Starting base-orphans-0.8.2 (lib)
Building base-orphans-0.8.2 (lib)
Downloaded primitive-0.7.0.0
Downloading dlist-0.8.0.7
Build profile: -w ghc-8.10.7 -O1
In order, the following would be built (use -v for more details):
- Diff-0.4.1 (lib) (requires download & build)
- OneTuple-0.3.1 (lib) (requires download & build)
[...]
....
As a side effect, the package's dependencies are also compiled, so the command may take some time.
Once done, a list of required dependencies can generated:
[source,shell]
....
% make make-use-cabal
USE_CABAL=QuickCheck-2.12.6.1 \
hashable-1.3.0.0 \
integer-logarithms-1.0.3 \
USE_CABAL= QuickCheck-2.12.6.1 \
hashable-1.3.0.0 \
integer-logarithms-1.0.3 \
[...]
....
Haskell packages may contain revisions, just like FreeBSD ports.
Revisions can affect only [.filename]#.cabal# files, but it is still important to pull them in.
To check `USE_CABAL` items for available revision updates, run following command:
[source,shell]
....
% make make-use-cabal-revs
USE_CABAL=QuickCheck-2.12.6.1_1 \
hashable-1.3.0.0 \
integer-logarithms-1.0.3_2 \
[...]
....
Note additional version numbers after `_` symbol.
Revisions can affect [.filename]#.cabal# files only.
Note additional version numbers after the `_` symbol.
Put newly generated `USE_CABAL` list instead of an old one.
Finally, [.filename]#distinfo# needs to be regenerated to contain all the distribution files:
@@ -1059,6 +1044,125 @@ The port is now ready for a test build and further adjustments like creating a p
If you are not testing your port in a clean environment like with Poudriere, remember to run `make clean` before any testing.
====
Some Haskell ports install various data files under `share/${PORTNAME}`. For such cases special handling is required on the port side.
The port should define the `CABAL_WRAPPER_SCRIPTS` knob listing each executable that is going to use data files. Moreover, in rare cases the program
being ported uses data files of other Haskell packages, in which case the `FOO_DATADIR_VARS` comes to the rescue.
[[cabal-ex2]]
.Handling Data Files in a Haskell Port
[example]
====
`devel/hs-profiteur` is a Haskell application that generates a single-page HTML with some content.
[.programlisting]
....
PORTNAME= profiteur
[...]
USES= cabal
USE_CABAL= OneTuple-0.3.1_2 \
QuickCheck-2.14.2 \
[...]
.include <bsd.port.mk>
....
It installs HTML templates under `share/profiteur`, so we need to add `CABAL_WRAPPER_SCRIPTS` knob:
[.programlisting]
....
[...]
USE_CABAL= OneTuple-0.3.1_2 \
QuickCheck-2.14.2 \
[...]
CABAL_WRAPPER_SCRIPTS= ${CABAL_EXECUTABLES}
.include <bsd.port.mk>
....
The program also tries to access the `jquery.js` file, which is a part of `js-jquery-3.3.1` Haskell package.
For that file to be found, we need to make the wrapper script to look for `js-jquery` data files in `share/profiteur` too.
We use `profiteur_DATADIR_VARS` for this:
[.programlisting]
....
[...]
CABAL_WRAPPER_SCRIPTS= ${CABAL_EXECUTABLES}
profiteur_DATADIR_VARS= js-jquery
.include <bsd.port.mk>
....
Now the port will install the actual binary into `libexec/cabal/profiteur` and the script into `bin/profiteur`.
====
There is no easy way to find out a proper value for the `FOO_DATADIR_VARS` knob apart from running the program and checking that everything works.
Luckily, the need to use `FOO_DATADIR_VARS` is very rare.
Another corner case when porting complex Haskell programs is the presence of VCS dependencies in the `cabal.project` file.
[[cabal-ex3]]
.Porting Haskell Applications with VCS Dependencies
[example]
====
`net-p2p/cardano-node` is an extremely complex piece of software. In its `cabal.project` there are a lot of blocks like this:
[.programlisting]
....
[...]
source-repository-package
type: git
location: https://github.com/input-output-hk/cardano-crypto
tag: f73079303f663e028288f9f4a9e08bcca39a923e
[...]
....
Dependencies of type `source-repository-package` are automatically pulled in by `cabal` during the build process.
Unfortunately, this makes use of the network after the `fetch` stage. This is disallowed by the ports framework.
These sources need to be listed in the port's Makefile. The `make-use-cabal` helper target can make it easy for packages hosted on GitHub.
Running this target after the usual `cabal-extract` and `cabal-configure` will produce not only the `USE_CABAL` knob, but also `GH_TUPLE`:
[source,shell]
....
% make make-use-cabal
USE_CABAL= Diff-0.4.1 \
Glob-0.10.2_3 \
HUnit-1.6.2.0 \
[...]
GH_TUPLE= input-output-hk:cardano-base:0f3a867493059e650cda69e20a5cbf1ace289a57:cardano_base/dist-newstyle/src/cardano-b_-c8db9876882556ed \
input-output-hk:cardano-crypto:f73079303f663e028288f9f4a9e08bcca39a923e:cardano_crypto/dist-newstyle/src/cardano-c_-253fd88117badd8f \
[...]
....
It might be useful to separate the `GH_TUPLE` items coming from `make-use-cabal` from the other ones to make it easy to update the port:
[.programlisting]
....
GH_TUPLE= input-output-hk:cardano-base:0f3a867493059e650cda69e20a5cbf1ace289a57:cardano_base/dist-newstyle/src/cardano-b_-c8db9876882556ed \
input-output-hk:cardano-crypto:f73079303f663e028288f9f4a9e08bcca39a923e:cardano_crypto/dist-newstyle/src/cardano-c_-253fd88117badd8f \
[...]
GH_TUPLE+= bitcoin-core:secp256k1:ac83be33d0956faf6b7f61a60ab524ef7d6a473a:secp
....
Haskell ports with VCS dependencies also require the following hack for the time being:
[.programlisting]
....
BINARY_ALIAS= git=true
....
====
[[using-autotools]]
== Using GNU Autotools
@@ -187,12 +187,15 @@ Uses package:devel/bison[] By default, with no arguments or with the `build` arg
Ports should not be created for Haskell libraries, see crossref:special[haskell-libs,Haskell Libraries] for more information.
====
Possible arguments: (none), `hpack`
Possible arguments: (none), `hpack`, `nodefault`
Sets default values and targets used to build Haskell software using Cabal.
A build dependency on the Haskell compiler port (GHC) is added.
If `hpack` argument is given, a build dependency on package:devel/hs-hpack[] is added and `hpack` is invoked at configuration step to generate.
cabal file.
A build dependency on the Haskell compiler port (package:lang/ghc[]) is added.
If there is some other version of GHC already listed in the `BUILD_DEPENDS` variable (for example, package:lang/ghc810[]), it would be used instead.
If the `hpack` argument is given, a build dependency on package:devel/hs-hpack[] is added and `hpack` is invoked at configuration step to
generate .cabal file.
If the `nodefault` argument is given, the framework will not try to pull the main distribution file from the Hackage.
This argument is implicitly added if `USE_GITHUB` or `USE_GITLAB` is present.
The framework provides the following variables:
@@ -200,32 +203,54 @@ The framework provides the following variables:
If the software uses Haskell dependencies, list them in this variable.
Each item should be present on Hackage and be listed in form `packagename-_0.1.2_`.
Dependencies can have revisions, which are specified after the `_` symbol.
Automatic generation of dependency list is supported, see crossref:special[using-cabal,Building Haskell Applications with `cabal`].
Automatic generation of the dependency list is supported, see crossref:special[using-cabal,Building Haskell Applications with `cabal`].
`CABAL_FLAGS`::
List of flags to be passed to `cabal-install` during the configuring and building stage.
The flags are passed verbatim.
This variable is usually used to enable or disable flags that are declared in the .cabal file.
Pass `foo` to enable the `foo` flag and `-foo` to disable it.
`EXECUTABLES`::
`CABAL_EXECUTABLES`::
List of executable files installed by the port.
Default value: `${PORTNAME}`.
Consult the .cabal file of the project being ported to get a list of possible
values for this variable. Each value corresponds to an `executable` stanza in the .cabal file.
Items from this list are automatically added to pkg-plist.
`SKIP_CABAL_PLIST`::
If defined, do not add items from `${EXECUTABLES}` to pkg-plist.
If defined, do not add items from `${CABAL_EXECUTABLES}` to pkg-plist.
`opt_USE_CABAL`::
Adds items to `${USE_CABAL}` depending on `opt` option.
`opt_EXECUTABLES`::
Adds items to `${EXECUTABLES}` depending on `opt` option.
`opt_CABAL_EXECUTABLES`::
Adds items to `${CABAL_EXECUTABLES}` depending on `opt` option.
`opt_CABAL_FLAGS`::
If `opt` is enabled, append the value to `${CABAL_FLAGS}`.
Otherwise, append `-value` to disable the flag.
Note that this behavior is slightly different from the plain `CABAL_FLAGS` as it does not accept values starting with `-`.
`CABAL_WRAPPER_SCRIPTS`::
A subset of `${CABAL_EXECUTABLES}` containing Haskell programs to be wrapped into a shell script
that sets `*_datadir` environment variables before running the program.
This also causes the actual Haskell binary to be installed under `libexec/cabal/` directory.
This knob is needed for Haskell programs that install their data files under `share/` directory.
`FOO_DATADIR_VARS`::
For an executable named `FOO` list Haskell packages, whose data files should be accessible by the executable.
List of extra Haskell packages, whose data files should be accessible by the executable named `FOO`.
The executable should be a part of `${CABAL_WRAPPER_SCRIPTS}`.
Haskell packages listed there should not have a version suffix.
`CABAL_PROJECT`::
Some Haskell projects may already have a `cabal.project` file, which is also generated by the ports framework.
If that is the case, use this variable to specify what to do with the original `cabal.project`.
Setting this variable to `remove` will cause the original file to be removed.
Setting this variable to `append` will:
. Move the original file to `cabal.project.${PORTNAME}` during the `extract` stage.
. Concatenate the original `cabal.project.${PORTNAME}` and the generated `cabal.project` into a single file after the `patch` stage.
Using `append` makes it possible to perform patching on the original file before it gets merged.
[[uses-cargo]]
== `cargo`