-
Notifications
You must be signed in to change notification settings - Fork 830
Description
Following up on #12334, I've noticed that a project B (csproj) cannot consume a reference assembly of a project A (fsproj) because the mvid cannot be read from the assembly.
Project structure:
A.fsproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<DotnetFscCompilerPath>C:\Users\nojaf\Projects\fsharp\artifacts\bin\fsc\Debug\net6.0\fsc.dll</DotnetFscCompilerPath>
<OtherFlags>--refout:obj\Debug\net7.0\refint\A.dll</OtherFlags>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
</PropertyGroup>
<ItemGroup>
<Compile Include="Library.fs" />
</ItemGroup>
</Project>
B.csproj
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\A\A.fsproj" />
</ItemGroup>
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
</PropertyGroup>
</Project>
Expected behavior
dotnet build of B.csproj will find the reference assembly of project A that was specified using the refout flag.
Actual behavior
In the MSBuild log we saw the following:
Could not extract the MVID from "obj\Debug\net7.0\refint\A.dll". Are you sure it is a reference assembly?
This warning was logged by CopyRefAssembly,
The main problem is that the mvid guid is empty.
The current Number of Sections inside the COFF Header is 3, whereas compared to a C# reference assembly this is 4. The .mvid section is missing from the F# generation.
The MSBuild task uses this section to read that guid.
This entire section could be added around
fsharp/src/Compiler/AbstractIL/ilwrite.fs
Lines 3884 to 3886 in 36af364
| let numSections = | |
| if hasEntryPointStub then 3 // .text, .sdata, .reloc | |
| else 2 // .text, .sdata |
Similar to .text, .sdata, .reloc I would assume. Conditional logic could be implemented using options.referenceAssemblyOnly.
Known workarounds
Besides adding the additional section, it is possible to extract the guid currently from the Module metadata table.
We were able to read it using:
#r "nuget: System.Reflection.Metadata"
open System.IO
open System.Reflection.PortableExecutable
let refDll = @"C:\Users\nojaf\Projects\reference-assemblies-sample\A\obj\Debug\net7.0\refint\A.dll"
let embeddedReader = new PEReader(File.OpenRead refDll)
let sourceReader = embeddedReader.GetMetadataReader()
let loc = sourceReader.GetModuleDefinition().Mvid
let mvid = sourceReader.GetGuid(loc)So, from a certain point of view, the mvid is there. Just not in the way that CopyRefAssembly reads it.
Related information
Provide any related information (optional):
- Operating system: Win11
- .NET Runtime kind: .NET 7 preview 4
- local compiler, main at 5b1a3ae