-
Notifications
You must be signed in to change notification settings - Fork 0
/
build.py
256 lines (205 loc) · 6.9 KB
/
build.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
import os
import shutil
import subprocess
import re
def main():
with open("src\\CMakeLists.txt", "r") as f:
content = f.read()
regex = re.compile(r"EXPORTED_FUNCTIONS=\[(.+)\]")
exported_functions = (
regex.search(content)
.group(1)
.replace("'", "")
.replace("[", "")
.replace("]", "")
.split(" ")[0]
.split(",")
)
exported_functions = [func[1:] for func in exported_functions if func != ""]
# Remove (build) and dist folders if they exist
# if os.path.exists("build"):
# shutil.rmtree("build")
if os.path.exists("dist"):
shutil.rmtree("dist")
# Create (build) and dist folders
if not os.path.exists("build"):
os.mkdir("build")
os.mkdir("dist")
# Change directory to build
os.chdir("build")
# Run cmake
subprocess.run("emcmake cmake -DCMAKE_BUILD_TYPE=Release ..", shell=True)
cores = os.cpu_count()
# Build project
subprocess.run("cmake --build . -j" + str(cores), shell=True)
# Change directory to src
os.chdir("src")
# Convert wasm to lua
subprocess.run("wasm2luau RbxCppProject.wasm > ..\\..\\dist\\main.lua", shell=True)
# Change directory back to build
os.chdir("..\\..")
# Remove build folder
# shutil.rmtree("build")
# Replace some stuff .-.
with open("dist\\main.lua", "r") as f:
content = f.read()
offsets = {
"__wasm_call_ctors": re.search(
r"\[\"__wasm_call_ctors\"\] = FUNC_LIST\[(\d+)\]", content
).group(1)
}
for func in exported_functions:
regex = re.compile(r"\[\"" + func + '"\] = FUNC_LIST\[(\d+)\]')
offsets[func] = regex.search(content).group(1)
content = re.sub(
r"local string_byte = string.byte",
"local string_byte = string.byte\n local string_char = string.char",
content,
)
content2 = content.split("local memory_at_0")
content = (
"""--!optimize 2
local lastSleep = 0
function peformSleepCheck()
if tick() - lastSleep >= 1 then
lastSleep = tick()
task.wait()
end
end
"""
+ content2[0].replace("--!optimize 2", "")
+ """local function load_string(memory, addr, len)
peformSleepCheck()
local temp = buffer_create(len)
buffer_copy(temp, 0, memory.data, addr, len)
return buffer_to_string(temp)
end
local function store_string(memory, addr, data, len)
peformSleepCheck()
local content = if not len or len == #data then data else string_sub(data, 1, len)
local temp = buffer_from_string(content)
buffer_copy(memory.data, addr, temp)
end
local function to_signed(num)
return num >= 0x80000000 and num - 0x100000000 or num
end
local function truncate_f64(num)
if num >= 0 then
return (math_floor(num))
else
return (math_ceil(num))
end
end
local function rt_truncate_u32_f32(num)
return (to_signed(truncate_f64(num)))
end
rt_truncate_u32_f64 = rt_truncate_u32_f32
local memory_at_0"""
+ content2[1]
)
function_defs = re.findall(r"local function .*\n", content)
for func in function_defs:
content = content.replace(func, func + " peformSleepCheck()\n")
### Start of Lua compatibility ###
"""
def transform_inline_if_then_else(content):
pattern = re.compile(
r"\bif\s+(.*?)\s+then\s+(.*?)\s+else\s+([^\),\s]+(?:\s*,\s*[^\),\s]+)*)"
)
def replace_match(match):
condition = match.group(1).strip()
true_expr = match.group(2).strip()
false_expr = match.group(3).strip()
return f"(({condition}) and {true_expr} or {false_expr})"
lines = content.split("\n")
transformed_lines = []
for line in lines:
stripped_line = (
line.lstrip()
)
if stripped_line.startswith("if "):
transformed_lines.append(line)
else:
original_line = line
while True:
match = pattern.search(original_line)
if not match:
break
replacement = replace_match(match)
start, end = match.span()
original_line = (
original_line[:start] + replacement + original_line[end:]
)
transformed_lines.append(original_line)
return "\n".join(transformed_lines)
content = transform_inline_if_then_else(content)
content = re.sub(r"0_(\d+)", r"\1", content)
"""
### End of Lua compatibility ###
content = re.sub(r"return function\(wasm\)(.|\n)*end", "", content)
content = (
content
+ """
--// Named function dictionary
local NamedFunctionList = {
--// WebAssembly
["__wasm_call_ctors"] = FUNC_LIST["""
+ offsets["__wasm_call_ctors"]
+ """];
--// Exported functions
"""
+ "\n".join(
[
f'["{func}"] = FUNC_LIST[{offsets[func]}];'
for func in exported_functions
]
)
+ """
}
--// Pre-init environment function setup
--// lua_call
FUNC_LIST["""
+ offsets["lua_call"]
+ """] = function (code)
code = load_string(memory_at_0, code, NamedFunctionList.strlen(code))
local loaded = loadstring(code)
local ret = loaded and loaded() or ""
if type(ret) ~= "string" then
ret = tostring(ret)
end
local addr = NamedFunctionList.malloc(#ret + 1)
store_string(memory_at_0, addr, ret .. "\\0", #ret + 1)
return addr
end
--// Initialize
run_init_code()
memory_at_0 = MEMORY_LIST[0]
NamedFunctionList.__wasm_call_ctors()
local function convertString(s)
if type(s) == "string" then
local addr = NamedFunctionList.malloc(#s + 1)
store_string(memory_at_0, addr, s .. "\\0", #s + 1)
return addr
else
return load_string(memory_at_0, s, NamedFunctionList.strlen(s))
end
end
""" + ("main" in exported_functions and "local exitCode = NamedFunctionList.main(..., #{...})" or "") + """
--// Return
return {
--// Exported functions
"""
+ "\n".join(
[f"{func} = NamedFunctionList.{func}," for func in exported_functions]
)
+ """
--// Wasynth related utilities
NamedFunctionList = NamedFunctionList;
convertString = convertString;
FUNC_LIST = FUNC_LIST;""" + ("main" in exported_functions and "\nexitCode = exitCode;" or "") + """
}"""
)
with open("dist\\main.lua", "w") as f:
f.write(content)
if __name__ == "__main__":
main()