<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>packaging &amp;mdash; Jerry of the Week</title>
    <link>https://write.in0rdr.ch/tag:packaging</link>
    <description>ˈdʒɛri - Individual who sends life against the grain no matter the consequences</description>
    <pubDate>Fri, 24 Apr 2026 00:02:42 +0000</pubDate>
    <item>
      <title>Building Haskell projects for Nix</title>
      <link>https://write.in0rdr.ch/building-haskell-projects-for-nix</link>
      <description>&lt;![CDATA[Similar to the last post on building a C project, today I quickly cover how to build a Haskell project.&#xA;&#xA;You might ask why? I got asked about that stuff by my friendly office colleague Samuel. By the way, without him I would have never installed/used Nixos in the first place. Good fella, go checkout his blog.&#xA;&#xA;#packaging #coding #nix #haskell&#xA;!--more--&#xA;&#xA;The goal was to package oama. Oama helps you to renew OAuth2 tokens from the command line. To be honest, I haven&#39;t checked the details on how it works yet, I was only interested in packaging it for Nix.&#xA;&#xA;I was reading a bit on how it can be used with my favorite msmtp client.&#xA;&#xA;Then I read some of the Nix documentation on how to build and use Haskell packages. They describe how to quickly bootstrap development environments (i.e., a Nix shell) using the handy cabal2nix utility.&#xA;&#xA;The first step for packaging was also to convert the cabal description of the package into a valid Nix expression which already proved useful for development purposes.&#xA;&#xA;git clone https://github.com/pdobsan/oama.git oama.git&#xA;cd oama.git&#xA;cabal2nix .   oama.nix&#xA;&#xA;Create default.nix:&#xA;Retrieve nixpkgs impurely from NIXPATH for now, you can pin it instead, of course.&#xA;{ pkgs ? import nixpkgs {} }:&#xA;&#xA;use the nixpkgs default haskell package set&#xA;pkgs.haskellPackages.callPackage ./oama.nix { }&#xA;&#xA;If you have a look at oama.nix it contains a lot of references to Haskell packages (.e.g, haskellPackages.aeson). The callPackage takes care of the name resolution in this case. haskellPackages.mkDerivation is a wrapper around stdenv.mkDerivation (see last post building a C project), but works without the standard Haskell build tool cabal-install.&#xA;&#xA;To build oama and quickly run it in a shell:&#xA;nix-shell -p cabal-install&#xA;nix-build default.nix&#xA;./result/bin/oama&#xA;&#xA;I did not look further into shellFor at this point, because I was interested in creating a Nix package that I can install globally.&#xA;&#xA;For this, I took the &#34;stdenv template&#34; from the last post) and merged 😻 it with the oama.nix output from cabal2nix. The result:&#xA;&#xA;let&#xA;  pkgs = import nixpkgs { };&#xA;  hpkgs = pkgs.haskellPackages;&#xA;in&#xA;  hpkgs.mkDerivation {&#xA;    pname = &#34;oama&#34;;&#xA;    version = &#34;0.10.1&#34;;&#xA;    src = pkgs.fetchgit {&#xA;      url = &#34;https://github.com/pdobsan/oama.git&#34;;&#xA;      rev = &#34;refs/tags/0.10.1&#34;;&#xA;      hash = &#34;sha256-mQBlCrF9rvFOfSOxhMi6JUKDJocFmO4Hhc3Zy7AqiXk=&#34;;&#xA;    };&#xA;&#xA;    isLibrary = true;&#xA;    isExecutable = true;&#xA;    libraryHaskellDepends = with hpkgs; [&#xA;      aeson base bytestring containers directory hsyslog http-conduit&#xA;      network-uri optparse-applicative pretty-simple process string-qq&#xA;      strings text time twain unix utf8-string warp yaml&#xA;    ];&#xA;    executableHaskellDepends = with hpkgs; [&#xA;      aeson base bytestring containers directory hsyslog http-conduit&#xA;      network-uri optparse-applicative pretty-simple process string-qq&#xA;      strings text time twain unix utf8-string warp yaml&#xA;    ];&#xA;&#xA;    mainProgram = &#34;oama&#34;;&#xA;    license = pkgs.lib.licenses.bsd3;&#xA;  }&#xA;&#xA;Essentially, I only had to use nix-prefetch-git to get the shasum of the git revision and make sure I use the pkgs and hpkgs (reference to pkgs.haskellPackages) correctly in the right places.&#xA;&#xA;Afterwards, again, building and installing oama globally was a peace of cake 🧁:&#xA;&#xA;nix-build oama.nix&#xA;nix-env -i -f oama.nix&#xA;&#xA;Now I only have to figure out what to do with this tool 🤔 but this is left for another post.&#xA;&#xA;div style=&#34;text-align:center; font-size: 0.8em&#34;&#xD;&#xA;a href=&#34;https://write.in0rdr.ch/feed&#34;&amp;#128732; RSS/a | a href=&#34;https://m.in0rdr.ch/in0rdr&#34;&amp;#128024; Fediverse/a | a href=&#34;https://chat.in0rdr.ch/#/guest?join=p0c@conference.in0rdr.ch&#34;&amp;#128172; XMPP/a&#xD;&#xA;/div]]&gt;</description>
      <content:encoded><![CDATA[<p>Similar to the last post on <a href="https://write.in0rdr.ch/building-and-installing-a-c-project-with-nix">building a C project</a>, today I quickly cover how to build a Haskell project.</p>

<p>You might ask why? I got asked about that stuff by my friendly office colleague Samuel. By the way, without him I would have never installed/used Nixos in the first place. Good fella, go checkout his <a href="https://blog.yosemitesam.ch">blog</a>.</p>

<p><a href="https://write.in0rdr.ch/tag:packaging" class="hashtag"><span>#</span><span class="p-category">packaging</span></a> <a href="https://write.in0rdr.ch/tag:coding" class="hashtag"><span>#</span><span class="p-category">coding</span></a> <a href="https://write.in0rdr.ch/tag:nix" class="hashtag"><span>#</span><span class="p-category">nix</span></a> <a href="https://write.in0rdr.ch/tag:haskell" class="hashtag"><span>#</span><span class="p-category">haskell</span></a>
</p>

<p>The goal was to package <a href="https://github.com/pdobsan/oama"><code>oama</code></a>. Oama helps you to renew OAuth2 tokens from the command line. To be honest, I haven&#39;t checked the details on how it works yet, I was only interested in packaging it for Nix.</p>

<p>I was reading a bit on <a href="https://wiki.archlinux.org/title/msmtp#OAuth2_Setup">how it can be used with my favorite <code>msmtp</code> client</a>.</p>

<p>Then I read some of the <a href="https://nixos.org/manual/nixpkgs/stable/#haskell">Nix documentation on how to build and use Haskell packages</a>. They describe how to quickly bootstrap development environments (i.e., a Nix shell) using the handy <a href="https://hackage.haskell.org/package/cabal2nix#readme"><code>cabal2nix</code> utility</a>.</p>

<p>The first step for packaging was also to convert the <code>cabal</code> description of the package into a valid Nix expression which already proved useful for development purposes.</p>

<pre><code class="language-bash">git clone https://github.com/pdobsan/oama.git oama.git
cd oama.git
cabal2nix . &gt; oama.nix
</code></pre>

<p>Create <code>default.nix</code>:</p>

<pre><code># Retrieve nixpkgs impurely from NIX_PATH for now, you can pin it instead, of course.
{ pkgs ? import &lt;nixpkgs&gt; {} }:

# use the nixpkgs default haskell package set
pkgs.haskellPackages.callPackage ./oama.nix { }
</code></pre>

<p>If you have a look at <code>oama.nix</code> it contains a lot of references to Haskell packages (.e.g, <a href="https://search.nixos.org/packages?channel=23.11&amp;show=haskellPackages.aeson"><code>haskellPackages.aeson</code></a>). The <code>callPackage</code> takes care of the name resolution in this case. <code>haskellPackages.mkDerivation</code> is a wrapper around <code>stdenv.mkDerivation</code> (see last post <a href="https://write.in0rdr.ch/building-and-installing-a-c-project-with-nix">building a C project</a>), but works without the standard Haskell build tool <code>cabal-install</code>.</p>

<p>To build <code>oama</code> and quickly run it in a shell:</p>

<pre><code class="language-bash">nix-shell -p cabal-install
nix-build default.nix
./result/bin/oama
</code></pre>

<p>I did not look further into <code>shellFor</code> at this point, because I was interested in creating a Nix package that I can install globally.</p>

<p>For this, I took the “stdenv template” from the last post and merged 😻 it with the <code>oama.nix</code> output from <code>cabal2nix</code>. The result:</p>

<pre><code class="language-nix">let
  pkgs = import &lt;nixpkgs&gt; { };
  hpkgs = pkgs.haskellPackages;
in
  hpkgs.mkDerivation {
    pname = &#34;oama&#34;;
    version = &#34;0.10.1&#34;;
    src = pkgs.fetchgit {
      url = &#34;https://github.com/pdobsan/oama.git&#34;;
      rev = &#34;refs/tags/0.10.1&#34;;
      hash = &#34;sha256-mQBlCrF9rvFOfSOxhMi6JUKDJocFmO4Hhc3Zy7AqiXk=&#34;;
    };

    isLibrary = true;
    isExecutable = true;
    libraryHaskellDepends = with hpkgs; [
      aeson base bytestring containers directory hsyslog http-conduit
      network-uri optparse-applicative pretty-simple process string-qq
      strings text time twain unix utf8-string warp yaml
    ];
    executableHaskellDepends = with hpkgs; [
      aeson base bytestring containers directory hsyslog http-conduit
      network-uri optparse-applicative pretty-simple process string-qq
      strings text time twain unix utf8-string warp yaml
    ];

    mainProgram = &#34;oama&#34;;
    license = pkgs.lib.licenses.bsd3;
  }
</code></pre>

<p>Essentially, I only had to use <code>nix-prefetch-git</code> to get the shasum of the git revision and make sure I use the <code>pkgs</code> and <code>hpkgs</code> (reference to <code>pkgs.haskellPackages</code>) correctly in the right places.</p>

<p>Afterwards, again, building and installing <code>oama</code> globally was a peace of cake 🧁:</p>

<pre><code class="language-bash">nix-build oama.nix
nix-env -i -f oama.nix
</code></pre>

<p>Now I only have to figure out what to do with this tool 🤔 but this is left for another post.</p>

<div style="text-align:center; font-size: 0.8em">
<a href="https://write.in0rdr.ch/feed">🛜 RSS</a> | <a href="https://m.in0rdr.ch/in0rdr">🐘 Fediverse</a> | <a href="https://chat.in0rdr.ch/#/guest?join=p0c@conference.in0rdr.ch">💬 XMPP</a>
</div>
]]></content:encoded>
      <guid>https://write.in0rdr.ch/building-haskell-projects-for-nix</guid>
      <pubDate>Fri, 17 May 2024 17:50:48 +0000</pubDate>
    </item>
    <item>
      <title>Building and installing a C project with Nix</title>
      <link>https://write.in0rdr.ch/building-and-installing-a-c-project-with-nix</link>
      <description>&lt;![CDATA[Today I learned how to build and install a simple C project on Nix(OS).&#xA;&#xA;After some reading on the Internet 📚, I finally understood the basics of building and installing a package from C sources using a Nix expression file (the .nix file in the following examples).&#xA;&#xA;#packaging #coding #nix #diary #c&#xA;&#xA;!--more--&#xA;&#xA;The expression file uses the standard build environment 🧰. Essentially, this environment abstracts the traditional Makefile based build proces (i.e., make &amp;&amp; make install).&#xA;&#xA;For learning purposes, I decided to package my hobby project, the text-based journaling program diary 📓.&#xA;&#xA;Writing the Nix expression file&#xA;&#xA;I built the expression file based on a an example from the Nix book.&#xA;&#xA;The Nix expression file diary.nix to install the stable version of the diary program fetches the source by tag from the Git repository:&#xA;&#xA;let&#xA;  pkgs = import nixpkgs { };&#xA;in&#xA;  pkgs.stdenv.mkDerivation {&#xA;    name = &#34;diary&#34;;&#xA;    version = &#34;v0.10&#34;;&#xA;    buildInputs = with pkgs; [&#xA;      ncurses&#xA;      curlFull&#xA;      lttng-ust&#xA;    ];&#xA;&#xA;    src = pkgs.fetchgit {&#xA;      url = &#34;https://git.in0rdr.ch/diary.git&#34;;&#xA;      rev = &#34;refs/tags/v0.10&#34;;&#xA;      hash = &#34;sha256-jDPfqUjf0ZETYqPxvEJ2/YFFjNsF7yvVQiThc5yMvjc=&#34;;&#xA;    };&#xA;&#xA;    installPhase = &#39;&#39;&#xA;      install -d $out/bin&#xA;      install -d $out/share/man/man1&#xA;      install -m755 diary $out/bin/&#xA;      install -m644 man1/diary.1 $out/share/man/man1/&#xA;    &#39;&#39;;&#xA;  }&#xA;&#xA;The mkDerivation call does most of the work. There we define the package name and version, as well all of the dependencies required to build the project. In this case, the diary program depends on the curl and ncurses libraries as well as the lttng tracing library.&#xA;&#xA;The source code src can be fetched conveniently from Git (using the fetchgit &#34;builder&#34;) or from other remote sources (see related &#34;fetch&#34; builtin functions).&#xA;&#xA;To build a nightly release from the master branch, I only had to slightly tune the src of the unstable Nix expression:&#xA;&#xA;    src = pkgs.fetchgit {&#xA;      url = &#34;https://git.in0rdr.ch/diary.git&#34;;&#xA;      hash = &#34;sha256-laKIVxfqJqBkB2d0F8tOOnpAXXRzHFfpjhAzZT8MX8k=&#34;;&#xA;    };&#xA;&#xA;The sha256 hash can be obtained using nix-prefetch-git:&#xA;&#xA;get hash for the specific tag/release&#xA;nix-prefetch-git https://git.in0rdr.ch/diary.git --rev refs/tags/v0.10&#xA;&#xA;get hash for latest nightly build from master branch&#xA;nix-prefetch-git https://git.in0rdr.ch/diary.git&#xA;&#xA;Finally, the installPhase needed a bit of tuning and has a small difference to what is commonly used in a Makefile on a traditional Linux distribution. But that was not too hard either, I simply had to translate my install target from the already existing Makefile.&#xA;&#xA;The  install target:&#xA;install: $(TARGET)&#xA;        install -m755 $(TARGET) $(BINDIR)/$(TARGET)&#xA;        install -d $(MANDIR)/man1&#xA;        install -m644 $(MAN1) $(MANDIR)/$(MAN1)&#xA;&#xA;The corresponding Nix installPhase:&#xA;      install -d $out/bin&#xA;      install -d $out/share/man/man1&#xA;      install -m755 diary $out/bin/&#xA;      install -m644 man1/diary.1 $out/share/man/man1/&#xA;&#xA;Very similar indeed. One point to note here is that the fixup phase will automatically install the man pages to the correct location.&#xA;&#xA;Building and installing the C project&#xA;&#xA;Once the expression file is written, building and installing the program is a peace of cake 🍰:&#xA;&#xA;Build stable package&#xA;nix-build nix/diary.nix&#xA;&#xA;Build latest nightly version&#xA;nix-build nix/diary-unstable.nix&#xA;&#xA;To install the package from the expression file to the user environment:&#xA;Install stable package&#xA;nix-env -i -f nix/diary.nix&#xA;&#xA;Install latest nightly version&#xA;nix-env -i -f nix/diary-unstable.nix&#xA;&#xA;You can even verify the location of the man page by using manpath -q or query the installed package with nix-env -q.&#xA;&#xA;Next steps&#xA;&#xA;Now that we have drafted the basic expression file, we might also add it to the nixpkgs repository on GitHub. I haven&#39;t checked the contributor requirements in detail yet.&#xA;&#xA;div style=&#34;text-align:center; font-size: 0.8em&#34;&#xD;&#xA;a href=&#34;https://write.in0rdr.ch/feed&#34;&amp;#128732; RSS/a | a href=&#34;https://m.in0rdr.ch/in0rdr&#34;&amp;#128024; Fediverse/a | a href=&#34;https://chat.in0rdr.ch/#/guest?join=p0c@conference.in0rdr.ch&#34;&amp;#128172; XMPP/a&#xD;&#xA;/div]]&gt;</description>
      <content:encoded><![CDATA[<p>Today I learned how to build and install a simple C project on Nix(OS).</p>

<p>After some reading on the Internet 📚, I finally understood the basics of building and installing a package from C sources using a Nix expression file (the <code>.nix</code> file in the following examples).</p>

<p><a href="https://write.in0rdr.ch/tag:packaging" class="hashtag"><span>#</span><span class="p-category">packaging</span></a> <a href="https://write.in0rdr.ch/tag:coding" class="hashtag"><span>#</span><span class="p-category">coding</span></a> <a href="https://write.in0rdr.ch/tag:nix" class="hashtag"><span>#</span><span class="p-category">nix</span></a> <a href="https://write.in0rdr.ch/tag:diary" class="hashtag"><span>#</span><span class="p-category">diary</span></a> <a href="https://write.in0rdr.ch/tag:c" class="hashtag"><span>#</span><span class="p-category">c</span></a></p>



<p>The expression file uses the <strong><a href="https://nixos.org/manual/nixpkgs/stable/#part-stdenv">standard build environment</a></strong> 🧰. Essentially, this environment abstracts the traditional <code>Makefile</code> based build proces (i.e., <code>make &amp;&amp; make install</code>).</p>

<p>For learning purposes, I decided to package my hobby project, the <a href="https://diary.p0c.ch">text-based journaling program <code>diary</code></a> 📓.</p>

<h2 id="writing-the-nix-expression-file">Writing the Nix expression file</h2>

<p>I built the expression file based on a an <strong><a href="https://book.divnix.com/ch06-01-simple-c-program.html">example from the Nix book</a></strong>.</p>

<p>The Nix expression file <a href="https://code.in0rdr.ch/diary/file/nix/diary.nix.html"><code>diary.nix</code></a> to install the stable version of the <code>diary</code> program fetches the source by tag from the Git repository:</p>

<pre><code class="language-nix">let
  pkgs = import &lt;nixpkgs&gt; { };
in
  pkgs.stdenv.mkDerivation {
    name = &#34;diary&#34;;
    version = &#34;v0.10&#34;;
    buildInputs = with pkgs; [
      ncurses
      curlFull
      lttng-ust
    ];

    src = pkgs.fetchgit {
      url = &#34;https://git.in0rdr.ch/diary.git&#34;;
      rev = &#34;refs/tags/v0.10&#34;;
      hash = &#34;sha256-jDPfqUjf0ZETYqPxvEJ2/YFFjNsF7yvVQiThc5yMvjc=&#34;;
    };

    installPhase = &#39;&#39;
      install -d $out/bin
      install -d $out/share/man/man1
      install -m755 diary $out/bin/
      install -m644 man1/diary.1 $out/share/man/man1/
    &#39;&#39;;
  }
</code></pre>

<p>The <code>mkDerivation</code> call does most of the work. There we define the package <code>name</code> and <code>version</code>, as well all of the dependencies required to build the project. In this case, the <code>diary</code> program depends on the <code>curl</code> and <code>ncurses</code> libraries as well as the <code>lttng</code> tracing library.</p>

<p>The source code <code>src</code> can be fetched conveniently from Git (using the <a href="https://nixos.org/manual/nix/stable/language/builtins.html#builtins-fetchGit"><code>fetchgit</code> “builder”</a>) or from other remote sources (see related <a href="https://nixos.org/manual/nix/stable/language/builtins.html">“fetch” builtin functions</a>).</p>

<p>To build a nightly release from the master branch, I only had to slightly tune the <code>src</code> of the <a href="https://code.in0rdr.ch/diary/file/nix/diary-unstable.nix.html">unstable Nix expression</a>:</p>

<pre><code class="language-nix">    src = pkgs.fetchgit {
      url = &#34;https://git.in0rdr.ch/diary.git&#34;;
      hash = &#34;sha256-laKIVxfqJqBkB2d0F8tOOnpAXXRzHFfpjhAzZT8MX8k=&#34;;
    };
</code></pre>

<p>The sha256 hash can be obtained using <a href="https://search.nixos.org/packages?channel=23.11&amp;show=nix-prefetch-git"><code>nix-prefetch-git</code></a>:</p>

<pre><code class="language-bash"># get hash for the specific tag/release
nix-prefetch-git https://git.in0rdr.ch/diary.git --rev refs/tags/v0.10

# get hash for latest nightly build from master branch
nix-prefetch-git https://git.in0rdr.ch/diary.git
</code></pre>

<p>Finally, the <a href="https://nixos.org/manual/nixpkgs/stable/#ssec-install-phase"><code>installPhase</code></a> needed a bit of tuning and has a small difference to what is commonly used in a <code>Makefile</code> on a traditional Linux distribution. But that was not too hard either, I simply had to translate my <code>install</code> target from the <a href="https://code.in0rdr.ch/diary/file/Makefile.html">already existing <code>Makefile</code></a>.</p>

<p>The  <code>install</code> target:</p>

<pre><code class="language-Makefile">install: $(TARGET)
        install -m755 $(TARGET) $(BINDIR)/$(TARGET)
        install -d $(MANDIR)/man1
        install -m644 $(MAN1) $(MANDIR)/$(MAN1)
</code></pre>

<p>The corresponding Nix <code>installPhase</code>:</p>

<pre><code class="language-nix">      install -d $out/bin
      install -d $out/share/man/man1
      install -m755 diary $out/bin/
      install -m644 man1/diary.1 $out/share/man/man1/
</code></pre>

<p>Very similar indeed. One point to note here is that the <a href="https://nixos.org/manual/nixpkgs/stable/#ssec-fixup-phase"><code>fixup</code> phase</a> will automatically install the man pages to the correct location.</p>

<h2 id="building-and-installing-the-c-project">Building and installing the C project</h2>

<p>Once the expression file is written, <a href="https://code.in0rdr.ch/diary/file/docs/NIX.md.html">building and installing</a> the program is a peace of cake 🍰:</p>

<pre><code class="language-bash"># Build stable package
nix-build nix/diary.nix

# Build latest nightly version
nix-build nix/diary-unstable.nix
</code></pre>

<p>To install the package from the expression file to the user environment:</p>

<pre><code class="language-bash"># Install stable package
nix-env -i -f nix/diary.nix

# Install latest nightly version
nix-env -i -f nix/diary-unstable.nix
</code></pre>

<p>You can even verify the location of the man page by using <code>manpath -q</code> or query the installed package with <code>nix-env -q</code>.</p>

<h2 id="next-steps">Next steps</h2>

<p>Now that we have drafted the basic expression file, we might also add it to the <code>nixpkgs</code> repository on GitHub. I haven&#39;t checked the <a href="https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md">contributor requirements</a> in detail yet.</p>

<div style="text-align:center; font-size: 0.8em">
<a href="https://write.in0rdr.ch/feed">🛜 RSS</a> | <a href="https://m.in0rdr.ch/in0rdr">🐘 Fediverse</a> | <a href="https://chat.in0rdr.ch/#/guest?join=p0c@conference.in0rdr.ch">💬 XMPP</a>
</div>
]]></content:encoded>
      <guid>https://write.in0rdr.ch/building-and-installing-a-c-project-with-nix</guid>
      <pubDate>Mon, 15 Apr 2024 18:20:17 +0000</pubDate>
    </item>
  </channel>
</rss>