Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CopyRefAssembly Could not extract the MVID from reference assembly #13216

Closed
nojaf opened this issue May 31, 2022 · 7 comments · Fixed by #13266
Closed

CopyRefAssembly Could not extract the MVID from reference assembly #13216

nojaf opened this issue May 31, 2022 · 7 comments · Fixed by #13266
Labels
Area-Build Everything related to building F# compiler, tooling and VS extension. Feature Improvement

Comments

@nojaf
Copy link
Contributor

nojaf commented May 31, 2022

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,

https://github.com/dotnet/roslyn/blob/b7838e90db7c7f1de309f8ef314e0aa8bfc6dab1/src/Compilers/Core/MSBuildTask/CopyRefAssembly.cs#L56

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.

https://github.com/dotnet/roslyn/blob/b7838e90db7c7f1de309f8ef314e0aa8bfc6dab1/src/Compilers/Core/MSBuildTask/MvidReader.cs#L90-L137

This entire section could be added around

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

//cc @dsyme @vzarytovskii @baronfel @jaredpar

@nojaf nojaf added the Bug label May 31, 2022
@vzarytovskii
Copy link
Member

Yeah, we probably should start emitting it as part of our work of FSharp.Build support of refassemblies.

@vzarytovskii vzarytovskii added Feature Improvement Area-Build Everything related to building F# compiler, tooling and VS extension. and removed Bug labels May 31, 2022
@jaredpar
Copy link
Member

Yeah, we probably should start emitting it as part of our work of FSharp.Build support of refassemblies.

Agree. The code in CopyRefAssembly is pretty standard for reading an MVID from a PE file. If this task is erroring then likely many other tools in the .NET ecosystem will similarly fail to read the F# ref assembly.

@KevinRansom
Copy link
Member

The MVIDsection is simply a build performance optimization for dotnet builds. It is not standard and very few if no other tools than copyrefassembly will expect it. It was added to roslyn to simplify the deterministic replacement of assemblies.

The PR that added it is here: dotnet/roslyn#19133

We will add the MVID section to F# reference assemblies to ensure that Projects that depend on F# reference assemblies can build and consume them correctly.

It should be noted that it is not required for reference assemblies to have this section, merely reference assemblies that are created and consumed during the build.

Kevin

@nojaf
Copy link
Contributor Author

nojaf commented Jun 1, 2022

Thanks all for clarifying this. I'd like to take a stab at adding the .mvid section.
Although, I'm not in Kansas anymore. Any pointers would be much appreciated.

@KevinRansom
Copy link
Member

It's just a PE file, there is nothing interesting to learn about doing it. I will do it, since I just suffered through figuring it out for the Arm64 stuff.

@nojaf
Copy link
Contributor Author

nojaf commented Jun 1, 2022

Fine by me 😸, thanks Kevin!

@KevinRansom
Copy link
Member

Ref assembly referencing works fine on the preview4 of net 6.0. It only seems to fail on net 7.0. I suppose that's when the build optimization was introduced.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Build Everything related to building F# compiler, tooling and VS extension. Feature Improvement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants