imazen / paragon

Help create a demo for delivering unmanaged dependencies with NuGet
The Unlicense
1 stars 0 forks source link

For brevity, let's call unmanaged dependencies udeps.

2017 update - looking for help

I spent the week after Christmas trying to figure out where NuGet is at, reading its source code, and trying to discover if I'm unblocked yet on anything. https://github.com/imazen/Imazen.NativeDependencyManager still appears blocked by shadow-copy. The docs that do exist contradict one another.

Given that I seem to always hit every NuGet corner case, perhaps somone would be interested in picking up a subset this project, and demonstrating how to use NuGet for udep delivery in a way that is seamless for end-users, works with test runners, and can be published via Travis/Appveyor?

Some history: https://github.com/NuGet/Home/issues/300

And https://github.com/aspnet/dnx/issues/402

Runtime IDs

.NET Core has documentation on "runtime IDs" https://docs.microsoft.com/en-us/dotnet/articles/core/rid-catalog http://www.natemcmaster.com/blog/2016/05/19/nuget3-rid-graph/

No clear answer on whether this is supported on .NET 4.6.1 or 4.6.2, and to what extent. I can find no mention of changes to udep discovery. Last I checked, x64 and x86 subfolders still weren't searched by default.

.NET Standard

We now have a way to target both .NET Full and .NET Core at the same time. Yay! https://github.com/dotnet/standard/blob/master/docs/versions.md

It's a bit leaky, but could be worse :) https://github.com/dotnet/standard/blob/master/docs/netstandard-20/README.md#net-framework-461-supporting-net-standard-20

And targeting specific versions got easier: Targeting different .NET editions is easier: https://docs.nuget.org/ndocs/guides/create-cross-platform-packages

runtime.{rid} nuget package convention?

Mostly used by Microsoft, but some others have started using it, too.

https://www.nuget.org/packages?q=runtime.win

Should we adopt this convention for rid-specific packages? It does namespace away these support packages.

Existing packages

We have a mega-package with all udeps together. This won't scale for large binaries. https://github.com/natemcmaster/libsqlite3-package See https://github.com/natemcmaster/libsqlite3-package/blob/master/SQLite.nuspec

https://github.com/NuGet/Home/issues/2782

Targeting different .NET editions is easier: https://docs.nuget.org/ndocs/guides/create-cross-platform-packages

2015 below here

Skip to end for specific questions.

Creating a template for .NET/native interop

vNext reduces reliance (and eventually, access) to OS APIs. To replace that functionality (or to be cross-platform), we must turn to open-source C and C++ libraries.

Challenges

  1. Exploits are more common in native code. Low-friction upstream merges, builds, tests, and static analysis are key to maintaining security. Burden of security responsibility always falls on the wrapper maintainer (at least, in the Win ecosystem).
  2. Visual Studio does not track or copy udeps.
  3. Udeps are not shadow-copied. Resulting issues include (but are not limited to) frequent deploy failures due to locked files.
  4. Not all udeps are assemblies (unmanaged assemblies often depend on physical .xml or data files which can't be embedded).
  5. No API to discover 'original' location. Compilation folder - .CodePoint check. Shadow-copied .Location - check. Directory assemblies were shadow-copied from? We can make educated (but often incorrect) guesses.
  6. NuGet is blind to udeps. Scripted solutions still break in some scenarios.
  7. MinGW (the most common cross-platform build environment) is poorly maintained and very underfunded.
  8. Cmake on windows can be painful.
  9. No compatibility between VS and GNU build toolchains.
  10. Interop can be impossible with more than one AppDomain per process. (If dll has any static configuration, or lacks its own thread safety). Looking at you, OpenCV.
  11. No safe/reliable lifecycle events to hook into and fixup DLL loading/copying and unloading (AFAIK). Mutexes in App_Start, perhaps? Failure would be permanent.
  12. Binding generation is still stupidly difficult. CppSharp is very promising; provides the smartest bindings I've seen to date. Unfortunately, it has minimal documentation, and could use assistance from native english speakers.

Known workarounds

2) Visual Studio ignores native assemblies.


Define subfolders in your project for each architecture, with all dependencies in each.

Use LoadLibraryEx to manually load the .dlls depending upon executing architecture.

Failures: Challenge 5 makes this imprecise. Makes versioning issues commonplace. Does not work for child dependencies - every project must subsume these CopyFile references to work. Messy


Host copies of udeps on a secure server with HTTPS support. During Application_Start, download the correct dependencies to /bin. Fails with file locking errors with multiple worker processes - or AppDomains- or recycling.


Embed copies of native dependencies in the managed DLLs, then extract them at runtime.

Failures: Very slow. Horrible bloating. Fails with file locking errors with multiple worker processes or AppDomains unless a new copy is created for each AppDomain.

End goals

Create a sample cross-platform, multi-architecture NuGet package with udeps - that just works in ASP.NET and ASP.NET vNext - even when you switch between 32 and 64-bit test runners. All processes (builds, tests, static analysis, binding generation) must be scripted and AppVeyor compatible.

To cover all bases, it should include indirect udeps and udeps with procwide configuration (like a callback fn).

This includes

Solid workarounds are fine - but what can't be worked around needs to be fixed in tooling.

Prerequisite goals

Define standards for

Real-world cases (Mine are mostly in an ASP.NET context).

I maintain .NET wrappers for libwebp, FreeImage, CAIR, FFmpeg, Ghostscript, and OpenCV. I'm working on a .NET wrapper for LibGD. I've experimented with many approaches to dependency management, but haven't found a reliable AND user-friendly solution. In turn, the ImageResizer plugins that depend on these wrappers are second-class citizens.

Specific questions

I know many of these are project-specific, but 'generally best direction' answers are great.

Recent feedback from a very helpful guy

SqlServerCompact handles native binaries with an apparently good result. LibGit2 has struggled with udeps, as has

There have been attempts to add native support to NuGet, something about Extension SDKs and more than one issue filed about it. CoApp has a video on making native (uncompiled) NuGet packages.

There's a NuGet package for copying stuff to the build directory, and an article about it.

The udeps topic has been brought up in the context of vNext as an issue also.

Libraries and authors who've dealt with the problem

https://npe.codeplex.com/discussions/462174 http://stackoverflow.com/questions/19478775/add-native-files-from-nuget-package-to-project-output-directory http://blog.nuget.org/20141023/package-manifests.html