NuGet/Home

Improvement: Handle platform specific assemblies (x86, x64 etc) with msbuild conditionals

sipsorcery opened this issue · 7 comments

Lots of us are having issues using nuget to package platform specific assemblies (#8435, #1221 etc). The crux of the problem is that while the platform specific artifacts can be packaged with nuget if the assembly reference(s) is platform specific there is no clean way to set it in the consuming project file.

To illustrate the problem my partial nuspec is:

<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
    <metadata>
   ....
    <references>
    <reference file="SIPSorceryMedia.dll" />
      </references>
    </metadata>
    <files>
      <file src="x86\Release\SIPSorceryMedia.dll" target="lib\net47" />
      <file src="SIPSorceryMedia.targets" target="build\SIPSorceryMedia.targets" />
      <file src="SIPSorceryMedia.props" target="build\SIPSorceryMedia.props" />
      <file src="x64\Release\*.dll" target="build\x64" />
      <file src="x86\Release\*.dll" target="build\x86" />
    </files>
</package>

The subsequent reference that ends up in a consuming project files is:

<Reference Include="SIPSorceryMedia, Version=1.1.7192.37613, Culture=neutral, processorArchitecture=x86">
  <HintPath>packages\SIPSorceryMedia.1.7.2\lib\net47\SIPSorceryMedia.dll</HintPath>
</Reference>

I have found no way to be able to override the hint path in that reference with the use of platform specific overrides in a .props or .targets file. For example if msbuild accepted an override on the hint path of the original reference it would be possible to use the example SIPSorceryMedia.props file shown below. Unfortunately it doesn't work.

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Reference Include="SIPSorceryMedia, Version=1.1.7192.37613, Culture=neutral, processorArchitecture=x64" Condition="'$(Platform)' == 'x64' or '$(Platform)' == 'AnyCPU'">
      <HintPath>packages\SIPSorceryMedia.1.7.2\build\x64\SIPSorceryMedia.dll</HintPath>
    </Reference>
  </ItemGroup>
</Project>

But what does work is if the reference inserted into the project file has a platform specific condition:

<Reference Condition="'$(Platform)' == 'x86' Include="SIPSorceryMedia, Version=1.1.7192.37613, Culture=neutral, processorArchitecture=x86">
  <HintPath>packages\SIPSorceryMedia.1.7.2\lib\net47\SIPSorceryMedia.dll</HintPath>
</Reference>

Suggested Improvement

The suggestion is if nuspec file references could be specified as:

<file src="x86\Release\SIPSorceryMedia.dll" target="lib\x86\net47" />
<file src="x64\Release\SIPSorceryMedia.dll" target="lib\x64\net47" />

Then the references could be added to the consuming project as shown below and which builds correctly when the msbuild platform is specified:

<Reference Include="SIPSorceryMedia, Version=1.1.7192.37613, Culture=neutral, processorArchitecture=x86" Condition="'$(Platform)' == 'x86'">
  <HintPath>packages\SIPSorceryMedia.1.7.2\build\x86\SIPSorceryMedia.dll</HintPath>
</Reference>
<Reference Include="SIPSorceryMedia, Version=1.1.7192.37613, Culture=neutral, processorArchitecture=x64" Condition="'$(Platform)' == 'x64'">
  <HintPath>packages\SIPSorceryMedia.1.7.2\build\x64\SIPSorceryMedia.dll</HintPath>
</Reference>

It is possible to build a package like this, that supports Packages.Config and PackageReference scenarios.

Your SIPSorceryMedia.1.0.0.nupkg would have a structure like this:

ref\netstandard2.0\SIPSorceryMedia.dll
runtimes\win-x64\lib\netstandard2.0\SIPSorceryMedia.dll
runtimes\win-x86\lib\netstandard2.0\SIPSorceryMedia.dll
build\netstandard2.0\SIPSorceryMedia.targets

the targets file would be created to handle packages.config scenarios.
It would need to conditionally include one of the runtimes dlls as appropriate.

Related docs:
https://docs.microsoft.com/en-us/dotnet/core/rid-catalog
https://docs.microsoft.com/en-us/nuget/create-packages/supporting-multiple-target-frameworks#architecture-specific-folders

Please let us (@rrelyea and @zivkan) know if you have any problems.

Thanks a lot for the pointers.

the targets file would be created to handle packages.config scenarios. It would need to conditionally include one of the runtimes dlls as appropriate.

That's the problem. I cannot find a way to make assembly reference in the targets/props files override the assembly reference that gets set when the nuget package is installed.

For example installing the nuget package in a consuming project results in the reference being added as below and the only way I have found to override it is the suggestion in my first post.

<Reference Include="SIPSorceryMedia, Version=2.0.1.36269, Culture=neutral, processorArchitecture=x86">
  <HintPath>packages\SIPSorceryMedia.2.0.1\lib\net47\SIPSorceryMedia.dll</HintPath>
</Reference>

I tried the creating the package as per the architecture specific folders reference but that does not seem to do anything useful.

My .nuget package ends up as shown below but the runtime dll's are not copied into the build output directory. Even so that wasn't a problem I was having any way. I am able to use a .targets file to copy the required runtime dll's to the appropriate locations.

The sole problem I'm having is the consuming project compiling against the reference assembly that does not match the build platform. I've not been able to find a way to get the build to use the correct reference assembly at compile time if it does not match the original reference added by the nuget install.

(in the diagram below lib\net47\SIPSorceryMedia.dll is compiled as x86)

nuget

Update: This is the build warning:

1>------ Rebuild All started: Project: WebRtcDaemon, Configuration: Release x64 ------
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(2106,5): warning MSB3270: There was a mismatch between the processor architecture of the project being built "AMD64" and the processor architecture of the reference "SIPSorceryMedia, Version=2.0.0.33779, Culture=neutral, processorArchitecture=x86", "x86". This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project through the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor architecture that matches the targeted processor architecture of your project.
1>  WebRtcDaemon -> C:\Dev\sipsorcery\sipsorcery-public\sipsorcery-media\samples\WebRtcDaemon\x64\Release\WebRTCDaemon.exe
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

At a glance, your attempts in your first post about putting a condition on $(PLATFORM) looks good. Someone would need to do some MSBuild debugging to understand why it didn't work (I recommend using msbuild -bl and open the msbuild.binlog file with https://github.com/KirillOsenkov/MSBuildStructuredLog/releases).

It's unclear to me if the project you're testing with uses packages.config (PC) or PackageReference (PR). If it's a PC project, then the runtimes/ files are not used, it's a new feature for PR.

To work correctly in PR projects, your compile-time assembly should be in ref/.. , not lib/... You can get useful information looking at obj/project.assets.json and checking which assets were selected from your package. To avoid the compiler warning about mismatched architecture, the assembly in ref/ should also be targeting AnyCPU. The C# compiler has a command line parameter (also available as an MSBuild property) to write a reference assembly. My understanding is that this is just like compiling your code but without any method bodies. I don't know if using this will always output an AnyCPU assembly, or if you will need a 3rd architecture target for your project (x86, x64 and AnyCPU).

At a glance, your attempts in your first post about putting a condition on $(PLATFORM) looks good.

Do you mean why the condition for the reference in the .props file didn't take priority over the reference in the main .vcxproj file? I will follow your instructions and see what the build log reveals.

It's unclear to me if the project you're testing with uses packages.config (PC) or PackageReference (PR). If it's a PC project, then the runtimes/ files are not used, it's a new feature for PR.

I'm using a package reference My mistake I am using the packages.config file (is it the only option for .Net Framework project files?). I'm adding my nuget package to a C# .Net 4.7 Console project using the Visual Studio 2019 Package Manager Console:

Package Manager Console Host Version 5.2.0.6090
PM> Install-Package SIPSorceryMedia -Source ..\..\SIPSorcery.Media\nuspec

The C# compiler has a command line parameter (also available as an MSBuild property) to write a reference assembly.

The source assembly is Managed C++. I guess it would be possible to front it with a reference C# assembly but that seems like a lot of overhead.

I spotted this adding-a-packagereference-condition to do with setting a framework condition on a nuget reference. The equivalent condition for a platform seems to be what's missing.

At a glance, your attempts in your first post about putting a condition on $(PLATFORM) looks good. Someone would need to do some MSBuild debugging to understand why it didn't work (I recommend using msbuild -bl and open the msbuild.binlog file with https://github.com/KirillOsenkov/MSBuildStructuredLog/releases).

A screenshot of the binlog analysis is shown below. The only thing I spotted that looked relevant was the DoubleWrites.

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\msbuild.exe -bl /p:Platform=x64 /t:clean,build WebRtcDaemon.sln
Building the projects in this solution one at a time. To enable parallel build, please add the "-m" switch.
Build started 23/09/2019 3:20:29 PM.
Project "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\WebRtcDaemon.sln" on node 1 (clean;build target(s)).
ValidateSolutionConfiguration:
  Building solution configuration "Debug|x64".
Project "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\WebRtcDaemon.sln" (1) is building "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\WebRtcDa
emon.csproj" (2) on node 1 (Clean target(s)).
CoreClean:
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\Media\max_intro.mp4".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\Media\testpattern.jpeg".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\Media\wizard.jpeg".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\Certs\localhost.pem".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\Certs\localhost.pfx".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\Certs\localhost_key.pem".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\avcodec-58.dll".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\avutil-56.dll".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\LIBEAY32.dll".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\SIPSorceryMedia.dll".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\srtp2.dll".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\SSLEAY32.dll".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\swresample-3.dll".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\swscale-5.dll".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\WebRTCDaemon.exe.config".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\WebRTCDaemon.exe".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\WebRTCDaemon.pdb".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\log4net.dll".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\NAudio.dll".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\SIPSorcery.dll".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\websocket-sharp.dll".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\log4net.xml".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\NAudio.xml".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\obj\x64\Debug\WebRtcDaemon.csprojAssemblyReference.cache".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\obj\x64\Debug\WebRtcDaemon.csproj.CoreCompileInputs.cache".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\obj\x64\Debug\WebRtcDaemon.csproj.CopyComplete".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\obj\x64\Debug\WebRTCDaemon.exe".
  Deleting file "C:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\obj\x64\Debug\WebRTCDaemon.pdb".
Done Building Project "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\WebRtcDaemon.csproj" (Clean target(s)).

Project "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\WebRtcDaemon.sln" (1) is building "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\WebRtcDa
emon.csproj" (2:2) on node 1 (default targets).
_HandlePackageFileConflicts:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\Microsoft.NET.Build.Extensions.ConflictResolution.targe
ts(33,5): message NETSDK1041: Encountered conflict between 'Reference:SIPSorceryMedia' and 'Reference:SIPSorceryMedia, Version=2.0.0.33779, Culture=neutral, processor
Architecture=x86'.  NETSDK1033: Choosing 'Reference:SIPSorceryMedia, Version=2.0.0.33779, Culture=neutral, processorArchitecture=x86' because AssemblyVersion '2.0.0.3
3779' is greater than '1.1.7192.14819'. [c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\WebRtcDaemon.csproj]
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\Microsoft.NET.Build.Extensions.ConflictResolution.targe
ts(33,5): message NETSDK1041: Encountered conflict between 'Reference:SIPSorceryMedia' and 'Reference:SIPSorceryMedia, Version=2.0.0.33779, Culture=neutral, processor
Architecture=x86'.  NETSDK1033: Choosing 'Reference:SIPSorceryMedia, Version=2.0.0.33779, Culture=neutral, processorArchitecture=x86' because AssemblyVersion '2.0.0.3
3779' is greater than '1.1.7192.14819'. [c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\WebRtcDaemon.csproj]
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(2106,5): warning MSB3270: There was a mismat
ch between the processor architecture of the project being built "AMD64" and the processor architecture of the reference "SIPSorceryMedia, Version=2.0.0.33779, Cultur
e=neutral, processorArchitecture=x86", "x86". This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project t
hrough the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor a
rchitecture that matches the targeted processor architecture of your project. [c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\WebRtcDaemon.csproj]
GenerateBindingRedirects:
  No suggested binding redirects from ResolveAssemblyReferences.
GenerateTargetFrameworkMonikerAttribute:
Skipping target "GenerateTargetFrameworkMonikerAttribute" because all output files are up-to-date with respect to the input files.
CoreCompile:
  C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Roslyn\csc.exe /noconfig /unsafe+ /nowarn:1701,1702 /nostdlib+ /platform:x64 /erro
  rreport:prompt /define:DEBUG;TRACE /highentropyva+ /reference:c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\log4net.2.0.8\lib\net45-full\log4net
  .dll /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\Microsoft.CSharp.dll" /reference:"C:\Program Files (x86)\Refer
  ence Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\mscorlib.dll" /reference:c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\NAudio.1.9.0\lib
  \net35\NAudio.dll /reference:c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\SIPSorcery.3.0.1\lib\netstandard2.0\SIPSorcery.dll /reference:c:\Dev\
  sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\SIPSorceryMedia.2.0.0\lib\net47\SIPSorceryMedia.dll /reference:"C:\Program Files (x86)\Reference Assembli
  es\Microsoft\Framework\.NETFramework\v4.7.2\System.Configuration.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7
  .2\System.Configuration.Install.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Core.dll" /reference:"C
  :\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Fr
  amework\.NETFramework\v4.7.2\System.Drawing.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.ServiceProc
  ess.dll" /reference:c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\WebSocketSharpFork.1.0.4.0\lib\net35\websocket-sharp.dll /reference:"C:\Progra
  m Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\Facades\netstandard.dll" /debug+ /debug:full /filealign:512 /out:obj\x64\Debug\WebRTCDae
  mon.exe /ruleset:"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Team Tools\Static Analysis Tools\\Rule Sets\MinimumRecommendedRules.ruleset" /subsys
  temversion:6.00 /target:exe /utf8output AppState.cs WebRTCDaemon.cs Program.cs Properties\AssemblyInfo.cs WebRTCService.cs WebRTCServiceInstaller.cs WebRtcSession.c
  s "C:\Users\aaron\AppData\Local\Temp\.NETFramework,Version=v4.7.2.AssemblyAttributes.cs"
  Using shared compilation with compiler from directory: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Roslyn
_CopyFilesMarkedCopyLocal:
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\WebSocketSharpFork.1.0.4.0\lib\net35\websocket-sharp.dll" to "c:\Dev\sipsorcery
  \sipsorcery-media\examples\WebRtcDaemon\x64\Debug\websocket-sharp.dll".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\SIPSorceryMedia.2.0.0\lib\net47\SIPSorceryMedia.dll" to "c:\Dev\sipsorcery\sips
  orcery-media\examples\WebRtcDaemon\x64\Debug\SIPSorceryMedia.dll".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\log4net.2.0.8\lib\net45-full\log4net.dll" to "c:\Dev\sipsorcery\sipsorcery-medi
  a\examples\WebRtcDaemon\x64\Debug\log4net.dll".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\SIPSorcery.3.0.1\lib\netstandard2.0\SIPSorcery.dll" to "c:\Dev\sipsorcery\sipso
  rcery-media\examples\WebRtcDaemon\x64\Debug\SIPSorcery.dll".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\log4net.2.0.8\lib\net45-full\log4net.xml" to "c:\Dev\sipsorcery\sipsorcery-medi
  a\examples\WebRtcDaemon\x64\Debug\log4net.xml".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\NAudio.1.9.0\lib\net35\NAudio.dll" to "c:\Dev\sipsorcery\sipsorcery-media\examp
  les\WebRtcDaemon\x64\Debug\NAudio.dll".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\NAudio.1.9.0\lib\net35\NAudio.xml" to "c:\Dev\sipsorcery\sipsorcery-media\examp
  les\WebRtcDaemon\x64\Debug\NAudio.xml".
  Creating "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\obj\x64\Debug\WebRtcDaemon.csproj.CopyComplete" because "AlwaysCreate" was specified.
_CopyOutOfDateSourceItemsToOutputDirectory:
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\Media\wizard.jpeg" to "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debu
  g\Media\wizard.jpeg".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\Media\max_intro.mp4" to "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\De
  bug\Media\max_intro.mp4".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\Certs\localhost_key.pem" to "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x6
  4\Debug\Certs\localhost_key.pem".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\Media\testpattern.jpeg" to "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64
  \Debug\Media\testpattern.jpeg".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\Certs\localhost.pfx" to "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\De
  bug\Certs\localhost.pfx".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\Certs\localhost.pem" to "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\De
  bug\Certs\localhost.pem".
_CopyOutOfDateSourceItemsToOutputDirectoryAlways:
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\SIPSorceryMedia.2.0.0\build\x64\avutil-56.dll" to "c:\Dev\sipsorcery\sipsorcery
  -media\examples\WebRtcDaemon\x64\Debug\avutil-56.dll".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\SIPSorceryMedia.2.0.0\build\x64\SIPSorceryMedia.dll" to "c:\Dev\sipsorcery\sips
  orcery-media\examples\WebRtcDaemon\x64\Debug\SIPSorceryMedia.dll".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\SIPSorceryMedia.2.0.0\build\x64\LIBEAY32.dll" to "c:\Dev\sipsorcery\sipsorcery-
  media\examples\WebRtcDaemon\x64\Debug\LIBEAY32.dll".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\SIPSorceryMedia.2.0.0\build\x64\avcodec-58.dll" to "c:\Dev\sipsorcery\sipsorcer
  y-media\examples\WebRtcDaemon\x64\Debug\avcodec-58.dll".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\SIPSorceryMedia.2.0.0\build\x64\SSLEAY32.dll" to "c:\Dev\sipsorcery\sipsorcery-
  media\examples\WebRtcDaemon\x64\Debug\SSLEAY32.dll".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\SIPSorceryMedia.2.0.0\build\x64\srtp2.dll" to "c:\Dev\sipsorcery\sipsorcery-med
  ia\examples\WebRtcDaemon\x64\Debug\srtp2.dll".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\SIPSorceryMedia.2.0.0\build\x64\swresample-3.dll" to "c:\Dev\sipsorcery\sipsorc
  ery-media\examples\WebRtcDaemon\x64\Debug\swresample-3.dll".
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\packages\SIPSorceryMedia.2.0.0\build\x64\swscale-5.dll" to "c:\Dev\sipsorcery\sipsorcery
  -media\examples\WebRtcDaemon\x64\Debug\swscale-5.dll".
_CopyAppConfigFile:
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\App.config" to "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\WebRT
  CDaemon.exe.config".
CopyFilesToOutputDirectory:
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\obj\x64\Debug\WebRTCDaemon.exe" to "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDa
  emon\x64\Debug\WebRTCDaemon.exe".
  WebRtcDaemon -> c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\x64\Debug\WebRTCDaemon.exe
  Copying file from "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\obj\x64\Debug\WebRTCDaemon.pdb" to "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDa
  emon\x64\Debug\WebRTCDaemon.pdb".
Done Building Project "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\WebRtcDaemon.csproj" (default targets).

Done Building Project "c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\WebRtcDaemon.sln" (clean;build target(s)).

Deferred Messages

  Detailed Build Summary
  ======================


  ============================== Build Hierarchy (IDs represent configurations) =====================================================
  Id                  : Exclusive Time   Total Time   Path (Targets)
  -----------------------------------------------------------------------------------------------------------------------------------
  0                   : 0.054s           0.688s       c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\WebRtcDaemon.sln (clean, build)
  | 1                 : 0.198s           0.198s       c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\WebRtcDaemon.csproj (Clean)
  . 2                 : 0.436s           0.436s       c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\WebRtcDaemon.csproj ()

  ============================== Node Utilization (IDs represent configurations) ====================================================
  Timestamp:            1        Duration   Cumulative
  -----------------------------------------------------------------------------------------------------------------------------------
  637048416292127892:   0        0.048s     0.048s
  637048416292607882:   1        0.198s     0.246s ...
  637048416294587841:   0        0.002s     0.248s
  637048416294608102:   2        0.436s     0.684s ........
  637048416298967843:   0        0.004s     0.688s
  -----------------------------------------------------------------------------------------------------------------------------------
  Utilization:          100.0    Average Utilization: 100.0

Build succeeded.

"c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\WebRtcDaemon.sln" (clean;build target) (1) ->
"c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\WebRtcDaemon.csproj" (default target) (2:2) ->
(ResolveAssemblyReferences target) ->
  C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(2106,5): warning MSB3270: There was a mism
atch between the processor architecture of the project being built "AMD64" and the processor architecture of the reference "SIPSorceryMedia, Version=2.0.0.33779, Cult
ure=neutral, processorArchitecture=x86", "x86". This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project
 through the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor
 architecture that matches the targeted processor architecture of your project. [c:\Dev\sipsorcery\sipsorcery-media\examples\WebRtcDaemon\WebRtcDaemon.csproj]

    1 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.81

binlog_analysis

Do you mean why the condition for the reference in the .props file didn't take priority over the reference in the main .vcxproj file? I will follow your instructions and see what the build log reveals.

I just meant that MSBuild supports skipping over XML elements when the condition evaluates to false. So the concept of having two <Reference elements, one pointing to the x86 dll and the other to the x64 dll, and using only one of them by using conditions, that's a conceptually sound idea. The syntax looked about right, so I wouldn't have been surprised if it worked.

Perhaps the issue is that $(Platform) isn't defined at MSBuild evaluation time, so both == 'x86' and == 'x64' evaluate to false. You can check the evaluation properties to see if that property is defined or not, and if so, what it's value is. If it's not defined, it might only get defined when running a target, in which case you'll need add the reference in a target, rather than a "global" property. The binlog viewer has a search to make it quick to find.

My mistake I am using the packages.config file

Then only option is to include a MSBuild props and/or targets file in your package, and do whatever is needed in there.

edit: I forgot to mention that you should not have any dlls in lib/ in this case. This will avoid the double-writes, and ensure that any reference added by your MSBuild props/targets file will be used.

is it the only option for .Net Framework project files?

For C++ projects, yes, it's the only option. For C#/VB.NET/F# SDK style projects, only PackageReference works, packages.config is not an option. For C#/VB.NET (and possibly F#) projects using non-SDK style projects, it's possible to choose. See the NuGet-General options in Tools-Options for the default and option to prompt on first package install.

@zivkan thanks to all your suggestions I was finally able to construct my nuget package so consuming projects build without warnings and get the correct native dll's copied to the output directory. The main thing was not to put anything in the nuget package's lib directory.

I've pasted the .nuspec, .props and .targets files below for the many others attempting the same thing:

.nuspec

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
  <metadata>
    <id>SIPSorceryMedia</id>
    <version>3.0.0</version>
	<title>SIPSorceryMedia</title>
    <authors>Aaron Clauson</authors>
    <owners>Aaron Clauson</owners>
	<requireLicenseAcceptance>false</requireLicenseAcceptance>
    <license type="expression">BSD-3-Clause</license>
    <projectUrl>https://www.sipsorcery.com/</projectUrl>
    <iconUrl>http://www.sipsorcery.com/mainsite/favicon.ico</iconUrl>
    <description>The SIPSorcery package for audio and video capabiltities.</description>
	<releaseNotes>Tweaked nuget package to remove build warnings due to mismatched platform reference.</releaseNotes>
    <copyright>Copyright (c) 2019, Aaron Clauson</copyright>
    <language>en-US</language>
    <tags>WebRtc MediaFoundation</tags>
	<repository type="git" url="https://github.com/sipsorcery/sipsorcery-media" branch="master" />
  </metadata>
  <files>
    <file src="SIPSorceryMedia.targets" target="build\SIPSorceryMedia.targets" />
    <file src="SIPSorceryMedia.props" target="build\SIPSorceryMedia.props" />
    <file src="..\x64\Release\*.dll" target="build\x64" />
    <file src="..\x86\Release\*.dll" target="build\x86" />
  </files>
</package>

.props

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Reference Include="SIPSorceryMedia" Condition="'$(Platform)' == 'x64' or '$(Platform)' == 'AnyCPU'">
		<HintPath>$(MSBuildThisFileDirectory)\..\build\x64\SIPSorceryMedia.dll</HintPath>
    </Reference>
	<Reference Include="SIPSorceryMedia" Condition="'$(Platform)' == 'x86'">
		<HintPath>$(MSBuildThisFileDirectory)\..\build\x86\SIPSorceryMedia.dll</HintPath>
    </Reference>
  </ItemGroup>
</Project>

.targets

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <NativeLibs Include="$(MSBuildThisFileDirectory)\..\build\x86\*.dll" Condition="'$(Platform)' == 'x86'" />
    <NativeLibs Include="$(MSBuildThisFileDirectory)\..\build\x64\*.dll" Condition="'$(Platform)' == 'x64' or '$(Platform)' == 'AnyCPU'" />
    <ContentWithTargetPath Include="@(NativeLibs)">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
      <TargetPath>%(Filename)%(Extension)</TargetPath>
    </ContentWithTargetPath>
  </ItemGroup>
</Project>