Some F# versions (1.9.4.15 and 1.9.4.17) had a few issues with Mono. This page explains how to fix them. However, these problems were reported to the F# team and have been fixed in F# 1.9.4.19. This page will remain online, since some tips might be useful.

Installation steps

1. Check you have a recent version of Mono. Mono updates are quite frequent and contain many bug fixes. It's a good idea to keep it up to date. For example, I tried the latest F# versions with Mono 1.2.3.1 and it didn't work. I recommend to have at least Mono 1.2.6.

2. Download the zip file from Microsoft Research website.

3. Run the following commands:

$ unzip fsharp-1.9.4.17.zip
$ cd FSharp-1.9.4.17
$ chmod +x install-mono.sh
$ sed -i.bak 's/^mono/& --runtime=v2.0.50727/' install-mono.sh
$ ./install-mono.sh

You will get error messages, just ignore them. Yes, there are an assertion failure and a sigabrt signal, I said you could ignore them.

4. Test the compiler

$ cd bin
$ echo 'printfn "test"' > test.fs
$ mono --runtime=v2.0.50727 fscp10.exe test.fs
$ mono test.exe
test

5. Patch fsi and recompile it

 $ cd ../source/fsharp
 $ sed -i.bak '519s/ w/ if not runningOnMono then&/' fsi.fs
 $ mono --runtime=v2.0.50727 ../../bin/fscp10.exe --define CLI_AT_LEAST_2_0 --no-warnings -O3 -g \
 -r ../../bin/FSharp.Compiler.dll -r ../../bin/FSharp.Compiler.Server.Shared.dll \
 -r ../../bin/FSharp.Compiler.Interactive.Settings.dll ../absil/ilreflect.fs console.fs fsi.fs -o ../../bin/new-fsi.exe
 $ cd ../../bin/
 $ mono new-fsi.exe --readline

And enjoy!

It's important to notice that you need the "--runtime=v2.0.50727" flag when you call Mono with fscp10.exe. You also need it for fsyacc and fslex.

When compiling fsi, you might get a warning related to absilsuppc.dll. Just ignore it (I don't know what's the problem, but it looks like it's not important). For some reason, readline is disabled by default on mono, but you should use it (or call fsi from a software like Emacs): add the "--readline" flag when you call fsi. If you don't use it, line editing might behave oddly.

Also, the compiler is quite slow on this version (I believe this is connected to the AOT), but softwares compiled with F# will work great. Mono is quite fast actually, there are not so much differences with Windows .Net.

Understanding

If you want to understand what was done or if something doesn't work, these notes might be useful.

CompilerGeneratedAttribute

The binary files in F# 1.9.4.17 are supposed to work with .NET 1.1. However, they use CompilerGeneratedAttribute, which is available only with .NET 2.0. To make them work, you need to explicitly tell Mono to use runtime .NET 2.0 and not to use the autodetection system. That's what the --runtime=v2.0.50727 flag does.

If you forget the flag, you get the following error:

 Unhandled Exception: System.TypeLoadException: A type load exception has occurred.
   at <StartupCode$fscp10>.$Microsoft.FSharp.Compiler.CommandLineMain._main () [0x00000]
Installation script

The sed command adds the "--runtime=v2.0.50727" flag to mono. The last two lines in the script should be removed (that's why you get error messages). Note that fsc.exe is a Windows native file, so don't try to use it.

FSI

If you run fsi.exe or fsi10.exe, you'll get the error:

Unhandled Exception: System.EntryPointNotFoundException: GetSystemMetrics
  at (wrapper managed-to-native) Microsoft.FSharp.Compiler.Interactive.Shell:GetSystemMetrics (int)
  at Microsoft.FSharp.Compiler.Interactive.Shell.warningForTabletPC () [0x00000]
  at <StartupCode$fsi10>.$Microsoft.FSharp.Compiler.Interactive.Shell._main () [0x00000]

The problem comes from this code in fsi.fs:

[<DllImport("user32.dll", EntryPoint=("GetSystemMetrics"))>]
extern bool GetSystemMetrics(int);
let warningForTabletPC() =
  let SM_TABLETPC = 86
  if GetSystemMetrics(SM_TABLETPC) then

This function is called only once. The goal is to print a warning for TabletPC users. Therefore the call to this function can be safely disabled. The easiest patch is to edit the file fsi.fs (line 519) and add a test. So, just replace:

do warningForTabletPC()

with:

do if not runningOnMono then warningForTabletPC()

Yes, that's what the short sed command did.

FSI and Winforms

This is not connected with this particular version of F#, but it's useful to know (I get it, since I'm using ssh without export display). If you get the following error message:

Unhandled Exception: System.TypeInitializationException: An exception was thrown by the type initializer for
System.Windows.Forms.WindowsFormsSynchronizationContext ---> System.TypeInitializationException:
An exception was thrown by the type initializer for System.Windows.Forms.XplatUI ---> System.ArgumentNullException:
Could not open display (X-Server required. Check you DISPLAY environment variable)

Then you should use the "--no-gui" flag to fsi, so that it doesn't use winforms.