Lua precompiled code

简介:
使用luac或者string.dump函数可以将Lua脚本编译成二进制格式, 编译后的代码同样可以使用lua运行.
预编译代码(二进制格式)加载速度比文本快, 但是文件可能更大, 同时二进制格式可以对代码起到一定的保护作用, 因为文本很容易暴露或被修改.
# vi test.lua
local a=1
function f() a=a+1 return a end
for i=1,20 do
  print(f())
end

使用luac把脚本转换成二进制编码
# luac -o ./test.lc test.lua

二进制文件test.lc和文本test.lua都可以使用lua执行
[root@db-172-16-3-150 ~]# lua ./test.lc
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[root@db-172-16-3-150 ~]# lua ./test.lua
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21


使用luac -l可以查看lua或lc文件的虚拟机指令.
produce  a  listing  of the compiled bytecode for Lua’s virtual machine.  Listing bytecodes is useful to learn about Lua’s virtual machine. If no files are given, then luac loads luac.out and lists  its  con tents.

[root@db-172-16-3-150 ~]# luac -l ./test.lc
main <test.lua:0,0> (13 instructions at 0x8673c0)
0+ params, 7 slots, 1 upvalue, 5 locals, 4 constants, 1 function
        1       [1]     LOADK           0 -1    ; 1
        2       [2]     CLOSURE         1 0     ; 0x867570
        3       [2]     SETTABUP        0 -2 1  ; _ENV "f"
        4       [3]     LOADK           1 -1    ; 1
        5       [3]     LOADK           2 -3    ; 20
        6       [3]     LOADK           3 -1    ; 1
        7       [3]     FORPREP         1 4     ; to 12
        8       [4]     GETTABUP        5 0 -4  ; _ENV "print"
        9       [4]     GETTABUP        6 0 -2  ; _ENV "f"
        10      [4]     CALL            6 1 0
        11      [4]     CALL            5 0 1
        12      [3]     FORLOOP         1 -5    ; to 8
        13      [5]     RETURN          0 1

function <test.lua:2,2> (6 instructions at 0x867570)
0 params, 2 slots, 1 upvalue, 0 locals, 1 constant, 0 functions
        1       [2]     GETUPVAL        0 0     ; a
        2       [2]     ADD             0 0 -1  ; - 1
        3       [2]     SETUPVAL        0 0     ; a
        4       [2]     GETUPVAL        0 0     ; a
        5       [2]     RETURN          0 2
        6       [2]     RETURN          0 1


使用string.dump这个函数可以将函数打包成二进制代码, 与luac的效果一致.
例如使用loadfile把lua文件加载为一个匿名函数, 然后使用string.dump转换成二进制代码.
使用io.open 和 file:write 写入文件.
例如 : 

> p = loadfile("/root/test.lua")  -- 加载文件, 输出一个匿名函数
> f = io.open("/root/test.lc", "wb")  -- 以写模式和二进制模式打开文件
> f:write(string.dump(p))  -- 使用file:write写文件, string.dump(p) 将函数转换成二进制格式
> f:close()  -- 关闭文件
> os.exit()
[root@db-172-16-3-150 ~]# lua test.lc
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

这个稍加修改就可以改成一个类似luac的脚本.
[root@db-172-16-3-150 ~]# vi luac.lua
p = loadfile(arg[1])
f = io.open(arg[2], "wb")
f:write(string.dump(p))
f:close()

使用这个脚本打包二进制文件.
[root@db-172-16-3-150 ~]# lua ./luac.lua "/root/test.lua" "/root/test.lc"
[root@db-172-16-3-150 ~]# ll /root/test.lc
-r-x------ 1 root root 495 Feb 19 14:36 /root/test.lc
[root@db-172-16-3-150 ~]# lua /root/test.lc
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

load和loadfile支持加载文本模式或二进制格式的编码, 默认同时允许. 例如 : 
> f = loadfile("/root/test.lc","t")  -- "t"表示text模式, 显然加载二进制格式的test.lc会失败
> f()
stdin:1: attempt to call global 'f' (a nil value)
stack traceback:
        stdin:1: in main chunk
        [C]: in ?
> f = loadfile("/root/test.lc","b")
> f()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21


[参考]
1. man luac
2. 

string.dump (function)

Returns a string containing a binary representation of the given function, so that a later load on this string returns a copy of the function (but with new upvalues).

3. 

load (ld [, source [, mode [, env]]])

Loads a chunk.

If ld is a string, the chunk is this string. If ld is a function, load calls it repeatedly to get the chunk pieces. Each call to ld must return a string that concatenates with previous results. A return of an empty string, nil, or no value signals the end of the chunk.

If there are no syntactic errors, returns the compiled chunk as a function; otherwise, returns nil plus the error message.

If the resulting function has upvalues, the first upvalue is set to the value of env, if that parameter is given, or to the value of the global environment. (When you load a main chunk, the resulting function will always have exactly one upvalue, the _ENV variable (see §2.2). When you load a binary chunk created from a function (see string.dump), the resulting function can have arbitrary upvalues.)

source is used as the source of the chunk for error messages and debug information (see §4.9). When absent, it defaults to ld, if ld is a string, or to "=(load)" otherwise.

The string mode controls whether the chunk can be text or binary (that is, a precompiled chunk). It may be the string "b" (only binary chunks), "t" (only text chunks), or "bt" (both binary and text). The default is "bt".

4. 

file:write (···)

Writes the value of each of its arguments to file. The arguments must be strings or numbers.

In case of success, this function returns file. Otherwise it returns nil plus a string describing the error.

5. 

file:close ()

Closes file. Note that files are automatically closed when their handles are garbage collected, but that takes an unpredictable amount of time to happen.

When closing a file handle created with io.popenfile:close returns the same values returned by os.execute.

6. 

io.open (filename [, mode])

This function opens a file, in the mode specified in the string mode. It returns a new file handle, or, in case of errors, nil plus an error message.

The mode string can be any of the following:

  • "r": read mode (the default);
  • "w": write mode;
  • "a": append mode;
  • "r+": update mode, all previous data is preserved;
  • "w+": update mode, all previous data is erased;
  • "a+": append update mode, previous data is preserved, writing is only allowed at the end of file.

The mode string can also have a 'b' at the end, which is needed in some systems to open the file in binary mode.

目录
相关文章
|
存储 NoSQL Redis
Redis的Lua脚本有什么作用?
Redis Lua脚本用于减少网络开销、实现原子操作及扩展指令集。它能合并操作降低网络延迟,保证原子性,替代不支持回滚的事务。通过脚本,代码复用率提高,且可自定义指令,如实现分布式锁,增强Redis功能和灵活性。
657 1
|
缓存 NoSQL 搜索推荐
【📕分布式锁通关指南 03】通过Lua脚本保证redis操作的原子性
本文介绍了如何通过Lua脚本在Redis中实现分布式锁的原子性操作,避免并发问题。首先讲解了Lua脚本的基本概念及其在Redis中的使用方法,包括通过`eval`指令执行Lua脚本和通过`script load`指令缓存脚本。接着详细展示了如何用Lua脚本实现加锁、解锁及可重入锁的功能,确保同一线程可以多次获取锁而不发生死锁。最后,通过代码示例演示了如何在实际业务中调用这些Lua脚本,确保锁操作的原子性和安全性。
765 6
【📕分布式锁通关指南 03】通过Lua脚本保证redis操作的原子性
|
消息中间件 NoSQL Java
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
Redis系列学习文章分享---第六篇(Redis实战篇--Redis分布式锁+实现思路+误删问题+原子性+lua脚本+Redisson功能介绍+可重入锁+WatchDog机制+multiLock)
766 0
|
NoSQL Redis 数据库
Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
通过本文的介绍,我们详细讲解了 Lua 脚本在 Redis 中的作用、`eval` 命令的使用方法以及 `redis.call` 和 `redis.pcall` 的区别和用法。通过合理使用 Lua 脚本,可以实现复杂的业务逻辑,确保操作的原子性,并减少网络开销,从而提高系统的性能和可靠性。
966 13
|
监控 安全
公司用什么软件监控电脑:Lua 脚本在监控软件扩展功能的应用
在企业环境中,电脑监控软件对保障信息安全、提升效率至关重要。Lua 脚本在此类软件中用于扩展功能,如收集系统信息、监控软件使用时长及文件操作,向指定服务器发送数据,支持企业管理和运营。
265 6
|
缓存 分布式计算 NoSQL
大数据-43 Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
大数据-43 Redis 功能扩展 Lua 脚本 对Redis扩展 eval redis.call redis.pcall
233 2
|
存储 JSON Ubuntu
如何使用 Lua 脚本进行更复杂的网络请求,比如 POST 请求?
如何使用 Lua 脚本进行更复杂的网络请求,比如 POST 请求?