diff --git a/SConstruct b/SConstruct index 62c61688..f944f63a 100644 --- a/SConstruct +++ b/SConstruct @@ -9,9 +9,14 @@ env.tools=['mingw'] env.Append(CPPDEFINES = ['LAPI_GDEXTENSION']) env.Append(CPPPATH = [Dir('src').abspath, Dir('external').abspath]) +env['sources'] = [] +Export('env') +SConscript("lua_libraries/SConscript") + sources = Glob('*.cpp') sources.append(Glob('src/*.cpp')) sources.append(Glob('src/classes/*.cpp')) +sources.append(env['sources']) if env["luaapi_luaver"] == 'jit': env.Append(CPPDEFINES=['LAPI_LUAJIT']) diff --git a/SCsub b/SCsub index b35f5e90..41a61235 100644 --- a/SCsub +++ b/SCsub @@ -18,6 +18,7 @@ if env["luaapi_luaver"] == "jit" and env['platform']=='javascript': Export('env_lua') SConscript('external/SCsub') +SConscript('lua_libraries/SCsub') if env["luaapi_luaver"] == 'jit': env_lua.Append(CPPDEFINES=['LAPI_LUAJIT']) diff --git a/doc_classes/LuaAPI.xml b/doc_classes/LuaAPI.xml index 3fb84801..379309b8 100644 --- a/doc_classes/LuaAPI.xml +++ b/doc_classes/LuaAPI.xml @@ -22,10 +22,11 @@ - + Bind lua libraries to the LuaAPI Object. + Returns an error if a library fails to bind. Note: in C#, the param Array must be a [code]Godot.Collections.Array[/code] and not a [code]System.Array[/code] class. diff --git a/external/SCsub b/external/SCsub index 26d1a54a..4eb63027 100644 --- a/external/SCsub +++ b/external/SCsub @@ -1,4 +1,3 @@ - Import('env') Import('env_lua') @@ -74,6 +73,7 @@ if luaver == "jit": else: env.Append(LIBPATH=[Dir("luaJIT/src").abspath]) env.Append(LIBS=['libluajit']) + env_lua.Append(CPPPATH=[Dir('luaJIT/src').abspath]) elif luaver == "5.1": env_lua.Append(CPPDEFINES='MAKE_LIB') @@ -87,7 +87,8 @@ elif luaver == "5.1": env_lua['CFLAGS'].remove('-std=gnu11') env_lua.Append(CFLAGS=['-std=c99']) - env_lua.add_source_files(env.modules_sources,'lua/*.c') + env_lua.Append(CPPPATH=[Dir('lua51').abspath]) + env_lua.add_source_files(env.modules_sources,'lua51/*.c') else: env_lua.Append(CPPDEFINES='MAKE_LIB') @@ -101,5 +102,6 @@ else: env_lua['CFLAGS'].remove('-std=gnu11') env_lua.Append(CFLAGS=['-std=c99']) - env_lua.add_source_files(env.modules_sources,'lua/onelua.c') + env_lua.Append(CPPPATH=[Dir('lua').abspath]) + env_lua.add_source_files(env.modules_sources, 'lua/onelua.c') diff --git a/lua_libraries/.gitignore b/lua_libraries/.gitignore new file mode 100644 index 00000000..7611336c --- /dev/null +++ b/lua_libraries/.gitignore @@ -0,0 +1,9 @@ +* + +!.gitignore +!SCsub +!SConscript +!codegen.py +!codegen.py +!README.md +!lua_libraries.h \ No newline at end of file diff --git a/lua_libraries/README.md b/lua_libraries/README.md new file mode 100644 index 00000000..90896888 --- /dev/null +++ b/lua_libraries/README.md @@ -0,0 +1,8 @@ +## Lua Libraries +This is a code gen module which allows you to statically compile a lua C library into this addon. Its as simple as downloading the source for the addon, and adding it as a folder with the library name in this folder. + +It is important that the folder name be exactly the library name in lowercase. No version numbers included. + +The code gen will auto detect it next time you build the addon. Either as a module or for GDExtension. + +This is very new and potentially very prone to failure. So for lpeg has been tested and confirmed to work. \ No newline at end of file diff --git a/lua_libraries/SConscript b/lua_libraries/SConscript new file mode 100644 index 00000000..82e1b668 --- /dev/null +++ b/lua_libraries/SConscript @@ -0,0 +1,10 @@ +Import('env') +from codegen import code_gen + +code_gen(env['luaapi_luaver'] == 'jit') + +sources = ['lua_libraries.gen.cpp'] +library_name = "liblualibraries{}{}".format(env['suffix'], env["LIBSUFFIX"]) + +env.Append(sources=["lua_libraries/lua_libraries.gen.cpp"]) +env.Append(CPPPATH=[Dir('.').abspath]) \ No newline at end of file diff --git a/lua_libraries/SCsub b/lua_libraries/SCsub new file mode 100644 index 00000000..de234c1e --- /dev/null +++ b/lua_libraries/SCsub @@ -0,0 +1,9 @@ +Import('env') +Import('env_lua') + +from codegen import code_gen + +code_gen(env['luaapi_luaver'] == 'jit') + +env_lua.add_source_files(env.modules_sources, "lua_libraries.gen.cpp") +env_lua.Append(CPPPATH=[Dir('.').abspath]) diff --git a/lua_libraries/codegen.py b/lua_libraries/codegen.py new file mode 100644 index 00000000..b0d142c9 --- /dev/null +++ b/lua_libraries/codegen.py @@ -0,0 +1,95 @@ +import os + +def code_gen(luaJIT=False): + lua_libraries = [ + "base", + "coroutine", + "debug", + "io", + "math", + "os", + "package", + "string", + "table", + "utf8" + ] + + luajit_libraries = [ + "base", + "bit", + "debug", + "ffi", + "io", + "jit", + "math", + "os", + "package", + "string", + "string_buffer", + "table" + ] + + libraries = lua_libraries + lib_source_files = [] + + if luaJIT: + libraries = luajit_libraries + + for library in os.listdir("./"): + if not os.path.isdir(library) or library == "__pycache__" or library == "bin": + continue + + libraries.append(library) + + for source_file in os.listdir("./%s" % library): + if source_file.endswith(".cpp") or source_file.endswith(".c"): + lib_source_files.append(os.path.join(library, source_file)) + + luaLibraries_gen_cpp = "#include \"lua_libraries.h\"\n#include \n#include \n\n" + + if len(lib_source_files) > 0: + for source_file in lib_source_files: + luaLibraries_gen_cpp += "#include \"%s\"\n" % source_file + luaLibraries_gen_cpp += "\n" + + luaLibraries_gen_cpp += "std::map luaLibraries = {\n" + + for library in libraries: + luaLibraries_gen_cpp += "\t{ \"%s\", luaopen_%s },\n" % (library, library) + + luaLibraries_gen_cpp += "};\n" + if luaJIT: + luaLibraries_gen_cpp += """ +bool loadLuaLibrary(lua_State *L, String libraryName) { + const char *lib_c_str = libraryName.ascii().get_data(); + if (luaLibraries[lib_c_str] == nullptr) { + return false; + } + + lua_pushcfunction(L, luaLibraries[lib_c_str]); + if (libraryName == "base") { + lua_pushstring(L, ""); + } else { + lua_pushstring(L, lib_c_str); + } + lua_call(L, 1, 0); + return true; +} +""" + else: + luaLibraries_gen_cpp += """ +bool loadLuaLibrary(lua_State *L, String libraryName) { + const char *lib_c_str = libraryName.ascii().get_data(); + if (luaLibraries[lib_c_str] == nullptr) { + return false; + } + + luaL_requiref(L, lib_c_str, luaLibraries[lib_c_str], 1); + lua_pop(L, 1); + return true; +} +""" + + gen_file = open("lua_libraries.gen.cpp", "w") + gen_file.write(luaLibraries_gen_cpp) + gen_file.close() \ No newline at end of file diff --git a/lua_libraries/lua_libraries.h b/lua_libraries/lua_libraries.h new file mode 100644 index 00000000..e8489e99 --- /dev/null +++ b/lua_libraries/lua_libraries.h @@ -0,0 +1,18 @@ +#ifndef LUA_LIBRARIES_H +#define LUA_LIBRARIES_H + +#include + +#ifndef LAPI_GDEXTENSION +#include "core/string/ustring.h" + +#include "core/variant/variant.h" +#else +#include + +using namespace godot; +#endif + +bool loadLuaLibrary(lua_State *L, String libraryName); + +#endif \ No newline at end of file diff --git a/src/classes/luaAPI.cpp b/src/classes/luaAPI.cpp index c6b4fdd7..b8ed1cb8 100644 --- a/src/classes/luaAPI.cpp +++ b/src/classes/luaAPI.cpp @@ -74,8 +74,8 @@ void LuaAPI::_bind_methods() { } // Calls LuaState::bindLibs() -void LuaAPI::bindLibraries(Array libs) { - state.bindLibraries(libs); +Ref LuaAPI::bindLibraries(TypedArray libs) { + return state.bindLibraries(libs); } void LuaAPI::setHook(Callable hook, int mask, int count) { diff --git a/src/classes/luaAPI.h b/src/classes/luaAPI.h index 9ef093e6..ec948b39 100644 --- a/src/classes/luaAPI.h +++ b/src/classes/luaAPI.h @@ -30,7 +30,6 @@ class LuaAPI : public RefCounted { LuaAPI(); ~LuaAPI(); - void bindLibraries(Array libs); void setHook(Callable hook, int mask, int count); void setUseCallables(bool value); @@ -54,8 +53,9 @@ class LuaAPI : public RefCounted { #endif Variant getRegistryValue(String name); - Ref setRegistryValue(String name, Variant var); + Ref setRegistryValue(String name, Variant var); + Ref bindLibraries(TypedArray libs); Ref doFile(String fileName); Ref doString(String code); Ref pushGlobalVariant(String name, Variant var); diff --git a/src/luaState.cpp b/src/luaState.cpp index 2aefeccc..3806dc9f 100644 --- a/src/luaState.cpp +++ b/src/luaState.cpp @@ -7,6 +7,8 @@ #include #include +#include + #ifndef LAPI_GDXTENSION #include #endif @@ -46,98 +48,19 @@ lua_State *LuaState::getState() const { return L; } -#ifndef LAPI_LUAJIT - // Binds lua libraries with the lua state -void LuaState::bindLibraries(Array libs) { +Ref LuaState::bindLibraries(TypedArray libs) { for (int i = 0; i < libs.size(); i++) { - String lib = ((String)libs[i]).to_lower(); - if (lib == "base") { - luaL_requiref(L, "", luaopen_base, 1); - lua_pop(L, 1); - // base will override print, so we take it back. User can still override them self - lua_register(L, "print", luaPrint); - } else if (lib == "table") { - luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 1); - lua_pop(L, 1); - } else if (lib == "string") { - luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 1); - lua_pop(L, 1); - } else if (lib == "math") { - luaL_requiref(L, LUA_MATHLIBNAME, luaopen_math, 1); - lua_pop(L, 1); - } else if (lib == "os") { - luaL_requiref(L, LUA_OSLIBNAME, luaopen_os, 1); - lua_pop(L, 1); - } else if (lib == "io") { - luaL_requiref(L, LUA_IOLIBNAME, luaopen_io, 1); - lua_pop(L, 1); - } else if (lib == "coroutine") { - luaL_requiref(L, LUA_COLIBNAME, luaopen_coroutine, 1); - lua_pop(L, 1); - } else if (lib == "debug") { - luaL_requiref(L, LUA_DBLIBNAME, luaopen_debug, 1); - lua_pop(L, 1); - } else if (lib == "package") { - luaL_requiref(L, LUA_LOADLIBNAME, luaopen_package, 1); - lua_pop(L, 1); - } else if (lib == "utf8") { - luaL_requiref(L, LUA_UTF8LIBNAME, luaopen_utf8, 1); - lua_pop(L, 1); + if (!loadLuaLibrary(L, libs[i])) { + return LuaError::newError(vformat("Library \"%s\" does not exist.", libs[i]), LuaError::ERR_RUNTIME); } - } -} - -#else - -// Binds lua libraries with the lua state -void LuaState::bindLibraries(Array libs) { - for (int i = 0; i < libs.size(); i++) { - String lib = ((String)libs[i]).to_lower(); - if (lib == "base") { - lua_pushcfunction(L, luaopen_base); - lua_pushstring(L, ""); - lua_call(L, 1, 0); - + if (libs[i] == "base") { lua_register(L, "print", luaPrint); - } else if (lib == "table") { - lua_pushcfunction(L, luaopen_table); - lua_pushstring(L, LUA_TABLIBNAME); - lua_call(L, 1, 0); - } else if (lib == "string") { - lua_pushcfunction(L, luaopen_string); - lua_pushstring(L, LUA_STRLIBNAME); - lua_call(L, 1, 0); - } else if (lib == "math") { - lua_pushcfunction(L, luaopen_math); - lua_pushstring(L, LUA_MATHLIBNAME); - lua_call(L, 1, 0); - } else if (lib == "os") { - lua_pushcfunction(L, luaopen_os); - lua_pushstring(L, LUA_OSLIBNAME); - lua_call(L, 1, 0); - } else if (lib == "io") { - lua_pushcfunction(L, luaopen_io); - lua_pushstring(L, LUA_IOLIBNAME); - lua_call(L, 1, 0); - } else if (lib == "debug") { - lua_pushcfunction(L, luaopen_debug); - lua_pushstring(L, LUA_DBLIBNAME); - lua_call(L, 1, 0); - } else if (lib == "package") { - lua_pushcfunction(L, luaopen_package); - lua_pushstring(L, LUA_LOADLIBNAME); - lua_call(L, 1, 0); - } else if (lib == "ffi") { - lua_pushcfunction(L, luaopen_ffi); - lua_pushstring(L, LUA_FFILIBNAME); - lua_call(L, 1, 0); } } + return nullptr; } -#endif - void LuaState::setHook(Callable hook, int mask, int count) { if (hook.is_null()) { lua_sethook(L, nullptr, 0, 0); diff --git a/src/luaState.h b/src/luaState.h index 6c797ff4..ef3fcf2b 100644 --- a/src/luaState.h +++ b/src/luaState.h @@ -18,7 +18,6 @@ class LuaAPI; class LuaState { public: void setState(lua_State *state, LuaAPI *lua, bool bindAPI); - void bindLibraries(Array libs); void setHook(Callable hook, int mask, int count); bool luaFunctionExists(String functionName); @@ -30,8 +29,9 @@ class LuaState { Variant callFunction(String functionName, Array args); Variant getRegistryValue(String name); - Ref setRegistryValue(String name, Variant var); + Ref setRegistryValue(String name, Variant var); + Ref bindLibraries(TypedArray libs); Ref pushVariant(Variant var) const; Ref pushGlobalVariant(String name, Variant var); Ref handleError(int lua_error) const;