Error when loading a C submodule from dll

55 views
Skip to first unread message

Jasper Klein

unread,
Dec 27, 2025, 2:57:39 PM (22 hours ago) Dec 27
to lua-l
I'm making a C module with submodules so I can load libraries with 'foo.bar' or 'foo.baz'.

This works fine on my Linux PC but on a Windows VM Lua fails to load the dll.
The following error is shown in the console:

Y:\PG1003\foo>.\..\x64\Debug\Lua54.exe .\test\main.lua
Running tests...
.\..\x64\Debug\Lua54.exe: error loading module 'foo.bar' from file './.\test\main.lua':
        %1 is not a valid Win32 application.


stack traceback:
        [C]: in ?
        [C]: in function 'require'
        ./.\test\tests/foo.lua:2: in main chunk
        [C]: in function 'require'
        ./.\test\test.lua:108: in function 'test.run_test_modules'
        (...tail calls...)
        .\test\main.lua:37: in main chunk
        [C]: in ?


The line './.\test\tests/foo.lua:2: in main chunk' is the call with the require for the submodule.
Also Windows shows an error messagebox that contains error status 0xc000012f.

This is with Lua 5.4.7.
I didn't try to reproduce the issue with older or newer versions of Lua.

Has anyone else encountered the same problem?
Can I fix this in the C module?
Or is this a bug in Lua?

-- Jasper

Spar

unread,
Dec 27, 2025, 3:40:43 PM (22 hours ago) Dec 27
to lua-l
You need to provide info about your compilation command. Do you export luaopen?
--
You received this message because you are subscribed to the Google Groups "lua-l" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lua-l+un...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/lua-l/934a2e2e-22f4-495c-afeb-3c217871e9can%40googlegroups.com.

Jasper Klein

unread,
Dec 27, 2025, 5:05:35 PM (20 hours ago) Dec 27
to lua-l
Op zaterdag 27 december 2025 om 21:40:43 UTC+1 schreef Spar:
You need to provide info about your compilation command. Do you export luaopen?

The Lua executable is linked to a Lua dll of the same version.
I use Visual Studio 2022 version 17.13 and the executable, dll and module are in the same solution and use the same compiler, the same language version and are build as debug.
The module is build with warning level 4 while Lua is build with warning level 3.

The luaopen_ functions are exported.
There are no issues when the functions are registered like a regular module.

This works on Windows and Linux
local foo = require( "foo" )  -- luaopen_foo

This fails for foo.dll on Windows but works for foo.so on Linux
local bar = require( "foo.bar" )  -- luaopen_foo_bar 

Sewbacca

unread,
Dec 27, 2025, 6:48:11 PM (19 hours ago) Dec 27
to lu...@googlegroups.com
gnu/clang export all symbols per default that's why it probably works on Linux. If luaopen_foo_bar is not found on Windows it is not exported.

If you think it is exported we'll need more info about your specific module. And it's compilation process.

~ Sewbacca

Jasper Klein

unread,
10:04 AM (3 hours ago) 10:04 AM
to lua-l
Okay, here are more details of the implementation and build process.

I'm implementing a hashing module for my own private project.
The hashing algoritms are categorized by using submodules.
To quote the manual about submodules:
"For instance, when requiring a.b.c, it will search for a C library for a. If found, it looks into it for an open function for the submodule; in our example, that would be luaopen_a_b_c. With this facility, a package can pack several C submodules into one single library, with each submodule keeping its original open function."

The hashing module is written in C++.
I've my own small header only library to help binding functions to the Lua world and to reduce boilerplate when dealing with userdata.

These compiler and linker flags are used by Visual Studio when building binaries for debug mode:

Lua dll

Compile flags:
/JMC /permissive- /ifcOutput "x64\Debug\" /GS /W3 /Zc:wchar_t /ZI /Gm- /Od /sdl /Fd"Y:\PG1003\x64\Debug\Lua54.pdb" /Zc:inline /fp:precise /D "LUA_BUILD_AS_DLL" /D "_CRT_SECURE_NO_WARNINGS" /D "_DEBUG" /D "_CONSOLE" /D "_WINDLL" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX /Zc:forScope /RTC1 /Gd /MDd /std:c++23preview /FC /Fa"x64\Debug\" /EHsc /nologo /Fo"x64\Debug\" /Fp"x64\Debug\Lua54.pch" /diagnostics:column

Linker flags:
/OUT:"Y:\PG1003\x64\Debug\Lua54.dll" /MANIFEST /NXCOMPAT /PDB:"Y:\PG1003\x64\Debug\Lua54.pdb" /DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /IMPLIB:"Y:\PG1003\x64\Debug\Lua54.lib" /DEBUG /DLL /MACHINE:X64 /INCREMENTAL /PGD:"Y:\PG1003\x64\Debug\Lua54.pgd" /SUBSYSTEM:WINDOWS /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"x64\Debug\Lua54.dll.intermediate.manifest" /LTCGOUT:"x64\Debug\Lua54.iobj" /ERRORREPORT:PROMPT /ILK:"x64\Debug\Lua54.ilk" /NOLOGO /TLBID:1

Lua exe

Compile flags:
/JMC /permissive- /ifcOutput "x64\Debug\" /GS /W4 /Zc:wchar_t /I"Y:\PG1003\LibLua54" /ZI /Gm- /Od /sdl /Fd"x64\Debug\vc143.pdb" /Zc:inline /fp:precise /D "LUA_BUILD_AS_DLL" /D "_CRT_SECURE_NO_WARNINGS" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX /Zc:forScope /RTC1 /Gd /MDd /std:c++23preview /FC /Fa"x64\Debug\" /EHsc /nologo /Fo"x64\Debug\" /Fp"x64\Debug\Lua54.pch" /diagnostics:column

Linker flags:
/OUT:"Y:\PG1003\x64\Debug\Lua54.exe" /MANIFEST /NXCOMPAT /PDB:"Y:\PG1003\x64\Debug\Lua54.pdb" /DYNAMICBASE "Lua54.lib" "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /DEBUG /MACHINE:X64 /INCREMENTAL /PGD:"Y:\PG1003\x64\Debug\Lua54.pgd" /SUBSYSTEM:CONSOLE /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"x64\Debug\Lua54.exe.intermediate.manifest" /LTCGOUT:"x64\Debug\Lua54.iobj" /ERRORREPORT:PROMPT /ILK:"x64\Debug\Lua54.ilk" /NOLOGO /LIBPATH:"Y:\PG1003\x64\Debug\" /TLBID:1

Module

Compile flags:
/JMC /permissive- /ifcOutput "x64\Debug\" /GS /W4 /Zc:wchar_t /I"Y:\PG1003\LibLua54" /ZI /Gm- /Od /sdl /Fd"x64\Debug\vc143.pdb" /Zc:inline /fp:precise /D "LUA_BUILD_AS_DLL" /D "_CRT_SECURE_NO_WARNINGS" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX /Zc:forScope /RTC1 /Gd /MDd /std:c++23preview /FC /Fa"x64\Debug\" /EHsc /nologo /Fo"x64\Debug\" /Fp"x64\Debug\Lua54.pch" /diagnostics:column

Linker flags:
/OUT:"Y:\PG1003\x64\Debug\hash.dll" /MANIFEST /NXCOMPAT /PDB:"Y:\PG1003\x64\Debug\hash.pdb" /DYNAMICBASE "Lua54.lib" "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /IMPLIB:"Y:\PG1003\x64\Debug\hash.lib" /DEBUG /DLL /MACHINE:X64 /INCREMENTAL /PGD:"Y:\PG1003\x64\Debug\hash.pgd" /SUBSYSTEM:WINDOWS /MANIFESTUAC:NO /ManifestFile:"x64\Debug\hash.dll.intermediate.manifest" /LTCGOUT:"x64\Debug\hash.iobj" /ERRORREPORT:PROMPT /ILK:"x64\Debug\hash.ilk" /NOLOGO /LIBPATH:"Y:\PG1003\x64\Debug\" /TLBID:1

The Lua executable and the module are dynamically linked to Lua54.dll.
These 3 projects (as they are called in Visual Studio) compile without errors and warnings.


The following is part of the source code.
To repeat myself; there are no errors thrown by Lua or Windows when `luaopen_hash_md5` is renamed to `luaopen_hash` and `require( "hash" )` is called instead of `require( "hash.md5" )`.

//
// Includes
//
// ...
//

#if defined( _WIN32 )
# define EXPORT __declspec( dllexport )
#else
# define EXPORT
#endif

//
// Implementation
//
// ...
//

static constexpr const luaL_Reg crc_functions[] =
{
    { "crc32", crc32::calculate_crc32 },
    { NULL,    NULL }
};

static constexpr const luaL_Reg md5_functions[] =
{
    { "md5",     md5::calculate_md5 },
    { "digest",  md5::make_digest },
    { NULL,      NULL }
};

extern "C"
{

EXPORT int luaopen_hash_crc( lua_State * const L ) noexcept
{
    luaL_checkversion( L );

    lua_newtable( L );
    luaL_setfuncs( L, crc_functions, 0 );

    return 1;
}

EXPORT int luaopen_hash_md5( lua_State * const L ) noexcept
{
    luaL_checkversion( L );

    register_metatable< md5::digest >( L );

    lua_newtable( L );
    luaL_setfuncs( L, md5_functions, 0 );

    return 1;
}

}


Augusto Goulart

unread,
11:01 AM (2 hours ago) 11:01 AM
to lu...@googlegroups.com
Do you **need** to use MSVS? I've made a CRC32 module and this is the build script (with MinGW):

targ='libluacrc32'

gcc -Wall -Wextra -Wpedantic -Wshadow -Wformat=2 \
    -fPIC $CFLAGS --std=c11 -O3 -c lookup.c $targ.c

if [ "$(printenv 'OS')" = 'Windows_NT' ]; then
  gcc -shared -lm -o $targ.dll $targ.o lookup.o $LFLAGS -llua55
else
  gcc -shared -lm -o $targ.so $targ.o lookup.o $LFLAGS
fi

It doesn't have submodules, so it might not be helpful to you, but here's the code: https://github.com/oAGoulart/libluacrc32/tree/master

Augusto

--
You received this message because you are subscribed to the Google Groups "lua-l" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lua-l+un...@googlegroups.com.

Jasper Klein

unread,
11:26 AM (2 hours ago) 11:26 AM
to lua-l
Op zondag 28 december 2025 om 17:01:47 UTC+1 schreef Augusto Goulart:
Do you **need** to use MSVS? I've made a CRC32 module and this is the build script (with MinGW):

 I've no experience using gcc on Windows.
All my projects run on Linux and Windows.
For Linux I use gcc and for Windows MSVC and for some projects also clang via Visual Studio.

Each compiler outputs different warnings and catches issues that other compilers do not catch.
This made my code more portable and better.
Also it helps me to track down the origin of compile errors when the error message is hard to understand.

-- Jasper

Sewbacca

unread,
11:33 AM (2 hours ago) 11:33 AM
to lu...@googlegroups.com
What do the lua commands

print(assert(package.loadlib(path, "luaopen_hash_crc"))())
print(assert(package.loadlib(path, "luaopen_hash_md5"))())

yield?

What does the cmd shell command:

dumpbin /SYMBOLS path | findstr luaopen_

yield?

You need to replace path with the path to your dll file.

All in all this looks correctly configured.

~ Sewbacca

Luau Project

unread,
11:38 AM (2 hours ago) 11:38 AM
to lu...@googlegroups.com
Around a year ago, I coded a hashing module like this (registered on LuaRocks under the name "lua-hash"), chaining "different classes" inside a main module.

Basically, I tried to follow the idea of OpenSSL + Windows bcrypt API. In short, I wrapped a few classes to open different algorithms (md5, sha256, ...), allowed the user to feed a context with data up to some point, then finalize the message digest.

If you "relax definitions" and consider userdata as a special table, you may have your main module exported as userdata "a", then set a submodule "b" as a field of "a". You can check the sources of my module to have ideas how I chained such submodules ( https://github.com/luau-project/lua-hash )
Reply all
Reply to author
Forward
0 new messages