New interface to function 'luaL_openselectedlibs'

Instead of preloading all non-loaded libraries, there is another
mask to select which libraries to preload.
This commit is contained in:
Roberto Ierusalimschy
2024-02-15 11:17:39 -03:00
parent c8121ce34b
commit 165389b27b
8 changed files with 80 additions and 56 deletions

22
linit.c
View File

@@ -21,12 +21,12 @@
/* /*
** Standard Libraries ** Standard Libraries. (Must be listed in the same ORDER of their
** respective constants LUA_<libname>K.)
*/ */
static const luaL_Reg stdlibs[] = { static const luaL_Reg stdlibs[] = {
{LUA_GNAME, luaopen_base}, {LUA_GNAME, luaopen_base},
{LUA_LOADLIBNAME, luaopen_package}, {LUA_LOADLIBNAME, luaopen_package},
{LUA_COLIBNAME, luaopen_coroutine}, {LUA_COLIBNAME, luaopen_coroutine},
{LUA_DBLIBNAME, luaopen_debug}, {LUA_DBLIBNAME, luaopen_debug},
{LUA_IOLIBNAME, luaopen_io}, {LUA_IOLIBNAME, luaopen_io},
@@ -35,30 +35,28 @@ static const luaL_Reg stdlibs[] = {
{LUA_STRLIBNAME, luaopen_string}, {LUA_STRLIBNAME, luaopen_string},
{LUA_TABLIBNAME, luaopen_table}, {LUA_TABLIBNAME, luaopen_table},
{LUA_UTF8LIBNAME, luaopen_utf8}, {LUA_UTF8LIBNAME, luaopen_utf8},
{NULL, NULL} {NULL, NULL}
}; };
/* /*
** require selected standard libraries and add the others to the ** require and preload selected standard libraries
** preload table.
*/ */
LUALIB_API void luaL_openselectedlibs (lua_State *L, int what) { LUALIB_API void luaL_openselectedlibs (lua_State *L, int load, int preload) {
int mask = 1; int mask;
const luaL_Reg *lib; const luaL_Reg *lib;
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
for (lib = stdlibs; lib->func; (lib++, mask <<= 1)) { for (lib = stdlibs, mask = 1; lib->name != NULL; lib++, mask <<= 1) {
if (what & mask) { /* selected? */ if (load & mask) { /* selected? */
luaL_requiref(L, lib->name, lib->func, 1); /* require library */ luaL_requiref(L, lib->name, lib->func, 1); /* require library */
lua_pop(L, 1); /* remove result from the stack */ lua_pop(L, 1); /* remove result from the stack */
} }
else { /* add library to PRELOAD table */ else if (preload & mask) { /* selected? */
lua_pushcfunction(L, lib->func); lua_pushcfunction(L, lib->func);
lua_setfield(L, -2, lib->name); lua_setfield(L, -2, lib->name); /* add library to PRELOAD table */
} }
} }
lua_assert((mask >> 1) == LUA_UTF8LIBK); lua_assert((mask >> 1) == LUA_UTF8LIBK);
lua_pop(L, 1); // remove PRELOAD table lua_pop(L, 1); /* remove PRELOAD table */
} }

View File

@@ -1223,8 +1223,9 @@ static lua_State *getstate (lua_State *L) {
static int loadlib (lua_State *L) { static int loadlib (lua_State *L) {
lua_State *L1 = getstate(L); lua_State *L1 = getstate(L);
int what = luaL_checkinteger(L, 2); int load = luaL_checkinteger(L, 2);
luaL_openselectedlibs(L1, what); int preload = luaL_checkinteger(L, 3);
luaL_openselectedlibs(L1, load, preload);
luaL_requiref(L1, "T", luaB_opentests, 0); luaL_requiref(L1, "T", luaB_opentests, 0);
lua_assert(lua_type(L1, -1) == LUA_TTABLE); lua_assert(lua_type(L1, -1) == LUA_TTABLE);
/* 'requiref' should not reload module already loaded... */ /* 'requiref' should not reload module already loaded... */

2
lua.c
View File

@@ -618,7 +618,7 @@ static void doREPL (lua_State *L) {
/* }================================================================== */ /* }================================================================== */
#if !defined(luai_openlibs) #if !defined(luai_openlibs)
#define luai_openlibs(L) luaL_openlibs(L) #define luai_openlibs(L) luaL_openselectedlibs(L, ~0, 0)
#endif #endif

View File

@@ -14,11 +14,11 @@
/* version suffix for environment variable names */ /* version suffix for environment variable names */
#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR #define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
#define LUA_GK 1 #define LUA_GLIBK 1
LUAMOD_API int (luaopen_base) (lua_State *L); LUAMOD_API int (luaopen_base) (lua_State *L);
#define LUA_LOADLIBNAME "package" #define LUA_LOADLIBNAME "package"
#define LUA_LOADLIBK (LUA_GK << 1) #define LUA_LOADLIBK (LUA_GLIBK << 1)
LUAMOD_API int (luaopen_package) (lua_State *L); LUAMOD_API int (luaopen_package) (lua_State *L);
@@ -56,10 +56,10 @@ LUAMOD_API int (luaopen_utf8) (lua_State *L);
/* open selected libraries */ /* open selected libraries */
LUALIB_API void (luaL_openselectedlibs) (lua_State *L, int what); LUALIB_API void (luaL_openselectedlibs) (lua_State *L, int load, int preload);
/* open all libraries */ /* open all libraries */
#define luaL_openlibs(L) luaL_openselectedlibs(L, ~0) #define luaL_openlibs(L) luaL_openselectedlibs(L, ~0, 0)
#endif #endif

View File

@@ -358,7 +358,7 @@ item = function (s)
local t, p = string.match(s, "^([^\n|]+)|()") local t, p = string.match(s, "^([^\n|]+)|()")
if t then if t then
s = string.sub(s, p) s = string.sub(s, p)
s = Tag.b(t..": ") .. s s = Tag.b(t) ..": " .. s
end end
return Tag.li(fixpara(s)) return Tag.li(fixpara(s))
end, end,

View File

@@ -664,7 +664,6 @@ Values equal to or less than 100 mean the collector will not wait to
start a new cycle. start a new cycle.
A value of 200 means that the collector waits for A value of 200 means that the collector waits for
the total number of objects to double before starting a new cycle. the total number of objects to double before starting a new cycle.
The default value is 200.
The garbage-collector step size controls the The garbage-collector step size controls the
size of each incremental step, size of each incremental step,
@@ -672,7 +671,6 @@ specifically how many objects the interpreter creates
before performing a step: before performing a step:
A value of @M{n} means the interpreter will create A value of @M{n} means the interpreter will create
approximately @M{n} objects between steps. approximately @M{n} objects between steps.
The default value is 250.
The garbage-collector step multiplier The garbage-collector step multiplier
controls the size of each GC step. controls the size of each GC step.
@@ -681,7 +679,6 @@ in each step, @M{n%} objects for each created object.
Larger values make the collector more aggressive. Larger values make the collector more aggressive.
Beware that values too small can Beware that values too small can
make the collector too slow to ever finish a cycle. make the collector too slow to ever finish a cycle.
The default value is 200.
As a special case, a zero value means unlimited work, As a special case, a zero value means unlimited work,
effectively producing a non-incremental, stop-the-world collector. effectively producing a non-incremental, stop-the-world collector.
@@ -711,7 +708,6 @@ after the last major collection.
For instance, for a multiplier of 20, For instance, for a multiplier of 20,
the collector will do a minor collection when the number of objects the collector will do a minor collection when the number of objects
gets 20% larger than the total after the last major collection. gets 20% larger than the total after the last major collection.
The default value is 25.
The minor-major multiplier controls the shift to major collections. The minor-major multiplier controls the shift to major collections.
For a multiplier @M{x}, For a multiplier @M{x},
@@ -721,7 +717,6 @@ than the total after the previous major collection.
For instance, for a multiplier of 100, For instance, for a multiplier of 100,
the collector will do a major collection when the number of old objects the collector will do a major collection when the number of old objects
gets larger than twice the total after the previous major collection. gets larger than twice the total after the previous major collection.
The default value is 100.
The major-minor multiplier controls the shift back to minor collections. The major-minor multiplier controls the shift back to minor collections.
For a multiplier @M{x}, For a multiplier @M{x},
@@ -731,7 +726,6 @@ of the objects allocated during the last cycle.
In particular, for a multiplier of 0, In particular, for a multiplier of 0,
the collector will immediately shift back to minor collections the collector will immediately shift back to minor collections
after doing one cycle of major collections. after doing one cycle of major collections.
The default value is 50.
} }
@@ -5885,13 +5879,6 @@ or @id{NULL} if there is a @x{memory allocation error}.
} }
@APIEntry{void luaL_openlibs (lua_State *L);|
@apii{0,0,e}
Opens all standard Lua libraries into the given state.
}
@APIEntry{ @APIEntry{
T luaL_opt (L, func, arg, dflt);| T luaL_opt (L, func, arg, dflt);|
@apii{0,0,-} @apii{0,0,-}
@@ -6073,7 +6060,7 @@ and sets the call result to @T{package.loaded[modname]},
as if that function has been called through @Lid{require}. as if that function has been called through @Lid{require}.
If @id{glb} is true, If @id{glb} is true,
also stores the module into the global @id{modname}. also stores the module into the global variable @id{modname}.
Leaves a copy of the module on the stack. Leaves a copy of the module on the stack.
@@ -6290,23 +6277,61 @@ Except for the basic and the package libraries,
each library provides all its functions as fields of a global table each library provides all its functions as fields of a global table
or as methods of its objects. or as methods of its objects.
To have access to these libraries, }
the @N{C host} program should call the @Lid{luaL_openlibs} function,
which opens all standard libraries.
@sect2{lualib-h| @title{Loading the Libraries in C code}
A @N{C host} program must explicitly load
the standard libraries into a state,
if it wants its scripts to use them.
For that,
the host program can call the function @Lid{luaL_openlibs}.
Alternatively, Alternatively,
the host program can open them individually by using the host can select which libraries to open,
@Lid{luaL_requiref} to call by using @Lid{luaL_openselectedlibs}.
@defid{luaopen_base} (for the basic library), Both functions are defined in the header file @id{lualib.h}.
@defid{luaopen_package} (for the package library), @index{lualib.h}
@defid{luaopen_coroutine} (for the coroutine library),
@defid{luaopen_string} (for the string library), The stand-alone interpreter @id{lua} @see{lua-sa}
@defid{luaopen_utf8} (for the UTF-8 library), already opens all standard libraries.
@defid{luaopen_table} (for the table library),
@defid{luaopen_math} (for the mathematical library), @APIEntry{void luaL_openlibs (lua_State *L);|
@defid{luaopen_io} (for the I/O library), @apii{0,0,e}
@defid{luaopen_os} (for the operating system library),
and @defid{luaopen_debug} (for the debug library). Opens all standard Lua libraries into the given state.
These functions are declared in @defid{lualib.h}.
}
@APIEntry{void luaL_openselectedlibs (lua_State *L, int load, int preload);|
@apii{0,0,e}
Opens (loads) and preloads selected libraries into the state @id{L}.
(To @emph{preload} means to add
the library loader into the table @Lid{package.preload},
so that the library can be required later by the program.
Keep in mind that @Lid{require} itself is provided
by the @emph{package} library.
If a program does not load that library,
it will be unable to require anything.)
The integer @id{load} selects which libraries to load;
the integer @id{preload} selects which to preload, among those not loaded.
Both are masks formed by a bitwise OR of the following constants:
@description{
@item{@defid{LUA_GLIBK} | the basic library.}
@item{@defid{LUA_LOADLIBK} | the package library.}
@item{@defid{LUA_COLIBK} | the coroutine library.}
@item{@defid{LUA_STRLIBK} | the string library.}
@item{@defid{LUA_UTF8LIBK} | the UTF-8 library.}
@item{@defid{LUA_TABLIBK} | the table library.}
@item{@defid{LUA_MATHLIBK} | the mathematical library.}
@item{@defid{LUA_IOLIBK} | the I/O library.}
@item{@defid{LUA_OSLIBK} | the operating system library.}
@item{@defid{LUA_DBLIBK} | the debug library.}
}
}
} }

View File

@@ -546,9 +546,9 @@ do
]], source) ]], source)
collectgarbage() collectgarbage()
local m2 = collectgarbage"count" * 1024 local m2 = collectgarbage"count" * 1024
-- load used fewer than 350 bytes. Code alone has more than 3*N bytes, -- load used fewer than 400 bytes. Code alone has more than 3*N bytes,
-- and string literal has N bytes. Both were not loaded. -- and string literal has N bytes. Both were not loaded.
assert(m2 > m1 and m2 - m1 < 350) assert(m2 > m1 and m2 - m1 < 400)
X = 0; code(); assert(X == N and Y == string.rep("a", N)) X = 0; code(); assert(X == N and Y == string.rep("a", N))
X = nil; Y = nil X = nil; Y = nil
@@ -1122,7 +1122,7 @@ assert(a == nil and c == 2) -- 2 == run-time error
a, b, c = T.doremote(L1, "return a+") a, b, c = T.doremote(L1, "return a+")
assert(a == nil and c == 3 and type(b) == "string") -- 3 == syntax error assert(a == nil and c == 3 and type(b) == "string") -- 3 == syntax error
T.loadlib(L1, 2) -- load only 'package' T.loadlib(L1, 2, ~2) -- load only 'package', preload all others
a, b, c = T.doremote(L1, [[ a, b, c = T.doremote(L1, [[
string = require'string' string = require'string'
local initialG = _G -- not loaded yet local initialG = _G -- not loaded yet
@@ -1141,7 +1141,7 @@ T.closestate(L1);
L1 = T.newstate() L1 = T.newstate()
T.loadlib(L1, 0) T.loadlib(L1, 0, 0)
T.doremote(L1, "a = {}") T.doremote(L1, "a = {}")
T.testC(L1, [[getglobal "a"; pushstring "x"; pushint 1; T.testC(L1, [[getglobal "a"; pushstring "x"; pushint 1;
settable -3]]) settable -3]])
@@ -1524,7 +1524,7 @@ end
do -- garbage collection with no extra memory do -- garbage collection with no extra memory
local L = T.newstate() local L = T.newstate()
T.loadlib(L, 1 | 2) -- load _G and 'package' T.loadlib(L, 1 | 2, 0) -- load _G and 'package'
local res = (T.doremote(L, [[ local res = (T.doremote(L, [[
_ENV = _G _ENV = _G
assert(string == nil) assert(string == nil)

View File

@@ -705,7 +705,7 @@ else
T.testC(state, "settop 0") T.testC(state, "settop 0")
T.loadlib(state, 1 | 2) -- load _G and 'package' T.loadlib(state, 1 | 2, 4) -- load _G and 'package', preload 'coroutine'
assert(T.doremote(state, [[ assert(T.doremote(state, [[
coroutine = require'coroutine'; coroutine = require'coroutine';