Building F# projects on NixOS with mono

Building F# on NixOS might result in Microsoft.FSharp.Targets target file not found. In order to cope with this, locate appropriate version of the Microsoft.FSharp.Targets file first:

1
echo $(dirname $(which fsharpc))/../lib/mono/4.5/Microsoft.FSharp.Targets

You might want to modify the version of mono currently used on your system.

Then just change all of your F# *.fsproj files from having this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<Choose>
  <When Condition="'$(VisualStudioVersion)' == '11.0'">
    <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\           ⟫⟫⟫
      F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
      <FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\       ⟫⟫⟫
        v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
    </PropertyGroup>
  </When>
  <Otherwise>
    <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\      ⟫⟫⟫
      v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
      <FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\                   ⟫⟫⟫
        v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
    </PropertyGroup>
  </Otherwise>
</Choose>
<Import Project="$(FSharpTargetsPath)" />

Please note that ⟫⟫⟫ is there to denote the wrapped line and should never appear in your real code.

To having this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<Choose>
  <When Condition="'$(VisualStudioVersion)' == '11.0'">
    <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\           ⟫⟫⟫
      F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
      <FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\       ⟫⟫⟫
        v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
    </PropertyGroup>
  </When>
  <Otherwise>
    <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\      ⟫⟫⟫
      v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
      <FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\                   ⟫⟫⟫
        v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
    </PropertyGroup>
    <PropertyGroup Condition="Exists('/run/current-system/sw/bin/../lib/mono/4.5/             ⟫⟫⟫
      Microsoft.FSharp.Targets')">
      <FSharpTargetsPath>/run/current-system/sw/bin/../lib/mono/4.5/                          ⟫⟫⟫
        Microsoft.FSharp.Targets</FSharpTargetsPath>
    </PropertyGroup>
  </Otherwise>
</Choose>
<Import Project="$(FSharpTargetsPath)" />

Notice how /run/current-system/sw/bin/../lib/mono/4.5/Microsoft.FSharp.Targets was added to test the path for FSharpTargetsPath variable.

Troubleshooting XBuild errors

In case you see errors like following:

1
2
3
4
/nix/store/l9cf3zbqassjkrcdggdfwr1sy6vjs6y5-mono-4.6.0.182/lib/mono/xbuild/14.0/bin/          ⟫⟫⟫
Microsoft.Common.targets: error : Cannot copy /nix/store/                                     ⟫⟫⟫
2rd3gd0sv7ipmhq4arflcs2zp8hsfj3m-fsharp-4.0.1.1/li b/mono/4.5/FSharp.Core.dll to              ⟫⟫⟫
/home/<user>/<path-to-project>/FSharp.Core.dll, as the source file doesn't exist.

Make sure to remove ~/.config/xbuild as it is the local cache for XBuild that remembers paths to F# libraries which prone to change in case you run nix-collect-garbage -d.