Skip to content

Commit 836c086

Browse files
authored
Add WebAssembly / JS build back (#27)
1 parent 92298a2 commit 836c086

File tree

7 files changed

+1729
-24
lines changed

7 files changed

+1729
-24
lines changed

.github/workflows/build.yml

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -220,21 +220,53 @@ jobs:
220220
# files: ./coverage.info
221221
# token: ${{ secrets.CODECOV_TOKEN }}
222222

223-
# web:
224-
# runs-on: ubuntu-latest
225-
# steps:
226-
# - uses: actions/checkout@v1
227-
# - uses: actions/checkout@v2
228-
# with:
229-
# repository: emscripten-core/emsdk
230-
# path: emsdk
231-
# - name: emsdk install
232-
# run: |
233-
# cd emsdk
234-
# ./emsdk install latest
235-
# ./emsdk activate latest
236-
# - name: make
237-
# run: |
238-
# source emsdk/emsdk_env.sh
239-
# emcmake cmake . -DLUAU_BUILD_WEB=ON -DCMAKE_BUILD_TYPE=Release
240-
# make -j2 Luau.Web
223+
verify-builtins:
224+
runs-on: ubuntu-latest
225+
steps:
226+
- uses: actions/checkout@v4
227+
228+
- uses: actions/checkout@v4
229+
with:
230+
repository: secondlife/lsl-definitions
231+
path: lsl-definitions
232+
233+
- name: Install dependencies
234+
run: pip install pyyaml llsd
235+
236+
- name: Generate builtins.txt
237+
run: |
238+
cd lsl-definitions
239+
python gen_definitions.py lsl_definitions.yaml gen_builtins_txt builtins.txt
240+
241+
- name: Verify builtins.txt matches
242+
run: |
243+
if ! diff -q builtins.txt lsl-definitions/builtins.txt; then
244+
echo "ERROR: builtins.txt is out of sync with secondlife/lsl-definitions"
245+
diff builtins.txt lsl-definitions/builtins.txt || true
246+
echo ""
247+
echo "To fix: clone secondlife/lsl-definitions and run:"
248+
echo " python gen_definitions.py lsl_definitions.yaml gen_builtins_txt /path/to/slua/builtins.txt"
249+
exit 1
250+
fi
251+
echo "builtins.txt is up to date"
252+
253+
web:
254+
runs-on: ubuntu-latest
255+
steps:
256+
- uses: actions/checkout@v1
257+
- uses: actions/checkout@v2
258+
with:
259+
repository: emscripten-core/emsdk
260+
path: emsdk
261+
- name: emsdk install
262+
run: |
263+
cd emsdk
264+
./emsdk install latest
265+
./emsdk activate latest
266+
- name: make
267+
run: |
268+
source emsdk/emsdk_env.sh
269+
emcmake cmake . -DLUAU_BUILD_WEB=ON -DCMAKE_BUILD_TYPE=Release
270+
make -j2 Luau.Web
271+
- name: smoke test
272+
run: node CLI/test/Web.test.js ./Luau.Web.js

.github/workflows/build_release.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,31 @@ jobs:
7777
runs-on: "ubuntu-22.04"
7878
steps:
7979
- uses: secondlife/action-autobuild-release@v3
80+
81+
web:
82+
needs: ["release"]
83+
runs-on: ubuntu-latest
84+
steps:
85+
- uses: actions/checkout@v1
86+
- uses: actions/checkout@v2
87+
with:
88+
repository: emscripten-core/emsdk
89+
path: emsdk
90+
- name: emsdk install
91+
run: |
92+
cd emsdk
93+
./emsdk install latest
94+
./emsdk activate latest
95+
- name: make
96+
run: |
97+
source emsdk/emsdk_env.sh
98+
emcmake cmake . -DLUAU_BUILD_WEB=ON -DCMAKE_BUILD_TYPE=Release
99+
make -j2 Luau.Web
100+
- uses: actions/upload-release-asset@v1
101+
env:
102+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
103+
with:
104+
upload_url: ${{ github.event.release.upload_url }}
105+
asset_path: Luau.Web.js
106+
asset_name: Luau.Web.js
107+
asset_content_type: application/octet-stream

CLI/src/LSLBuiltins.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,16 @@ void luauSL_init_global_builtins(const char* builtins_file)
6363
sSLConstantStrings.clear();
6464

6565
LUAU_ASSERT(builtins_file != nullptr);
66-
std::ifstream fp(builtins_file, std::ios::binary);
6766

68-
if (!fp.good())
67+
std::ifstream file_stream(builtins_file);
68+
if (!file_stream)
6969
{
70-
fprintf(stderr, "couldn't open %s", builtins_file);
70+
fprintf(stderr, "couldn't open %s\n", builtins_file);
7171
exit(EXIT_FAILURE);
7272
}
7373

7474
std::string line;
75-
while (std::getline(fp, line))
75+
while (std::getline(file_stream, line))
7676
{
7777
// ignore comment and blank lines
7878
if (!line.rfind("//", 0) || !line.rfind('\r', 0) || !line.rfind('\n', 0) || line.empty())

CLI/src/Web.cpp

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
#include "lua.h"
33
#include "lualib.h"
44
#include "luacode.h"
5+
#include "llsl.h"
56

67
#include "Luau/Common.h"
78
#include "Luau/Frontend.h"
89
#include "Luau/BuiltinDefinitions.h"
10+
#include "Luau/LSLBuiltins.h"
911

1012
#include <string>
1113
#include <memory>
@@ -62,17 +64,48 @@ struct DemoConfigResolver : Luau::ConfigResolver
6264
Luau::Config defaultConfig;
6365
};
6466

67+
// SL mode state
68+
static lua_SLRuntimeState sl_state;
69+
70+
static void userthread_callback(lua_State* LP, lua_State* L)
71+
{
72+
if (LP == nullptr)
73+
return;
74+
lua_setthreaddata(L, lua_getthreaddata(LP));
75+
}
76+
6577
static void setupState(lua_State* L)
6678
{
6779
luaL_openlibs(L);
6880

81+
// SL mode setup
82+
lua_setthreaddata(L, &sl_state);
83+
sl_state.slIdentifier = LUA_SL_IDENTIFIER;
84+
lua_callbacks(L)->userthread = userthread_callback;
85+
86+
// SL libraries
87+
luaopen_sl(L, true);
88+
luaopen_ll(L, true);
89+
lua_pop(L, 1);
90+
91+
// JSON and Base64
92+
luaopen_cjson(L);
93+
lua_pop(L, 1);
94+
luaopen_llbase64(L);
95+
lua_pop(L, 1);
96+
97+
// Set SL constants on _G
98+
luaSL_set_constant_globals(L);
99+
69100
luaL_sandbox(L);
101+
lua_fixallcollectable(L);
70102
}
71103

72104
static std::string runCode(lua_State* L, const std::string& source)
73105
{
74106
size_t bytecodeSize = 0;
75107
char* bytecode = luau_compile(source.data(), source.length(), nullptr, &bytecodeSize);
108+
lua_setmemcat(L, 0);
76109
int result = luau_load(L, "=stdin", bytecode, bytecodeSize, 0);
77110
free(bytecode);
78111

@@ -87,7 +120,9 @@ static std::string runCode(lua_State* L, const std::string& source)
87120
return error;
88121
}
89122

123+
lua_setmemcat(L, 2);
90124
lua_State* T = lua_newthread(L);
125+
lua_setmemcat(L, 0);
91126

92127
lua_pushvalue(L, -2);
93128
lua_remove(L, -3);
@@ -189,16 +224,34 @@ extern "C" const char* executeScript(const char* source)
189224
if (strncmp(flag->name, "Luau", 4) == 0)
190225
flag->value = true;
191226

227+
// Initialize SL builtins once from embedded file
228+
static bool builtins_initialized = false;
229+
if (!builtins_initialized)
230+
{
231+
luauSL_init_global_builtins("/builtins.txt");
232+
builtins_initialized = true;
233+
}
234+
192235
// create new state
193236
std::unique_ptr<lua_State, void (*)(lua_State*)> globalState(luaL_newstate(), lua_close);
194237
lua_State* L = globalState.get();
195238

196239
// setup state
197240
setupState(L);
198241

199-
// sandbox thread
242+
// sandbox thread first (like REPL does)
200243
luaL_sandboxthread(L);
201244

245+
// Event and timer managers (after sandbox)
246+
luaSL_createeventmanager(L);
247+
lua_ref(L, -1);
248+
lua_pushvalue(L, -1); // Duplicate for timer manager (it expects LLEvents on stack)
249+
lua_setglobal(L, "LLEvents");
250+
251+
luaSL_createtimermanager(L);
252+
lua_ref(L, -1);
253+
lua_setglobal(L, "LLTimers");
254+
202255
// static string for caching result (prevents dangling ptr on function exit)
203256
static std::string result;
204257

CLI/test/Web.test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Smoke test for Luau.Web
2+
// Usage: node Web.test.js ./Luau.Web.js
3+
4+
const Module = require(require('path').resolve(process.cwd(), process.argv[2]));
5+
6+
Module.onRuntimeInitialized = () => {
7+
const exec = Module.cwrap('executeScript', 'string', ['string']);
8+
const err = exec('print(ZERO_VECTOR)');
9+
process.exit(err ? 1 : 0);
10+
};

CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ endif()
302302

303303
if(LUAU_BUILD_WEB)
304304
target_compile_options(Luau.Web PRIVATE ${LUAU_OPTIONS})
305-
target_link_libraries(Luau.Web PRIVATE Luau.Compiler Luau.VM Luau.Analysis)
305+
target_link_libraries(Luau.Web PRIVATE Luau.Compiler Luau.VM Luau.Analysis Luau.CLI.lib)
306306

307307
# declare exported functions to emscripten
308308
target_link_options(Luau.Web PRIVATE -sEXPORTED_FUNCTIONS=["_executeScript","_checkScript"] -sEXPORTED_RUNTIME_METHODS=["ccall","cwrap"])
@@ -312,6 +312,9 @@ if(LUAU_BUILD_WEB)
312312

313313
# the output is a single .js file with an embedded wasm blob
314314
target_link_options(Luau.Web PRIVATE -sSINGLE_FILE=1)
315+
316+
# Embed builtins.txt into the wasm virtual filesystem for SL constants
317+
target_link_options(Luau.Web PRIVATE --embed-file ${CMAKE_SOURCE_DIR}/builtins.txt@/builtins.txt)
315318
endif()
316319

317320
# validate dependencies for internal libraries

0 commit comments

Comments
 (0)