We have been happily using system.data.sqlite in a project for a while. Our application is published as a single file (which bundles all of the executable and DLL files into aaa single runtime for user convenience). We recently went through an update cycle Increasing the version of the tooling and various libraries and started getting warnings about the library
Steps to reproduce
- Create a simple.net core application e.g.
dotnet new console -lang F#
- Add the SQLite library e.g.
dotnet add package System.Data.SQLite.Core --version 1.0.112.2
- Edit the project file to publish to a single file. For clarity the full example project file is included below
- attempt to publish
dotnet publish
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<PublishTrimmed>true</PublishTrimmed>
<PublishSingleFile>true</PublishSingleFile>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<Compile Include="Program.fs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.112.2" />
</ItemGroup>
</Project>
Publish
The publishing process fails (here I am using 3.1.201) Because the relative bundle paths contained inside the nuget package are both the same for net standard 2.0 and net standard 2.1. The bundling process can't copy both of them into the same location and so it fails.
$ dotnet --info
.NET Core SDK (reflecting any global.json):
Version: 3.1.201
Commit: b1768b4ae7
$ dotnet publish
Microsoft (R) Build Engine version 16.5.0+d4cbfca49 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.
Restore completed in 200.73 ms for C:\src\Playground3\Playground3.fsproj.
Playground3 -> C:\src\Playground3\bin\Debug\netcoreapp3.1\win-x64\Playground3.dll
Optimizing assemblies for size, which may change the behavior of the app. Be sure to test after publishing. See: https://aka.ms/dotnet-illink
C:\Program Files\dotnet\sdk\3.1.201\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Publish.targets(881,5): error MSB4018: The "GenerateBundle" task failed unexpectedly. [C:\src\Playground3\Playground3.fsproj]
C:\Program Files\dotnet\sdk\3.1.201\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Publish.targets(881,5): error MSB4018: System.ArgumentException: Invalid input specification: Found multiple entries with the same BundleRelativePath [C:\src\Playground3\Playground3.fsproj]
C:\Program Files\dotnet\sdk\3.1.201\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Publish.targets(881,5): error MSB4018: at Microsoft.NET.HostModel.Bundle.Bundler.GenerateBundle(IReadOnlyList`1 fileSpecs) [C:\src\Playground3\Playground3.fsproj]
C:\Program Files\dotnet\sdk\3.1.201\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Publish.targets(881,5): error MSB4018: at Microsoft.NET.Build.Tasks.GenerateBundle.ExecuteCore() [C:\src\Playground3\Playground3.fsproj]
C:\Program Files\dotnet\sdk\3.1.201\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Publish.targets(881,5): error MSB4018: at Microsoft.NET.Build.Tasks.TaskBase.Execute() [C:\src\Playground3\Playground3.fsproj]
C:\Program Files\dotnet\sdk\3.1.201\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Publish.targets(881,5): error MSB4018: at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute() [C:\src\Playground3\Playground3.fsproj]
C:\Program Files\dotnet\sdk\3.1.201\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Publish.targets(881,5): error MSB4018: at Microsoft.Build.BackEnd.TaskBuilder.ExecuteInstantiatedTask(ITaskExecutionHost taskExecutionHost, TaskLoggingContext taskLoggingContext, TaskHost taskHost, ItemBucket bucket, TaskExecutionMode howToExecuteTask) [C:\src\Playground3\Playground3.fsproj]
Running the publishing process in diagnostic mode you can see the issue dotnet publish -v diag
- netstandard2.0 and netstandard2.1 libs both try to publish to the same relative path, upsetting the publisher. I think the fix is to either publish them to different paths, or perhaps to avoid bundling both versions of netstandard in one package. The paket tool also provides this warning when working through dependencies
Could detect native library in 'C:\Users\daz\.nuget\packages\system.data.sqlite.core\1.0.112.2\runtimes\linux-x64\native\netstandard2.0\SQLite.Interop.dll' which is incorrectly packaged because it should be directly under 'native' or in the 'nativeassets' folder, please tell the package author
The impact of this is that it seems impossible with latest dotnet core tooling to publish a single file if this library is used. Not sure what we can do to work around, but probably hacking the nuget package for now.
C:\Users\daz\.nuget\packages\system.data.sqlite.core\1.0.112.2\runtimes\win-x64\native\netstandard2.0\SQLite.Interop.dll
AssetType=native
CopyLocal=true
CopyToPublishDirectory=PreserveNewest
DestinationSubPath=SQLite.Interop.dll
NuGetPackageId=System.Data.SQLite.Core
NuGetPackageVersion=1.0.112.2
PackageName=System.Data.SQLite.Core
PackageVersion=1.0.112.2
PathInPackage=runtimes/win-x64/native/netstandard2.0/SQLite.Interop.dll
RelativePath=SQLite.Interop.dll <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
C:\Users\daz\.nuget\packages\system.data.sqlite.core\1.0.112.2\runtimes\win-x64\native\netstandard2.1\SQLite.Interop.dll
AssetType=native
CopyLocal=true
CopyToPublishDirectory=PreserveNewest
DestinationSubPath=SQLite.Interop.dll
NuGetPackageId=System.Data.SQLite.Core
NuGetPackageVersion=1.0.112.2
PackageName=System.Data.SQLite.Core
PackageVersion=1.0.112.2
PathInPackage=runtimes/win-x64/native/netstandard2.1/SQLite.Interop.dll
RelativePath=SQLite.Interop.dll <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
The Nuget package is not correctly authored. The native library SQLite.Interop.dll is inside a framework-dependent folder:
runtimes\win-x64\native\netstandard2.0\SQLite.Interop.dll
runtimes\win-x64\native\netstandard2.1\SQLite.Interop.dll
This is wrong. As mentioned in the original description, it should be directly inside the native folder, like this:
runtimes\win-x64\native\SQLite.Interop.dll
The framework folder inside native is not required because the native DLL is identical for all frameworks (or at least it should be, I don't know why the build
folder contains another set of interop DLLs). See Support multiple .NET versions on MSDN.
For single file publishing, everything inside the native folder will be flattened and thus cause publishing to fail because of the duplicate interop dll. There's also another ticket about this: 02ec01b7c355d1e2fee5