OCaml example project using flakes

I’ve been recently been plaing around with Nix my new Macbook Pro, and have been interested in experimenting with OCaml. As part of this I’ve made an over-engineered Hello World example project, demonstrating how to set up OCaml with Nix flakes and Dune. I’ve got no idea of it’s useful to anybody, but I thought I’d publish it in the off-chance it is.

Let me know if I’ve done anything particularly silly, or if I’m missing anything in the documentation that might be worth mentioning. I’m neither an expert in Nix, nor an expert in OCaml or Dune, so this is very likely! It’s released under MIT-0 so feel free to do whatever you want with it. :slight_smile:

5 Likes

this repo is amazing! And I’m learning so much just from reading the file! So thank-you so much for writing this. My question is: how do you get dependencies needed? I have my dependencies listed in the .opam file, and usually I would do opam install . --deps-only, but it feels wrong to have that in the preBuild, and it also feels wrong to repeat the dependencies in the nativeBuildInputs

btw, my project is here, and I’m failing to build using your example: GitHub - mimoo/nixbyexample: Learn nix by example

Thanks, glad to hear that you’ve found it useful! A big goal was to attempt to keep things relatively straightforward and easy to follow. From what I’ve seen nix files often tend to end up as big blobs of spaghetti, so I was doing my best to avoid that fate.

My question is: how do you get dependencies needed? I have my dependencies listed in the .opam file, and usually I would do opam install . --deps-only , but it feels wrong to have that in the preBuild , and it also feels wrong to repeat the dependencies in the nativeBuildInputs

Yeah I’d like to have an example of this at some stage. I think if you want to do this without the duplication you might need to use something like opam-nix. I tried this a while back, but found the documentation, API, and examples confusing and failed to make much progress. The API also seemed to result in somewhat ugly looking nix expressions which was kind of disappointing, so I’ve shelved this for now. If you can figure it out though I’d love to learn from you.

1 Like

What do you mean by ‘failing to build’? Do you get some sort of error?

ah yeah, I found the same and was unable to use it. I created an issue there hopefully they see it: example file · Issue #14 · tweag/opam-nix · GitHub

yeah the errors I’m getting is that dune can’t find the dependencies (even though I added them to the list in the flake.nix). If you clone the repo you can try nix run, but tbh I think I should just spend the time to understand this opam-nix.

Trying from HEAD, seems like:

  • ocamlPackages.ppx_deri is not on nixPkgs? I changed it to ocamlPackages.ppx_deriving instead.
  • The libraries also need to be in buildInputs not nativeBuildInputs. IIUC OCaml links to these dynamically, so they need to remain on the host platform.
  • The order of the outputs seems significant too, where the first one is the default package. You could probably just remove the stuff related to documentation generation though.
  • I’m not sure if you need a .opam file right now, as this is not something that I imagine will be distributed on the package manager? The main utility of that would be collaborating with non-nix developers (which is really important to support), but seeing this is a project all about Nix I’m not sure how useful that is.
diff --git a/flake.nix b/flake.nix
index c5393b7..f5b3611 100644
--- a/flake.nix
+++ b/flake.nix
@@ -9,7 +9,7 @@
     # Precisely filter files copied to the nix store
     nix-filter.url = "github:numtide/nix-filter";
   };
-
+
   outputs = { self, nixpkgs, flake-utils, nix-filter }:
     flake-utils.lib.eachDefaultSystem (system:
       let
@@ -54,21 +54,24 @@

             src = ocaml-src;

-            outputs = [ "doc" "out" ];
+            outputs = [ "out" "doc" ];

+            # Build time dependencies
             nativeBuildInputs = [
               ocamlPackages.odoc
-              ocamlPackages.yojson
+              ocamlPackages.ppx_deriving
+            ];
+
+            # Runtime dependencies
+            buildInputs = [
+              ocamlPackages.core
+              ocamlPackages.core_unix
               ocamlPackages.jingoo
-              ocamlPackages.ppx_deri
+              ocamlPackages.yojson
             ];

             strictDeps = true;

-            preBuild = ''
-              dune build ./bin/main.exe
-            '';
-
             postBuild = ''
               echo "building docs"
               dune build @doc -p byexample
diff --git a/tools/bin/dune b/tools/bin/dune
index a686527..aa67305 100644
--- a/tools/bin/dune
+++ b/tools/bin/dune
@@ -1,5 +1,7 @@
 (executable
  (name main)
+ (public_name byexample)
+ (package byexample)
  (libraries core yojson jingoo byexample)
  (preprocess
   (pps ppx_deriving.show)))
diff --git a/tools/byexample.opam b/tools/byexample.opam
deleted file mode 100644
index aa05e3b..0000000
--- a/tools/byexample.opam
+++ /dev/null
@@ -1,21 +0,0 @@
-opam-version: "2.0"
-name: "byexample"
-version: "~dev"
-synopsis: "by Example"
-maintainer: "David Wong <davidwong.crypto@gmail.com>"
-authors: "David Wong <davidwong.crypto@gmail.com>"
-license: "The MIT License (MIT)"
-homepage: "https://github.com/o1-labs/ocamlbyexample"
-bug-reports: "David Wong <davidwong.crypto@gmail.com>"
-depends: [
-  "dune" {>= "2.8.5"}
-  "core" {>= "0.14.1"}
-  "core_unix" {>= "0.15.0"}
-  "yojson" {>= "1.7.0"}
-  "jingoo" {>= "1.4.3"}
-  "ppx_deriving" {>= "5.2.1"}
-]
-build: [
-  [make]
-]
-install: [make "install"]
diff --git a/tools/dune-project b/tools/dune-project
index ea2f268..a57b0cd 100644
--- a/tools/dune-project
+++ b/tools/dune-project
@@ -1,3 +1,4 @@
 (lang dune 2.8)

-(name byexample)
+(package
+ (name byexample))
diff --git a/tools/lib/dune b/tools/lib/dune
index ac2d42c..190e36a 100644
--- a/tools/lib/dune
+++ b/tools/lib/dune
@@ -1,5 +1,6 @@
 (library
  (name byexample)
+ (package byexample)
  (libraries core core_unix core_unix.sys_unix yojson jingoo)
  (preprocess
   (pps ppx_deriving.show)))
1 Like

I’ve actually figured out a better way to generate the docs. You might find my recent changes useful to look at: Comparing 36f3f9feb1058d3a2f27dfc7ec214fdfbf317c31..1eafd35a6e4f43893505451292b0e1fe425caf4e · brendanzab/ocaml-flake-example · GitHub

1 Like