olegtarasov / NativeLibraryManager

A .NET Standard 2.0 library to manage native dependencies stored as binary resources.
MIT License
30 stars 5 forks source link

Fails to load native library for OS X #5

Open define-private-public opened 4 years ago

define-private-public commented 4 years ago

This is from my Bassoon project. Everything is working 100% for Windows and Linux. The PortAudioSharp portion is working fine on OS X , but the libsndfileSharp isn't loading the native libsndfile.dylib DLL when trying to run a program. libsndfile.dylib depends on a few other native libraries (e.g. libogg.dylib, libFLAC.dylib, etc). I'm wondering if that's the problem.

Using the FileInfo sample in my repo (which uses libsndfileSharp). I first tried a dotnet run with DYLD_LIBRARY_PATH set to where I compiled out the *.dylib files. And everything worked fine. But then using the NuGet package version (v.0.2), it reported Unable to load shared library 'sndfile' or one of its dependencies. I set DY_PRINT_LIBRARIES=1 and it reported this:

dyld: loaded: /Users/ben/.nuget/packages/libsndfilesharp/0.2.0/lib/netstandard2.0/libsndfile.dylib
dyld: unloaded: /Users/ben/.nuget/packages/libsndfilesharp/0.2.0/lib/netstandard2.0/libsndfile.dylib

At least one of those other native deps should show up after the loaded part, but none of them did.

libsndfileSharp csproj: https://gitlab.com/define-private-public/Bassoon/-/blob/release_nuget_packaging/src/Bassoon/libsndfileSharp/libsndfileSharp.csproj#L37

define-private-public commented 4 years ago

I just tried setting export DYLD_LIBRARY_PATH=/Users/ben/.nuget/packages/libsndfilesharp/0.2.0/lib/netstandard2.0 before doing the dotnet run. I noticed that the extracted .dylib files were found in there. It worked.

I'm wondering if this may just be some path issue.

olegtarasov commented 4 years ago

Hi @define-private-public!

Sorry for such a late reply. I've just pushed version 1.0.19 to Nuget. Library manager now adds the path to which native dependencies are being extracted to DYLD_LIBRARY_PATH under MacOs. Please check if this version solves your problem without specifying DYLD_LIBRARY_PATH manually before dotnet run. If so, I will add similar handlers for Linux and Windows.

define-private-public commented 4 years ago

Sorry for the late response. I have this on my TODO within the next days. Thanks!

olegtarasov commented 4 years ago

So I did some testing and it seems that modifying library search path is the way to go. I've pushed v. 1.0.21, where library search path modification is on by default on all platforms, and explicit library loading is off. Automated tests now run on every build and show that this approach works consistently on all three platforms.

I'm closing this issue for now, but feel free to reopen it if v. 1.0.21 doesn't solve your problem.

olegtarasov commented 4 years ago

Orrrrr not :) Seems that variable modification doesn't work all the time, need to poke around some more.

olegtarasov commented 4 years ago

OK, so here's what I've found. Changing variables such as DYLD_LIBRARY_PATH at runtime is completely useless, since they are taken into account only at process startup, and then any change to them is ignored. That's why it worked when you set this variable before calling dotnet.

The only reliable way of successfully using [DllImport] seems to involve extracting dependencies to process' current directory.

Explicit library loading also works, but only on Windows and Linux, but not MacOs 🤦.

As for your problem, extracting dependencies to current directory instead of assembly's location might help in your particular case. Please update nuget package to v. 1.0.22 and let me know if it solves your problem. You don't need to change anything in your code, but you might want to remove this constructor argument in your code (it just doesn't do anything now): https://gitlab.com/define-private-public/Bassoon/-/blob/release_nuget_packaging/src/Bassoon/libsndfileSharp/libsndfileSharp.cs#L36.

define-private-public commented 4 years ago

Hi, Sorry for responding to this 3 weeks late (been preoccupied).

I took this for a test drive and things do seem to be working on OS X now with my Bassoon package (e.g. if you look at the sample Jukebox app, and have it pull from NuGet with the latest package of Bassoon instead of using a local project reference).

Though, on Linux and OS X, I couldn't simply run dotnet run anymore in the directory where my projects .csproj lives. I had to do "LD_LIBRARY_PATH=pwd dotnet run" and "DYLD_LIBRARY_PATH=pwd dotnet run" respectively. This is a minor inconvenience, but at least it's working on OS X now. An ideal would be not have to manually specify the library path, but that could be taken care of with telling any users (for the moment at least) to wrap their dotnet run commands in a shell script.

I still want to double check things on Windows. Thanks again for your work on this project. I still find it easier to follow than some of the other solutions for doing multi-platform native libraries..

define-private-public commented 4 years ago

I took the new version out for a test run on Window as well. Doing a dotnet run work fine without having to specify any extra path stuff. Both in the windows console and an MSYS2 environment.

An ideal for OS X and Linux would not having to specify the library path (and not populating the running directory with the native DLLs), but I'll take this for now since it works with minimal adjustment. If you want to close this ticket, I don't have any more need for it. I'm willing to help you test this library further.

jclaessens97 commented 4 years ago

Hi guys, any update on this? I just started to use this library because we're using 3 different environments. Linux for our server, myself for development on osx and the rest of my team to develop on Windows. I'm trying to set it up but like stated in this issue it doesn't seem to work for osx.

I'm not sure what the solution is for now? I set my env vars to the following:

image

But I still get this error:

image

Thanks!

RobertoMachorro commented 3 years ago

I find myself in the same situation. The native library depends on a few Boost (C++) dylibs and doesn't find them unless I set the DYLD path prior to launching. Instead of using _ DYLD_LIBRARYPATH, I'm using DYLD_FALLBACK_LIBRARY_PATH, as it is "safer". Setting up the following in code, doesn't work:

Environment.SetEnvironmentVariable("DYLD_FALLBACK_LIBRARY_PATH", ".");

I'm hoping for a more elegant solution that launching with env vars. Using NativeLibraryManager v1.0.23