Subject: Linker not finding library

From: Stefano Cossu <[email-masked]>
Date: Fri, 6 Feb 2026 16:34:02 -0500

Hello there,
I am running into a basic linker problem in Alpine, where the linker 
cannot find libraries outside of /usr/lib.

Running in a basic docker container:

$ docker run -it alpine:latest sh
/ # apk add lua5.4-dev lua5.4-linotify
(1/8) Installing lua5.4-libs (5.4.8-r0)
(2/8) Installing ncurses-terminfo-base (6.5_p20251123-r0)
(3/8) Installing libncursesw (6.5_p20251123-r0)
(4/8) Installing readline (8.3.1-r0)
(5/8) Installing lua5.4 (5.4.8-r0)
(6/8) Installing pkgconf (2.5.1-r0)
(7/8) Installing lua5.4-dev (5.4.8-r0)
(8/8) Installing lua5.4-linotify (0.5-r2)
Executing busybox-1.37.0-r30.trigger
OK: 10.8 MiB in 24 packages
/ # export LD_LIBRARY_PATH=/usr/local/lib:/usr/lib
/ # ldd /usr/lib/lua/5.4/inotify.so
	/lib/ld-musl-x86_64.so.1 (0x7ee2fa7d2000)
	libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7ee2fa7d2000)
Error relocating /usr/lib/lua/5.4/inotify.so: lua_touserdata: symbol not 
found
Error relocating /usr/lib/lua/5.4/inotify.so: lua_getfield: symbol not found
Error relocating /usr/lib/lua/5.4/inotify.so: lua_gettop: symbol not found
Error relocating /usr/lib/lua/5.4/inotify.so: luaL_checklstring: symbol 
not found
Error relocating /usr/lib/lua/5.4/inotify.so: lua_setfield: symbol not found
Error relocating /usr/lib/lua/5.4/inotify.so: lua_newuserdatauv: symbol 
not found
Error relocating /usr/lib/lua/5.4/inotify.so: lua_pushvalue: symbol not 
found
Error relocating /usr/lib/lua/5.4/inotify.so: lua_pushnil: symbol not found
Error relocating /usr/lib/lua/5.4/inotify.so: luaL_error: symbol not found
Error relocating /usr/lib/lua/5.4/inotify.so: lua_settop: symbol not found
Error relocating /usr/lib/lua/5.4/inotify.so: lua_pushcclosure: symbol 
not found
Error relocating /usr/lib/lua/5.4/inotify.so: lua_type: symbol not found
Error relocating /usr/lib/lua/5.4/inotify.so: lua_pushboolean: symbol 
not found
Error relocating /usr/lib/lua/5.4/inotify.so: lua_setmetatable: symbol 
not found
Error relocating /usr/lib/lua/5.4/inotify.so: lua_rawseti: symbol not found
Error relocating /usr/lib/lua/5.4/inotify.so: luaL_newmetatable: symbol 
not found
Error relocating /usr/lib/lua/5.4/inotify.so: lua_pushstring: symbol not 
found
Error relocating /usr/lib/lua/5.4/inotify.so: luaL_checkinteger: symbol 
not found
Error relocating /usr/lib/lua/5.4/inotify.so: luaL_checkudata: symbol 
not found
Error relocating /usr/lib/lua/5.4/inotify.so: luaL_setfuncs: symbol not 
found
Error relocating /usr/lib/lua/5.4/inotify.so: lua_toboolean: symbol not 
found
Error relocating /usr/lib/lua/5.4/inotify.so: lua_createtable: symbol 
not found
Error relocating /usr/lib/lua/5.4/inotify.so: lua_pushinteger: symbol 
not found
/ #

All the above symbols are in /usr/lib/liblua-5.4.so.0, e.g.

/ # readelf -s /usr/lib/liblua-5.4.so.0 | grep lua_touserdata
    238: 0000000000005a70    13 FUNC    GLOBAL DEFAULT    9 lua_touserdata

but even if I add /usr/lib to LD_LIBRARY_PATH, the symbols are not found.

This is not specific to Lua or to the linotify library, I tried with 
other non-system libraries as well.

Is there something else that I need set up?

Thanks,
Stefano

---

From: Jeffrey Walton <[email-masked]>
Date: Fri, 6 Feb 2026 17:09:07 -0500

> Is there something else that I need set up?

I seem to recall Musl rejects all library paths if there is one bad library
path, even via RPATH and RUNPATH.  Note that this is different behavior
from GNU's link loader. Also see <
https://www.openwall.com/lists/musl/2020/05/21/2> and <
https://www.openwall.com/lists/musl/2021/11/17/1>.

Can you dump the RPATH and RUNPATH and verify each one of them is valid?

Jeff

---

From: Stefano Cossu <[email-masked]>
Date: Fri, 6 Feb 2026 17:23:48 -0500

> Can you dump the RPATH and RUNPATH and verify each one of them is valid?
If you are referring to env variables, those are both empty for me:

/ # echo $SRPATH

/ # echo $RUNPATH

---

From: Jeffrey Walton <[email-masked]>
Date: Sat, 7 Feb 2026 12:53:03 -0500

> If you are referring to env variables, those are both empty for me:

I see you found the answer, so this was a dead end.  But for completeness:

    readelf -d /usr/lib/lua/5.4/inotify.so | grep -E 'RPATH|RUNPATH'

Jeff

---

From: Stefano Cossu <[email-masked]>
Date: Sat, 7 Feb 2026 19:02:58 -0500

Thanks, Jeff. As you may have guessed, I am still learning my way around 
C and related tooling. I appreciate the help.
s

On 2/7/26 12:53 PM, Jeffrey Walton wrote:
> 
> 
> On Fri, Feb 6, 2026 at 5:24 PM Stefano Cossu <[email-masked] 
> <mailto:[email-masked]>> wrote:
> 
> 
>

---

From: Naomi Rennie-Waldock <[email-masked]>
Date: Fri, 6 Feb 2026 22:49:09 +0000

On 06/02/2026 21:34, Stefano Cossu wrote:
> Error relocating /usr/lib/lua/5.4/inotify.so: lua_touserdata: symbol 
> not found

Can you give a non-lua example? For lua, this is expected due to musl 
intentionally not supporting lazy binding[1]

A quick test of something non-lua works as expected:

~ # ldd hello
         /lib/ld-musl-x86_64.so.1 (0x7fad2a4f1000)
Error loading shared library libhello.so: No such file or directory 
(needed by hello)
         libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7fad2a4f1000)
Error relocating hello: hello: symbol not found
~ # LD_LIBRARY_PATH=. ldd hello
         /lib/ld-musl-x86_64.so.1 (0x7fa8a7ad3000)
         libhello.so => ./libhello.so (0x7fa8a7ac1000)
         libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7fa8a7ad3000)
~ # LD_LIBRARY_PATH=. ./hello
Hello world

[1] https://wiki.musl-libc.org/functional-differences-from-glibc.html#Lazy-bindings

---

From: Stefano Cossu <[email-masked]>
Date: Fri, 6 Feb 2026 18:15:41 -0500

Thanks for the reference to lazy bindings, Naomi. Eventually I will have 
to resolve it for Lua as well and I'll keep your reference handy, but 
for now, I tried to compile and execute a program from scratch that uses 
LMDB, another non-system lib that I need to link against:

/ # apk add musl-dev lmdb-dev gcc
[…]
/ # cat test.c
#include <stdio.h>
#include "lmdb.h"

int main() {
     printf("LMDB test: %s\n", mdb_strerror(MDB_SUCCESS));
     return 0;
}

/ # gcc -llmdb -L/usr/lib test.c -o test.o
/usr/lib/gcc/x86_64-alpine-linux-musl/15.2.0/../../../../x86_64-alpine-linux-musl/bin/ld: 
/tmp/ccgjDlGg.o: in function `main':
test.c:(.text+0xa): undefined reference to `mdb_strerror'
collect2: error: ld returned 1 exit status

I can't even seem to link in the build phase in this case. The library 
I'm looking at has the symbol indeed:

/ # readelf -s /usr/lib/liblmdb.so | grep mdb_strerror
     87: 0000000000007f70    72 FUNC    GLOBAL DEFAULT    9 mdb_strerror

s

---

From: Naomi Rennie-Waldock <[email-masked]>
Date: Fri, 6 Feb 2026 23:23:47 +0000

On 06/02/2026 23:15, Stefano Cossu wrote:
> Thanks for the reference to lazy bindings, Naomi. Eventually I will 
> have to resolve it for Lua as well and I'll keep your reference handy, 
> but for now, I tried to compile and execute a program from scratch 
> that uses LMDB, another non-system lib that I need to link against:
>

Ahh, you've got your arguments are in the wrong order, the lib needs to 
listed be after the sources that depend on it. Example:

~ # gcc lmdb-test.c -llmdb -o lmdb-test && ./lmdb-test
LMDB test: Successful return: 0

---

From: Stefano Cossu <[email-masked]>
Date: Fri, 6 Feb 2026 18:30:33 -0500

Oops, sorry. OK, now it compiles and runs, so back to Lua: I'm not 
familiar with lazy bindings. Is that a compilation option? Meaning, if I 
recompile Lua with default Musl options, would it behave correctly? In 
that case, I wonder why the Alpine package comes with lazy bindings. Or 
is there something else?

Thanks,
s

On 2/6/26 6:23 PM, Naomi Rennie-Waldock wrote:
>> /usr/lib/gcc/x86_64-alpine-linux-musl/15.2.0/../../../../x86_64- 
>> alpine-linux-musl/bin/ld: /tmp/ccgjDlGg.o: in function `main':

---

From: Naomi Rennie-Waldock <[email-masked]>
Date: Fri, 6 Feb 2026 23:40:00 +0000

On 06/02/2026 23:30, Stefano Cossu wrote:
> familiar with lazy bindings. Is that a compilation option? Meaning, if 
> I recompile Lua with default Musl options, would it behave correctly? 
> In that case, I wonder why the Alpine package comes with lazy 
> bindings. Or is there something else?
>
> Thanks,
> s
>

It's just a design difference between glibc and musl. ldd will probably 
give "symbol not found" for libs that are loaded by something else as 
plugins (PHP extensions do the same thing), but it will otherwise still 
function correctly. The sample from the lua-linotify readme works 
correctly, despite ldd's errors:

~ # cat test.lua
local inotify = require 'inotify'
local handle = inotify.init()

-- Watch for new files and renames
local wd = handle:addwatch('/root', inotify.IN_CREATE, inotify.IN_MOVE)

local events = handle:read()

for _, ev in ipairs(events) do
     print(ev.name .. ' was created or renamed')
end

-- Done automatically on close, I think, but kept to be thorough
handle:rmwatch(wd)

handle:close()
~ # lua5.4 test.lua &
~ # touch a
a was created or renamed

If you really do need to run ldd on lua libs, you can make it preload 
lua to quiet the errors:

~ # LD_PRELOAD=/usr/lib/lua5.4/liblua.so ldd /usr/lib/lua/5.4/inotify.so
         /lib/ld-musl-x86_64.so.1 (0x7fd156f35000)
         /usr/lib/lua5.4/liblua.so => /usr/lib/lua5.4/liblua.so 
(0x7fd156ef2000)
         libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7fd156f35000)

---

From: Stefano Cossu <[email-masked]>
Date: Fri, 6 Feb 2026 20:59:03 -0500

OK, I think I got sidetracked by the ldd error when I tried on more 
general libraries while debugging a "symbol not found" for a Lua/C 
library that I built on top of LMDB and the Lua API.

the LD_PRELOAD env variable works, though:

LD_PRELOAD="/usr/lib/liblmdb.so:/usr/lib/libuuid.so:/usr/lib/libxxhash.so" 
lua5.4 -e 'term = require "volksdata.term"'

(volksdata is my library that uses the 3 libraries in LD_PRELOAD)

As I need to preload several libraries (notably NOT lua.h), I could add 
those to ld.so.preload, but I'm just wondering if this is more like a 
hack than a recommended practice.

Thanks a lot for the help so far.
s

---

From: Naomi Rennie-Waldock <[email-masked]>
Date: Sat, 7 Feb 2026 02:39:57 +0000

On 07/02/2026 01:59, Stefano Cossu wrote:
> As I need to preload several libraries (notably NOT lua.h), I could 
> add those to ld.so.preload, but I'm just wondering if this is more 
> like a hack than a recommended practice.
>

Can you try building volksdata with these two changes to the Makefile:

-CFLAGS = -shared -Wall -Wextra -fPIC
+CFLAGS += -shared -Wall -Wextra -fPIC

-LDFLAGS = -L$(PREFIX)/lib -L$(VOLK_LIBDIR) -llua -llmdb -lxxhash -luuid
+LDFLAGS += -L$(PREFIX)/lib -L$(VOLK_LIBDIR) -llua -Wl,--no-as-needed 
-llmdb -lxxhash -luuid

And then build with: CFLAGS=$(pkg-config lua5.4 --cflags) 
LDFLAGS=$(pkg-config lua5.4 --libs) make

That should give you a working build:

~/volksdata_lua # CFLAGS=$(pkg-config lua5.4 --cflags) 
LDFLAGS=$(pkg-config lua5.4 --libs) make install
mkdir -p lib/
cc -I/usr/local/include -Iext/volksdata/build/include 
-I/usr/include/lua5.4 -shared -Wall -Wextra -fPIC -DNDEBUG -O3 -g0 
-L/usr/lib/lua5.4 -llua -lm -L/usr/local/lib -Lext/volksdata/build -llua 
-Wl,--no-as-needed -llmdb -lxxhash -luuid -o lib/volksdata.so src/*.c 
ext/volksdata/build/libvolksdata.a
mkdir -p /usr/local/lib/lua/5.4
install -p lib/volksdata.so /usr/local/lib/lua/5.4
~/volksdata_lua # LD_PRELOAD=/usr/lib/lua5.4/liblua.so ldd 
/usr/local/lib/lua/5.4/volksdata.so
         /lib/ld-musl-x86_64.so.1 (0x7f7d1f0e1000)
         /usr/lib/lua5.4/liblua.so => /usr/lib/lua5.4/liblua.so 
(0x7f7d1f071000)
         liblmdb.so.0 => /usr/lib/liblmdb.so.0 (0x7f7d1f059000)
         libxxhash.so.0 => /usr/lib/libxxhash.so.0 (0x7f7d1f046000)
         libuuid.so.1 => /usr/lib/libuuid.so.1 (0x7f7d1f03d000)
         libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7f7d1f0e1000)
~/volksdata_lua #  lua5.4 -e 'term = require "volksdata.term"'
02:36:16 INFO  src/environment.c:123: Volksdata environment initialized.
02:36:16 INFO  src/environment.c:149: Volksdata environment torn down.

---

From: Stefano Cossu <[email-masked]>
Date: Fri, 6 Feb 2026 21:55:28 -0500

Amazing! It's working now. Thanks so much for finding this bug. It's 
just a fluke that it didn't break with glibc...
s

On 2/6/26 9:39 PM, Naomi Rennie-Waldock wrote:
>> LD_PRELOAD="/usr/lib/liblmdb.so:/usr/lib/libuuid.so:/usr/lib/ 
>> libxxhash.so" lua5.4 -e 'term = require "volksdata.term"'
>>
> +LDFLAGS += -L$(PREFIX)/lib -L$(VOLK_LIBDIR) -llua -Wl,--no-as-needed - 
> llmdb -lxxhash -luuid
> 
> 
> And then build with: CFLAGS=$(pkg-config lua5.4 --cflags) LDFLAGS=$(pkg- 
> config lua5.4 --libs) make
> 
> 
> ~/volksdata_lua # CFLAGS=$(pkg-config lua5.4 --cflags) LDFLAGS=$(pkg- 
> config lua5.4 --libs) make install
> mkdir -p lib/
> cc -I/usr/local/include -Iext/volksdata/build/include -I/usr/include/ 
> lua5.4 -shared -Wall -Wextra -fPIC -DNDEBUG -O3 -g0 -L/usr/lib/lua5.4 - 
> llua -lm -L/usr/local/lib -Lext/volksdata/build -llua -Wl,--no-as-needed 
> -llmdb -lxxhash -luuid -o lib/volksdata.so src/*.c ext/volksdata/build/ 
> libvolksdata.a
> ~/volksdata_lua # LD_PRELOAD=/usr/lib/lua5.4/liblua.so ldd /usr/local/ 
> lib/lua/5.4/volksdata.so