mirror of
https://github.com/luau-lang/luau.git
synced 2024-11-15 14:25:44 +08:00
Add web workflow to build Repl with Emscripten (#222)
This also separates Emscripten build into a new target / source to make it more decoupled.
This commit is contained in:
parent
2740f69f32
commit
5961261a1c
19
.github/workflows/build.yml
vendored
19
.github/workflows/build.yml
vendored
@ -83,3 +83,22 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: coverage
|
name: coverage
|
||||||
path: coverage
|
path: coverage
|
||||||
|
|
||||||
|
web:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: emscripten-core/emsdk
|
||||||
|
path: emsdk
|
||||||
|
- name: emsdk install
|
||||||
|
run: |
|
||||||
|
cd emsdk
|
||||||
|
./emsdk install latest
|
||||||
|
./emsdk activate latest
|
||||||
|
- name: make
|
||||||
|
run: |
|
||||||
|
source emsdk/emsdk_env.sh
|
||||||
|
emcmake cmake . -DLUAU_BUILD_WEB=ON -DCMAKE_BUILD_TYPE=Release
|
||||||
|
make -j2 Luau.Web
|
||||||
|
23
.github/workflows/release.yml
vendored
23
.github/workflows/release.yml
vendored
@ -33,3 +33,26 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: luau-${{matrix.os}}
|
name: luau-${{matrix.os}}
|
||||||
path: Release\luau*.exe
|
path: Release\luau*.exe
|
||||||
|
|
||||||
|
web:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: emscripten-core/emsdk
|
||||||
|
path: emsdk
|
||||||
|
- name: emsdk install
|
||||||
|
run: |
|
||||||
|
cd emsdk
|
||||||
|
./emsdk install latest
|
||||||
|
./emsdk activate latest
|
||||||
|
- name: make
|
||||||
|
run: |
|
||||||
|
source emsdk/emsdk_env.sh
|
||||||
|
emcmake cmake . -DLUAU_BUILD_WEB=ON -DCMAKE_BUILD_TYPE=Release
|
||||||
|
make -j2 Luau.Web
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: Luau.Web.js
|
||||||
|
path: Luau.Web.js
|
||||||
|
39
CLI/Repl.cpp
39
CLI/Repl.cpp
@ -198,11 +198,6 @@ static std::string runCode(lua_State* L, const std::string& source)
|
|||||||
error += "\nstack backtrace:\n";
|
error += "\nstack backtrace:\n";
|
||||||
error += lua_debugtrace(T);
|
error += lua_debugtrace(T);
|
||||||
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
// nicer formatting for errors in web repl
|
|
||||||
error = "Error:" + error;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
fprintf(stdout, "%s", error.c_str());
|
fprintf(stdout, "%s", error.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,39 +205,6 @@ static std::string runCode(lua_State* L, const std::string& source)
|
|||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
const char* executeScript(const char* source)
|
|
||||||
{
|
|
||||||
// setup flags
|
|
||||||
for (Luau::FValue<bool>* flag = Luau::FValue<bool>::list; flag; flag = flag->next)
|
|
||||||
if (strncmp(flag->name, "Luau", 4) == 0)
|
|
||||||
flag->value = true;
|
|
||||||
|
|
||||||
// create new state
|
|
||||||
std::unique_ptr<lua_State, void (*)(lua_State*)> globalState(luaL_newstate(), lua_close);
|
|
||||||
lua_State* L = globalState.get();
|
|
||||||
|
|
||||||
// setup state
|
|
||||||
setupState(L);
|
|
||||||
|
|
||||||
// sandbox thread
|
|
||||||
luaL_sandboxthread(L);
|
|
||||||
|
|
||||||
// static string for caching result (prevents dangling ptr on function exit)
|
|
||||||
static std::string result;
|
|
||||||
|
|
||||||
// run code + collect error
|
|
||||||
result = runCode(L, source);
|
|
||||||
|
|
||||||
return result.empty() ? NULL : result.c_str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Excluded from emscripten compilation to avoid -Wunused-function errors.
|
|
||||||
#ifndef __EMSCRIPTEN__
|
|
||||||
static void completeIndexer(lua_State* L, const char* editBuffer, size_t start, std::vector<std::string>& completions)
|
static void completeIndexer(lua_State* L, const char* editBuffer, size_t start, std::vector<std::string>& completions)
|
||||||
{
|
{
|
||||||
std::string_view lookup = editBuffer + start;
|
std::string_view lookup = editBuffer + start;
|
||||||
@ -564,5 +526,4 @@ int main(int argc, char** argv)
|
|||||||
return failed;
|
return failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
106
CLI/Web.cpp
Normal file
106
CLI/Web.cpp
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||||
|
#include "lua.h"
|
||||||
|
#include "lualib.h"
|
||||||
|
#include "luacode.h"
|
||||||
|
|
||||||
|
#include "Luau/Common.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static void setupState(lua_State* L)
|
||||||
|
{
|
||||||
|
luaL_openlibs(L);
|
||||||
|
|
||||||
|
luaL_sandbox(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string runCode(lua_State* L, const std::string& source)
|
||||||
|
{
|
||||||
|
size_t bytecodeSize = 0;
|
||||||
|
char* bytecode = luau_compile(source.data(), source.length(), nullptr, &bytecodeSize);
|
||||||
|
int result = luau_load(L, "=stdin", bytecode, bytecodeSize, 0);
|
||||||
|
free(bytecode);
|
||||||
|
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
const char* msg = lua_tolstring(L, -1, &len);
|
||||||
|
|
||||||
|
std::string error(msg, len);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_State* T = lua_newthread(L);
|
||||||
|
|
||||||
|
lua_pushvalue(L, -2);
|
||||||
|
lua_remove(L, -3);
|
||||||
|
lua_xmove(L, T, 1);
|
||||||
|
|
||||||
|
int status = lua_resume(T, NULL, 0);
|
||||||
|
|
||||||
|
if (status == 0)
|
||||||
|
{
|
||||||
|
int n = lua_gettop(T);
|
||||||
|
|
||||||
|
if (n)
|
||||||
|
{
|
||||||
|
luaL_checkstack(T, LUA_MINSTACK, "too many results to print");
|
||||||
|
lua_getglobal(T, "print");
|
||||||
|
lua_insert(T, 1);
|
||||||
|
lua_pcall(T, n, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string error;
|
||||||
|
|
||||||
|
if (status == LUA_YIELD)
|
||||||
|
{
|
||||||
|
error = "thread yielded unexpectedly";
|
||||||
|
}
|
||||||
|
else if (const char* str = lua_tostring(T, -1))
|
||||||
|
{
|
||||||
|
error = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
error += "\nstack backtrace:\n";
|
||||||
|
error += lua_debugtrace(T);
|
||||||
|
|
||||||
|
error = "Error:" + error;
|
||||||
|
|
||||||
|
fprintf(stdout, "%s", error.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" const char* executeScript(const char* source)
|
||||||
|
{
|
||||||
|
// setup flags
|
||||||
|
for (Luau::FValue<bool>* flag = Luau::FValue<bool>::list; flag; flag = flag->next)
|
||||||
|
if (strncmp(flag->name, "Luau", 4) == 0)
|
||||||
|
flag->value = true;
|
||||||
|
|
||||||
|
// create new state
|
||||||
|
std::unique_ptr<lua_State, void (*)(lua_State*)> globalState(luaL_newstate(), lua_close);
|
||||||
|
lua_State* L = globalState.get();
|
||||||
|
|
||||||
|
// setup state
|
||||||
|
setupState(L);
|
||||||
|
|
||||||
|
// sandbox thread
|
||||||
|
luaL_sandboxthread(L);
|
||||||
|
|
||||||
|
// static string for caching result (prevents dangling ptr on function exit)
|
||||||
|
static std::string result;
|
||||||
|
|
||||||
|
// run code + collect error
|
||||||
|
result = runCode(L, source);
|
||||||
|
|
||||||
|
return result.empty() ? NULL : result.c_str();
|
||||||
|
}
|
@ -9,6 +9,7 @@ project(Luau LANGUAGES CXX)
|
|||||||
|
|
||||||
option(LUAU_BUILD_CLI "Build CLI" ON)
|
option(LUAU_BUILD_CLI "Build CLI" ON)
|
||||||
option(LUAU_BUILD_TESTS "Build tests" ON)
|
option(LUAU_BUILD_TESTS "Build tests" ON)
|
||||||
|
option(LUAU_BUILD_WEB "Build Web module" OFF)
|
||||||
option(LUAU_WERROR "Warnings as errors" OFF)
|
option(LUAU_WERROR "Warnings as errors" OFF)
|
||||||
|
|
||||||
add_library(Luau.Ast STATIC)
|
add_library(Luau.Ast STATIC)
|
||||||
@ -18,26 +19,22 @@ add_library(Luau.VM STATIC)
|
|||||||
|
|
||||||
if(LUAU_BUILD_CLI)
|
if(LUAU_BUILD_CLI)
|
||||||
add_executable(Luau.Repl.CLI)
|
add_executable(Luau.Repl.CLI)
|
||||||
if(NOT EMSCRIPTEN)
|
|
||||||
add_executable(Luau.Analyze.CLI)
|
add_executable(Luau.Analyze.CLI)
|
||||||
else()
|
|
||||||
# add -fexceptions for emscripten to allow exceptions to be caught in C++
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# This also adds target `name` on Linux/macOS and `name.exe` on Windows
|
# This also adds target `name` on Linux/macOS and `name.exe` on Windows
|
||||||
set_target_properties(Luau.Repl.CLI PROPERTIES OUTPUT_NAME luau)
|
set_target_properties(Luau.Repl.CLI PROPERTIES OUTPUT_NAME luau)
|
||||||
|
|
||||||
if(NOT EMSCRIPTEN)
|
|
||||||
set_target_properties(Luau.Analyze.CLI PROPERTIES OUTPUT_NAME luau-analyze)
|
set_target_properties(Luau.Analyze.CLI PROPERTIES OUTPUT_NAME luau-analyze)
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(LUAU_BUILD_TESTS AND NOT EMSCRIPTEN)
|
if(LUAU_BUILD_TESTS)
|
||||||
add_executable(Luau.UnitTest)
|
add_executable(Luau.UnitTest)
|
||||||
add_executable(Luau.Conformance)
|
add_executable(Luau.Conformance)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(LUAU_BUILD_WEB)
|
||||||
|
add_executable(Luau.Web)
|
||||||
|
endif()
|
||||||
|
|
||||||
include(Sources.cmake)
|
include(Sources.cmake)
|
||||||
|
|
||||||
target_compile_features(Luau.Ast PUBLIC cxx_std_17)
|
target_compile_features(Luau.Ast PUBLIC cxx_std_17)
|
||||||
@ -72,16 +69,18 @@ if(LUAU_WERROR)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(LUAU_BUILD_WEB)
|
||||||
|
# add -fexceptions for emscripten to allow exceptions to be caught in C++
|
||||||
|
list(APPEND LUAU_OPTIONS -fexceptions)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_compile_options(Luau.Ast PRIVATE ${LUAU_OPTIONS})
|
target_compile_options(Luau.Ast PRIVATE ${LUAU_OPTIONS})
|
||||||
target_compile_options(Luau.Analysis PRIVATE ${LUAU_OPTIONS})
|
target_compile_options(Luau.Analysis PRIVATE ${LUAU_OPTIONS})
|
||||||
target_compile_options(Luau.VM PRIVATE ${LUAU_OPTIONS})
|
target_compile_options(Luau.VM PRIVATE ${LUAU_OPTIONS})
|
||||||
|
|
||||||
if(LUAU_BUILD_CLI)
|
if(LUAU_BUILD_CLI)
|
||||||
target_compile_options(Luau.Repl.CLI PRIVATE ${LUAU_OPTIONS})
|
target_compile_options(Luau.Repl.CLI PRIVATE ${LUAU_OPTIONS})
|
||||||
|
|
||||||
if(NOT EMSCRIPTEN)
|
|
||||||
target_compile_options(Luau.Analyze.CLI PRIVATE ${LUAU_OPTIONS})
|
target_compile_options(Luau.Analyze.CLI PRIVATE ${LUAU_OPTIONS})
|
||||||
endif()
|
|
||||||
|
|
||||||
target_include_directories(Luau.Repl.CLI PRIVATE extern)
|
target_include_directories(Luau.Repl.CLI PRIVATE extern)
|
||||||
target_link_libraries(Luau.Repl.CLI PRIVATE Luau.Compiler Luau.VM)
|
target_link_libraries(Luau.Repl.CLI PRIVATE Luau.Compiler Luau.VM)
|
||||||
@ -93,20 +92,10 @@ if(LUAU_BUILD_CLI)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT EMSCRIPTEN)
|
|
||||||
target_link_libraries(Luau.Analyze.CLI PRIVATE Luau.Analysis)
|
target_link_libraries(Luau.Analyze.CLI PRIVATE Luau.Analysis)
|
||||||
endif()
|
|
||||||
|
|
||||||
if(EMSCRIPTEN)
|
|
||||||
# declare exported functions to emscripten
|
|
||||||
target_link_options(Luau.Repl.CLI PRIVATE -sEXPORTED_FUNCTIONS=['_executeScript'] -sEXPORTED_RUNTIME_METHODS=['ccall','cwrap'] -fexceptions)
|
|
||||||
|
|
||||||
# custom output directory for wasm + js file
|
|
||||||
set_target_properties(Luau.Repl.CLI PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/docs/assets/luau)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(LUAU_BUILD_TESTS AND NOT EMSCRIPTEN)
|
if(LUAU_BUILD_TESTS)
|
||||||
target_compile_options(Luau.UnitTest PRIVATE ${LUAU_OPTIONS})
|
target_compile_options(Luau.UnitTest PRIVATE ${LUAU_OPTIONS})
|
||||||
target_include_directories(Luau.UnitTest PRIVATE extern)
|
target_include_directories(Luau.UnitTest PRIVATE extern)
|
||||||
target_link_libraries(Luau.UnitTest PRIVATE Luau.Analysis Luau.Compiler)
|
target_link_libraries(Luau.UnitTest PRIVATE Luau.Analysis Luau.Compiler)
|
||||||
@ -115,3 +104,17 @@ if(LUAU_BUILD_TESTS AND NOT EMSCRIPTEN)
|
|||||||
target_include_directories(Luau.Conformance PRIVATE extern)
|
target_include_directories(Luau.Conformance PRIVATE extern)
|
||||||
target_link_libraries(Luau.Conformance PRIVATE Luau.Analysis Luau.Compiler Luau.VM)
|
target_link_libraries(Luau.Conformance PRIVATE Luau.Analysis Luau.Compiler Luau.VM)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(LUAU_BUILD_WEB)
|
||||||
|
target_compile_options(Luau.Web PRIVATE ${LUAU_OPTIONS})
|
||||||
|
target_link_libraries(Luau.Web PRIVATE Luau.Compiler Luau.VM)
|
||||||
|
|
||||||
|
# declare exported functions to emscripten
|
||||||
|
target_link_options(Luau.Web PRIVATE -sEXPORTED_FUNCTIONS=['_executeScript'] -sEXPORTED_RUNTIME_METHODS=['ccall','cwrap'])
|
||||||
|
|
||||||
|
# add -fexceptions for emscripten to allow exceptions to be caught in C++
|
||||||
|
target_link_options(Luau.Web PRIVATE -fexceptions)
|
||||||
|
|
||||||
|
# the output is a single .js file with an embedded wasm blob
|
||||||
|
target_link_options(Luau.Web PRIVATE -sSINGLE_FILE=1)
|
||||||
|
endif()
|
||||||
|
@ -224,3 +224,9 @@ if(TARGET Luau.Conformance)
|
|||||||
tests/Conformance.test.cpp
|
tests/Conformance.test.cpp
|
||||||
tests/main.cpp)
|
tests/main.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(TARGET Luau.Web)
|
||||||
|
# Luau.Web Sources
|
||||||
|
target_sources(Luau.Web PRIVATE
|
||||||
|
CLI/Web.cpp)
|
||||||
|
endif()
|
||||||
|
Loading…
Reference in New Issue
Block a user