1
0
Fork 0
mirror of https://github.com/opentx/opentx.git synced 2025-07-15 12:25:12 +03:00

Add runtime Lua script pre-compilation and general .luac file support (#3318) (#4119)

* [simu] simpgmspace: Populate file date/time/size  in f_stat(); Add f_utime(); Fix f_getcwd() on Windows; Fix f_mkdir() build error on Windows.

* [Lua] Add runtime support for script pre-compilation. Changes behavior with LUA_COMPILER (Re: https://github.com/opentx/opentx/issues/3318):
  All .lua scripts are now compiled and saved to binary "bytecode" file (.luac extension) upon first execution;
  Scripts are also automatically re-compiled if .lua source file is newer than existing .luac file;
  The pre-compiled .luac version is loaded if modification time is newer or equivalent to .lua source file;
  If a .luac version of a script exists, then the .lua version does not need to be present;
  Guards against bytecode compatibility issues (binaries from 64-bit sim will not run on 32-bit sim/radio);
  In SIMU and DEBUG builds, the source .lua file is always preferred in order to preserve full debug info (this is is controlled with new LUA_SCRIPT_LOAD_MODE macro, see lua_api.h);
  GC is now run after each script is loaded.

* [Lua] Add loadScript() API function as alternative to loadfile() from Lua base. This can take advantage of the new OTx script pre-compilation features to reduce memory footprint when loading functions dynamically. This is an interface to luaLoadScriptFileToState(). Fully documented.

* [SD][Lua] Flexible file extensions support:
  Allow for variable length file extensions throughout system (no longer hard-coded in LEN_FILE_EXTENSION);
  Fixes issues with renaming files in SD manager which have file extensions longer than ".ext";
  Expand general support for multiple file extensions per file type in sdListFiles() (eg. .lua and .luac for scripts);
  Lua scripts with .luac extensions can now be selected in custom/telemetry/function menus even if no .lua version exists (duplicates are not shown);
  .luac files can now also be executed from SD file manager UI.

* [Build] Added CMake options for LUA_COMPILER and LUA_SCRIPT_LOAD_MODE.

* Cosmetics.

* [SD][gui] Improve efficiency of some file name handling routines in sdmanager GUI and sdListFiles() by extending getFileExtension() function. Use shared isExtensionMatching() in place of isImageFileExtension(). Only allow executing .luac files when LUA_COMPILER defined (as per request).

* [simpgmspace] Fix f_mkdir() for MSVC build and misc. cleanup.

* [Lua] Use getFileExtension() in script loader to determine file type and check for buffer overflow.
This commit is contained in:
Max Paperno 2016-12-17 04:56:40 -05:00 committed by Bertrand Songis
parent 28006d26a9
commit 5d5dc67605
12 changed files with 594 additions and 205 deletions

View file

@ -1131,6 +1131,78 @@ static int luaGetRSSI(lua_State * L)
return 3;
}
/*luadoc
@function loadScript(file [, mode], [,env])
Load a Lua script file. This is similar to Lua's own loadfile() API method, but it uses
OpenTx's optional pre-compilation feature to (possibly) save memory and time during load.
@param file (string) Full path and file name of script. The file extension is optional and ignored (see "mode" param to control
which extension will be used). However, if an extension is specified, it should be ".lua" (or ".luac"), otherwise it is treated
as part of the file name and the .lua/.luac will be appended to that.
@param mode (string) (optional) Controls whether to force loading the text (.lua) or binary (.luac, that is, a pre-compiled file)
version of the script. By default OTx will load the newest version and compile a new binary if necessary (overwriting any
existing .luac version of the same script, and stripping some debug info like line numbers). You can use this to bypass the automatic
script version check and set specific compilation options in OpenTx.
Possible values are:
"b" only binary.
"t" only text.
"T" (default on simulator) prefer text but load binary if that is the only version available.
"bt" (default on radio) either binary or text, whichever is newer (binary preferred when timestamps are equal).
Add "x" to avoid automatic compilation of source file to .luac version.
Eg: "tx", "bx", or "btx".
Add "c" to force compilation of source file to .luac version (even if existing version is newer than source file).
Eg: "tc" or "btc" (forces "t", overrides "x").
Add "d" to keep extra debug info in the compiled binary.
Eg: "td", "btd", or "tcd" (no effect with just "b" or with "x").
Note that you will get an error if you specify "b" or "t" and that specific version of the file does not exist (eg. no .luac file when "b" is used).
Also note that mode is NOT passed on to Lua's loader function, so unlike with loadfile() the actual file content is not checked (as if no mode or "bt" were passed to loadfile()).
@param env (integer) See documentation for Lua function loadfile().
@returns Same as from Lua API loadfile() method.
If the script was loaded w/out errors then the loaded script (or "chunk") is returned as a function;
Otherwise, returns nil plus the error message
@usage
fun, err = loadScript("/SCRIPTS/FUNCTIONS/print.lua")
if (fun ~= nil) then
fun("Hello from loadScript()")
else
print(err)
end
@status current Introduced in 2.2.0
*/
static int luaLoadScript(lua_State * L)
{
// this function is replicated pretty much verbatim from luaB_loadfile() and load_aux() in lbaselib.c
const char *fname = luaL_optstring(L, 1, NULL);
const char *mode = luaL_optstring(L, 2, NULL);
int env = (!lua_isnone(L, 3) ? 3 : 0); // 'env' index or 0 if no 'env'
lua_settop(L, 0);
if (fname != NULL && luaLoadScriptFileToState(L, fname , mode) == SCRIPT_OK) {
if (env != 0) { // 'env' parameter?
lua_pushvalue(L, env); // environment for loaded function
if (!lua_setupvalue(L, -2, 1)) // set it as 1st upvalue
lua_pop(L, 1); // remove 'env' if not used by previous call
}
return 1;
}
else {
// error (message should be on top of the stack)
if (!lua_isstring(L, -1)) {
// probably didn't find a file or had some other error before luaL_loadfile() was run
lua_pushfstring(L, "loadScript(\"%s\", \"%s\") error: File not found", (fname != NULL ? fname : "nul"), (mode != NULL ? mode : "bt"));
}
lua_pushnil(L);
lua_insert(L, -2); // move nil before error message
return 2; // return nil plus error message
}
}
const luaL_Reg opentxLib[] = {
{ "getTime", luaGetTime },
{ "getDateTime", luaGetDateTime },
@ -1152,6 +1224,7 @@ const luaL_Reg opentxLib[] = {
{ "defaultChannel", luaDefaultChannel },
{ "getRSSI", luaGetRSSI },
{ "killEvents", luaKillEvents },
{ "loadScript", luaLoadScript },
#if LCD_DEPTH > 1 && !defined(COLORLCD)
{ "GREY", luaGrey },
#endif