fsprojects / FSharp.Formatting

F# tools for generating documentation (Markdown processor and F# code formatter)
https://fsprojects.github.io/FSharp.Formatting/
Other
462 stars 155 forks source link

Package references cannot be resolved when trying to build API documentation programmatically #833

Closed kMutagene closed 10 months ago

kMutagene commented 10 months ago

Hi there,

I am trying to build API documentation for Plotly.NET programmatically, following the instructions from the docs. However, this fails for every project where there are external dependencies. Here is for example the error for Plotly.NET, which depends on a few packages, one of them bein DynamicObj:

code:

ApiDocs.GenerateHtml(
    inputs = [
        ApiDocInput.FromFile(
            @"C:\Users\schne\source\repos\plotly\Plotly.NET\src\Plotly.NET\bin\Release\netstandard2.0\Plotly.NET.dll"
        )
    ],
    output = @"C:\Users\schne\source\repos\plotly\Plotly.NET\src",
    collectionName = "Plotly.NET",
    substitutions = []
)
Full error ``` loading 1 assemblies... registering entities for assembly Plotly.NET... Error: FSharp.Compiler.DiagnosticsLogger+UnresolvedPathReferenceNoRange: Assembly: DynamicObj, full path: DynamicObj.DynamicObj at FSharp.Compiler.TypedTree.CcuThunk.EnsureDerefable(String[] requiringPath) in D:\a\_work\1\s\src\Compiler\TypedTree\TypedTree.fs:line 5437 at FSharp.Compiler.TypedTree.NonLocalEntityRef.TryDeref(Boolean canError) in D:\a\_work\1\s\src\Compiler\TypedTree\TypedTree.fs:line 3319 at FSharp.Compiler.TypedTree.EntityRef.get_Deref() in D:\a\_work\1\s\src\Compiler\TypedTree\TypedTree.fs:line 3395 at FSharp.Compiler.TypedTreeOps.stripTyEqnsA(TcGlobals g, Boolean canShortcut, TType ty) in D:\a\_work\1\s\src\Compiler\TypedTree\TypedTreeOps.fs:line 764 at FSharp.Compiler.TypedTreeOps.tyargsEnc(TcGlobals g, FSharpList`1 gtpsType, FSharpList`1 gtpsMethod, FSharpList`1 args) in D:\a\_work\1\s\src\Compiler\TypedTree\TypedTreeOps.fs:line 8768 at FSharp.Compiler.TypedTreeOps.typeEnc(TcGlobals g, FSharpList`1 gtpsType, FSharpList`1 gtpsMethod, TType ty) in D:\a\_work\1\s\src\Compiler\TypedTree\TypedTreeOps.fs:line 8741 at FSharp.Compiler.TypedTreeOps.XmlDocArgsEnc(TcGlobals g, FSharpList`1 gtpsType, FSharpList`1 gtpsMethod, FSharpList`1 argTys) in D:\a\_work\1\s\src\Compiler\TypedTree\TypedTreeOps.fs:line 8772 at FSharp.Compiler.TypedTreeOps.XmlDocSigOfVal(TcGlobals g, Boolean full, String path, Val v) in D:\a\_work\1\s\src\Compiler\TypedTree\TypedTreeOps.fs:line 8832 at FSharp.Compiler.InfoReader.GetXmlDocSigOfScopedValRef(TcGlobals g, EntityRef tcref, ValRef vref) in D:\a\_work\1\s\src\Compiler\Checking\InfoReader.fs:line 1105 at FSharp.Compiler.Symbols.FSharpMemberOrFunctionOrValue.get_XmlDocSig() in D:\a\_work\1\s\src\Compiler\Symbols\Symbols.fs:line 2027 at FSharp.Formatting.ApiDocs.CrossReferences.getXmlDocSigForMember(FSharpMemberOrFunctionOrValue memb) in /home/runner/work/FSharp.Formatting/FSharp.Formatting/src/FSharp.Formatting.ApiDocs/GenerateModel.fs:line 707 at FSharp.Formatting.ApiDocs.CrossReferenceResolver.registerMember(FSharpMemberOrFunctionOrValue memb) in /home/runner/work/FSharp.Formatting/FSharp.Formatting/src/FSharp.Formatting.ApiDocs/GenerateModel.fs:line 801 at FSharp.Formatting.ApiDocs.CrossReferenceResolver.registerEntity(FSharpEntity entity) in /home/runner/work/FSharp.Formatting/FSharp.Formatting/src/FSharp.Formatting.ApiDocs/GenerateModel.fs:line 831 at .$GenerateModel.assemblies@2939.Invoke(FSharpEntity arg00) at Microsoft.FSharp.Collections.SeqModule.Iterate[T](FSharpFunc`2 action, IEnumerable`1 source) in D:\a\_work\1\s\src\FSharp.Core\seq.fs:line 602 at FSharp.Formatting.ApiDocs.ApiDocModel.Generate(FSharpList`1 projects, String collectionName, FSharpOption`1 libDirs, FSharpOption`1 otherFlags, Boolean qualify, FSharpOption`1 urlRangeHighlight, String root, FSharpList`1 substitutions, FSharpFunc`2 onError, ApiDocFileExtensions extensions) in /home/runner/work/FSharp.Formatting/FSharp.Formatting/src/FSharp.Formatting.ApiDocs/GenerateModel.fs:line 2939 at FSharp.Formatting.ApiDocs.ApiDocs.GenerateHtml(FSharpList`1 inputs, String output, String collectionName, FSharpList`1 substitutions, FSharpOption`1 template, FSharpOption`1 root, FSharpOption`1 qualify, FSharpOption`1 libDirs, FSharpOption`1 otherFlags, FSharpOption`1 urlRangeHighlight, FSharpOption`1 onError) in /home/runner/work/FSharp.Formatting/FSharp.Formatting/src/FSharp.Formatting.ApiDocs/ApiDocs.fs:line 153 at .$FSI_0025.main@() at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr) ``` I have tried browsing the source code of the command tool for hints how these references can be resolved by the tool, but had no success. Is there a way to make sure these references can be resolved?
nojaf commented 10 months ago

Hello,

I think this might be the same problem as in https://github.com/fsprojects/FSharp.Formatting/issues/616#issuecomment-1200877765.

Could you try and reference the missing dll using the ?otherFlags parameter? Something like otherFlags = [ "-r:MyPath/ToMy/Assembly.dll" ]

kMutagene commented 10 months ago

Hi @nojaf, thanks for the response, I'll give this a spin.

However, the referenced assemblies are not contained in the compilation output, so I guess the standard way is referencing these packages from the nuget cache (i do not use paket)?

kMutagene commented 10 months ago

Adding references the way you suggested works fine, thanks. here is the solution. Note that i used <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> in my .fsproj file so that the dependency dlls are put into the same folder as the compilation output of the library.

I hoped that the references would not be necessary then, because the dependency dlls are in the same folder, but i still have to set the otherFlags option sadly.

ApiDocs.GenerateHtml(
    inputs = [
        ApiDocInput.FromFile(
            @"path\to\bin\Debug\netstandard2.0\Plotly.NET.dll"
        )
    ],
    output = @"C:\Users\schne\source\repos\plotly\Plotly.NET\src",
    collectionName = "Plotly.NET",
    substitutions = [],
    otherFlags = [ 
        @"-r:path\to\bin\Debug\netstandard2.0\Giraffe.ViewEngine.StrongName.dll" 
        @"-r:path\to\bin\Debug\netstandard2.0\DynamicObj.dll"
        @"-r:path\to\bin\Debug\netstandard2.0\Newtonsoft.Json.dll"
    ]
)
kMutagene commented 10 months ago

For future reference, I found that setting libDirs is enough when all dependencies are in one folder:

A combination of <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> in the fsproj file and setting libDirs to the compilation output path leads to only one folder with all dependecies referenced. This might be easier especially for large projects with many dependencies:

ApiDocs.GenerateHtml(
    inputs = [
        ApiDocInput.FromFile(
            @"C:\Users\schne\source\repos\plotly\Plotly.NET\src\Plotly.NET\bin\Debug\netstandard2.0\Plotly.NET.dll"
        )
    ],
    output = @"C:\Users\schne\source\repos\plotly\Plotly.NET\src",
    collectionName = "Plotly.NET",
    substitutions = [],
    libDirs = [ @"C:\Users\schne\source\repos\plotly\Plotly.NET\src\Plotly.NET\bin\Debug\netstandard2.0\"]
)