Once you have F# installed and operating, refer to the resources below for platform specific techniques,
tools, and resources.

This guide includes resources related to cross-platform development with F#. To contribute to this guide, log on to GitHub, edit this page and send a pull request.

Note that the resources listed below are provided only for educational purposes related to the F# programming language. The F# Software Foundation does not endorse or recommend any commercial products, processes, or services. Therefore, mention of commercial products, processes, or services should not be construed as an endorsement or recommendation.

Cross-platform users may also be interested in Fable, an F# compiler that emits JavaScript.

Editing

Some editors have specific support for F#, either builtin or through addons provided by the F# community:

Xamarin Studio has built-in support for F# development on OSX and Windows.

Emacs for Mac and Linux. There is an F# mode for Emacs that extends Emacs with syntax highlighting for F#, support for working with F# Interactive, automatic indentation and more.

Visual Studio Code for Mac, Linux and Windows. This is a free, open source, cross platform source code editor
supporting a lot of languages.
F# is supported by the Ionide project and is a nice integration. To install, press Ctrl+P and enter the following to install the Ionide package for VS Code.

Documentation

Projects and Build Automation

.fsproj and .sln files

You can use xbuild to build projects and solutions described by the .fsproj and .sln file
formats from Visual Studio without change.
Xamarin Studio and MonoDevelop can also create and manage .fsproj and .sln files.

Use xbuild to build projects and solutions:

xbuild RocketPart.fsproj
xbuild RocketSolution.sln

Many people doing cross-platform or Mac/Linux development don’t like .sln files because the file format
is not very amenable to human editing. If so, you can also create a .fsproj file that brings together a collection of
.fsproj files. Example of this can be found
on F# Core Engineering

Tooling around F# projects often relies on .fsproj files being present, for example the
autocompletion in emacs mode or
Vim will not work with out one, except when editing an F# script. These .fsproj
files are special XML files, and can therefor be somewhat unwieldy to maintain
by hand. To help with this you can use tools such as Xamarin Studio or MonoDevelop to
create and maintain them, or command line tools such as Forge (see below).

Forge

Forge is a self contained tool for
generating and managing projects. It allows the generation of new projects based
on an expanding list of templates. It also encapsulates the best practices for those
projects in terms of tooling and layout. The generated projects contain .fsproj files,
which can in turn be managed via forge as well making sure cross platform builds as well
as editor integration works out of the box. Of course forge can also manage the .fsproj
files for existing projects.

Makefiles

The F# command-line compiler (fsharpc) can be used with Makefiles in the usual way.

FAKE

FAKE is a build-and-publish automation utility sometimes used by F# programmers (partly because
builds are automated using F# itself, and partly because it is a great tool).

Package Repositories and Dependency Management

NuGet

NuGet is an open-source, cross-platform package management tool with many thousands
of packages available. See the documentation.
It is used extensively on Windows ecosystem but is growing in its cross-platform use.

Using nuget from the command line

For those on Mac/Linux, familiarity with the command-line NuGet.exe utility is highly useful.
Get the command line utility like this:

F# project files (.fsproj) can be configure to automatically get NuGet packages during a build. The
project file should have a line like this (adjust the ‘…’ to reference a copy of NuGet.targets checked into your project).

ReactiveUI - Reactive UI is an MVVM framework built on top of
the Reactive Extensions. Version 5.0 is “totally Portable-Friendly”, and supports Xamarin.iOS, Xamarin.Android,
Xamarin.Mac, .NET 4.5 (WPF), Windows Phone 8 and Windows Store Apps (WinRT).

Akavache - Akavache is an asynchronous, persistent (i.e. writes to disk) key-value store created for writing desktop and mobile applications in C# and F#. Think of it like memcached for desktop apps.
At the time of writing, it is compatible with .NET 4.0/4.5, Mono 3.0 (including Xamarin.Mac), Silverlight 5, Windows Phone 7.1/8.0, and WinRT (Metro / Modern UI / Windows Store / Whatever Microsoft Is Calling That Tablet’y OS Thing That They Make).

Splat – It has cross platform APIs for
images and colors, with platform-specific extension methods to go back and forth
between the platform-specific native types.

OxyPlot – OxyPlot is a cross-platform plotting library for .NET.
The core is a portable library, the package OxyPlot.GtkSharp is usable on Mac/OSX.

There are a wide range of cross-platform libraries available as part of the core libraries
available to F#, for example:

Portable (PCL) Libraries

Portable .NET libraries have access to less core functionality, called a “portable profile”, but can be used
across multiple platforms and multiple profiles of .NET. For example, a portable library may
be usable on Mac, Linux, Android, iOS, Windows and Windows Store apps (depending on the versions
of runtime machinery used and other factors).

F# portable libraries reference FSharp.Core versions such as 2.3.5.1, with matching mscorlib versions.
A binding redirect may be neeeded to ensure bindings to these libraries redirect correctly, e.g. to
FSharp.Core 4.4.0.0.

When authoring a Portable library on OSX and Linux, be sure to reference the FSharp.Core nuget package to find the right profile version of FSharp.Core. This is simpler
than reying on any specific version incuded with your F# installation.

Binding Redirects

Applications will almost certainly need to specify “binding redirects” for some or all components where multiple
versions of components need to be “unified” to one master version at runtime. This applies particularly to FSharp.Core
but also to other components. For instance, see examples of binding redirects for FSharp.Cpre.

Unit Testing

Fuchu

Fuchu is a test library for .NET, supporting C# and VB.NET but with a special focus on F#. It draws heavily from Haskell’s test-framework and HUnit. You can read about the rationale and underlying concepts in this blog post, or tests should be first-class values so that you can move them around and execute them in any context that you want. Also, if they are first-class values, then you can take extra care with what the test methods return, making integrations with external libraries much cheaper.

Install-Package Fuchu

Since tests are values, it’s easy to extend the framework to integrate with other tooling, e.g. with FsCheck to use a fuzzing/randomization approach to testing (see below)

Install-Package Fuchu.FsCheck

Fuchu also has an integration with PerfUtil which can be used to automate performance testing and trending in a continuous integration environment.

Install-Package Fuchu.PerfUtil

FsCheck

FsCheck is a tool for testing .NET programs automatically.
The programmer provides a specification of the program,
in the form of properties which functions, methods or objects should satisfy,
and FsCheck then tests that the properties hold in a large number of randomly generated cases.

NUnit

NUnit is an open-source, cross-platform unit-testing
framework for F# and other .NET languages. It is written
in C# and has been completely redesigned to take advantage of many .NET language features,
for example custom attributes and other reflection related capabilities.
Also xUnit is a good alternative for NUnit.

FsUnit

Continuous Integration builds

Using Travis and AppVeyor

Perhaps the simplest way to regularly build and test your work across multiple platforms is to use Travis.

You can automate the build and test of all commits and pull requests to GitHub projects
on Linux and OSX by using Travis. This is very easy to arrange, just add a .travis.yml file to your project root (example, example ), and register the project in your Travis account.

Setting the language to “objective-c” causes Travis to use an OSX machine for build.

Miscellaneous Notes on Open Source and Cross Platform Development

Testing on multiple platforms

If you are Windows developers, you can set up a Vagrant box in order to test your libraries and tools on Mono (though often a Travis build is simpler, see above)
A detailed guide of setting up Vagrant is available here.

Dos and Don’ts

Generally use / instead of \ on paths. In .fsproj files you can generally use either.

In .fsproj files, don’t use copy commands on PostBuildEvent’s, but use the MSBuild Copy task itself (example)

Don’t assume pdbs are always created after the compilation

Executables included in .NET may not exist in Mono or may have a different name or location e.g. SvcUtil etc

External components that would be available via NuGet in Windows might be included as part of Mono - Rx, TDF etc

Don’t rely the registry, also Mono can use a version of it, it can have permissions issues

Beware differences in behaviour with loading assemblies which is a very niche problem though. Generally the less trodden the code is, the more subtle differences there are.

When using NUnit, create your test fixtures with classes and methods, exactly the way you’d do in C# (Trying to use modules as test fixtures will trigger odd behaviors on Xamarin Studio).

Differences in F# Interactive DLL resolution. Use

#I @"./lib/FAKE/tools"
#r @"./lib/FAKE/tools/FakeLib.dll"

Not just

#r @"./lib/FAKE/tools/FakeLib.dll"

If your build executes binaries and tasks, make sure the “x” permissions are
set for Fsc.exe etc. and all other executables triggered by xbuild.

Developing Cross-Platform and Multi-Targeting Type Providers

F# type providers are compile-time components that must execute on your machine during build and development.

A type provider executing on Mac/Linux can expose some small differences in the implementation of .NET, for example in
the System.Type implementation. The ProvidedTypes API can normally be adjusted to account for these.

To help isolate the problem, try the following:

Start with a simple file that uses the type provider and compile it using fsc.exe on Windows. This should succeed.

Now compile the file on Windows using the open source fsc.exe (this will run using .NET). This should succeed (if not, there is a bug in the open source compiler).

Now compile the file on Windows using the open source mono fsc.exe (this will run using Mono). If this fails, then there are differences in Mono vs .NET exposed by the type provider. The type provider can probably be adjusted.

If that succeeded, then try the same command-line compilation on, say, OSX. If this fails then the type provider may not be cross-platform, e.g. may rely on Windows-only functionality. Diagnostics from the type provider may need improving.

If that succeeded, then check if the type provider works from MonoDevelop. If not then the problem is with the MonoDevelop binding (but that is very unlikely because it doesn’t know anything specific about type providers).

Switching to command-line compilations will help localize the problem.