2
votes

I've been working at this for a while now and I can't figure out what's wrong.

At this point I've built everything from source and it still doesn't work. My environment is Windows 10 x64 and I'm compiling with Cygwin's MinGW-w64. Everything is compiled as i686 (32-bit) and not x86_64.

For reference, instances where I use gcc is actually i686-w64-mingw32-gcc. liblua53.dll.a and libyaml.a were compiled from source using Lua 5.3.5 and LibYAML 0.2.2.

I built the objects:

gcc -DVERSION=\"git-5695363\" -Ilua-5.3/src -Ilibyaml/src/include -c ext/yaml/emitter.c -o emitter.o
gcc -DVERSION=\"git-5695363\" -Ilua-5.3/src -Ilibyaml/src/include -c ext/yaml/scanner.c -o scanner.o
gcc -DVERSION=\"git-5695363\" -Ilua-5.3/src -Ilibyaml/src/include -c ext/yaml/parser.c -o parser.o
gcc -DVERSION=\"git-5695363\" -Ilua-5.3/src -Ilibyaml/src/include -c ext/yaml/yaml.c -o yaml.o

Then linked:

gcc -shared -static -s -Llua-5.3/dist -Llibyaml/dist emitter.o parser.o scanner.o yaml.o -lyaml -llua53.dll -o lyaml.dll

I've linked it as -shared because the output is a dll and as -static because I'm statically linking libyaml.a. I also tried compiling with dynamic linking to libyaml.dll with the same error from Lua.

My Lua environment was compiled from the source and compiler:

> lua53.exe -v
Lua 5.3.5  Copyright (C) 1994-2018 Lua.org, PUC-Rio

Running a simple script works fine:

> lua53.exe -e 'print("Hello!")'
Hello!

But I can't load the library:

> lua53.exe -e 'require("lyaml")'
lua53.exe: error loading module 'lyaml' from file 'lyaml.dll':
        The specified procedure could not be found.

stack traceback:
        [C]: in ?
        [C]: in function 'require'
        (command line):1: in main chunk
        [C]: in ?

I know that this is an error from Windows but I don't know what procedure is missing or where it's coming from.

I also checked that all dynamic-linking dependencies are being met and functions are being exported:

enter image description here

How can I debug this further?

2

2 Answers

2
votes

I ended up building everything on Linux and ran into the same problem but with a much more useful error:

$LD_LIBRARY_PATH=. ./test.lua
/bin/lua: error loading module 'lyaml' from file './lyaml.so':
        ./lyaml.so: undefined symbol: luaopen_lyaml
stack traceback:
        [C]: in ?
        [C]: in function 'require'
        ./test.lua:5: in main chunk
        [C]: in ?

The problem is that Lua binds the "luaopen_" symbol to the name of the library being loaded. So require("somelib") would be for somelib.dll with a an exact-matching luaopen_somelib export symbol. I built the library as lyaml.dll (to match the library name) but this symbol was exported as luaopen_yaml, which meant that Lua was looking for luaopen_lyaml (which didn't exist).

Several solutions are possible:

  • Modify the export in the source code to match the file name.
  • Modify the file name to match the export from the source code.
  • Ignore the discrepancy completely and use package.loadlib() which allows this.

I've opted for the third solution. Thank you @PaulKulchenko for the third solution.

The key takeaway from this is that there is by default a tight coupling between require(), the export symbol, and the file name of library being loaded.

1
votes

Since you are already using Dependency walker, I recommend using its "Profile" feature. You can start profiling on lua53.exe file and when you execute the require command, the profiler will show you the trace of all DLLs being loaded and any errors related to their load as well as the details of the error that you don't see from the Lua message.

You can also execute package.loadlib("lyaml.dll", "luaopen_yaml") to confirm that the signature is valid; you should get a function back that, when executed, will return the actual package.