Просмотр исходного кода

Record dynamic dependencies in .note.dlopen elf section

Anonymous Maarten 2 недель назад
Родитель
Сommit
0a6b80717c

+ 20 - 0
CMakeLists.txt

@@ -302,6 +302,7 @@ dep_option(SDL_ARMNEON             "Use NEON assembly routines" ON "SDL_ASSEMBLY
 dep_option(SDL_LSX                 "Use LSX assembly routines" ON "SDL_ASSEMBLY;SDL_CPU_LOONGARCH64" OFF)
 dep_option(SDL_LASX                "Use LASX assembly routines" ON "SDL_ASSEMBLY;SDL_CPU_LOONGARCH64" OFF)
 
+dep_option(SDL_DLOPEN_NOTES        "Record dlopen dependencies in .note.dlopen section" TRUE UNIX_SYS OFF)
 set_option(SDL_LIBC                "Use the system C library" ${SDL_LIBC_DEFAULT})
 set_option(SDL_SYSTEM_ICONV        "Use iconv() from system-installed libraries" ${SDL_SYSTEM_ICONV_DEFAULT})
 set_option(SDL_LIBICONV            "Prefer iconv() from libiconv, if available, over libc version" OFF)
@@ -1712,6 +1713,25 @@ elseif(EMSCRIPTEN)
   CheckLibUnwind()
 
 elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
+
+  if(SDL_DLOPEN_NOTES)
+    set(CHECK_ELF_DLNOTES_SRC [==[
+    #ifndef __ELF__
+      ELF DL notes is only supported on ELF platforms
+    #endif
+    __attribute__ ((used,aligned(4),section(".note.dlopen"))) static const struct {
+      struct { int a; int b; int c; } hdr; char name[4]; __attribute__((aligned(4))) char json[24];
+    } dlnote = { { 4, 0x407c0c0aU, 16 }, "FDO", "[\\"a\\":{\\"a\\":\\"1\\",\\"b\\":\\"2\\"}]" };
+    int main(int argc, char *argv[]) {
+      return argc + dlnote.hdr.a;
+    }
+    ]==])
+    check_c_source_compiles("${CHECK_ELF_DLNOTES_SRC}" COMPILER_SUPPORTS_ELFNOTES)
+    if(COMPILER_SUPPORTS_ELFNOTES)
+      set(HAVE_DLOPEN_NOTES TRUE)
+    endif()
+  endif()
+
   if(SDL_AUDIO)
     if(NETBSD)
         set(SDL_AUDIO_DRIVER_NETBSD 1)

+ 1 - 1
docs/README-linux.md

@@ -26,7 +26,7 @@ Ubuntu 22.04+ can also add `libpipewire-0.3-dev libwayland-dev libdecor-0-dev li
 Fedora 35, all available features enabled:
 
     sudo yum install gcc git-core make cmake \
-    alsa-lib-devel pulseaudio-libs-devel nas-devel pipewire-devel \
+    alsa-lib-devel pulseaudio-libs-devel pipewire-devel \
     libX11-devel libXext-devel libXrandr-devel libXcursor-devel libXfixes-devel \
     libXi-devel libXScrnSaver-devel dbus-devel ibus-devel \
     systemd-devel mesa-libGL-devel libxkbcommon-devel mesa-libGLES-devel \

+ 2 - 0
include/build_config/SDL_build_config.h.cmake

@@ -235,6 +235,8 @@
 #cmakedefine HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR 1
 #cmakedefine HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP 1
 
+#cmakedefine HAVE_DLOPEN_NOTES 1
+
 /* SDL internal assertion support */
 #cmakedefine SDL_DEFAULT_ASSERT_LEVEL_CONFIGURED 1
 #ifdef SDL_DEFAULT_ASSERT_LEVEL_CONFIGURED

+ 1 - 0
src/SDL_internal.h

@@ -63,6 +63,7 @@
 #include "SDL_build_config.h"
 
 #include "dynapi/SDL_dynapi.h"
+#include "dynapi/SDL_dynapi_dlopennote.h"
 
 #if SDL_DYNAMIC_API
 #include "dynapi/SDL_dynapi_overrides.h"

+ 9 - 2
src/audio/aaudio/SDL_aaudio.c

@@ -53,6 +53,13 @@ struct SDL_PrivateAudioData
 
 #define LIB_AAUDIO_SO "libaaudio.so"
 
+SDL_ELF_NOTE_DLOPEN(
+    "audio-aaudio",
+    "Support for audio through AAudio",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    LIB_AAUDIO_SO
+);
+
 typedef struct AAUDIO_Data
 {
     SDL_SharedObject *handle;
@@ -313,8 +320,8 @@ static bool BuildAAudioStream(SDL_AudioDevice *device)
     ctx.AAudioStreamBuilder_setFormat(builder, format);
     ctx.AAudioStreamBuilder_setSampleRate(builder, device->spec.freq);
     ctx.AAudioStreamBuilder_setChannelCount(builder, device->spec.channels);
-	
-    // If no specific buffer size has been requested, the device will pick the optimal 
+
+    // If no specific buffer size has been requested, the device will pick the optimal
 	if(SDL_GetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES)) {
 	    ctx.AAudioStreamBuilder_setBufferCapacityInFrames(builder, 2 * device->sample_frames); // AAudio requires that the buffer capacity is at least
 	    ctx.AAudioStreamBuilder_setFramesPerDataCallback(builder, device->sample_frames);      // twice the size of the data callback buffer size

+ 7 - 0
src/audio/alsa/SDL_alsa_audio.c

@@ -207,6 +207,13 @@ static bool load_alsa_syms(void)
 
 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
 
+SDL_ELF_NOTE_DLOPEN(
+    "audio-libalsa",
+    "Support for audio through libalsa",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    SDL_AUDIO_DRIVER_ALSA_DYNAMIC
+);
+
 static void UnloadALSALibrary(void)
 {
     if (alsa_handle) {

+ 7 - 0
src/audio/jack/SDL_jackaudio.c

@@ -50,6 +50,13 @@ static bool load_jack_syms(void);
 
 #ifdef SDL_AUDIO_DRIVER_JACK_DYNAMIC
 
+SDL_ELF_NOTE_DLOPEN(
+    "audio-libjack",
+    "Support for audio through libjack",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    SDL_AUDIO_DRIVER_JACK_DYNAMIC
+);
+
 static const char *jack_library = SDL_AUDIO_DRIVER_JACK_DYNAMIC;
 static SDL_SharedObject *jack_handle = NULL;
 

+ 7 - 0
src/audio/pipewire/SDL_pipewire.c

@@ -93,6 +93,13 @@ static int (*PIPEWIRE_pw_properties_setf)(struct pw_properties *, const char *,
 
 #ifdef SDL_AUDIO_DRIVER_PIPEWIRE_DYNAMIC
 
+SDL_ELF_NOTE_DLOPEN(
+    "audio-libpipewire",
+    "Support for audio through libpipewire",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    SDL_AUDIO_DRIVER_PIPEWIRE_DYNAMIC
+);
+
 static const char *pipewire_library = SDL_AUDIO_DRIVER_PIPEWIRE_DYNAMIC;
 static SDL_SharedObject *pipewire_handle = NULL;
 

+ 7 - 0
src/audio/pulseaudio/SDL_pulseaudio.c

@@ -133,6 +133,13 @@ static bool load_pulseaudio_syms(void);
 
 #ifdef SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC
 
+SDL_ELF_NOTE_DLOPEN(
+    "audio-libpulseaudio",
+    "Support for audio through libpulseaudio",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC
+);
+
 static const char *pulseaudio_library = SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC;
 static SDL_SharedObject *pulseaudio_handle = NULL;
 

+ 7 - 0
src/audio/sndio/SDL_sndioaudio.c

@@ -108,6 +108,13 @@ static bool load_sndio_syms(void)
 
 #ifdef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
 
+SDL_ELF_NOTE_DLOPEN(
+    "audio-libsndio",
+    "Support for audio through libsndio",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
+);
+
 static void UnloadSNDIOLibrary(void)
 {
     if (sndio_handle) {

+ 7 - 0
src/camera/pipewire/SDL_camera_pipewire.c

@@ -109,6 +109,13 @@ static int (*PIPEWIRE_pw_properties_setf)(struct pw_properties *, const char *,
 
 #ifdef SDL_CAMERA_DRIVER_PIPEWIRE_DYNAMIC
 
+SDL_ELF_NOTE_DLOPEN(
+    "camera-libpipewire",
+    "Support for camera through libpipewire",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    SDL_CAMERA_DRIVER_PIPEWIRE_DYNAMIC
+);
+
 static const char *pipewire_library = SDL_CAMERA_DRIVER_PIPEWIRE_DYNAMIC;
 static SDL_SharedObject *pipewire_handle = NULL;
 

+ 9 - 1
src/core/linux/SDL_dbus.c

@@ -24,12 +24,20 @@
 
 #ifdef SDL_USE_LIBDBUS
 // we never link directly to libdbus.
-static const char *dbus_library = "libdbus-1.so.3";
+#define SDL_DRIVER_DBUS_DYNAMIC "libdbus-1.so.3"
+static const char *dbus_library = SDL_DRIVER_DBUS_DYNAMIC;
 static SDL_SharedObject *dbus_handle = NULL;
 static char *inhibit_handle = NULL;
 static unsigned int screensaver_cookie = 0;
 static SDL_DBusContext dbus;
 
+SDL_ELF_NOTE_DLOPEN(
+    "core-libdbus",
+    "Support for D-Bus IPC",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED,
+    SDL_DRIVER_DBUS_DYNAMIC
+);
+
 static bool LoadDBUSSyms(void)
 {
 #define SDL_DBUS_SYM2_OPTIONAL(TYPE, x, y)                   \

+ 16 - 1
src/core/linux/SDL_udev.c

@@ -36,7 +36,22 @@
 #include "SDL_evdev_capabilities.h"
 #include "../unix/SDL_poll.h"
 
-static const char *SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" };
+#define SDL_UDEV_FALLBACK_LIBS "libudev.so.1", "libudev.so.0" 
+
+static const char *SDL_UDEV_LIBS[] = { SDL_UDEV_FALLBACK_LIBS };
+
+#ifdef SDL_UDEV_DYNAMIC
+#define SDL_UDEV_DLNOTE_LIBS SDL_UDEV_DYNAMIC, SDL_UDEV_FALLBACK_LIBS
+#else
+#define SDL_UDEV_DLNOTE_LIBS SDL_UDEV_FALLBACK_LIBS
+#endif
+
+SDL_ELF_NOTE_DLOPEN(
+    "events-udev",
+    "Support for events through libudev",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED,
+    SDL_UDEV_DLNOTE_LIBS
+);
 
 static SDL_UDEV_PrivateData *_this = NULL;
 

+ 98 - 0
src/dynapi/SDL_dynapi_dlopennote.h

@@ -0,0 +1,98 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2025 Sam Lantinga <[email protected]>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef SDL_dynapi_dlopennote_h
+#define SDL_dynapi_dlopennote_h
+
+#define SDL_ELF_NOTE_DLOPEN_PRIORITY_REQUIRED    "required"
+#define SDL_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED "recommended"
+#define SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED   "suggested"
+
+#if defined(__ELF__) && defined(HAVE_DLOPEN_NOTES)
+
+#define SDL_ELF_NOTE_DLOPEN_VENDOR "FDO"
+#define SDL_ELF_NOTE_DLOPEN_TYPE 0x407c0c0aU
+
+#define SDL_ELF_NOTE_INTERNAL2(json, variable_name)                 \
+    __attribute__((aligned(4), used, section(".note.dlopen")))      \
+    static const struct {                                           \
+        struct {                                                    \
+            Uint32 n_namesz;                                        \
+            Uint32 n_descsz;                                        \
+            Uint32 n_type;                                          \
+        } nhdr;                                                     \
+        char name[4];                                               \
+        __attribute__((aligned(4))) char dlopen_json[sizeof(json)]; \
+    } variable_name = {                                             \
+        {                                                           \
+             sizeof(SDL_ELF_NOTE_DLOPEN_VENDOR),                    \
+             sizeof(json),                                          \
+             SDL_ELF_NOTE_DLOPEN_TYPE                               \
+        },                                                          \
+        SDL_ELF_NOTE_DLOPEN_VENDOR,                                 \
+        json                                                        \
+    }
+
+#define SDL_ELF_NOTE_INTERNAL(json, variable_name) \
+    SDL_ELF_NOTE_INTERNAL2(json, variable_name)
+
+#define SDL_SONAME_ARRAY1(N1) "[\"" N1 "\"]"
+#define SDL_SONAME_ARRAY2(N1,N2) "[\"" N1 "\",\"" N2 "\"]"
+#define SDL_SONAME_ARRAY3(N1,N2,N3) "[\"" N1 "\",\"" N2 "\",\"" N3 "\"]"
+#define SDL_SONAME_ARRAY4(N1,N2,N3,N4) "[\"" N1 "\",\"" N2 "\",\"" N3 "\",\"" N4 "\"]"
+#define SDL_SONAME_ARRAY5(N1,N2,N3,N4,N5) "[\"" N1 "\",\"" N2 "\",\"" N3 "\",\"" N4 "\",\"" N5 "\"]"
+#define SDL_SONAME_ARRAY6(N1,N2,N3,N4,N5,N6) "[\"" N1 "\",\"" N2 "\",\"" N3 "\",\"" N4 "\",\"" N5 "\",\"" N6 "\"]"
+#define SDL_SONAME_ARRAY7(N1,N2,N3,N4,N5,N6,N7) "[\"" N1 "\",\"" N2 "\",\"" N3 "\",\"" N4 "\",\"" N5 "\",\"" N6 "\",\"" N7 "\"]"
+#define SDL_SONAME_ARRAY8(N1,N2,N3,N4,N5,N6,N7,N8) "[\"" N1 "\",\"" N2 "\",\"" N3 "\",\"" N4 "\",\"" N5 "\",\"" N6 "\",\"" N7 "\",\"" N8 "\"]"
+#define SDL_SONAME_ARRAY_GET(N1,N2,N3,N4,N5,N6,N7,N8,NAME,...) NAME
+#define SDL_SONAME_ARRAY(...) \
+    SDL_SONAME_ARRAY_GET(__VA_ARGS__, \
+         SDL_SONAME_ARRAY8, \
+         SDL_SONAME_ARRAY7, \
+         SDL_SONAME_ARRAY6, \
+         SDL_SONAME_ARRAY5, \
+         SDL_SONAME_ARRAY4, \
+         SDL_SONAME_ARRAY3, \
+         SDL_SONAME_ARRAY2, \
+         SDL_SONAME_ARRAY1 \
+    )(__VA_ARGS__)
+
+// Create "unique" variable name using __LINE__,
+// so creating elf notes on the same line is not supported
+#define SDL_ELF_NOTE_JOIN2(A,B) A##B
+#define SDL_ELF_NOTE_JOIN(A,B) SDL_ELF_NOTE_JOIN2(A,B)
+#define SDL_ELF_NOTE_UNIQUE_NAME SDL_ELF_NOTE_JOIN(s_dlopen_note_, __LINE__)
+
+#define SDL_ELF_NOTE_DLOPEN(feature, description, priority, ...) \
+    SDL_ELF_NOTE_INTERNAL(                                       \
+        "[{\"feature\":\"" feature                               \
+        "\",\"description\":\"" description                      \
+        "\",\"priority\":\"" priority                            \
+        "\",\"soname\":" SDL_SONAME_ARRAY(__VA_ARGS__) "}]",     \
+        SDL_ELF_NOTE_UNIQUE_NAME)
+
+#else
+
+#define SDL_ELF_NOTE_DLOPEN(...)
+
+#endif
+
+#endif

+ 9 - 0
src/hidapi/SDL_hidapi.c

@@ -40,6 +40,15 @@
 
 #ifndef SDL_HIDAPI_DISABLED
 
+#ifdef SDL_LIBUSB_DYNAMIC
+SDL_ELF_NOTE_DLOPEN(
+    "hidabi-libusb",
+    "Support for joysticks through libusb",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    SDL_LIBUSB_DYNAMIC
+);
+#endif
+
 #if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK)
 #include "../core/windows/SDL_windows.h"
 #endif

+ 9 - 1
src/io/io_uring/SDL_asyncio_liburing.c

@@ -44,9 +44,17 @@ static bool (*AsyncIOFromFile)(const char *file, const char *mode, SDL_AsyncIO *
 // we never link directly to liburing.
 // (this says "-ffi" which sounds like a scripting language binding thing, but the non-ffi version
 // is static-inline code we can't lookup with dlsym. This is by design.)
-static const char *liburing_library = "liburing-ffi.so.2";
+#define SDL_DRIVER_LIBURING_DYNAMIC "liburing-ffi.so.2"
+static const char *liburing_library = SDL_DRIVER_LIBURING_DYNAMIC;
 static void *liburing_handle = NULL;
 
+SDL_ELF_NOTE_DLOPEN(
+    "io-io_uring",
+    "Support for async IO through liburing",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    SDL_DRIVER_LIBURING_DYNAMIC
+);
+
 #define SDL_LIBURING_FUNCS \
     SDL_LIBURING_FUNC(int, io_uring_queue_init, (unsigned entries, struct io_uring *ring, unsigned flags)) \
     SDL_LIBURING_FUNC(struct io_uring_probe *,io_uring_get_probe,(void)) \

+ 18 - 11
src/storage/steam/SDL_steamstorage.c

@@ -23,6 +23,23 @@
 
 #include "../SDL_sysstorage.h"
 
+#if defined(_WIN64)
+#define SDL_DRIVER_STEAMAPI_DYNAMIC "steam_api64.dll"
+#elif defined(_WIN32)
+#define SDL_DRIVER_STEAMAPI_DYNAMIC "steam_api.dll"
+#elif defined(__APPLE__)
+#define SDL_DRIVER_STEAMAPI_DYNAMIC "libsteam_api.dylib"
+#else
+#define SDL_DRIVER_STEAMAPI_DYNAMIC "libsteam_api.so"
+#endif
+
+SDL_ELF_NOTE_DLOPEN(
+    "storage-steam",
+    "Support for Steam user storage",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    SDL_DRIVER_STEAMAPI_DYNAMIC
+);
+
 // !!! FIXME: Async API can use SteamRemoteStorage_ReadFileAsync
 // !!! FIXME: Async API can use SteamRemoteStorage_WriteFileAsync
 
@@ -154,17 +171,7 @@ static SDL_Storage *STEAM_User_Create(const char *org, const char *app, SDL_Prop
         return NULL;
     }
 
-    steam->libsteam_api = SDL_LoadObject(
-#if defined(_WIN64)
-        "steam_api64.dll"
-#elif defined(_WIN32)
-        "steam_api.dll"
-#elif defined(__APPLE__)
-        "libsteam_api.dylib"
-#else
-        "libsteam_api.so"
-#endif
-    );
+    steam->libsteam_api = SDL_LoadObject(SDL_DRIVER_STEAMAPI_DYNAMIC);
     if (steam->libsteam_api == NULL) {
         SDL_free(steam);
         return NULL;

+ 31 - 0
src/video/SDL_egl.c

@@ -110,6 +110,37 @@
 #define DEFAULT_OGL_ES2    "libGLESv2.so.2"
 #define DEFAULT_OGL_ES_PVR "libGLES_CM.so.1"
 #define DEFAULT_OGL_ES     "libGLESv1_CM.so.1"
+
+SDL_ELF_NOTE_DLOPEN(
+    "egl-opengl",
+    "Support for OpenGL",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    DEFAULT_OGL, ALT_OGL
+);
+SDL_ELF_NOTE_DLOPEN(
+    "egl-egl",
+    "Support for EGL",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    DEFAULT_EGL
+);
+SDL_ELF_NOTE_DLOPEN(
+    "egl-es2",
+    "Support for EGL ES2",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    DEFAULT_OGL_ES2
+);
+SDL_ELF_NOTE_DLOPEN(
+    "egl-es-pvr",
+    "Support for EGL ES PVR",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    DEFAULT_OGL_ES_PVR
+);
+SDL_ELF_NOTE_DLOPEN(
+    "egl-ogl-es",
+    "Support for OpenGL ES",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    DEFAULT_OGL_ES
+);
 #endif // SDL_VIDEO_DRIVER_RPI
 
 #if defined(SDL_VIDEO_OPENGL) && !defined(SDL_VIDEO_VITA_PVR_OGL)

+ 7 - 0
src/video/kmsdrm/SDL_kmsdrmdyn.c

@@ -29,6 +29,13 @@
 
 #ifdef SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC
 
+SDL_ELF_NOTE_DLOPEN(
+    "video-kmsdrm",
+    "Support for KMSDRM",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC
+);
+
 typedef struct
 {
     void *lib;

+ 7 - 0
src/video/kmsdrm/SDL_kmsdrmvulkan.c

@@ -42,6 +42,13 @@
 #define DEFAULT_VULKAN "libvulkan.so.1"
 #endif
 
+SDL_ELF_NOTE_DLOPEN(
+    "kmsdrm-vulkan",
+    "Support for Vulkan on KMSDRM",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    DEFAULT_VULKAN
+);
+
 bool KMSDRM_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path)
 {
     VkExtensionProperties *extensions = NULL;

+ 7 - 0
src/video/offscreen/SDL_offscreenvulkan.c

@@ -42,6 +42,13 @@ static const char *s_defaultPaths[] = {
 #endif
 };
 
+SDL_ELF_NOTE_DLOPEN(
+    "offscreen-vulkan",
+    "Support for offscreen Vulkan",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    "libvulkan.so.1"
+);
+
 #if defined( SDL_PLATFORM_APPLE )
 #include <dlfcn.h>
 

+ 20 - 12
src/video/openvr/SDL_openvrvideo.c

@@ -53,6 +53,19 @@ struct SDL_GLContextState
 #include <SDL3/SDL_opengles2_gl2.h>
 #endif
 
+#ifdef SDL_PLATFORM_WINDOWS
+#define SDL_OPENVR_DRIVER_DYNAMIC "openvr_api.dll"
+#else
+#define SDL_OPENVR_DRIVER_DYNAMIC "openvr_api.so"
+#endif
+
+SDL_ELF_NOTE_DLOPEN(
+    "video-openvr",
+    "Support for OpenVR video",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    SDL_OPENVR_DRIVER_DYNAMIC
+);
+
 #define MARKER_ID 0
 #define MARKER_STR "vr-marker,frame_end,type,application"
 
@@ -1474,6 +1487,7 @@ static SDL_VideoDevice *OPENVR_CreateDevice(void)
 {
     SDL_VideoDevice *device;
     SDL_VideoData *data;
+    const char *hint;
 
 #ifdef SDL_PLATFORM_WINDOWS
     SDL_RegisterApp(NULL, 0, NULL);
@@ -1495,19 +1509,13 @@ static SDL_VideoDevice *OPENVR_CreateDevice(void)
     }
     device->internal = data;
 
-    {
-        const char * hint = SDL_GetHint(SDL_HINT_OPENVR_LIBRARY);
-        if (hint)
-            data->openVRLIB = SDL_LoadObject(hint);
-#ifdef SDL_PLATFORM_WINDOWS
-        if (!data->openVRLIB)
-            data->openVRLIB = SDL_LoadObject("openvr_api.dll");
-#else
-        if (!data->openVRLIB)
-            data->openVRLIB = SDL_LoadObject("openvr_api.so");
-#endif
+    hint = SDL_GetHint(SDL_HINT_OPENVR_LIBRARY);
+    if (hint) {
+        data->openVRLIB = SDL_LoadObject(hint);
+    }
+    if (!data->openVRLIB) {
+        data->openVRLIB = SDL_LoadObject(SDL_OPENVR_DRIVER_DYNAMIC);
     }
-
     if (!data->openVRLIB) {
         SDL_SetError("Could not open OpenVR API Library");
         goto error;

+ 39 - 0
src/video/wayland/SDL_waylanddyn.c

@@ -28,6 +28,45 @@
 
 #ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC
 
+SDL_ELF_NOTE_DLOPEN(
+    "wayland",
+    "Support for Wayland video",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC
+);
+#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL
+SDL_ELF_NOTE_DLOPEN(
+    "wayland",
+    "Support for Wayland video",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL
+);
+#endif
+#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR
+SDL_ELF_NOTE_DLOPEN(
+    "wayland",
+    "Support for Wayland video",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR
+);
+#endif
+#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON
+SDL_ELF_NOTE_DLOPEN(
+    "wayland",
+    "Support for Wayland video",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON
+);
+#endif
+#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR
+SDL_ELF_NOTE_DLOPEN(
+    "wayland",
+    "Support for Wayland video",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_LIBDECOR
+);
+#endif
+
 typedef struct
 {
     SDL_SharedObject *lib;

+ 7 - 0
src/video/wayland/SDL_waylandvulkan.c

@@ -41,6 +41,13 @@
 #define DEFAULT_VULKAN "libvulkan.so.1"
 #endif
 
+SDL_ELF_NOTE_DLOPEN(
+    "wayland-vulkan",
+    "Support for Vulkan on wayland backend",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    DEFAULT_VULKAN
+);
+
 bool Wayland_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path)
 {
     VkExtensionProperties *extensions = NULL;

+ 69 - 7
src/video/x11/SDL_x11dyn.c

@@ -38,25 +38,87 @@ typedef struct
     const char *libname;
 } x11dynlib;
 
-#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT
+SDL_ELF_NOTE_DLOPEN(
+    "x11",
+    "Support for video through X11 backend",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED,
+    SDL_VIDEO_DRIVER_X11_DYNAMIC
+);
+
+#ifdef SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT
+SDL_ELF_NOTE_DLOPEN(
+    "x11",
+    "Support for video through X11 backend",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED,
+    SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT
+);
+#else
 #define SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT NULL
 #endif
-#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR
+
+#ifdef SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR
+SDL_ELF_NOTE_DLOPEN(
+    "x11",
+    "Support for video through X11 backend",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED,
+    SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR
+);
+#else
 #define SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR NULL
 #endif
-#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2
+
+#ifdef SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2
+SDL_ELF_NOTE_DLOPEN(
+    "x11",
+    "Support for video through X11 backend",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED,
+    SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2
+);
+#else
 #define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 NULL
 #endif
-#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XFIXES
+
+#ifdef SDL_VIDEO_DRIVER_X11_DYNAMIC_XFIXES
+SDL_ELF_NOTE_DLOPEN(
+    "x11",
+    "Support for video through X11 backend",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED,
+    SDL_VIDEO_DRIVER_X11_DYNAMIC_XFIXES
+);
+#else
 #define SDL_VIDEO_DRIVER_X11_DYNAMIC_XFIXES NULL
 #endif
-#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR
+
+#ifdef SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR
+SDL_ELF_NOTE_DLOPEN(
+    "x11",
+    "Support for video through X11 backend",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED,
+    SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR
+);
+#else
 #define SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR NULL
 #endif
-#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS
+
+#ifdef SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS
+SDL_ELF_NOTE_DLOPEN(
+    "x11",
+    "Support for video through X11 backend",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED,
+    SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS
+);
+#else
 #define SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS NULL
 #endif
-#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST
+
+#ifdef SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST
+SDL_ELF_NOTE_DLOPEN(
+    "x11",
+    "Support for video through X11 backend",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED,
+    SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST
+);
+#else
 #define SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST NULL
 #endif
 

+ 14 - 0
src/video/x11/SDL_x11vulkan.c

@@ -39,6 +39,20 @@
 #define DEFAULT_X11_XCB "libX11-xcb.so.1"
 #endif
 
+SDL_ELF_NOTE_DLOPEN(
+    "x11-vulkan",
+    "Support for vulkan on X11",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    DEFAULT_VULKAN
+);
+
+SDL_ELF_NOTE_DLOPEN(
+    "x11-vulkan",
+    "Support for vulkan on X11",
+    SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+    DEFAULT_X11_XCB
+);
+
 /*
 typedef uint32_t xcb_window_t;
 typedef uint32_t xcb_visualid_t;