3

I'm trying to run an SFML.NET game on MacOS having ported the game to .NET Core.

I have been unable to get SFML to load its native dependencies correctly at runtime, so I set up a minimal test example to try to isolate the issue, and still get the following error output (I have set DYLD_PRINT_LIBRARIES):

dyld: loaded: /System/Library/Frameworks/CoreData.framework/Versions/A/CoreData
dyld: loaded: /System/Library/Frameworks/ServiceManagement.framework/Versions/A/ServiceManagement
dyld: loaded: /System/Library/PrivateFrameworks/BackgroundTaskManagement.framework/Versions/A/BackgroundTaskManagement
dyld: loaded: /usr/lib/libxslt.1.dylib
dyld: loaded: /usr/local/share/dotnet/shared/Microsoft.NETCore.App/2.2.0/libclrjit.dylib
dyld: loaded: /usr/local/share/dotnet/shared/Microsoft.NETCore.App/2.2.0/System.Globalization.Native.dylib
dyld: loaded: /usr/local/share/dotnet/shared/Microsoft.NETCore.App/2.2.0/System.Native.dylib
Hello World!
dyld: loaded: /Users/ashley/RiderProjects/SFML.NET Test/SFML.NET Test/bin/Debug/netcoreapp2.2/libcsfml-window.dylib
dyld: unloaded: /Users/ashley/RiderProjects/SFML.NET Test/SFML.NET Test/bin/Debug/netcoreapp2.2/libcsfml-window.dylib
dyld: loaded: libcsfml-window.dylib
dyld: unloaded: libcsfml-window.dylib

Unhandled Exception: System.DllNotFoundException: Unable to load shared library 'libcsfml-window.dylib' or one of its dependencies. In order to help diagnose loading problems, consider setting the DYLD_PRINT_LIBRARIES environment variable: dlopen(liblibcsfml-window.dylib.dylib, 1): image not found
   at SFML.Window.VideoMode.sfVideoMode_getDesktopMode()
   at SFML.Window.VideoMode.get_DesktopMode() in /Users/ashley/SFML.Net/src/Window/VideoMode.cs:line 86
   at SFML.NET_Test.Program.Main(String[] args) in /Users/ashley/RiderProjects/SFML.NET Test/SFML.NET Test/Program.cs:line 12
dyld: unloaded: /usr/local/share/dotnet/shared/Microsoft.NETCore.App/2.2.0/libhostpolicy.dylib

The code I am trying to run is as follows:

using System;
using SFML.Graphics;
using SFML.Window;

namespace SFML.NET_Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            RenderWindow window = new RenderWindow(VideoMode.DesktopMode, "Test");
            while (true)
            {
            }
        }
    }
}

I have copies of the relevant native libraries in the running directory and the executable bin (this isn't a permanent set-up -- just while experimenting) and it seems to try to load both in sequence, before giving up and unloading them.

Given this, I'm basically wondering what can lead to this occurring?

I suspect it might indicate my library is the wrong version? (I've tried CSFML 2.2, 2.3, 2.5, so for my sanity's sake I hope this isn't the case) Or maybe there are missing dependencies that it's trying and failing to load? Is there any way to get further debug information out of dyld?

I've tried searching around about this, but it's quite difficult to find any useful resources so I'd appreciate pointers from people who understand the runtime linking system better.

I'm not entirely sure what extra information will be useful for helping answer this. My hope is that there's a specific, well-defined set of scenarios in which this behaviour can surface, which I can apply to fix my specific problem. Otherwise, I'm very happy to provide any additional information that helps.

My .NET Core version is 2.2.101

Ashley Davies
  • 1,873
  • 1
  • 23
  • 42
  • The error states "consider setting the DYLD_PRINT_LIBRARIES environment variable", have you tried that? (eg. `DYLD_PRINT_LIBRARIES=YES`) – l'L'l Jan 12 '19 at 03:42
  • Yeah -- setting that variable enables the `dyld:...` output shown in my log (there's a _lot_ more of it, but I cropped most of it out; it was just loading reasonably normal stuff which loads for all projects and dotnet command runs) – Ashley Davies Jan 12 '19 at 04:37
  • With `DYLD_PRINT_LIBRARIES=YES` post 3-10 lines directly above where the error happens. – l'L'l Jan 12 '19 at 04:42
  • Sure - I've aded another 7 lines from before it outputs "Hello, World". There's another ~100 or so lines like this, all seeming fairly typical. – Ashley Davies Jan 12 '19 at 05:01
  • Okay try adding this to your environment variables: `DYLD_FALLBACK_LIBRARY_PATH="/Users/ashley/RiderProjects/SFML.NET Test/SFML.NET Test/bin/Debug/netcoreapp2.2/"`. – l'L'l Jan 12 '19 at 05:24
  • I set this, and it then loads all of the other libraries as normal, but before it gets to even printing anything it loads what seem like _extra_ ones, and then fails to load `libproc`. I've dumped the last parts of the log to Pastebin: https://pastebin.com/CegZx0nJ I'm not sure if this is related, though -- it does seem to be _finding_ the libraries in the absence of a fallback path (both in my working directory _and_ the bin directory), it just immediately unloads them after loading them, then keeps looking as though they didn't satisfy the dependency correctly. – Ashley Davies Jan 12 '19 at 16:17
  • You can also put additional paths into `DYLD_FALLBACK_LIBRARY_PATH`. For example `"/Users/ashley/RiderProjects/SFML.NET Test/SFML.NET Test/bin/Debug/netcoreapp2.2:/usr/local/share/dotnet/shared:/usr/lib/"`. As for the reason it's not finding the library locations in the first place I'm not exactly sure. [I might suggest trying this minimal example](https://en.sfml-dev.org/forums/index.php?topic=16397.0) to see if you have a similar problem. If everything compiles without issue then it's likely there's something misplaced along the way or perhaps it's a simple configuration issue. – l'L'l Jan 12 '19 at 17:36
  • Sorry -- to clarify, it is finding the library, it's just proceeding to unload it immediately. It finds two instances of it, one in my working dir, and one in my bin dir. I'm just wondering why it refuses to keep it loaded; I thought it might be a bad version but I've tried a few. I had stumbled upon that guide, but it's for .NET Framework under Mono - I'm running .NET Core, so lots of it isn't applicable anymore and it's difficult to tell if any is relevant without a deeper understanding of the linking process than I possess. Thanks for the help though, I appreciate the effort! – Ashley Davies Jan 12 '19 at 17:43
  • 1
    The important part I believe is more or less the section in the linked example which is titled "Fixing library paths". The `InstallNameToolGUI` ([code here](https://github.com/garvankeeley/install-name-tool-gui)) is a GUI based upon wrapper for the command-line utility `otool` in `macOS`. In situations like yours it's ideal for checking the loader paths of `dylibs` in determining where things might have gone awry... – l'L'l Jan 12 '19 at 17:48
  • Thanks! That seems to uncover the problem here; they're referencing other SFML libraries with the wrong filenames and relative to @rpath, which I imagine isn't being set right. I'm not sure why, since they're prebuilt binaries, but I think I can sort it from there. If you can post about that tool as an answer I'd be happy to accept it :) – Ashley Davies Jan 12 '19 at 18:39
  • 1
    You're welcome! I'm glad that it helped. [This document](https://www.mono-project.com/docs/advanced/pinvoke/) might be helpful in regards with how to handle the path issues perhaps. I'll definitely summarize what we discussed and post an answer later today, cheers! – l'L'l Jan 12 '19 at 19:31

1 Answers1

1

After the discussion in the comments it appears the pre-built binaries for SMFL have incorrect paths and filenames set within them. These type of issues can generally be solved by otool and install name tool utilities to inspect the binaries and then change the paths/name of the libraries that need to be loaded.

An example with otool -l might look like this:

$ otool -l /path/to/binary
Load command 2 <-- OLD
          cmd LC_ID_DYLIB
      cmdsize 40
         name libtest.dylib (offset 24)
   time stamp 1 Wed Dec 31 18:00:01 1969

To change the path you could do:

$ install_name_tool -id "@loader_path/../libtest.dylib" libtest.dylib 

which would give you a new path such as:

Load command 2 <-- NEW
          cmd LC_ID_DYLIB
      cmdsize 64
         name @loader_path/../libtest.dylib (offset 24)

If you wanted to use rpath instead you could do:

$ install_name_tool -id "@rpath/libtest.dylib" libtest.dylib

I answered a previous question regarding rpath and loader_path which goes into more detail on the subject. Every scenario is potentially different in the case of loading dynamic libraries, so it really comes down to what you find out by investigating via otool -l.

l'L'l
  • 44,951
  • 10
  • 95
  • 146