LmCast :: Stay tuned in

The Holy Grail of Linux Binary Compatibility: Musl and Dlopen

Recorded: Jan. 26, 2026, 3 p.m.

Original Summarized

The Holy Grail of Linux Binary Compatibility: musl + dlopen · quaadgras graphics.gd · Discussion #242 · GitHub

Skip to content

Navigation Menu

Toggle navigation

Sign in

Appearance settings

PlatformAI CODE CREATIONGitHub CopilotWrite better code with AIGitHub SparkBuild and deploy intelligent appsGitHub ModelsManage and compare promptsMCP RegistryNewIntegrate external toolsDEVELOPER WORKFLOWSActionsAutomate any workflowCodespacesInstant dev environmentsIssuesPlan and track workCode ReviewManage code changesAPPLICATION SECURITYGitHub Advanced SecurityFind and fix vulnerabilitiesCode securitySecure your code as you buildSecret protectionStop leaks before they startEXPLOREWhy GitHubDocumentationBlogChangelogMarketplaceView all featuresSolutionsBY COMPANY SIZEEnterprisesSmall and medium teamsStartupsNonprofitsBY USE CASEApp ModernizationDevSecOpsDevOpsCI/CDView all use casesBY INDUSTRYHealthcareFinancial servicesManufacturingGovernmentView all industriesView all solutionsResourcesEXPLORE BY TOPICAISoftware DevelopmentDevOpsSecurityView all topicsEXPLORE BY TYPECustomer storiesEvents & webinarsEbooks & reportsBusiness insightsGitHub SkillsSUPPORT & SERVICESDocumentationCustomer supportCommunity forumTrust centerPartnersOpen SourceCOMMUNITYGitHub SponsorsFund open source developersPROGRAMSSecurity LabMaintainer CommunityAcceleratorArchive ProgramREPOSITORIESTopicsTrendingCollectionsEnterpriseENTERPRISE SOLUTIONSEnterprise platformAI-powered developer platformAVAILABLE ADD-ONSGitHub Advanced SecurityEnterprise-grade security featuresCopilot for BusinessEnterprise-grade AI featuresPremium SupportEnterprise-grade 24/7 supportPricing

Search or jump to...

Search code, repositories, users, issues, pull requests...

Search

Clear

Search syntax tips

Provide feedback


We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Cancel

Submit feedback

Saved searches

Use saved searches to filter your results more quickly

Name

Query

To see all available qualifiers, see our documentation.

Cancel

Create saved search

Sign in

Sign up

Appearance settings

Resetting focus

You signed in with another tab or window. Reload to refresh your session.
You signed out in another tab or window. Reload to refresh your session.
You switched accounts on another tab or window. Reload to refresh your session.

Dismiss alert

quaadgras

/

graphics.gd

Public

Uh oh!

There was an error while loading. Please reload this page.


Notifications
You must be signed in to change notification settings

Fork
31

Star
676

Code

Issues
1

Pull requests
0

Discussions

Actions

Projects
0

Security
0

Insights

Additional navigation options

Code

Issues

Pull requests

Discussions

Actions

Projects

Security

Insights

The Holy Grail of Linux Binary Compatibility: musl + dlopen

#242

Splizard


announced in
Announcements

The Holy Grail of Linux Binary Compatibility: musl + dlopen

#242

Splizard

Jan 26, 2026
·
2 comments

Return to top

Discussion options

Uh oh!

There was an error while loading. Please reload this page.




Quote reply


edited

Uh oh!

There was an error while loading. Please reload this page.



Splizard

Jan 26, 2026

Maintainer

-

I guess using Go + Godot to build native & installable Android & iOS binaries (without any proprietary SDKs) was too easy. So it's time for a real challenge...
Linux Binary Compatibility
(some background reading: https://jangafx.com/insights/linux-binary-compatibility)
For a while now, it's been very easy to reliably ship command line software & servers for Linux, just run go build and out pops a single static binary that will run on any Linux distribution running kernel 3.2 or later (which was released in 2012, so there's plenty of room for backwards compatibility).
The problems begin to creep in when you want access to hardware accelerated graphics. All the GPU drivers on Linux require accessing dynamic libraries via the C ABI. These C libraries are built against a particular libc, which is most commonly glibc but there are also a selection of musl-based distributions. If you compile a glibc library or executable, it won't run on a musl system and vice-versa. That's a big incompatibility right there!
In fact, I've directly experienced this, as I recently replaced the OS on my personal computer with the musl edition of Void Linux. Compiling the Zed editor with musl for example, was quite the challenge. It turns out that building graphics.gd projects on musl was also very broken. Go doesn't properly support c-shared or c-archive when building against musl.
That's a problem, firstly because this is my distro now, I need to be able to build graphics.gd projects! Secondly, in theory, musl has better support for static linking than glibc; so if there's any solution to this Linux Binary Compatibility mess, it's probably going to have something to do with musl.
Supporting musl
To work around these musl issues with Go, I had to patch the runtime with a build-overlay that applies when building for GOOS=musl. This is a new GOOS that I've introduced to graphics.gd, specifically to make musl builds possible.
Next up, I decided to ditch c-shared builds for musl, these were only convenient because you could easily plug and play Go into the official Godot binaries. The Godot Foundation doesn't provide official musl builds, so instead, I'm linking the Go code directly with Godot c-archive to end up with a single binary. Amazing, graphics.gd supports musl now!
There's just one issue, this means whenever somebody wants to release their project for Linux, they would have to create two builds, a Linux glibc build + a musl build and somehow communicate to their users, to pick the correct binary. Hell, before I installed Void Linux I didn't even fully comprehend the differences between musl and glibc, this feels like I'm simply contributing to the problem!
Single Static Binaries + Graphics
Hold up! Earlier I reported that a key benefit of musl was better static library support. There should be a way to build a graphics.gd project into a single static binary. Well, here's the thing. Yes, you can totally do this. Godot includes all of it's dependencies on Linux, everything else is dynamically loaded at runtime, so just add the -static command and...
ERROR Dynamic loading not supported
Ouch, Godot wants to use dlopen to interface with X11, Wayland, OpenGL, Vulkan etc. As it turns out, musl refuses to implement dlopen for static binaries. They don't want anyone to load a glibc library from musl because there are fundamental incompatibilities between how they implement TLS (thread-local-storage).
Don't worry though! As dlopen is compiled as a weak symbol, this means, that as long as graphics.gd implements it, there's still a chance to get a single static binary that can execute on any Linux system 3.2 onwards.
The Holy Grail
There's some precedent for this, there's the detour technique in C which will let you dlopen SDL and show graphics when running without a standard library. There's also Cosmopolitan's dlopen which uses a similar technique. So the solution here is to extend this for musl.
The way this works, is by including (or compiling) a small C program for the target machine. We load the program and execute into it from the same process. This program brings in the host's dynamic linker so that we can steal the system's dlopen and longjmp back into graphics.gd. We wrap any dynamically loaded functions with an assembly trampoline that switches to the system's libc TLS for the duration of the call. It all starts looking a lot like cgo.
So after much hair pulling and LLM wrangling, it turns out that musl + dlopen is all we need to produce single static binaries + graphics for Linux. Everyone can now enjoy the Go single-static-binary experience on Linux with full support for hardware accelerated graphics.
Try it!
Here's a build of the graphics.gd Dodge The Creeps sample project that should execute (and hopefully render graphics) on any Linux system with gcc installed (we don't embed the helper binaries yet).
https://release.graphics.gd/dodge_the_creeps.static
You can also cross-compile your own project (on any supported platform)
GOOS=musl GOARCH=amd64 gd build
Note you may need to delete your export_presets.cfg so that the new musl export preset is added to your project

Beta
Was this translation helpful?
Give feedback.

14
You must be logged in to vote

👍
5
🎉
2
❤️
5
🚀
14
👀
2


All reactions

👍
5

🎉
2

❤️
5

🚀
14

👀
2

Replies:

2 comments


Oldest


Newest


Top

Comment options

Uh oh!

There was an error while loading. Please reload this page.




Quote reply

phreda4

Jan 26, 2026

-

I use the dlopen/dlsym technique in Linux and loadlibrary/getprocaddress in my language's VM.
Loading, sdl2, the same code (r3forth) works in both operating systems.
Assembly isn't necessary for the calls (of course, the language is specific).
Although I don't use floating-point numbers, these types of calls are very complicated (in fact, I don't use them) because the assignment depends on the parameter's position (poor design?).
I have the problem of doing the same for Android and the web; I think I'll have to simulate this mechanism. What do you recommend I research to do this? Is the interface with Godot similar ? I'd like to see how to add my language to this engine too.

Beta
Was this translation helpful?
Give feedback.

2
You must be logged in to vote


All reactions

0 replies

Comment options

Uh oh!

There was an error while loading. Please reload this page.




Quote reply

X-Ryl669

Jan 26, 2026

-

Doesn't work for me:
Thread 1 "dodge_the_creep" received signal SIGSEGV, Segmentation fault.
0x0000000002b13d16 in foreign_tramp ()
(gdb) bt
#0 0x0000000002b13d16 in foreign_tramp ()
#1 0x00007fffaa55a5a0 in ?? ()
#2 0x00007ffff75e4558 in ?? ()
#3 0x00007fff5ffec436 in ?? ()
#4 0x00007fffaa2ed710 in ?? ()
#5 0x00007fffffffc0d0 in ?? ()
#6 0x00007fff5ffe5ecc in ?? ()
#7 0x00007fffffffc0d0 in ?? ()
#8 0x00007fff5f9cc488 in ?? ()
#9 0x00007fffaa559a40 in ?? ()
#10 0x0000000000000000 in ?? ()
(gdb)

Beta
Was this translation helpful?
Give feedback.

2
You must be logged in to vote


All reactions

0 replies

Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment

Category

📣

Announcements

Labels

None yet

3 participants

Footer

© 2026 GitHub, Inc.

Footer navigation

Terms

Privacy

Security

Status

Community

Docs

Contact

Manage cookies

Do not share my personal information

You can’t perform that action at this time.

The Holy Grail of Linux Binary Compatibility: musl + dlopen delves into a significant technical challenge – creating a standalone, hardware-accelerated graphics application (specifically, the "dodge_the_creeps" sample project) that can run on Linux without relying on proprietary SDKs or dynamic library dependencies. The core problem centers around the incompatibility between glibc-based Linux distributions and musl-based distributions, particularly when dealing with graphics acceleration. This essay, by Splizard, details the innovative solution employed to achieve this, highlighting the intricacies of building a single, static binary for Linux using musl.

The author’s initial experience, replacing their personal computer’s operating system with Void Linux (a musl-based distribution), directly exposed the fundamental issue. Compiling graphics.gd projects with musl proved incredibly difficult, demonstrating the inherent conflict when libraries like glibc, which rely on dynamic linking and dlopen for accessing graphics drivers, are incompatible with musl’s approach to static linking. The need to integrate with hardware acceleration, a common requirement for graphics applications, further complicates the situation.

The solution proposes using Godot’s engine as a fundamental layer. Godot, by design, utilizes dynamic loading for its dependencies on Linux. This means it loads libraries at runtime via dlopen. However, musl refuses to implement dlopen for static binaries, primarily due to fundamental differences in how it handles thread-local storage (TLS) compared to glibc. The ingenious workaround lies in leveraging the “dlopen/dlsym technique.” This method, often employed in languages like Forth, involves creating a small C program that is compiled and executed along with the main application. This program then utilizes dlopen to load a glibc library and uses dlsym to invoke functions from that library. The critical step is a "longjmp" back into the main graphics.gd application, effectively hijacking the execution flow and managing the TLS context.

To reconcile this with Godot, the author employs a build-overlay specifically for GOOS=musl. This overlay facilitates the creation of a musl-compatible build of graphics.gd. The key innovation is the explicit rejection of c-shared builds, which are convenient but inherently reliant on the glibc dynamic linking infrastructure. Instead, the application is directly linked with Godot’s c-archive. This creates a single static binary. The single static binary also requires a small C program to be included, acting as a bridge.

Despite the successful implementation, the author acknowledges the remaining issue – the inherent difficulties in coordinating a cross-platform distribution of the application. The need for both glibc and musl builds, and the subsequent communication to the end-user to select the correct binary, represents a challenge. The discussion briefly touches on the precedent set by techniques like the "detour technique" and Cosmopolitan’s dlopen approach, both offering similar solutions.

The author provides a downloadable build of the "dodge_the_creeps" sample project, packaged as a static binary. The build instructions call for a GOOS=musl build targeting AMD64 architecture. The importance of deleting the export_presets.cfg file is emphasized – this is crucial in triggering the creation of the musl build. The author also notes the potential complexity of managing this project across different platforms, ultimately highlighting the core challenge of achieving truly universal Linux binary compatibility. The discussion concludes with a call for research into solutions for Android and the web, mirroring the complexity of the original challenge.