-
Notifications
You must be signed in to change notification settings - Fork 564
Description
The original motivation for this investigation was #2534. That exact example of the problem was resolved another way in the Xamarin.Android version included with Visual Studio 2019 Preview 2. (The problematic System.Memory NuGet package was already scheduled to be imported into the Mono base class libraries, so the latest Xamarin.Android now provides its own System.Memory.dll facade assembly, circumventing the NuGet package problem. On top of that, the latest System.Memory NuGet package version 4.5.2 switched away from using the problematic exclude="Compile" attribute in the .nuspec file.)
But the general problem remains, and it could affect other NuGet packages in the future if the usage of reference assemblies in NuGet packages becomes more common.
Steps to Reproduce
-
Unzip the attached test case.
-
Change directory in a Developer Command Prompt into the NugetExcludeCompile\AndroidApp1 directory.
-
Attempt to build the project, restoring the custom NuGet packages along the way:
msbuild -restore -p:RestoreSources=..\packages
Expected Behavior
The project builds successfully. Also, building the SignAndroidPackage target should produce an APK that includes the full (not the reference assembly) version of NetStandardLibrary1.dll. That way, when the app runs on device or emulator, the new NetStandardLibrary2.Class1 () statement will complete without error.
The included NetCoreConsoleApp1 and NetFrameworkConsoleApp1 projects demonstrate the expected behavior.
Actual Behavior
The build fails during the ResolveAssemblies task:
"C:\Temp\NugetExcludeCompile\AndroidApp1\AndroidApp1.csproj" (default target) (1:7) ->
(_ResolveAssemblies target) ->
C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Xamarin\Android\Xamarin.Android.Common.targets(1925,2): error XA2002: Can not resolve reference: `NetStandardLibrary1`, referenced by `NetStandardLibrary2`. Please add a NuGet package or assembly reference for `NetStandardLibrary1`, or remove the reference to `NetStandardLibrary2`.Investigation
The problem is that ResolveAssemblies does not look up the NetStandardLibrary1.dll dependency of NetStandardLibrary2.dll using the runtime entry from the obj\project.assets.json file. This isn't a problem for most NuGet packages because the compile entry in obj\project.assets.json causes the assembly dependency to be included directly in the FilteredAssemblies item. But with this test case, the NuGet restore process has correctly set the compile entry to the _._ placeholder value:
"Contoso.Test.NetStandardLibrary1/0.1.1": {
"type": "package",
"compile": {
"ref/netstandard2.0/_._": {}
},
"runtime": {
"lib/netstandard2.0/NetStandardLibrary1.dll": {}
}
},Why is the _._ placeholder value correct?
It is correct because NetStandardLibrary2\Contoso.Test.NetStandardLibrary2.nuspec file uses the exclude="Compile" attribute to specify that Contoso.Test.NetStandardLibrary1 is not a compile dependency for projects consuming Contoso.Test.NetStandardLibrary2:
<dependencies>
<dependency id="Contoso.Test.NetStandardLibrary1" version="0.1.1" exclude="Compile" />
</dependencies>Is it valid for the .nuspec file to use exclude="Compile" for Contoso.Test.NetStandardLibrary1?
I believe so, yes. The Csc task does not require NetStandardLibrary1.dll to build AndroidApp1 successfully. (The Csc task completes successfully during step 3 of the steps to reproduce.) It therefore seems acceptable or even appropriate for the .nuspec file from NetStandardLibrary2 to specify that the NetStandardLibrary1.dll assembly is not required for compilation.
Potential Fixes
Based on the story up to this point, it seems that the special handling of reference assemblies in ResolveAssemblies might need to be extended so that it not only looks up and adds the runtime assembly for each reference assembly, but also looks up any corresponding dependencies entries in the obj\project.assets.json lock file and adds the runtime assemblies for each of those dependencies too.
Another question to consider might be how .NET Framework console projects determine which assemblies to copy into the output bin directory for PackageReference items. That mechanism successfully copies NetStandardLibrary1.dll to the bin directory. Could that mechanism be re-used for Xamarin.Android, or does the ResolveAssemblies task do some other special things that are unique to Xamarin.Android? (From a quick look at ResolveAssemblies, I see that one thing that might require special handling is .mdb files.)
Version Information
Visual Studio 2019 Preview
Xamarin.Android SDK 9.1.103.8 (HEAD/9a258c43)
Log File
Steps to Modify the Custom NuGet Packages
Modifying the custom NuGet packages is slightly unusual compared to normal app and library builds, so here are the steps for that in case they might come in handy.
-
Delete the *.nuget.* and project.assets.json files from the obj directory of the AndroidApp1 project (or delete the whole obj directory).
-
Delete any cached copies of the NuGet packages from %USERPROFILE%\.nuget\packages. Otherwise, the NuGet restore process will use the cached copies.
-
In a Developer Command Prompt, change directory into NetStandardLibrary2 (for example).
-
Build the
Packtarget, supplying the .nuspec file in theNuspecFileproperty:msbuild -restore -t:Pack -p:NuspecFile=Contoso.Test.NetStandardLibrary2.nuspec -p:Configuration=Release
-
Repeat step 3 of the steps to reproduce to restore the NuGet packages into the AndroidApp1 project and build it.