I’m hunting for my perfect web application language (sure to be a future post). So I’ve been exploring OCaml. I prefer Nix for configuring development environments. It keeps things self-contained and increases the chances that I won’t have painful setup issues when I revisit projects months or years later.
I created a flake.nix
that configured OCaml and used ocaml-overlay to add Dream to my development environment:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
| {
description = "Expiments in ocaml";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
flake-parts.url = "github:hercules-ci/flake-parts";
ocaml-overlay = {
url = "github:nix-ocaml/nix-overlays";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = inputs@{ self, nixpkgs, flake-parts, ocaml-overlay, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
systems = [ "aarch64-darwin" "x86_64-linux" "aarch64-linux" ];
perSystem = { pkgs, system, inputs', ... }: {
_module.args.pkgs = import inputs.nixpkgs {
inherit system;
config.allowUnfree = true;
overlays = [
ocaml-overlay.overlays.default
];
};
packages = { };
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
ocaml
ocamlPackages.dune_3
ocamlPackages.findlib
ocamlPackages.ocamlformat
ocamlPackages.ocaml-lsp
ocamlPackages.utop
ocamlPackages.dream
ocamlPackages.dream-html
];
};
};
};
}
|
This got me up and running until I wanted to use the live reload functionality described in the published documentation. Unfortunately, this feature is only present on main not the 1.0.0.0-alpha5 release present in OPAM and ocaml-overlay.
I created an overlay to update dream
to use the code onmain
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| self: super: {
ocamlPackages = super.ocamlPackages // rec {
dream-pure = super.ocamlPackages.dream-pure.overrideAttrs (old: {
version = "1.0.0-78c79e3328414768fa2ede0623d741f63ea5c4f1";
src = super.fetchFromGitHub {
owner = "aantron";
repo = "dream";
rev = "78c79e3328414768fa2ede0623d741f63ea5c4f1";
hash = "sha256-mx0DAzu8L0jVCMrCvefVLPZX3E+C8SUv9wjcqZcG29Q=";
fetchSubmodules = true;
leaveDotGit = false;
deepClone = false;
};
});
dream = super.ocamlPackages.dream.overrideAttrs (old: {
inherit (dream-pure) src version;
propagatedBuildInputs = with self.ocamlPackages;
old.propagatedBuildInputs ++ [ markup lambdasoup ];
prePatch = "";
});
}
|
This was a tad more complicated than expected. The dream
derivation gets its source from the dream-pure
derivation. So I updated that and changed the reference in dream
accordingly. So far so good.
Next I wanted to try out Dream_html. However, upon adding this to flake.nix
ocaml failed to compile indicating that there were two versions of dream
present.
1
2
3
4
5
6
7
8
| ❯ nix develop
warning: Git tree '/Users/bromanko/Code/ocaml' is dirty
error: builder for '/nix/store/48x8ixc5gkxv1jwp67phbyrmg8zfqr5i-nix-shell-env.drv' failed with exit code 1;
last 3 log lines:
> Conflicting ocaml packages detected
> findlib: [WARNING] Package dream has multiple definitions in /nix/store/34v2r793d12zpi5xbx76qwh887c1yh8q-ocaml5.1.1-dream-1.0.0-alpha5/lib/ocaml/5.1.1/site-lib/dream/META, /nix/store/ybmsg15f5r0lbcijnw9m031zzyaad78l-ocaml5.1.1-dream-1.0.0-alpha5/lib/ocaml/5.1.1/site-lib/dream/META
> Set dontDetectOcamlConflicts to true to disable this check.
For full logs, run 'nix log /nix/store/48x8ixc5gkxv1jwp67phbyrmg8zfqr5i-nix-shell-env.drv'.
|
Looking at the dream-html derivation in emacs-overlay
I could see that I’d need to override it to add the reference to my updated version of dream
.
1
2
3
4
| # Prior overlay code elided...
dream-html = super.ocamlPackages.dream-html.overrideAttrs
(old: { propogatedBuildInputs = [ dream ]; });
|
And… it didn’t work. I got the same error that there were two conflicting dream
packages. Where was that other, original version, coming from? And how could I debug this since the configuration is all in a devShell
?
Today I learned that you can build a devShell with nix build
:
1
| ❯ nix build -L .#devShells.aarch64-darwin.default`
|
I added some debug logging to the overlays to try and sort out where the dependency was coming from:
1
2
3
4
5
6
7
8
9
| dream-html = super.ocamlPackages.dream-html.overrideAttrs (old: {
prePatch = ''
echo "####################### building dream-html..."
ocamlfind query dream
echo "My dream path ${dream}"
echo "Original dream path ${super.ocamlPackages.dream}"
'';
propogatedBuildInputs = [ dream ];
});
|
The dream-html
overlay is still referencing the original version of dream
rather than using my overlay.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| ❯ nix build -L .#devShells.aarch64-darwin.default
warning: Git tree '/Users/bromanko/Code/ocaml' is dirty
ocaml5.1.1-dream-html> Running phase: unpackPhase
ocaml5.1.1-dream-html> unpacking source archive /nix/store/d4x42dv5g9l4nfgkhix53nwjzxqadpdk-source
ocaml5.1.1-dream-html> source root is source
ocaml5.1.1-dream-html> Running phase: patchPhase
ocaml5.1.1-dream-html> ####################### building dream-html...
ocaml5.1.1-dream-html> /nix/store/ybmsg15f5r0lbcijnw9m031zzyaad78l-ocaml5.1.1-dream-1.0.0-alpha5/lib/ocaml/5.1.1/site-lib/dream
ocaml5.1.1-dream-html> My dream path /nix/store/dxi13p10n42xy6rwxhcpmb7d89c8cy8s-ocaml5.1.1-dream-1.0.0-alpha5
ocaml5.1.1-dream-html> Original dream path /nix/store/ybmsg15f5r0lbcijnw9m031zzyaad78l-ocaml5.1.1-dream-1.0.0-alpha5
ocaml5.1.1-dream-html> Running phase: updateAutotoolsGnuConfigScriptsPhase
ocaml5.1.1-dream-html> Running phase: configurePhase
ocaml5.1.1-dream-html> no configure script, doing nothing
ocaml5.1.1-dream-html> Running phase: buildPhase
ocaml5.1.1-dream-html> Running phase: installPhase
ocaml5.1.1-dream-html> Running phase: fixupPhase
ocaml5.1.1-dream-html> checking for references to /private/tmp/nix-build-ocaml5.1.1-dream-html-1.1.0.drv-0/ in /nix/store/g5ng1if7nkgf5fgk8nja575mpzgvsdqn-ocaml5.1.1-dream-html-1.1.0...
ocaml5.1.1-dream-html> patching script interpreter paths in /nix/store/g5ng1if7nkgf5fgk8nja575mpzgvsdqn-ocaml5.1.1-dream-html-1.1.0
ocaml5.1.1-dream-html> stripping (with command strip and flags -S) in /nix/store/g5ng1if7nkgf5fgk8nja575mpzgvsdqn-ocaml5.1.1-dream-html-1.1.0/lib
nix-shell> Running phase: buildPhase
|
Oh my.
Do you see it?
😮💨
I can’t spell propagated…