Lua native extension module fails to load .dll?

Hello! I’ve built a huge Renoise tool for the Akai Fire, and for performance reasons I’m trying to extend it with a native .dll module written in C++ or Rust. But I can’t get the Renoise scripting system to load a .dll file at all. I’ve tried targeting x86 (32-bit) and x64 (64-bit) architectures, tried “stdcall” and “C” calling conventions, etc. But I can’t seem to get luaopen_pyre_bridge or pyre_bridge or any such module-named function to be called. The pyre_bridge.dll file is found by require(), but I guess the .dll isn’t successfully being loaded. My other test programs are able to LoadLibrary and call test functions just fine (this is all Win10 for now). Is there something special about the Renoise Lua implementation that I need to know in order to get a native extension module to load? I’m not even doing anything with Lua yet, just trying to get a .dll function called from the Renoise tool.

An example of a tool with a native (.c, .cc, .cpp, or .rs source, .dll built) module that successfully loads would be very helpful.

package.cpath: .\?.dll;C:\Program Files\Renoise 3.2.1\?.dll;C:\Program Files\Renoise 3.2.1\loadall.dll;C:\Users\skylark\AppData\Roaming\Renoise\V3.2.1\Scripts\Libraries\?.dll;C:\Program Files\Renoise 3.2.1\Resources\Scripts\Libraries\?.dll
*** error loading module 'pyre_bridge' from file '.\pyre_bridge.dll':
***   The specified module could not be found.
*** 
*** stack traceback:
***   [C]: ?
***   [C]: in function 'require'
***   main.lua:15: in main chunk
1 Like

I can’t say what from the info you’ve given (and if ‘pyre_bridge’ is), but doesn’t the external c library have to follow a particular protocol/format and register functions etc (https://www.lua.org/pil/26.html) ?

Yes, that’s what my .dll does. It’s actually a Rust cdylib with extern “C” call convention – and it works great with various other Lua host setups (written in C++). For example, I got interop working smoothly with Lua 5.1.5 statically linked, dynamically linked, 32-bit, and 64-bit. I even got Renoise to call into my function, but I had to do it using package.loadlib() using the full path to the .dll – so if I can just get access to the lua_State* from within the script to pass into that function, then I should be off and running. Ideally, though, require() called from Renoise would behave the same way that I’m seeing require() behave in the other test hosts. It finds the .dll and calls luaopen_modulename(lua_state). It even works with submodules contained in the .dll, as documented. Strangely, Renoise require() does find the .dll file but doesn’t successfully load it and call my luaopen_… function.

I guess the answer might be buried in here but I feel so close with this package.loadlib() technique. The fact that Renoise can call my function is proof that it can load the .dll (it’s not a transitive dependency or architecture or call convention problem). Now I just need to get the lua_State* to pass in so I can tell Lua where my functions are…ideally with require(), but I’ll settle for a hack if it works. :slight_smile:

Whoa, I got require() working as expected by moving my tool’s local copy of the .dll out to ...AppData\Roaming\Renoise\V3.2.1\Scripts\Libraries !

This is exciting to see it work, but seems like it would be quite a problem for deployment to users if they have to move files out of the tool folder. I thought keeping everything self-contained was ideal for Renoise tools?

1 Like

Ok. Sounds as though you are kinda all set then :slight_smile:

Could you add the current tool folder to package.path ?

I did that in order to have multiple tools all load common Lua files from a shared relative folder.

https://jamesbritt.com/posts/sharing-lua-script-files-among-renoise-tools.html

But I haven’t worked with DLLs so I don’t know if this applies.

1 Like

Yeah, I’m good to go, thanks a lot 4tey and Neurogami!

I think the issue is something about the package.cpath having .\?.dll as the first entry. It messes up dll loading somehow, but I have a workaround. If I hack the cpath to look in renoise.tool().bundle_path first, then require() works correctly, my .dll happily loads and runs. :slight_smile:

2 Likes

Sweet! This may come in handy one day.

1 Like