Setting up a new OCaml environment in 2026 is not yet a fluid experience

One complexity with OCaml on Windows for library mainteners is that multiple flavours are supported (Cygwin, MSYS2, MinGW, MSVC). And only Cygwin and MSYS2 flavours support external dependencies.

On Debian, it is simplier, Opam deals with the apt package management, only one gcc toolchain is proposed and things are transparent for the user.

I have already succeed in using Gtk with OCaml (with lablgtk and Diskuv)… there were many issues to fix: 1/ compiling Gtk itself was difficult (no OCaml involved), 2/ setting a compiling environment usable by compiling tools (adequate PATH and other environment variables) (no OCaml involved), 3/ dealing with gcc / msvc incompatible options (no OCaml involved, but cc flags were set in a dune flags)… and surely some other issues.

I also remember DLL produced by msvc with badly exported names for an OCaml/FlexLink use. For pg_query, there are also incompatible .h files if I remember well.

Then, the Windows environment is far less programmer friendly than Linux. We can’t say that the OCaml environment is the main culprit. The fact that many libraries from Opam were developped when Windows wasn’t supported doesn’t help too.

Not sure I agree. I mean, there are lots of people programming on Windows without any issue. Windows is a great dev platform, if you don’t expect it to be Unix but treat it as Windows. (and of course, with WSL, you do have Unix as well)

But as a personal experience, Node.js works great, Python works great, Racket works great. The “obsolete” Pascal (Lazarus/Free Pascal) works great and lets you do sophisticated GUI cross platform apps, without the need to deal with any Gtk or other dependencies. All these languages are cross platform yet work beautifully on Windows.

TBH, I think we can very much say that. OCaml’s environment it not a “native” Windows one, and this causes a ton of problems.

2 Likes

Let’s try Python and its PIP package manager…

C:\Users\frede>pip download psycopg2 --no-binary :all: -d ./sources
Collecting psycopg2
  Downloading psycopg2-2.9.11.tar.gz (379 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 379.6/379.6 kB 875.3 kB/s eta 0:00:00
  Preparing metadata (setup.py) ... error
  error: subprocess-exited-with-error

  × python setup.py egg_info did not run successfully.
  │ exit code: 1
  ╰─> [23 lines of output]
      running egg_info
      creating C:\Users\frede\AppData\Local\Temp\pip-pip-egg-info-2gdhb_4s\psycopg2.egg-info
      writing C:\Users\frede\AppData\Local\Temp\pip-pip-egg-info-2gdhb_4s\psycopg2.egg-info\PKG-INFO
      writing dependency_links to C:\Users\frede\AppData\Local\Temp\pip-pip-egg-info-2gdhb_4s\psycopg2.egg-info\dependency_links.txt
      writing top-level names to C:\Users\frede\AppData\Local\Temp\pip-pip-egg-info-2gdhb_4s\psycopg2.egg-info\top_level.txt
      writing manifest file 'C:\Users\frede\AppData\Local\Temp\pip-pip-egg-info-2gdhb_4s\psycopg2.egg-info\SOURCES.txt'

      Error: pg_config executable not found.

      pg_config is required to build psycopg2 from source.  Please add the directory
      containing pg_config to the $PATH or specify the full executable path with the
      option:

          python setup.py build_ext --pg-config /path/to/pg_config build ...

      or with the pg_config option in 'setup.cfg'.

Obviously, things are not that easy to recompile a package. What makes Python/PIP easy for most users is that it just downloads pre-compiled binaries. Opam is a source only package manager and then you can have the same issues than with PIP using only source. (I admit you can have more since the OCaml Windows port is recent and packages are not all ported).

And if some environments support a cross-platform GUI library, it is because someone created such a library, and ported to each supported environment. OCaml can’t exempt you to port such a library. The simplier way is to create a binding to a cross-platform library (GTk, Qt, SDL…), then the port is already done.

I have no knowledge of psycopg2, but a quick web search showed that the same issue can manifest on all platforms, it’s absolutely not Windows specific. It’s a basic dependency issue, very different to the stuff one can encounter when trying to install OCaml stuff in Windows.

Sure, when you can actually install said bindings.

Yes.

Note also that the official opam Windows experience is rather new. Packages are tested in the opam-repository CI only since about a year and a failure there is not a refusal to merge (IIRC).

For upstream package devs on Unix it’s also a bit difficult to easily get a testing environment (see point 2. here) and further complicated for some of us on arm laptops by the fact that opam Windows on arm is not an official reality.

But I recently made great progress towards that here with an elaborate bootstrap procedure requiring you only to type two commands in a QEMU window with a graphical cmd.exe. This then allows you to generate bespoke Windows Validation OS images unattended in which you can login to a cmd.exe prompt followed by pwsh via the SAC console. But I’m hitting a wall (and soon timing out on that for now) on trying to install winget on these images – I’ll try to sum up the problems in a couple issue and see if any of my trusted Windows devs can shed better light.

8 Likes

There are some eyewateringly hacky approaches to this in Support installing WinGet on Docker for Windows containers · Issue #4144 · microsoft/winget-cli · GitHub and other threads. winget really wants a graphical console…

1 Like

What do you mean by environment and “native” Windows?

You can write OCaml agnostic programs which even call C programs and are compiled into native Windows executables. Opam has also the knowledge of MSYS2 and Cygwin package manager, and this enables projects which deals with source dependencies better than Python/PIP. Complex project construction can be enabled by the Dune_configurator module which can feed dune with computed flags (this avoid the need of Unix tools, like the Bourne shell interpreter). Even filename handling can be done in a compatible way (using the Filename module).

NOTE: The dependency support is not magic, you need some lines like the following for each OS you know:

depexts: [
  ["qt515quickcontrols2" "qt515base" ] {os-family = "debian"}]

Then the issue is not the environment (I mean the OCaml toolchain, Dune, and Opam). The issue deals mainly with the fact that developping a C file which is compatible with many environments is not always easy, and may need many #ifdef / #else / #endif, and a configure file which tests the characteristics of the OS (this can even be needed between Linux and other Unix like systems). For a long time, Windows wasn’t supported by OCaml. This explains that many Opam packages were not adapted to Windows if needed, and some may even need some Unix tools to compile if they compile. (But MSYS2 or Cygwin may fill the gap). You may wait a long time before having all Opam packages ported to Windows (this depends of each package mainteners). (And, you may have not portable modules like Core_unix, epoll binding for Linux, etc).

3 Likes

As mentioned in the issue I think it’s more about being able to install .msix and .msixbundle files than a graphical console console thing. Basically I’m not able to get Add-AppxPackage or dism /Add-AppxProvisionedPackage to work.

Looking at the .cab contents I believe this should live in the Microsoft-WinVOS-Deployment-Package but adding this package (which lives in an Experimental directory) brings all sorts of problem that I will describe in an issue on the telvm project :–) Perhaps waiting for a new release of WinVOS (which happened monthly last year) is the answer though.

1 Like

Native Windows means it doesn’t need what is a “Unix emulation” environment installed for it to (hopefully) work.

Like you say:

:up_arrow: this means it’s not “native” Windows.

This also defines the whole user experience: when you install OCaml, according to the official tutorial here: OCaml on Windows · OCaml Documentation , you’ll watch an installer pop-up and asking you questions about something called Cygwin, and you’ll be expected to know what that is.

Because, as that same tutorial clarifies:

opam requires a Unix-like environment to function. By default, opam relies on Cygwin and is also compatible with MSYS2.

At init-time, opam scans your machine for available Unix environments and prompts you to choose your favourite option. We recommend to let it create its own internal Cygwin installation that will remain managed by opam. This cuts down possible interferences from other tools that interact with such environments. Think of it as a sandboxed environment.

:up_arrow: this means it’s not “native” Windows.

Compare that with Racket, Python, Node.js: you download a Windows installer, you double click it, it installs a Windows native app without any special environment. You get some icons in the Start menu and you can either start their built in IDE or a Terminal with the env vars already set. “Native” Windows installer, “native” Windows application, behaving in a perfectly predictable Windows way.

There are 5 minutes separating you from a decision to download the Racket installer to actually coding in Racket, and in those 5 minutes nothing will happen that wouldn’t be familiar to a typical Windows user.

Thing is, even after you do have that Cygwin env installed, things will not be smooth and predictable (as I found out). Packages will not compile (for various reasons), especially if they involve external libs and so on. And since the whole env is quite alien, debugging what’s happening is very difficult, as can be witnessed in this forum or on GitHub.

1 Like

Right, it’s just that it works fine if a graphical console is available (which was the same as twenty years ago when I first packaged up OCaml code for XenServer and had to get MSI files autoinstalling!). There is a really hacky workaround I got a bit further with that involves using Chocolatey to install the third-party “Advanced Installer” that can repackage msix files, but I didn’t feel that was trustworthy enough for even a local setup for me.

It’s remarkable that a Microsoft-authored CLI doesn’t support installation on Microsoft’s own native containers (which themselves are regularly broken with their own upgrades). Which leads onto…

I think it’s important to note the distinction between the OCaml compiler and the OCaml package ecosystem. The OCaml compiler has supported Windows brilliantly since its inception, and I’ve helped to ship several products that work great (most recently Docker for Desktop) for over a 100 million Windows users. And other major OCaml users like Lexifi are on Windows as well. This is usually a hand-crafted monorepo of OCaml code.

Where we trip up is the ecosystem of packages, which are a mess for any programming languages I’ve used on Windows when you go beyond the non-trivial or the .NET ecosystem. For example, I spent days recently trying to figure out how to get Python and GDAL working together on Windows. Do you use uv (nope, cram doesnt work), or pip (installing GDAL DLLs fails), or Conda (works, but its a closed source distribution), or Miniconda, or Anaconda, or some serpentes-inspired combination? Similar story with some Node packages that have C bindings – the reason you often don’t notice this is because thre are hidden binary bundles that are downloaded, and if you try to reproduce the supply chain from scratch it all comes crumbling down.

Windows is more difficult to support than Linux not because of the diversity of toolchains, but because CI is near impossible to get working with any decent kind of feedback loop (see the start of this thread!). We’re making steady progress though! Between Opam 2.2+ and WSL2, things are in a happier place than ever before.

9 Likes

Thanks for the precision. I am used to remember the OCaml on Windows · OCaml Documentation page and its Tiers. For a while, the Tier 1 was in the future (probably OCaml 5 / Opam 2.2), and we had a temporary solution at fdopen. But I understand the OCaml compiler was supported on Windows, but not Opam. And now, Opam is supported (and native), but not all packages are compatible. “One step at a time”.

1 Like

As mentioned in the issue I think it’s more about being able to install .msix and .msixbundle files than a graphical console console thing. Basically I’m not able to get Add-AppxPackage or dism /Add-AppxProvisionedPackage to work.

I use install-winget.ps1 · GitHub to get winget installed on Windows Sandbox. Periodically I need to update the versions and components. I suspect Windows Sandbox has the same problems as Docker.

Aside: I will be trying to get wine working with MSVC in an automated fashion sometime next month. So just wine, cl.exe, cmd.exe, ocamlopt.exe, related executables and DLLs, and probably my own build tool and dune.exe. If you don’t mind, what do you need winget for? (this might belong in a separate thread)

2 Likes

Well I precisely can’t use that script since Add-AppxPackage is not working.

I’m just interested in having a reasonably working Windows image that I can access via the cli to troubleshoot my opam packages on the platform myself (it seems hard to find Windows users who are knowledgable enough about OCaml and C linking).

winget seems just handy to get git and opam and I guess msvc and co.

4 Likes

I don’t follow… “OCaml and C linking” deals with libffi, ctypes-foreign, ctypes-cstubs, and if you are using Windows, flexdll.

dism /Add-AppxProvisionedPackage and winget is from an other domain (perhaps like apt registry management in Debian or its lower level dpkg). Quite unrelated to OCaml.

(Makes sense to me. If you are a *nix package maintainer, it would be ideal to have a locally runnable Windows environment to test out Windows changes. And for reproducibility it is ideal to use the same tools that Windows users who file bug reports use … which is winget, git, Cygwin GCC / MSVC, (etc.) … especially for the harder user-reported Windows problems involving linking and compile flags)

6 Likes

13h

Makes sense to me. If you are a *nix package maintainer, it would be ideal to have a locally runnable Windows environment to test out Windows changes. And for reproducibility it is ideal to use the same tools that Windows users who file bug reports use

Ideal, for whom? As author of an open-source package I provide what is useful for me and in an environment that I have available, find useful, or enjoy. Anyone invested in Windows can take it and put in the work to make it work for them but I feel any expectation towards authors to provide packages on specific platforms is not in the spirit of open source. This is not limited to Windows and I would say the same about specific Unix platforms or architectures as well.

2 Likes

Sure, the package author if free to support a restricted set of platforms (and no author have an access to Windows, MacOS, FreeBSD, Linux). But if the infrastructure (a CI/CD) does stress incompatibilities, it can ease the work of authors who are encline to support multiple platforms.

One strength of Python is that it has a rich set of packages which works on multiple platforms.

And the Opam registry is unique. It would be clumsy to register pg_query (the original) and pg_query_windows (a Windows port).

1 Like

Let’s say ideal for an OCaml package maintainer that values cross-platform development then :–)

P.S. I don’t have a love for Windows personally, but note that professionally, as soon as you escape the tech bubble to small and medium sized enterprises you are faced with an ocean of Windows boxes. It’s nice to be able to use OCaml there too.

9 Likes

The key word is professionally. Now money is involved and I think that’s fair because this ocean of windows boxes does not pay back in the currency of source code or patches or otherwise Windows support would be stronger naturally.

1 Like

Sorry; I was responding to specifics in this thread rather than making a universal statement. I’ll be more careful next time.

Use whatever software and environments you wish!

1 Like