From 0214c7605e8475efbe81f246a56a7a9938f33767 Mon Sep 17 00:00:00 2001 From: bjorn Date: Sat, 7 Jul 2018 13:54:53 -0700 Subject: [PATCH] Support requiring dll/so files; Still WIP --- src/api/filesystem.c | 71 ++++++++++++++++++++++++++++++++++---------- src/luax.c | 14 +++++++++ src/luax.h | 1 + src/util.c | 29 ++++++++++++++++++ src/util.h | 3 ++ 5 files changed, 102 insertions(+), 16 deletions(-) diff --git a/src/api/filesystem.c b/src/api/filesystem.c index fa154f97..f8752f0a 100644 --- a/src/api/filesystem.c +++ b/src/api/filesystem.c @@ -32,8 +32,7 @@ static int pushDirectoryItem(void* userdata, const char* path, const char* filen int l_lovrFilesystemLoad(lua_State* L); -// Loader to help Lua's require understand PhysFS. -static int filesystemLoader(lua_State* L) { +static int moduleLoader(lua_State* L) { const char* module = luaL_gsub(L, lua_tostring(L, -1), ".", "/"); lua_pop(L, 2); @@ -49,6 +48,58 @@ static int filesystemLoader(lua_State* L) { return 0; } +static const char* libraryExtensions[] = { +#ifdef _WIN32 + ".dll", NULL +#elif __APPLE__ + ".so", ".dylib", NULL +#else + ".so", NULL +#endif +}; + +static int libraryLoader(lua_State* L) { + const char* modulePath = luaL_gsub(L, lua_tostring(L, -1), ".", "/"); + const char* moduleFunction = luaL_gsub(L, lua_tostring(L, -1), ".", "_"); + lua_pop(L, 3); + + char* path; int i; + vec_foreach(lovrFilesystemGetCRequirePath(), path, i) { + for (const char** extension = libraryExtensions; *extension != NULL; extension++) { + char buffer[64]; + snprintf(buffer, 63, "%s%s", modulePath, *extension); + const char* filename = luaL_gsub(L, path, "??", buffer); + filename = luaL_gsub(L, filename, "?", modulePath); + lua_pop(L, 2); + + if (lovrFilesystemIsFile(filename)) { + const char* realPath = lovrFilesystemGetRealDirectory(filename); + void* library = lovrLoadLibrary(realPath); + + snprintf(buffer, 63, "luaopen_%s", moduleFunction); + void* function = lovrLoadSymbol(library, buffer); + if (!function) { + snprintf(buffer, 63, "loveopen_%s", moduleFunction); + function = dlsym(library, buffer); + if (!function) { + snprintf(buffer, 63, "lovropen_%s", moduleFunction); + function = dlsym(library, buffer); + } + } + + if (function) { + lua_pushcfunction(L, (lua_CFunction) function); + return 1; + } else { + lovrCloseLibrary(library); + } + } + } + } + + return 0; +} + int l_lovrFilesystemInit(lua_State* L) { lua_newtable(L); luaL_register(L, NULL, lovrFilesystem); @@ -61,20 +112,8 @@ int l_lovrFilesystemInit(lua_State* L) { lovrFilesystemInit(arg0, arg1); lua_pop(L, 3); - // Add custom package loader - lua_getglobal(L, "table"); - lua_getfield(L, -1, "insert"); - lua_getglobal(L, "package"); - lua_getfield(L, -1, "loaders"); - lua_remove(L, -2); - if (lua_istable(L, -1)) { - lua_pushinteger(L, 2); // Insert our loader after package.preload - lua_pushcfunction(L, filesystemLoader); - lua_call(L, 3, 0); - } - - lua_pop(L, 1); - + luax_registerloader(L, moduleLoader, 2); + luax_registerloader(L, libraryLoader, 3); return 1; } diff --git a/src/luax.c b/src/luax.c index 39d15d3c..70d17039 100644 --- a/src/luax.c +++ b/src/luax.c @@ -45,6 +45,20 @@ int luax_emptymodule(lua_State* L) { return 1; } +void luax_registerloader(lua_State* L, lua_CFunction loader, int index) { + lua_getglobal(L, "table"); + lua_getfield(L, -1, "insert"); + lua_getglobal(L, "package"); + lua_getfield(L, -1, "loaders"); + lua_remove(L, -2); + if (lua_istable(L, -1)) { + lua_pushinteger(L, index); + lua_pushcfunction(L, loader); + lua_call(L, 3, 0); + } + lua_pop(L, 1); +} + void luax_registertype(lua_State* L, const char* name, const luaL_Reg* functions) { // Push metatable diff --git a/src/luax.h b/src/luax.h index cc51b5c2..b72ba55a 100644 --- a/src/luax.h +++ b/src/luax.h @@ -31,6 +31,7 @@ int luax_preloadmodule(lua_State* L, const char* key, lua_CFunction f); int luax_emptymodule(lua_State* L); +void luax_registerloader(lua_State* L, lua_CFunction loader, int index); void luax_registertype(lua_State* L, const char* name, const luaL_Reg* functions); void luax_extendtype(lua_State* L, const char* base, const char* name, const luaL_Reg* baseFunctions, const luaL_Reg* functions); int luax_releasetype(lua_State* L); diff --git a/src/util.c b/src/util.c index e0e187e8..8fc16296 100644 --- a/src/util.c +++ b/src/util.c @@ -8,6 +8,7 @@ #include #else #include +#include #endif _Thread_local void* lovrErrorContext = NULL; @@ -45,6 +46,34 @@ void lovrRelease(void* object) { if (ref && --ref->count == 0) ref->free(object); } +void* lovrLoadLibrary(const char* filename) { +#ifdef _WIN32 + return LoadLibrary(WIN_UTF8ToString(filename)); +#elif EMSCRIPTEN + return NULL; +#else + return dlopen(filename, RTLD_LAZY); +#endif +} + +void* lovrLoadSymbol(void* library, const char* symbol) { +#ifdef _WIN32 + return GetProcAddress((HMODULE) library, symbol); +#elif EMSCRIPTEN + return NULL; +#else + return dlsym(library, symbol); +#endif +} + +void lovrCloseLibrary(void* library) { +#ifdef _WIN32 + FreeLibrary((HMODULE) library); +#elif !defined(EMSCRIPTEN) + dlclose(library); +#endif +} + // https://github.com/starwing/luautf8 size_t utf8_decode(const char *s, const char *e, unsigned *pch) { unsigned ch; diff --git a/src/util.h b/src/util.h index 476b3c0e..7317e816 100644 --- a/src/util.h +++ b/src/util.h @@ -29,5 +29,8 @@ void lovrSleep(double seconds); void* lovrAlloc(size_t size, void (*destructor)(void* object)); void lovrRetain(void* object); void lovrRelease(void* object); +void* lovrLoadLibrary(const char* filename); +void* lovrLoadSymbol(void* library, const char* symbol); +void lovrCloseLibrary(void* library); size_t utf8_decode(const char *s, const char *e, unsigned *pch); uint32_t nextPo2(uint32_t x);