While toying with mixed-language assemblies (e.g. here or here) I came across a couple of bizarre link errors. I am not looking for "don't do that" advice or alternatives, but rather I'd like to understand what these errors are supposed to mean, since neither makes much sense at face value.
C# code:
// csppStub.cs
public static partial class To
{
static partial void Do();
extern public static bool Done();
}
C++ code:
// cspp.cpp
public ref class To abstract sealed
{
// lnk2022 metadata operation failed (801311D6):
// Differing number of methods in duplicated types (To): (0x02000002).
static void Do() { }
// lnk2022 metadata operation failed (801311D8):
// Differing number of parameters in duplicated method (types: To; methods: Done): (0x06000001).
public: static bool Done() { return true; }
};
VS 2015 project file:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectName>cspp</ProjectName>
<ProjectGuid>{A6FF913B-C27A-4CBC-A847-B15CFA7AE80F}</ProjectGuid>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset>
<CLRSupport>true</CLRSupport>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup>
<_ProjectFileVersion>14.0.25123.0</_ProjectFileVersion>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Link>
<AdditionalDependencies>$(OutDir)\csppStub.netmodule;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Windows</SubSystem>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
<ClCompile>
<CompileAsManaged>true</CompileAsManaged>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="cspp.cpp">
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</CompileAsManaged>
<ExceptionHandling Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Async</ExceptionHandling>
</ClCompile>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="csppStub.cs">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">csc /target:module /out:$(OutDir)\csppStub.netmodule csppStub.cs</Command>
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkObjects>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)\csppStub.netmodule</Outputs>
</CustomBuild>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
Build output:
Error LNK2022 metadata operation failed (801311D8): Differing number of parameters in duplicated method (types: To; methods: Done): (0x06000001).
Error LNK2022 metadata operation failed (801311D6): Differing number of methods in duplicated types (To): (0x02000002).
The linker is pretty confounded by what you are trying to do, so its diagnostic is not stellar. A common issue in C++/CLI code is that it may encounter the same ref class declaration in multiple object files. Caused by the #include directive. Not something that ever happens in C#, the partial
keyword is resolved at compile-time.
The linker has to do something about it, it needs to filter down these duplicates to a single definition that it can emit in the metadata. It performs a test to ensure that the class definition are exactly the same. LNK2022 when they are not. Common causes for that is a macro or different compile options.
But in this case the duplicates came from the C# and the C++/CLI declarations. Abandon all hope, that will never be a match. The extern
keyword does not do what you think it does, it is a directive for the jitter and tells it that it needs to find the function elsewhere. Not a lot of other places it knows about, nor is it extensible, limited to functions that the CLR implements, [DllImport] declarations and COM interop.
There is no mechanism at all in metadata that resembles partial
. You'll have to consider getting ahead with the normal boring way you'd do this in .NET, inheritance and polymorphism. The C++/CLI class can use the C# class as its base and the C# class can be abstract
.