Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions docs/features/refout.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ The `CoreCompile` target supports a new output, called `IntermediateRefAssembly`
The `Csc` task supports a new output, called `OutputRefAssembly`, which parallels the existing `OutputAssembly`.
Both of those basically map to the `/refout` command-line parameter.

An additional task, called `CopyRefAssembly`, is provided along with the existing `Csc` task. It takes a `SourcePath` and a `DestinationPath` and generally copies the file from the source over to the destination. But if it can determine that the contents of those two files match (by comparing their MVIDs, see details below), then the destination file is left untouched.
An additional task, called `CopyRefAssembly`, is provided along with the existing `Csc` task. It takes a `SourcePath` and a `DestinationPath` and generally copies the file from the source over to the destination. But if it can determine that the contents of those two files match (by comparing their MVIDs), then the destination file is left untouched.

As a side-note, `CopyRefAssembly` uses the same assembly resolution/redirection trick as `Csc` and `Vbc`, to avoid type loading problems with `System.IO.FileSystem`.

Expand All @@ -68,7 +68,6 @@ With C# 7.1, the compiler now honours the `EmitOptions.IncludePrivateMembers` fl
Method bodies aren't compiled when using `EmitMetadataOnly`. Even the diagnostic check for emitting methods lacking a body (`void M();`) is filtered from declaration diagnostics, so such code will successfully emit with `EmitMetadataOnly`.

Later on, the `EmitOptions.TolerateErrors` flag will allow emitting error types as well.
`Emit` was modified to produce a new PE section called ".mvid" containing a copy of the MVID, when emitting ref assemblies. This makes it easy for `CopyRefAssembly` to extract and compare MVIDs from ref assemblies.

Going back to the 4 driving scenarios:
1. For a regular compilation, `EmitMetadataOnly` is left to `false` and no `metadataPeStream` is passed into `Emit`.
Expand Down
122 changes: 0 additions & 122 deletions src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -573,11 +573,9 @@ internal static void Main()

verifyEntryPoint(output, expectZero: false);
VerifyMethods(output, "C", new[] { "void C.Main()", "C..ctor()" });
VerifyMvid(output, hasMvidSection: false);

verifyEntryPoint(metadataOutput, expectZero: false);
VerifyMethods(metadataOutput, "C", new[] { "void C.Main()", "C..ctor()" });
VerifyMvid(metadataOutput, hasMvidSection: true);
}

void verifyEntryPoint(MemoryStream stream, bool expectZero)
Expand All @@ -588,110 +586,6 @@ void verifyEntryPoint(MemoryStream stream, bool expectZero)
}
}

private class TestResourceSectionBuilder : ResourceSectionBuilder
{
public TestResourceSectionBuilder()
{
}

protected override void Serialize(BlobBuilder builder, SectionLocation location)
{
builder.WriteInt32(0x12345678);
builder.WriteInt32(location.PointerToRawData);
builder.WriteInt32(location.RelativeVirtualAddress);
}
}

private class TestPEBuilder : ManagedPEBuilder
{
public static readonly Guid s_mvid = Guid.Parse("a78fa2c3-854e-42bf-8b8d-75a450a6dc18");

public TestPEBuilder(PEHeaderBuilder header,
MetadataRootBuilder metadataRootBuilder,
BlobBuilder ilStream,
ResourceSectionBuilder nativeResources)
: base(header, metadataRootBuilder, ilStream, nativeResources: nativeResources)
{
}

protected override ImmutableArray<Section> CreateSections()
{
return base.CreateSections().Add(
new Section(".mvid", SectionCharacteristics.MemRead |
SectionCharacteristics.ContainsInitializedData |
SectionCharacteristics.MemDiscardable));
}

protected override BlobBuilder SerializeSection(string name, SectionLocation location)
{
if (name.Equals(".mvid", StringComparison.Ordinal))
{
var sectionBuilder = new BlobBuilder();
sectionBuilder.WriteGuid(s_mvid);
return sectionBuilder;
}

return base.SerializeSection(name, location);
}
}

[Fact]
public void MvidSectionNotFirst()
{
var ilBuilder = new BlobBuilder();
var metadataBuilder = new MetadataBuilder();

var peBuilder = new TestPEBuilder(
PEHeaderBuilder.CreateLibraryHeader(),
new MetadataRootBuilder(metadataBuilder),
ilBuilder,
nativeResources: new TestResourceSectionBuilder());

var peBlob = new BlobBuilder();
peBuilder.Serialize(peBlob);

var peStream = new MemoryStream();
peBlob.WriteContentTo(peStream);

peStream.Position = 0;
using (var peReader = new PEReader(peStream))
{
AssertEx.Equal(new[] { ".text", ".rsrc", ".reloc", ".mvid" },
peReader.PEHeaders.SectionHeaders.Select(h => h.Name));

peStream.Position = 0;
var mvid = BuildTasks.MvidReader.ReadAssemblyMvidOrEmpty(peStream);
Assert.Equal(TestPEBuilder.s_mvid, mvid);
}
}

/// <summary>
/// Extract the MVID using two different methods (PEReader and MvidReader) and compare them.
/// We only expect an .mvid section in ref assemblies.
/// </summary>
private void VerifyMvid(MemoryStream stream, bool hasMvidSection)
{
stream.Position = 0;
using (var reader = new PEReader(stream))
{
var metadataReader = reader.GetMetadataReader();
Guid mvidFromModuleDefinition = metadataReader.GetGuid(metadataReader.GetModuleDefinition().Mvid);

stream.Position = 0;
var mvidFromMvidReader = BuildTasks.MvidReader.ReadAssemblyMvidOrEmpty(stream);

Assert.NotEqual(Guid.Empty, mvidFromModuleDefinition);
if (hasMvidSection)
{
Assert.Equal(mvidFromModuleDefinition, mvidFromMvidReader);
}
else
{
Assert.Equal(Guid.Empty, mvidFromMvidReader);
}
}
}

[Fact]
public void EmitRefAssembly_PrivatePropertySetter()
{
Expand All @@ -713,8 +607,6 @@ public class C
VerifyMethods(output, "C", new[] { "System.Int32 C.<PrivateSetter>k__BackingField", "System.Int32 C.PrivateSetter.get", "void C.PrivateSetter.set",
"C..ctor()", "System.Int32 C.PrivateSetter { get; private set; }" });
VerifyMethods(metadataOutput, "C", new[] { "System.Int32 C.PrivateSetter.get", "C..ctor()", "System.Int32 C.PrivateSetter { get; }" });
VerifyMvid(output, hasMvidSection: false);
VerifyMvid(metadataOutput, hasMvidSection: true);
}
}

Expand Down Expand Up @@ -1218,20 +1110,6 @@ private static void CompareAssemblies(string sourceTemplate, string change1, str
{
AssertEx.NotEqual(image1.GetBuffer(), image2.GetBuffer(), message: $"Expecting difference for includePrivateMembers={includePrivateMembers} case, but they matched.");
}

var mvid1 = BuildTasks.MvidReader.ReadAssemblyMvidOrEmpty(image1);
var mvid2 = BuildTasks.MvidReader.ReadAssemblyMvidOrEmpty(image2);

if (!includePrivateMembers)
{
Assert.NotEqual(Guid.Empty, mvid1);
Assert.Equal(expectMatch, mvid1 == mvid2);
}
else
{
Assert.Equal(Guid.Empty, mvid1);
Assert.Equal(Guid.Empty, mvid2);
}
}

#if NET472
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@
<ProjectReference Include="..\..\..\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj" />
<ProjectReference Include="..\..\Portable\Microsoft.CodeAnalysis.CSharp.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\Core\MSBuildTask\MvidReader.cs">
<Link>Emit\MvidReader.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" />
<PackageReference Include="Microsoft.DiaSymReader" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@
<ProjectReference Include="..\..\..\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj" />
<ProjectReference Include="..\..\Portable\Microsoft.CodeAnalysis.CSharp.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\Core\MSBuildTask\MvidReader.cs">
<Link>Emit\MvidReader.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" />
<PackageReference Include="Microsoft.DiaSymReader" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@
<ProjectReference Include="..\..\..\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj" />
<ProjectReference Include="..\..\Portable\Microsoft.CodeAnalysis.CSharp.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\Core\MSBuildTask\MvidReader.cs">
<Link>Emit\MvidReader.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" />
<PackageReference Include="Microsoft.DiaSymReader" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@
<ProjectReference Include="..\..\..\Test\Utilities\CSharp\Microsoft.CodeAnalysis.CSharp.Test.Utilities.csproj" />
<ProjectReference Include="..\..\..\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj" />
<ProjectReference Include="..\..\Portable\Microsoft.CodeAnalysis.CSharp.csproj" />
<Compile Include="..\..\..\Core\MSBuildTask\MvidReader.cs">
<Link>Emit\MvidReader.cs</Link>
</Compile>
<PackageReference Include="Microsoft.CSharp" />
<PackageReference Include="Microsoft.DiaSymReader" />
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
Expand Down
8 changes: 6 additions & 2 deletions src/Compilers/Core/MSBuildTask/CopyRefAssembly.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

using System;
using System.IO;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

Expand Down Expand Up @@ -96,11 +98,13 @@ private bool Copy()
return true;
}

private Guid ExtractMvid(string path)
private static Guid ExtractMvid(string path)
{
using (FileStream source = File.OpenRead(path))
using (PEReader reader = new PEReader(source))
{
return MvidReader.ReadAssemblyMvidOrEmpty(source);
var metadataReader = reader.GetMetadataReader();
return metadataReader.GetGuid(metadataReader.GetModuleDefinition().Mvid);
}
}
}
Expand Down
1 change: 0 additions & 1 deletion src/Compilers/Core/MSBuildTask/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
<Compile Include="$(MSBuildThisFileDirectory)ManagedCompiler.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ManagedToolTask.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MapSourceRoots.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MvidReader.cs" />
<Compile Include="$(MSBuildThisFileDirectory)PropertyDictionary.cs" />
<Compile Include="$(MSBuildThisFileDirectory)RCWForCurrentContext.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ShowMessageForImplicitlySkipAnalyzers.cs" />
Expand Down
Loading
Loading