Repository navigation
compileopts,builder: add -libc=glibc for linking system shared libraries - #5838
davecheney wants to merge 2 commits into
Conversation
|
Another libc? what's wrong with musl? Factually, nothing, but practically if you are trying to link against something like SDL2/3 then glibc is rusted on. Therefore this PR adds the option to switch from musl to glibc on linux systems specifically to link against bigass frameworks like SDL. The upside from taking this patch is there is a viable path to building linux + sdl apps using tinygo. |
dgryski
left a comment
There was a problem hiding this comment.
LGTM but I haven't tested it. We should probably add a small makefile test target to make sure this keeps working.
I'll gin up a SDL example as this is the proof in the pudding |
That also sounds good, but we should have at least minimal test coverage here, IMO. |
Leave it with me |
TinyGo links Linux binaries against the musl it ships, statically. That is a good default: it is the reason a build behaves the same on any machine and produces a single file. It also makes it impossible to link against a system shared library. Any shared library on a glibc distribution drags glibc in behind it, and two libcs cannot share a process. Whichever installs the thread pointer first owns it, and the other one's TLS accesses then read the wrong memory. Linking SDL and calling SDL_Init segfaults inside glibc's calloc, reading its malloc tcache through musl's TCB. There is a second, earlier failure hiding behind that one. lld only emits PT_INTERP when told --dynamic-linker, which nothing does here, so a binary that pulls in a shared library names no interpreter at all: it loads with its PLT unresolved and the first call through it lands on a null GOT entry. That one looks like a bug but is really the same story, since it is only reachable by linking a shared library in the first place. So add the other half: -libc=glibc uses the glibc already on the machine, linked dynamically, the way darwin-libSystem and mingw-w64 already use the system libc on their platforms. Linux was the odd one out. Tested on linux/amd64: the default build is still statically linked musl; -libc=glibc builds and runs both a pure Go program and a cgo program that calls into SDL2; the picolibc board targets are unaffected.
2d64ea4 to
d3f5837
Compare
Add a small cgo program that links against the system glibc and runs it from TestBuild on linux hosts. It calls gnu_get_libc_version, which only glibc has, and it uses malloc and errno on the main thread and on a goroutine. These use glibc's TLS, so the program only runs if the binary names the dynamic linker and glibc owns the thread pointer. The test skips if the glibc development files are not installed.
|
@deadprogram PTAL. I added a glibc test to the linux-assert build. |
|
Thanks @davecheney for working on this. Being able to link SDL on Linux will be very useful. Here are a few notes, edited from an automated review.
|
TinyGo links Linux binaries against the musl it ships, statically. That is a good default: it is the reason a build behaves the same on any machine and produces a single file. It also makes it impossible to link against a system shared library.
Any shared library on a glibc distribution drags glibc in behind it, and two libcs cannot share a process. Whichever installs the thread pointer first owns it, and the other one's TLS accesses then read the wrong memory. Linking SDL and calling SDL_Init segfaults inside glibc's calloc, reading its malloc tcache through musl's TCB.
There is a second, earlier failure hiding behind that one. lld only emits PT_INTERP when told --dynamic-linker, which nothing does here, so a binary that pulls in a shared library names no interpreter at all: it loads with its PLT unresolved and the first call through it lands on a null GOT entry. That one looks like a bug but is really the same story, since it is only reachable by linking a shared library in the first place.
So add the other half: -libc=glibc uses the glibc already on the machine, linked dynamically, the way darwin-libSystem and mingw-w64 already use the system libc on their platforms. Linux was the odd one out.
Tested on linux/amd64: the default build is still statically linked musl; -libc=glibc builds and runs both a pure Go program and a cgo program that calls into SDL2; the picolibc board targets are unaffected.