Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ concurrency:
env:
BUILD_TYPE: Debug
SQLITE_VERSION: 3390100 # 3.39.1
EMSDK_VERSION: 4.0.10

jobs:
check:
Expand Down Expand Up @@ -66,6 +67,38 @@ jobs:
with:
folder: ${{ matrix.path }}

build-with-emscripten:
runs-on: ubuntu-24.04
name: "Build with emscripten"
needs: [ check ]

steps:
- uses: actions/checkout@v4
with:
submodules: recursive

- name: Setup emsdk
uses: mymindstorm/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14
with:
version: ${{ env.EMSDK_VERSION }}
actions-cache-folder: 'emsdk-cache'

- name: Verify
run: emcc -v

- name: Compile
shell: bash
run: |
emcmake cmake -Bbuild \
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
-DARK_SANITIZERS=Off \
-DARK_COVERAGE=Off \
-DARK_BUILD_EXE=Off \
-DARK_BUILD_MODULES=Off \
-DARK_TESTS=Off \
-DARK_UNITY_BUILD=On
cmake --build build --config ${{ env.BUILD_TYPE }} -j $(nproc)

build:
runs-on: ${{ matrix.config.os }}
name: ${{ matrix.config.name }}
Expand Down
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,19 @@ include/Ark/Constants.hpp
/fct-ok/
/fct-bad/

# WASM
/public/node_modules
/public/*.wasm.wasm
/public/*.wasm.js
/public/package.json
/public/package-lock.json

# Folders
.vs/
.idea/
.cache/
build/
build_emscripten/
ninja/
cmake-build-*/
out/
Expand Down
77 changes: 56 additions & 21 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,18 @@ option(ARK_TESTS "Build ArkScript unit tests" Off)
option(ARK_BENCHMARKS "Build ArkScript benchmarks" Off)
option(ARK_COVERAGE "Enable coverage while building (clang, gcc) (requires ARK_TESTS to be On)" Off)
option(ARK_UNITY_BUILD "Enable unity build" Off)
option(ARK_JS_ONLY "Compiles to native JS (No WASM). Can be used only when compiling with emsdk" OFF)

include(cmake/link_time_optimization.cmake)
include(cmake/sanitizers.cmake)
if (${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
set(ARK_EMSCRIPTEN TRUE)
endif ()

if (NOT ARK_EMSCRIPTEN)
include(cmake/link_time_optimization.cmake)
include(cmake/sanitizers.cmake)
include(GNUInstallDirs) # Uses GNU Install directory variables
endif ()
include(cmake/CPM.cmake)
include(GNUInstallDirs) # Uses GNU Install directory variables

# configure installer.iss
configure_file(
Expand All @@ -48,7 +55,9 @@ file(GLOB_RECURSE SOURCE_FILES
${ark_SOURCE_DIR}/lib/fmt/src/format.cc)

add_library(ArkReactor SHARED ${SOURCE_FILES})
enable_lto(ArkReactor)
if (NOT ARK_EMSCRIPTEN)
enable_lto(ArkReactor)
endif ()
target_include_directories(ArkReactor
PUBLIC
${ark_SOURCE_DIR}/include)
Expand All @@ -59,6 +68,31 @@ if (ARK_UNITY_BUILD)
set_source_files_properties(src/arkreactor/VM/VM.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION true)
endif ()

if (ARK_EMSCRIPTEN)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/public")

# ArkScript lib needs to know if we are building an exe to enable/disable specific code for embedding
target_compile_definitions(ArkReactor PRIVATE ARK_BUILD_EXE=1)

add_executable(ArkEmscripten ${ark_SOURCE_DIR}/src/arkemscripten/main.cpp)
target_link_libraries(ArkEmscripten PUBLIC ArkReactor)
target_compile_features(ArkEmscripten PRIVATE cxx_std_20)

# enable_lto(ArkEmscripten)

if (ARK_JS_ONLY)
message(STATUS "Setting compilation target to native JavaScript")
set(CMAKE_EXECUTABLE_SUFFIX ".js")
set_target_properties(ArkReactor PROPERTIES LINK_FLAGS "-s WASM=0 -s NO_DISABLE_EXCEPTION_CATCHING")
set_target_properties(ArkEmscripten PROPERTIES LINK_FLAGS "-s WASM=0 -s NO_DISABLE_EXCEPTION_CATCHING -s EXPORTED_FUNCTIONS='[_main]' -s EXPORTED_RUNTIME_METHODS=['run'] -lembind")
else ()
message(STATUS "Setting compilation target to WASM")
set(CMAKE_EXECUTABLE_SUFFIX ".wasm.js")
set_target_properties(ArkReactor PROPERTIES LINK_FLAGS "-s WASM=1 -s NO_DISABLE_EXCEPTION_CATCHING")
set_target_properties(ArkEmscripten PROPERTIES LINK_FLAGS "-s WASM=1 -s NO_DISABLE_EXCEPTION_CATCHING -s EXPORTED_FUNCTIONS='[_main]' -s EXPORTED_RUNTIME_METHODS=['run'] -lembind")
endif ()
endif ()

if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG OR APPLE)
message(STATUS "Enabling computed gotos")
target_compile_definitions(ArkReactor PRIVATE ARK_USE_COMPUTED_GOTOS=1)
Expand All @@ -81,7 +115,7 @@ if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG OR APPLE)
-fvisibility=hidden
-fno-semantic-interposition
)
if (NOT ARK_BENCHMARKS)
if (NOT ARK_BENCHMARKS AND NOT ARK_EMSCRIPTEN)
target_compile_options(ArkReactor PRIVATE -Werror)
endif ()

Expand Down Expand Up @@ -150,22 +184,23 @@ configure_file(
${ark_SOURCE_DIR}/include/Ark/Constants.hpp)

# Installation rules

# Installs the dynamic library file.
install(TARGETS ArkReactor
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})

# Install header files
install(DIRECTORY ${ark_SOURCE_DIR}/include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

# Install the standard library
if (NOT ARK_NO_STDLIB)
install(DIRECTORY ${ark_SOURCE_DIR}/lib/std/
DESTINATION ${CMAKE_INSTALL_LIBDIR}/Ark/std
FILES_MATCHING PATTERN "*.ark"
PATTERN "std/tests" EXCLUDE
PATTERN "std/.github" EXCLUDE)
if (NOT ARK_EMSCRIPTEN)
# Installs the dynamic library file.
install(TARGETS ArkReactor
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})

# Install header files
install(DIRECTORY ${ark_SOURCE_DIR}/include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

# Install the standard library
if (NOT ARK_NO_STDLIB)
install(DIRECTORY ${ark_SOURCE_DIR}/lib/std/
DESTINATION ${CMAKE_INSTALL_LIBDIR}/Ark/std
FILES_MATCHING PATTERN "*.ark"
PATTERN "std/tests" EXCLUDE
PATTERN "std/.github" EXCLUDE)
endif ()
endif ()

# COMPILATION RELATED
Expand Down
63 changes: 63 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>ArkScript emscripten</title>
</head>
<body>
<div>
<textarea id="code" cols="80" rows="10"></textarea>
<button id="run">Submit</button>
</div>
<div>
<textarea id="output" cols="80" rows="10" readonly></textarea>
</div>

<script>
let output = "";
log = console.log;
window.console.log = (message) => {
output = message;
};

var Module = {
onRuntimeInitialized: function () {
document.getElementById("run").addEventListener("click", () => {
const code = document.getElementById("code").value;
console.log(code);

try {
Module.run(code);
document.getElementById("output").innerText = output;
} catch (e) {
document.getElementById("output").innerText = e;
}
});
}
};
</script>

<script>
(function (e, t) {
console.log("Loading client...");

const scriptName = `ArkEmscripten${e.WebAssembly ? ".wasm" : ""}.js`;
console.log(`Script set to ${scriptName}`);

const loader = t.createElement("script");
loader.async = true;
loader.type = "text/javascript";
loader.src = scriptName;
loader.onerror = (t) => {
console.error("Script Error");
console.error(t);
setTimeout(() => {
e.location.reload();
}, 3000);
};

const node = t.getElementsByTagName("script")[0];
node.parentNode.insertBefore(loader, node);
})(window, document);
</script>
</body>
</html>
7 changes: 7 additions & 0 deletions public/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// For development purpose only

const express = require('express');
const app = express();

app.use(express.static('./'));
app.listen(3000);
27 changes: 27 additions & 0 deletions src/arkemscripten/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include <Ark/Ark.hpp>
#include <emscripten.h>
#include <emscripten/bind.h>

#include <string>

extern "C" {
void __attribute__((noinline)) EMSCRIPTEN_KEEPALIVE run(const std::string& code)
{
Ark::State state;
state.doString(code);

Ark::VM vm(state);
vm.run();
}
}

EMSCRIPTEN_BINDINGS(arkscript)
{
using namespace emscripten;
function("run", &run);
}

int main()
{
return 0;
}
Loading