-
Notifications
You must be signed in to change notification settings - Fork 109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"Library e_sqlite3 not found" on net472, but works on netcoreapp3.1 #389
Comments
Unit test projects with .NET framework are always troublesome. If you're talking about xunit, try adding an xunit.runner.json file that contains:
|
That's a good idea, but that didn't solve the problem. I checked the debugger to confirm the managed dll was loaded from its original location and that looked good. Here is my updated solution: |
Every release of SQLitePCLRaw is tested on net472 as part of the build process. For example, here is one of the test programs I use. It should work for you as well: csproj:
cs:
I took a glance at your zip file. I'm not 100% sure what is different, but it might be the need to add the SQLitePCLRaw bundle package to the top-level console app instead of to the library. |
Ok, I see what's going on. Your Now here's a potential opportunity to improve the packages though, because nuget is supposed to solve this for us, and this is why in my test and console projects I had these two extra properties: <RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
<RuntimeIdentifier>win-x86</RuntimeIdentifier> This allows my project to target either of two architectures, and because your nuget package correctly follows the But the odd thing (which led to me filing this bug) was that although the native binary was placed, your managed code couldn't find it. Do you have managed code that explicitly looks for the binary in that |
"since that is how .NET Framework, .NET Core, and nuget/msbuild are designed to work by default" Are they? Where is that explained? That doesn't seem to be the way that .NET Core is designed to work by default. In fact, the current approach is an attempt to have .NET Framework emulate the way I understood things to work for .NET Core. I have also had use cases where people needed both native libs to be present so they could switch back and forth between 32 and 64 bit builds. But that is a vague recollection from quite some time ago. This may not be currently relevant. Bottom line: Your explanation sounds good, but this code has been in place for quite a few years, and I have learned to be very cautious of making an improvement which actually turns out to be a regression, especially in this particular area. |
Sure! Here are some docs for your review: This one talks about the nuget runtimes folder pattern which you are already conforming to.
Note that it talks about how NuGet picks files from one runtimes folder. You can see this in action by building the projects in my sample .zip. Then if you look at You'll also notice that .NET Framework and .NET Core automatically load native binaries from p/invoke signatures, and that Windows itself (via All this is to say Microsoft has up and down the runtime and build tools stack endeavored to make it easy. Your specialized library loading code defeats this. Downsides include:
TBH, that actually works well for me too, since in fact I am building an (all dependencies included) extension for an app that may load my extension in either a 32-bit or 64-bit process. So I like that your library allows packing and loading multiple architectures. I just do not think that it should come at a cost of breaking the more common and Microsoft build chain-supported scenario. At minimum, I think you should allow your native loader to find the native binary next to the managed assembly. That would un-break the intended scenario. Thoughts? |
(Mostly content-free update) So far I haven't actually taken the time to think hard about this issue. That targets file (and pretty much anything else that applies to .NET Framework but not .NET Core) is an area of the code I try to avoid thinking about. That said, here is what has been going through my brain: Since I don't like thinking about this targets file, I usually rely on advice from people at Microsoft to tell me if I got it right. The current approach was designed with lots of input from people at Microsoft who seemed awfully smart. When that conversation ended, those people seemed happy with the result, so I haven't touched the targets file since then. Now you have arrived, and you are also a person at Microsoft who seems awfully smart, and you're not happy. Spock in Star Trek IV might wonder if this is a good time for a colorful metaphor. That conversation with the previous round of awfully smart Microsofties was a long time ago. Maybe something changed? It looks like I'm going to have to turn my brain on and actually think about this issue. But that's not happening until 2021. ;-) |
I'd say that's likely, depending on how long ago we're talking about here. I can also ask a few MS folks to chime in here as well who are more direct area owners of the build toolset and runtimes so they can weigh in on my suggestions. Maybe some that I am thinking of are even among the set that helped you before. Happy new year! 🥂 |
I also have experienced this dreaded I'm not sure if this applies to your scenario but I have figured out a way to never get this error by embedding the That's a lot of work on the developer side but you can be 100% sure that the library will always load properly. But all of this doesn't help with the issue at hand which is about not having ton of work to do. I'm not sure what's the best/correct way to fix this issue, but I'll just remind you of #252 which might be related. |
I finally got back to digging into this issue. This involved re-learning some of my own code which I hadn't looked at in a while. The suggestion above from @AArnott was to "allow your native loader to find the native binary next to the managed assembly" and add a condition to the targets file. But I started wondering what benefit my native loader is actually providing. See #419 So, as part of my exploration, I have implemented a more heavy-handed approach wherein (for .NET Framework) I eliminate my native loader (going back to dllimport) and remove the targets file. After that, adding the RuntimeIdentifiers and RuntimeIdentifier props gets my test suite running again. |
pre-release 2.0.5-pre20210521085756 has been pushed up to nuget, including the change described in #419 to default to use dllimport on .NET Framework. |
2.0.5-pre20210521085756 worked great. |
…ets file that applies only to .NET Framework, and is used to copy the native sqlite binaries into position. I removed the targets file in commit 1b2e505, as an experimental change resulting from discussion in #389. However, dotnet/efcore#19396 contains mention of a case that broke. So now the targets file is back, the with the change suggested by @AArnott in #389, only copy the native binaries when the RuntimeIdentifier property is not set.
Fixed in 2.0.5 |
…et framework now uses the dynamic provider again, but now the search possibilities includes WHERE_ADJACENT to catch the case where a RuntimeIdentifier was specified so the right dll ends up adjacent to the other outputs instead of in a runtime/rid subdir. trying to un-break anycpu builds. attempts to fix #444 and #446 and #451
This worked for me. I was targetting net461 and various netcoreapp and net5/6 |
Same issue here with 4.7.2. |
Given the most trivial netstandard2.0 library that consumes
SQLitePCLRaw.bundle_green
2.0.4, that is then brought in by a unit test project that targets both netcoreapp3.1 and net472, we see the net472 one uniquely fails with this error:Yet looking at the bin directory for each target, we see both net472 and netcoreapp3.1 has
e_sqlite3
in the directory alongside the test assembly.What do I need to do so that net472 can find the native binary?
Minimal repro: SqliteTest.zip
The text was updated successfully, but these errors were encountered: