OCaml: Difference between revisions

Aura (talk | contribs)
Updated OCaml language by providing additional references to Nixpkgs manual.
Aura (talk | contribs)
Clarified interaction with Opam.
Line 1: Line 1:
[[File:OCaml Logo.svg|alt=The OCaml logo: an orange background with a white foreground of a camel.|thumb|OCaml logo]]
[[File:OCaml Logo.svg|alt=The OCaml logo: an orange background with a white foreground of a camel.|thumb|OCaml logo]]


According to the official [ocaml.org Ocaml website]:<blockquote>
According to the official [ocaml.org Ocaml website]:<blockquote>
Line 9: Line 7:




Most packages related to OCaml, in particular the OCaml compiler and many libraries, belong to the '''ocamlPackages''' attribute set of nixpkgs. Tools for OCaml development are, in particular, available:
Most packages related to OCaml, in particular the OCaml compiler and many libraries, belong to the <code>ocamlPackages</code> attribute set of nixpkgs. Tools for OCaml development are, in particular, available:


* the [https://dune.build/ dune] builder;
* the [https://dune.build/ dune] builder;
Line 16: Line 14:


=== Build tooling ===
=== Build tooling ===
Modern development practices in OCaml tend to use '''dune''', a builder dedicated for OCaml projects. Nixpkgs provide a dedicated builder: [https://nixos.org/manual/nixpkgs/stable/#sec-language-ocaml-packaging buildDuneProject].
Modern development in OCaml tend to use <code>dune</code>, a build system dedicated for OCaml projects. Nixpkgs provide a dedicated helper [https://nixos.org/manual/nixpkgs/stable/#sec-language-ocaml-packaging buildDuneProject] to facilitate integration with <code>dune</code>.
 
An example minimal flake for OCaml development is available below:
 
{{Code|1=// flake.nix
{
  description = "Minimal flake for OCaml projects.";
  inputs = {
    flake-utils.url = "github:numtide/flake-utils";
    nixpkgs.url = "nixpkgs";
  };
  outputs =
    {
      self,
      flake-utils,
      nixpkgs,
      ...
    }:
    flake-utils.lib.eachDefaultSystem (
      system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
      in
      {
        packages = {
          default =
          buildDunePackage {
            pname = "My Ocaml Package";
            duneVersion = "3";
            version = "0.1";
            minimalOCamlVersion = "4.14";
            installTargets = "all doc";
            src = ./.;
            nativeBuildInputs = with p; [
              dune_3
            ];
          };
        };
        devShells = {
          default = pkgs.mkShell {
            name = "Ocaml development shell environment.";
            inputsFrom = [ self.packages.${system}.default ];
            packages = with pkgs.ocaml-ng.ocamlPackages; [
              ocamlformat
              ocaml-lsp
              utop
              pkgs.gnumake
            ];
            shellHook = ''
              echo "Welcome in the devshell."
            '';
          };
        };
      }
    );
}|lang=nix}}


'''dune''' can generate a '''.opam''' file, which can be ingested by tools like [https://github.com/tweag/opam-nix opam-nix] to automatically generate a derivation.  
<code>nix develop</code> followed by <code>dune init project myproject</code> will drop you in a development shell.  


Manual package building is also possible using the following approaches:
==== Opam ====
OCaml has its own package manager, [https://opam.ocaml.org/ opam]. Trying to use it imperatively with Nix will result in errors. However, <code>opam</code> can generate a <code>.opam</code> file, which can be ingested by tools like [https://github.com/tweag/opam-nix opam-nix] to automatically generate a Nix derivation.


==== Findlib, ocamlfind ====
==== Manual build with ocamlc, findlib, ocamlfind ====
OCaml libraries are usually located using [http://projects.camlcity.org/projects/findlib.html findlib] and the associated '''ocamlfind''' tool. These tools are found under the '''ocamlPackages.findlib''' attribute and rely on the '''OCAMLPATH''' environment variable.
OCaml libraries are usually located using [http://projects.camlcity.org/projects/findlib.html findlib] and the associated <code>ocamlfind</code> tool. These tools are found under the <code>ocamlPackages.findlib</code> attribute and rely on the <code>OCAMLPATH</code> environment variable.


A hook in the '''findlib''' package will automatically populate this variable with the paths to the other libraries. For instance, when starting a shell with
A hook in the <code>findlib</code> package will automatically populate this variable with the paths to the other libraries. For instance, when starting a shell with
<code>nix-shell --packages ocamlPackages.findlib ocamlPackages.batteries</code>
<code>nix-shell --packages ocamlPackages.findlib ocamlPackages.batteries</code>
will set the '''OCAMLPATH''' variable so that '''ocamlfind''' can locate the '''batteries''' library.
will set the <code>OCAMLPATH</code> variable so that <code>ocamlfind</code> can locate the <code>batteries</code> library.


This hook also sets the '''CAML_LD_LIBRARY_PATH''' environment variable that is used for locating the dynamically loaded shared libraries (aka stublibs).
This hook also sets the <code>CAML_LD_LIBRARY_PATH</code> environment variable that is used for locating the dynamically loaded shared libraries (aka stublibs).


=== Scripting with OCaml ===
=== Scripting with OCaml ===
Line 46: Line 100:
<code>nix-env -iA nixpkgs.emacsPackagesNg.tuareg</code>.
<code>nix-env -iA nixpkgs.emacsPackagesNg.tuareg</code>.


Emacs must be configured to be able to find this package: you may need to add a line like this to your '''.emacs''' file, somewhere between <code>(require 'package)</code> and <code>(package-initialize)</code>:
Emacs must be configured to be able to find this package: you may need to add a line like this to your <code>.emacs</code> file, somewhere between <code>(require 'package)</code> and <code>(package-initialize)</code>:


<syntaxHighlight lang=emacs>
<syntaxHighlight lang=emacs>
Line 58: Line 112:
Beware that merlin is specific to one particular version of OCaml (it won’t work correctly with a compiler of a different version).
Beware that merlin is specific to one particular version of OCaml (it won’t work correctly with a compiler of a different version).


To configure Emacs and enable the merlin mode, add the following to your '''.emacs''':
To configure Emacs and enable the merlin mode, add the following to your <code>.emacs</code>:


<syntaxHighlight lang=emacs>
<syntaxHighlight lang=emacs>
Line 66: Line 120:
</syntaxHighlight>
</syntaxHighlight>


Also, a specific variable ('''merlin-command''') of the merlin mode must be overridden (its default is '''opam'''):
Also, a specific variable (<code>merlin-command</code>) of the merlin mode must be overridden (its default is <code>opam</code>):


<syntaxHighlight lang=emacs>
<syntaxHighlight lang=emacs>
Line 74: Line 128:
</syntaxHighlight>
</syntaxHighlight>


A useful complement to merlin is [https://www.typerex.org/ocp-indent.html '''ocp-indent'''], a customizable tool to indent OCaml code. It can be installed using <code>nix-env -iA nixpkgs.ocamlPackages.ocpIndent</code>. To enable it in Emacs, don’t forget to add the following line to your '''.emacs''':
A useful complement to merlin is [https://www.typerex.org/ocp-indent.html '''ocp-indent'''], a customizable tool to indent OCaml code. It can be installed using <code>nix-env -iA nixpkgs.ocamlPackages.ocpIndent</code>. To enable it in Emacs, don’t forget to add the following line to your <code>.emacs</code>:


<syntaxHighlight lang=emacs>
<syntaxHighlight lang=emacs>
Line 81: Line 135:


=== Specific version of the OCaml compiler ===
=== Specific version of the OCaml compiler ===
Various versions of the '''ocamlPackage''' attribute set are available, corresponding to various versions of OCaml. For instance, the attribute set '''ocaml-ng.ocamlPackages_4_04''' contains the OCaml compiler at version 4.04 and OCaml libraries compiled with that particular compiler.
Various versions of the <code>ocamlPackage</code> attribute set are available, corresponding to various versions of OCaml. For instance, the attribute set <code>ocaml-ng.ocamlPackages_4_04</code> contains the OCaml compiler at version 4.04 and OCaml libraries compiled with that particular compiler.


==== Custom version ====
==== Custom version ====
So as to get the set of OCaml libraries built with/for a custom version of the OCaml compiler, e.g., to enable '''flambda''' support, you may use the '''ocamlPackages.overrideScope''' function:
So as to get the set of OCaml libraries built with/for a custom version of the OCaml compiler, e.g., to enable <code>flambda</code> support, you may use the <code>ocamlPackages.overrideScope</code> function:


<syntaxHighlight lang=nix>
<syntaxHighlight lang=nix>