Skip to content

Commit 819effa

Browse files
committed
Add doc about making brew package with dune pkg
Signed-off-by: Stephen Sherratt <[email protected]>
1 parent 605f300 commit 819effa

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

doc/howto/homebrew-package.rst

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
How to make a Homebrew Package with Dune
2+
========================================
3+
4+
This guide will show you how to make a Homebrew package for an application
5+
using Dune package management. The only dependency of the Homebrew package will
6+
be Dune, and all OCaml dependencies (including the OCaml compiler) will be
7+
installed by Dune while building the Homebrew package.
8+
9+
To use Dune package management to build a project as a Homebrew package, the
10+
project must have a source archive hosted online somewhere (e.g. a gzipped
11+
tarball on the project's Github release page).
12+
13+
Before making a Homebrew package, it's a good idea to familiarize yourself with
14+
Homebrew's terminology and packaging conventions `here
15+
<https://docs.brew.sh/Adding-Software-to-Homebrew>`__.
16+
17+
Homebrew packages are recommended to be source-based, and for the source code
18+
to be explicitly versioned, so for this example assume ``my_app`` has a
19+
versioned archive hosted on Github with version ``0.1.0``.
20+
21+
Homebrew can generate a starting point for a formula if you point it at a
22+
source archive hosted on Github:
23+
24+
.. code:: console
25+
26+
$ brew create https://github.com/me/my_app/archive/refs/tags/0.1.0.tar.gz
27+
28+
A source archive like the one in the above command is generated when you
29+
release a project on Github. The above command will generate a file named
30+
``my_app.rb`` in your current tap. All the project metadata will be filled in
31+
automatically based on the project on Github. All we need to do now is to
32+
specify dependencies and the commands ``brew`` should run when installing the
33+
package.
34+
35+
Here's the complete formula for ``my_app``. Note that the ``test`` section is
36+
intended to be a sanity check of the core functionality of the package, not a
37+
complete integration test suite. Read more about Homebrew package tests `here
38+
<https://docs.brew.sh/Formula-Cookbook#add-a-test-to-the-formula>`__. Note
39+
however that tests run in an environment without access to build dependencies
40+
such as Dune, so ``dune runtest`` can't be used to test Homebrew packages.
41+
42+
.. code:: ruby
43+
44+
class MyApp < Formula
45+
desc "My awesome app"
46+
homepage "https://github.com/me/my_app"
47+
url "https://github.com/me/my_app/releases/download/0.1.0/0.1.0.tar.gz"
48+
sha256 "eb8705de406441675747a639351d0d59bffe7b9f5b05ec9b6e11b4c4c9d7a6ee"
49+
license "MIT"
50+
51+
depends_on "dune" => :build
52+
53+
def install
54+
system "dune", "pkg", "lock"
55+
system "dune", "build", "@install", "--release", "--only-packages", "my_app"
56+
system "dune", "install", "--prefix=#{prefix}", "my_app"
57+
end
58+
59+
test do
60+
# Test your application here!
61+
system "my_app", "--version"
62+
end
63+
end
64+
65+
This assumes that the name of the package in the source archive is ``my_app``.
66+
That is, the archive contains a ``dune-project`` file defining a package named
67+
``my_app``, or that the archive contains a ``my_app.opam``. The archive may
68+
contain multiple packages provided that ``my_app`` is one of them.
69+
70+
Note the first install command: ``dune pkg lock``. This is only necessary if
71+
the source archive doesn't contain a lockdir (a ``dune.lock`` directory
72+
containing the transitive dependency closure of the package). Running ``dune
73+
pkg lock`` invokes Dune's dependency solver resolving the dependencies in
74+
``dune-project`` or ``my_app.opam`` against the current tip of the `Opam
75+
Repository <https://github.com/ocaml/opam-repository>`_. Solving dependencies
76+
while installing a Homebrew package means that the exact versions of
77+
dependencies may be different each time the Homebrew package is installed. For
78+
this reason it's advised to use source archives which already contain a
79+
lockdir, and omit the ``dune pkg lock`` command when packaging a Dune project
80+
for Homebrew. However in some situations solving dependencies at install time
81+
is unavoidable, such as when packaging a project whose source archive is
82+
already released and lacks a lockdir.
83+
84+
If there are any packages with external dependencies (i.e. ``depexts``) in
85+
``my_app``'s transitive dependency closure, their corresponding Homebrew
86+
package must be added as a dependency of ``my_app``'s Homebrew packages by
87+
adding a ``depends_on`` entry for each. List all the external dependencies
88+
among ``my_app``'s transitive dependency closure by running:
89+
90+
.. code:: console
91+
92+
$ dune show depexts
93+
94+
External dependencies can be platform-specific, so if you're planning to make the
95+
Homebrew package available for macOS, be sure to run the above command on a Mac
96+
to determine which external dependencies need to be added to the formula.

doc/howto/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ These guides will help you use Dune's features in your project.
2323
toplevel
2424
rule-generation
2525
override-default-entrypoint
26+
homebrew-package

0 commit comments

Comments
 (0)