Search code examples
c#linux.net-corepinvokebgfx

bgfx shared library "undefined symbol: XLockDisplay" from .NET Core on Linux


I'm trying to write a simple bgfx application in C# with .NET Core. It works fine on Windows, but it fails at runtime on Linux with the following error:

/usr/bin/dotnet: symbol lookup error: /home/user/Documents/Projects/GameEngine/GameEngine/bin/Debug/netcoreapp2.0/libbgfx-shared-libDebug.so: undefined symbol: XLockDisplay

I'm very ignorant about C++ (especially on Linux) and I already tried all I could think about. I'm looking for hints to fix this problem. Thank you very much for your help.

Reference Code

This is the constructor of the class I use to create a new X11 window. It works and the window is opened correctly.

public GameWindow()
{
    // (snip)

    XInitThreads();

    dpy = XOpenDisplay(IntPtr.Zero);
    if (dpy == IntPtr.Zero)
        throw new ApplicationException("XOpenDisplay failed");

    var s = XDefaultScreen(dpy);
    win = XCreateSimpleWindow(dpy, XRootWindow(dpy, s), 10, 10, Width, Height, 1, XBlackPixel(dpy, s), XWhitePixel(dpy, s));
    XSelectInput(dpy, win, XEventMask.ExposureMask | XEventMask.KeyPressMask);
    XMapWindow(dpy, win);

    // (snip)

    WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", false);
    XSetWMProtocols(dpy, win, new[] { WM_DELETE_WINDOW }, 1);
}

This is where I create the window and assign it to bgfx.

using (var window = new GameWindow())
{
    Bgfx.SetWindowHandle(window.Handle);

    var inited = Bgfx.Init();  // <- this line causes the crash

    // (snip)
}

This is the Bgfx.Init() function.

public static bool Init (InitSettings settings = null) {
    InitSettings.Native native;
    NativeMethods.bgfx_init_ctor(&native);

    // (snip)

    return NativeMethods.bgfx_init(&native);  // <- this line causes the crash
}

Things I noticed

  • The included C++ examples run fine, I'm only encountering this problem from C# (though the library is statically linked in the C++ examples; I'm linking dynamically with PInvoke from C#).

  • I identified the crash to be triggered from glcontext_glx.cpp:66. All the code before this line does indeed run (I checked the tracelogs and they are actually printed until the crash, and I do successfully interact from C# with the library in other ways before that function call is made).

  • Oddly, the libbgfx-shared-libDebug.so (3.6MB) weighs less than the libbgfx-shared-libRelease.so (5.4MB). The opposite is true for the Windows build by Michael Popoloski (bgfx.dll 728KB and bgfx_debug.dll 3.5MB).

  • I do XCreateSimpleWindow() from C# before initializing bgfx, and the window does appear, therefore the X11 library is actually linked correctly.

Things I tried

  • Compiling libbgfx-shared-libDebug.so from Michael Popoloski's bgfx fork (the author of the PInvoke library I'm using from C#) instead of from the original repository - no change
  • Using the release library instead of the debug library - no change
  • Inspecting the library with readelf -d libbgfx-shared-libDebug.so to see if X11 marked as a static dependency - it is not
  • Checking from /proc/1234/maps that the shared X11 library is loaded - the same library is loaded in my C# test and in the included C++ example
  • Running .NET Core without the debugger - no change
  • Forcing preload of the libbgfx-shared-libDebug.so library with LD_PRELOAD and LD_LIBRARY_PATH - no change
  • Commenting the offending line at glcontext_glx.cpp:66 and rebuilding - the error changed from undefined symbol: XLockDisplay to undefined symbol: glXQueryVersion, which is called in the next line
  • Adding -lm -lpthread -lX11 flags to the compiler (as suggested by jdweng) - that error line is not printed anymore, but the program still crashes when XLockDisplay is called

Interesting things

Static dependencies of libbgfx-shared-libDebug.so:

user@ASUS-MINT ~/Documents/Projects/GameEngine/GameEngine/bin/Debug/netcoreapp2.0 $ readelf -d libbgfx-shared-libDebug.so 

Dynamic section at offset 0x1571d0 contains 28 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [librt.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so.2]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [ld-linux-x86-64.so.2]
 (snip)

Maps for dotnet while running my code:

user@ASUS-MINT ~ $ cat /proc/32502/maps
00400000-00418000 r-xp 00000000 08:06 185073                             /usr/share/dotnet/dotnet
(snip)
7fe844bed000-7fe844d42000 r-xp 00000000 08:06 1616067                    /home/user/Documents/Projects/GameEngine/GameEngine/bin/Debug/netcoreapp2.0/libbgfx-shared-libDebug.so
7fe844d42000-7fe844f42000 ---p 00155000 08:06 1616067                    /home/user/Documents/Projects/GameEngine/GameEngine/bin/Debug/netcoreapp2.0/libbgfx-shared-libDebug.so
7fe844f42000-7fe844f45000 r--p 00155000 08:06 1616067                    /home/user/Documents/Projects/GameEngine/GameEngine/bin/Debug/netcoreapp2.0/libbgfx-shared-libDebug.so
7fe844f45000-7fe844f4d000 rw-p 00158000 08:06 1616067                    /home/user/Documents/Projects/GameEngine/GameEngine/bin/Debug/netcoreapp2.0/libbgfx-shared-libDebug.so
(snip)
7fe8455aa000-7fe8456df000 r-xp 00000000 08:06 2370342                    /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0
7fe8456df000-7fe8458df000 ---p 00135000 08:06 2370342                    /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0
7fe8458df000-7fe8458e0000 r--p 00135000 08:06 2370342                    /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0
7fe8458e0000-7fe8458e4000 rw-p 00136000 08:06 2370342                    /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0
(snip)

Maps for the included C++ example (no reference to libbgfx-shared-libDebug.so):

user@ASUS-MINT ~ $ cat /proc/351/maps
00400000-007fe000 r-xp 00000000 08:06 1607279                            /home/user/bgfx/bgfx/.build/linux64_gcc/bin/examplesDebug
(snip)
7f6ad126c000-7f6ad13a1000 r-xp 00000000 08:06 2370342                    /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0
7f6ad13a1000-7f6ad15a1000 ---p 00135000 08:06 2370342                    /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0
7f6ad15a1000-7f6ad15a2000 r--p 00135000 08:06 2370342                    /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0
7f6ad15a2000-7f6ad15a6000 rw-p 00136000 08:06 2370342                    /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0
(snip)

Solution

  • I feel guilty answering my own question without a real solution, but here I go...

    I kept investigating how to solve this problem with no avail. After two years of inactivity, I decided to try again.

    Since 2018 I have formatted my computer and installed various operating system updates, probably even some X11 updates; I updated all project dependencies, including bgfx, to the latest version; and I upgraded from .NET Core App 2.0 to 3.0.

    Maybe there was something wrong with the version of bgfx that I was using? Maybe there was a bug in the dynamic linking in that version of the .NET runtime? Maybe there was a problem with my version of Xlib.so?

    I guess I will never really know, but now it works. Magic.