Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
407 views
in Technique[技术] by (71.8m points)

.net - Anycpu nuget package the requires either 32 bit or 64 bit package

I have a (anycpu) nuget package "my_shared_library" that must reference a nuget package "non_anycpu_dependency" that comes as either 32 bit or 64 bit (it is database access dll).

I want both 32 bit and 64 bit applications to be able to use "my_shared_library".

How can I have both 32 bit and 64 bit programs use "my_shared_library"?

I was thinking I would either have to have 2 versions of "my_shared_library" or maybe there is some way at run-time to pick the correct 32bit/64bit nuget package of "non_anycpi_dependency" based on the run-time bit-ness.

Has anyone solved this problem? Since most database dlls are not anycpu I would think this is a common problem.

Thanks in advance,

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Has anyone solved this problem?

Yes, Microsoft has. They needed to solve this exact same problem for their SQL Server Compact package. It has a single managed assembly, System.Data.SqlServerCe.dll, acting like the adapter to a managed program, and a bunch of native DLLs that implement the actual database engine. The way they bind to the native DLL entrypoints is not something I ever recommend, I'll work from the assumption that you use pinvoke. I recommend you use this technique to ensure that the client program can run AnyCPU.

Repeating the essence of that post, you want to execute this code somewhere in an initialization method or a static constructor:

public static void SetupDatabaseBinaries() {
    var path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
    path = Path.Combine(path, IntPtr.Size == 8 ? "amd64" : "x86");
    bool ok = SetDllDirectory(path);
    if (!ok) throw new System.ComponentModel.Win32Exception();
}

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetDllDirectory(string path);

The only non-trivial step is to get the user's project to copy the native DLL(s) into the project's amd64/x86 directories. This requires a post-build step, just the way the Compact package does it. You'll want to download the Nuget package to see how they did this, it isn't very trivial. Run VS elevated, create a dummy Console mode project and retrieve the Nuget package for Sql Server Compact. After it is installed, use Project + Properties, Build events tab and note how it added this post build event:

if not exist "$(TargetDir)x86" md "$(TargetDir)x86"
xcopy /s /y "$(SolutionDir)packagesMicrosoft.SqlServer.Compact.4.0.8876.1NativeBinariesx86*.*" "$(TargetDir)x86"
if not exist "$(TargetDir)amd64" md "$(TargetDir)amd64"
xcopy /s /y "$(SolutionDir)packagesMicrosoft.SqlServer.Compact.4.0.8876.1NativeBinariesamd64*.*" "$(TargetDir)amd64"

Nothing much to it, it doesn't do anything more than creating the x86 and amd64 subdirectories and copies the DLLs into them. The tricky part is having your Nuget package add this build event. Have a look-see at the package folder for the magic that accomplished this. You probably want to follow the example as closely as possible to avoid mistakes. Look at the packagesMicrosoft.SqlServer.Compact.4.0.8876.1ools directory, it contains two PowerShell script files that do this. Install.ps1 runs at the end of the install. The function that creates the post-build step is in VS.psm1, Add-PostBuildEvent. Good luck with it.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...