Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# assembly references causing build issues?

We have an F# assembly (AssemblyOne) that references another F# assembly (AssemblyTwo) in a single Visual Studio 2012 solution. AssemblyTwo has a reference to a C# DLL (MyCSharpLib).

A function defined in AssemblyOne calls a function defined in AssemblyTwo:

namespace AssemblyOne

[<RequireQualifiedAccess>]
module MyModuleA =
    let FetchResult id =
        let result = AssemblyTwo.MyModuleC.FetchResult id
        result

The function called in AssemblyTwo calls another function (FetchActualResult()) in the same assembly that takes a parameter of type MyCSharpType that belongs to the referenced C# DLL (MyCSharpLib):

namespace AssemblyTwo

[<RequireQualifiedAccess>]
module MyModuleB  =
    let FetchActualResult(myCSharpType:MyCSharpLib.MyCSharpType, id:int)
        //return a result

[<RequireQualifiedAccess>]
module MyModuleC =
    let FetchResult id =
        let myCSharpType = new MyCSharpLib.MyCSharpType()
        MyModuleB.FetchActualResult(myCSharpType, id)

The solution compiles and builds in Visual Studio; however, when we try to build the project from the command line using MSBuild, the build fails, with the following error in the msbuild.log:

error FS0074: The type referenced through 'MyCSharpLib' is defined in an assembly that is not referenced. You must add a reference to assembly 'MyCSharpLib'.

It appears the type exposed as a parameter from MyCSharpLib in the FetchActualResult() function signature in AssemblyTwo is causing the error. AssemblyOne now needs a reference to MyCSharpLib, even though AssemblyOne does not directly use anything from MyCSharpLib. If we remove the parameter from the function signature the solution builds with no errors.

We have further explored this problem by replicating the code with the following use cases ('->' indicates assembly reference):

  • F# AssemblyOne -> F# AssemblyTwo -> MyCSharpLib (C# DLL) (does not build)
  • F# AssemblyOne -> F# AssemblyTwo -> MyFSharpLib (F# DLL) (does not build)
  • F# AssemblyOne -> F# AssemblyTwo -> C# AssemblyThree (assembly in same solution) (does not build)
  • F# AssemblyOne -> F# AssemblyTwo -> F# AssemblyThree (assembly in same solution) (builds)

Can this behaviour be explained?

like image 936
daithimurf Avatar asked Feb 01 '16 10:02

daithimurf


1 Answers

Assuming that there is a typo in your sources as DWright pointed out, I'd say that this error may arise just from the fact that by this code you define a static class MyModuleB with exposed method parameter of an external type MyCsharpType.

This is how the Fsharp code translates to IL (from ILSpy - retranslated to Csharp):

...
public static class MyModuleB
{
    public static string FetchActualResult(MyCSharpType myCSharpType, int id)
    {
        return myCSharpType.Fetch(id);
    }
}

If you don't expose the type so that it's statically visible, the error might not appear. This, however, would depend on the implementation of the compiler.

I can imagine, that during compilation of MyModuleA, one configuration of compilation process or version of compiler can try to "touch" MyModuleB, and thus try to reach the unreferenced parameter type, and other might just not touch MyModuleB. It depends.

So the problem seems to me being not in the compilation process, but in the fact, that you expose usage of a type for which you don't reference its assembly.

like image 187
LubosTomsa Avatar answered Sep 29 '22 12:09

LubosTomsa