Skip to content

Instantly share code, notes, and snippets.

@RajaniCode
Last active February 16, 2025 18:49
Show Gist options
  • Save RajaniCode/4b59b283143b18f6ffa9929546b2f2e6 to your computer and use it in GitHub Desktop.
Save RajaniCode/4b59b283143b18f6ffa9929546b2f2e6 to your computer and use it in GitHub Desktop.
WebAssembly
###########################################################################################################################
# WebAssembly (Wasm)
###########################################################################################################################
***************************************************************************************************************************
# Emscripten # WebAssembly (Wasm) # emsdk # emcc # em++ # Node.js # HTML # Python # Web Audio
***************************************************************************************************************************
% git clone https://github.com/emscripten-core/emsdk.git
% cd emsdk
% ./emsdk install latest
% ./emsdk activate latest
% source ./emsdk_env.sh
% emcc --version
% em++ --version
# C
% mkdir -p C
% cd C
% nano index.c
[
#include <stdio.h>
int main() {
printf("%s\n", __VERSION__);
printf("%s\n", __DATE__);
printf("%s\n", __TIME__);
return 0;
}
]
% cat index.c
[
% gcc --version
% gcc index.c -o index
% ./index
]
# Emscripten JavaScript
% emcc index.c -o index.js
% node --version
# Emscripten Node.js
% node index.js
# Emscripten HTML
# Emscripten optimize code for size
% emcc index.c -O3 -o index.html
===========================================================================================================================
# HTTP Server
===========================================================================================================================
[
% npm install http-server --global
]
% npm --version
% http-server -p 8000
[
% python3 --version
% python3 -m http.server 8000
]
[
% export PATH="$HOME/Downloads/Software/OpenJDK/JDK23.0.1/jdk-23.0.1.jdk/Contents/Home/bin/":$PATH
% java --version
% jwebserver --port 8000
]
[
% ruby --version
% gem install webrick
% ruby -run -e httpd . -p 8000
]
[
% php --version
% php -S 127.0.0.1:8000
]
===========================================================================================================================
# Terminal New Window
===========================================================================================================================
% curl http://127.0.0.1:8000
% open http://127.0.0.1:8000
===========================================================================================================================
# Emscripten # WebAssembly (Wasm) # em++ # Python # Web Audio
===========================================================================================================================
% mkdir -p Emscripten
% cd Emscripten
# git sparse-checkout
# https://github.com/emscripten-core/emscripten/tree/main/test/webaudio
# https://github1s.com/emscripten-core/emscripten/tree/main/test/webaudio
% git clone --filter=blob:none --no-checkout --sparse https://github.com/emscripten-core/emscripten
% cd emscripten
% git sparse-checkout add test/webaudio
% git checkout
% ls -a
% cd test/webaudio
% mkdir -p test && nano test/cors.txt
[
#!/usr/bin/env python3
from http.server import ThreadingHTTPServer, SimpleHTTPRequestHandler, test
import sys
class CORSRequestHandler (SimpleHTTPRequestHandler):
def end_headers (self):
#self.send_header('Access-Control-Allow-Origin', '*')
self.send_header("Cross-Origin-Opener-Policy", "same-origin")
self.send_header("Cross-Origin-Embedder-Policy", "require-corp")
SimpleHTTPRequestHandler.end_headers(self)
if __name__ == '__main__':
test(CORSRequestHandler, ThreadingHTTPServer, protocol="HTTP/1.1", port=int(sys.argv[1]) if len(sys.argv) > 1 else 8000, bind = '127.0.0.1')
]
% cat test/cors.txt
% python3 test/cors.txt
# Browse
http://127.0.0.1:8000/test/test.html
===========================================================================================================================
# Terminal New Window
===========================================================================================================================
% cd Emscripten
% cd emscripten/test/webaudio
% em++ --version
% em++ audioworklet.c -s ENVIRONMENT='web','worker' -sAUDIO_WORKLET=1 -sWASM_WORKERS=1 -o test/test.htm
===========================================================================================================================
***************************************************************************************************************************
***************************************************************************************************************************
# C/C++ # WebAssembly (wasm) # Emscripten # emcc # em++ # Node.js # HTML
***************************************************************************************************************************
% mkdir -p C
% cd C
% brew install emscripten
% emcc --version
% em++ --version
% nano index.c
[
#include <stdio.h>
int main() {
printf("%s\n", __VERSION__);
printf("%s\n", __DATE__);
printf("%s\n", __TIME__);
return 0;
}
]
% cat index.c
[
% gcc --version
% gcc index.c -o index
% ./index
]
# Emscripten JavaScript
% emcc index.c -o index.js
% node --version
# Emscripten Node.js
% node index.js
# Emscripten HTML
# Emscripten optimize the code for size
% emcc index.c -O3 -o index.html
===========================================================================================================================
# HTTP Server
===========================================================================================================================
[
% npm install http-server --global
]
% npm --version
% http-server -p 8000
[
% python3 --version
% python3 -m http.server 8000
]
[
% export PATH="$HOME/Downloads/Software/OpenJDK/JDK23.0.1/jdk-23.0.1.jdk/Contents/Home/bin/":$PATH
% java --version
% jwebserver --port 8000
]
[
% ruby --version
% gem install webrick
% ruby -run -e httpd . -p 8000
]
[
% php --version
% php -S 127.0.0.1:8000
]
===========================================================================================================================
# Terminal New Window
===========================================================================================================================
% curl http://127.0.0.1:8000
% open http://127.0.0.1:8000
===========================================================================================================================
***************************************************************************************************************************
***************************************************************************************************************************
# TypeScript # WebAssembly (wasm) # AssemblyScript # npm # asc
***************************************************************************************************************************
% mkdir -p TypeScript
% cd TypeScript
% nano index.ts
[
export function math(x: i32, y: i32): i32 {
return x * y;
}
]
% cat index.ts
# AssemblyScript Compiler for WebAssembly (wasm)
[
% npm install -g assemblyscript
]
% asc --version
# index.ts to wasm
% asc index.ts -o index.wasm
% nano index.js
[
export const wasm = async (source, importObject) => {
let response = undefined;
if (!importObject) {
importObject = { imported_func: { arg: () => console.log(arg) },
};
}
if (WebAssembly.instantiateStreaming) {
response = await WebAssembly.instantiateStreaming(
fetch(source),
importObject
);
} else {
const fetchThenInstantiate = async () => {
const buffer = await fetch(source).then(response =>
response.arrayBuffer()
);
return WebAssembly.instantiate(buffer, importObject);
};
response = await fetchThenInstantiate();
}
return response;
};
const wasmFunc = async () => {
const module = await wasm("./index.wasm");
const x = 5;
const y = 7;
const result = module.instance.exports.math(5, 7);
document.body.innerHTML = `Browser: ${navigator.userAgent} <br\><br\> Math: ${x} x ${y} = ${result}`;
};
wasmFunc();
]
% cat index.js
% nano index.html
[
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>TypeScript WebAssembly</title>
<script type="module" src="./index.js"></script>
</head>
<body></body>
</html>
]
% cat index.html
[
% wget https://www.google.com/favicon.ico
]
===========================================================================================================================
# HTTP Server
===========================================================================================================================
[
% npm install http-server --global
]
% npm --version
% http-server -p 8000
[
% python3 --version
% python3 -m http.server 8000
]
[
% export PATH="$HOME/Downloads/Software/OpenJDK/JDK23.0.1/jdk-23.0.1.jdk/Contents/Home/bin/":$PATH
% java --version
% jwebserver --port 8000
]
[
% ruby --version
% gem install webrick
% ruby -run -e httpd . -p 8000
]
[
% php --version
% php -S 127.0.0.1:8000
]
===========================================================================================================================
# Terminal New Window
===========================================================================================================================
% curl http://127.0.0.1:8000
% open http://127.0.0.1:8000
===========================================================================================================================
***************************************************************************************************************************
***************************************************************************************************************************
# Swift # WebAssembly (wasm) # SwiftWasm
***************************************************************************************************************************
===========================================================================================================================
# Default Swift # Export SwiftWasm # SwiftWasm Swift
===========================================================================================================================
---------------------------------------------------------------------------------------------------------------------------
# NB # Swift # macOS Package Installer # https://swift.org/install/macos/package_installer/
---------------------------------------------------------------------------------------------------------------------------
# An Xcode toolchain (.xctoolchain) includes a copy of the compiler, LLDB, and other related tools needed to provide a cohesive development experience for working in a specific version of Swift
# To select the installed toolchain in Xcode, navigate to Xcode > Toolchains.
# Xcode uses the selected toolchain for building Swift code, debugging, and even code completion and syntax coloring. You’ll see a new toolchain indicator in Xcode’s toolbar when Xcode is using an installed toolchain. Select the default toolchain to go back to Xcode’s built-in tools.
# Selecting a toolchain in Xcode affects the IDE only. To use the installed toolchain with xcrun, pass the --toolchain swift option. For example:
% xcrun --version
% xcrun --toolchain swift swift --version
# xcodebuild, pass the -toolchain swift option.
# Alternatively, you may select the toolchain on the command line by exporting the TOOLCHAINS environment variable as follows:
% export TOOLCHAINS=$(plutil -extract CFBundleIdentifier raw /Library/Developer/Toolchains/<toolchain name>.xctoolchain/Info.plist)
---------------------------------------------------------------------------------------------------------------------------
# To start anew # Toolchains # swift sdk # wasmtime
---------------------------------------------------------------------------------------------------------------------------
# Remove Toolchains
[
% ls /Library/Developer/Toolchains
% sudo rm -rf /Library/Developer/Toolchains
% ls ~/Library/Developer/Toolchains
% sudo rm -rf ~/Library/Developer/Toolchains
]
# Remove swift sdk
% swift sdk list
[
% swift sdk remove 5.10.0-RELEASE-wasm
]
# wasmtime
# Remove the following from $HOME/.zshrc # % cat $HOME/.zshrc
[
export WASMTIME_HOME="$HOME/.wasmtime"
export PATH="$WASMTIME_HOME/bin:$PATH"
]
---------------------------------------------------------------------------------------------------------------------------
# swift # swiftc
---------------------------------------------------------------------------------------------------------------------------
% mkdir -p Swift
% cd Swift
# Swift
% swift --version
[
swift-driver version: 1.115.1 Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
Target: arm64-apple-macosx15.0
]
# Swift Compile
% swiftc --version
[
swift-driver version: 1.115.1 Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
Target: arm64-apple-macosx15.0
]
% ls -l `which swift`
% ls /usr/bin
[
swift
swift-inspect
swiftc
]
---------------------------------------------------------------------------------------------------------------------------
# Swift Xcode Toolchain # Install # pkg
---------------------------------------------------------------------------------------------------------------------------
# Download the appropriate Swift toolchain version from swift.org/install and install the pkg
# swift-5.10-RELEASE-osx.pkg
[
# Debugging Symbols # pkg
# swift-5.10-RELEASE-osx-symbols.pkg
]
# swift # swiftc # Same # After installing swift-5.10-RELEASE-osx.pkg
# Swift
% swift --version
[
swift-driver version: 1.115.1 Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
Target: arm64-apple-macosx15.0
]
# Swift Compile
% swiftc --version
[
swift-driver version: 1.115.1 Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
Target: arm64-apple-macosx15.0
]
# The package installer will install an Xcode toolchain into /Library/Developer/Toolchains/
% ls /Library/Developer/Toolchains
[
swift-5.10-RELEASE.xctoolchain swift-latest.xctoolchain
]
# Remove Toolchains
[
% ls /Library/Developer/Toolchains
% sudo rm -rf /Library/Developer/Toolchains
]
---------------------------------------------------------------------------------------------------------------------------
# Swift SDK for WebAssembly # Cross compile to WebAssembly
---------------------------------------------------------------------------------------------------------------------------
# Match the Swift Toolchain Version # swift-5.10-RELEASE # swift-wasm-5.10.0-RELEASE
# Install Swift SDKs for WebAssembly
% wget https://github.com/swiftwasm/swift/releases/download/swift-wasm-5.10.0-RELEASE/swift-wasm-5.10.0-RELEASE-macos_arm64.artifactbundle.zip
% swift sdk install swift-wasm-5.10.0-RELEASE-macos_arm64.artifactbundle.zip
% swift sdk list
[
5.10.0-RELEASE-wasm
]
# Remove swift sdk
[
% swift sdk list
% swift sdk remove 5.10.0-RELEASE-wasm
]
# Swift File
% nano sample.swift
[
#if os(macOS)
print("macOS")
#elseif os(iOS)
print("iOS")
#elseif os(watchOS)
print("watchOS")
#elseif os(tvOS)
print("tvOS")
#endif
#if swift(>=5.0)
print("Swift >= 5.0")
#else
print("Swift < 5.0")
#endif
print("[1, 3, 5, 7].reduce(0, +) = \([1, 3, 5, 7].reduce(0, +))")
print("[1, 3, 5, 7].reduce(1, *) = \([1, 3, 5, 7].reduce(1, *))")
]
% cat sample.swift
# Swift Compile
% swiftc sample.swift
# Swift Run
% ./sample
[
macOS
Swift >= 5.0
[1, 3, 5, 7].reduce(0, +) = 16
[1, 3, 5, 7].reduce(1, *) = 105
]
---------------------------------------------------------------------------------------------------------------------------
# SwiftWasm Toolchain # Install # pkg
---------------------------------------------------------------------------------------------------------------------------
% wget https://github.com/swiftwasm/swift/releases/download/swift-wasm-5.10.0-RELEASE/swift-wasm-5.10.0-RELEASE-macos_arm64.pkg
[
% curl -L -o swift-wasm-5.10.0-RELEASE-macos_arm64.pkg https://github.com/swiftwasm/swift/releases/download/swift-wasm-5.10.0-RELEASE/swift-wasm-5.10.0-RELEASE-macos_arm64.pkg
]
# swift-wasm-5.10.0-RELEASE-macos_arm64.pkg
# The package installer will install an Xcode toolchain into /Library/Developer/Toolchains/
% ls /Library/Developer/Toolchains
[
swift-5.10-RELEASE.xctoolchain swift-latest.xctoolchain swift-wasm-5.10.0-RELEASE.xctoolchain
]
# swift # swiftc # Same # Before exporting swift-wasm-5.10.0-RELEASE.xctoolchain
# Swift
% swift --version
[
swift-driver version: 1.115.1 Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
Target: arm64-apple-macosx15.0
]
# Swift Compile
% swiftc --version
[
swift-driver version: 1.115.1 Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
Target: arm64-apple-macosx15.0
]
# export swift-wasm Toolchain
% export PATH="/Library/Developer/Toolchains/swift-wasm-5.10.0-RELEASE.xctoolchain/usr/bin/":$PATH
# swift # swiftc # Changed # After exporting swift-wasm-5.10.0-RELEASE.xctoolchain
# SwiftWasm Swift
% swift --version
[
SwiftWasm Swift version 5.10-dev (LLVM e98989b1092ff3a, Swift 23e8e340a7a32a7)
Target: arm64-apple-darwin24.1.0
]
% swiftc --version
[
SwiftWasm Swift version 5.10-dev (LLVM e98989b1092ff3a, Swift 23e8e340a7a32a7)
Target: arm64-apple-darwin24.1.0
]
# Compile the Swift code into WebAssembly with WASI
% swiftc -target wasm32-unknown-wasi sample.swift -o sample.wasm
# Run the produced binary with wasmtime (or other WebAssembly runtime) # After downloading and installing the wasmtime
[
% wget -O - https://wasmtime.dev/install.sh | bash
% wget https://wasmtime.dev/install.sh -v -O install.sh; sudo chmod +x ./install.sh; ./install.sh
% curl -o install.sh https://wasmtime.dev/install.sh -sSf; sudo chmod +x ./install.sh; ./install.sh
]
% curl https://wasmtime.dev/install.sh -sSf | bash
[
...
Editing user profile (/Users/rajaniapple/.zshrc)
Finished installation. Open a new terminal to start using Wasmtime!
]
% cat $HOME/.zshrc
[
export WASMTIME_HOME="$HOME/.wasmtime"
export PATH="$WASMTIME_HOME/bin:$PATH"
]
---------------------------------------------------------------------------------------------------------------------------
# Terminal New Window # wasmtime
---------------------------------------------------------------------------------------------------------------------------
% wasmtime --version
# Run For Same Output As Above # Swift Run
% wasmtime sample.wasm
[
Swift >= 5.0
[1, 3, 5, 7].reduce(0, +) = 16
[1, 3, 5, 7].reduce(1, *) = 105
]
---------------------------------------------------------------------------------------------------------------------------
# The produced binary depends on WASI which is an interface of system call for WebAssembly
# So you need to use WASI supported runtime and when you run the binary on browser, you need WASI polyfill library like @bjorn3/browser_wasi_shim
# A pure javascript shim for WASI
# Implementation status: A subset of wasi_snapshot_preview1 is implemented. The rest either throws an exception, returns an error or is incorrectly implemented.
# npm install @bjorn3/browser_wasi_shim --save
---------------------------------------------------------------------------------------------------------------------------
===========================================================================================================================
# SwiftPM package to WebAssembly # SwiftPM # SwiftWasm
===========================================================================================================================
# Terminal New Window
% mkdir -p SwiftWasm
% cd SwiftWasm
# export swift-wasm Toolchain
% export PATH="/Library/Developer/Toolchains/swift-wasm-5.10.0-RELEASE.xctoolchain/usr/bin/":$PATH
# Create a package from template
% swift --version
[
SwiftWasm Swift version 5.10-dev (LLVM e98989b1092ff3a, Swift 23e8e340a7a32a7)
Target: arm64-apple-darwin24.1.0
]
% swift package init --type executable --name Sample
# Build the Project into a WebAssembly binary # SwiftPM # SwiftWasm
# --triple option, which indicates that you are building for the target
% swift build --triple wasm32-unknown-wasi
# Run the produced binary
% wasmtime --version
% wasmtime ./.build/wasm32-unknown-wasi/debug/Sample.wasm
[
Hello, world!
]
===========================================================================================================================
# SwiftPM package to WebAssembly # SwiftPM # Swift SDK # Default Swift
===========================================================================================================================
# Terminal New Window
% mkdir -p SwiftSDK
% cd SwiftSDK
# Create a package from template
# Default Swift
% swift --version
[
swift-driver version: 1.115.1 Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
Target: arm64-apple-macosx15.0
]
# Build the Project into a WebAssembly binary # SwiftPM # Swift SDK # Default Swift
% swift package init --type executable --name Sample
# When Swift SDK is installed
# swift build --swift-sdk <SDK name>
% swift sdk list
% swift build --swift-sdk 5.10.0-RELEASE-wasm
# Run the produced binary
% wasmtime --version
% wasmtime ./.build/wasm32-unknown-wasi/debug/Sample.wasm
[
Hello, world!
]
===========================================================================================================================
# Swift # WebAssembly (wasm) # SwiftWasm # WebAssembly Text Format
===========================================================================================================================
# Swift
% swift --version
[
swift-driver version: 1.115.1 Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
Target: arm64-apple-macosx15.0
]
# https://github.com/apple/swift-for-wasm-examples # zip # main
[
% wget --output-document=swift-for-wasm-examples-main.zip https://github.com/apple/swift-for-wasm-examples/archive/main.z
% unzip swift-for-wasm-examples-main.zip -d swift-for-wasm-wat-example && mv swift-for-wasm-wat-example/swift-for-wasm-examples-main/* $(pwd)/swift-for-wasm-wat-example
]
% mkdir swift-for-wasm-wat-example && tar -xvzf swift-for-wasm-examples-main.zip -C swift-for-wasm-wat-example --strip-components 1
% cd swift-for-wasm-wat-example
# swift repl # Swift # Swift # Date # Time
import Foundation
let dateTimeNow = Date()
print("Swift Cocoa Date Time Now: \(dateTimeNow.description)")
# Swift
# Date # Time
# linear memory # offset # 36
% nano WATExample/Sources/WATExample/main.swift
[
import Foundation
import WasmKit
import WAT
let dateTimeNow = Date()
print("Swift Cocoa Date Time Now: \(dateTimeNow.description)")
// Compute WAT file path.
let watURL = URL(fileURLWithPath: #filePath)
.deletingLastPathComponent()
.deletingLastPathComponent()
.deletingLastPathComponent()
.appendingPathComponent("factorial.wat")
// Parse from WAT to binary Wasm module.
let binaryModule = try wat2wasm(String(decoding: Data(contentsOf: watURL), as: UTF8.self))
// Parse as WasmKit IR.
let parsedModule = try parseWasm(bytes: binaryModule)
let engine = Engine()
let store = Store(engine: engine)
// Initialize WasmKit runtime
let imports: Imports = [
"host": [
// Pass host printer function as a closure
"print": ExternalValue.function(Function(store: store, type: .init(parameters: [.i32, .i32])) { caller, args in
guard let start = args.first?.i32,
let offset = args.last?.i32
else { return [] }
// Decode linear memory
let string = String(
decoding: caller.instance!.exports[memory: "memory"]!.data[Int(start) ..< Int(start + offset)],
as: UTF8.self
)
// Print the result
print("Guest module printed: \(string)")
return []
}
),
]
]
// Instantiate the module
let moduleInstance = try parsedModule.instantiate(store: store, imports: imports)
// Call `main` function
let result = try moduleInstance.exports[function: "main"]!()
print("Returned value: \(result)")
]
% cat WATExample/Sources/WATExample/main.swift
# WebAssembly Text # Print
# call $factorial (i64.const 10) # factorial # 10
# call $print (i32.const 0) (i32.const 36) # linear memory # offset # 36
% nano WATExample/factorial.wat
[
(module
(import "host" "print"
(func $print (param (; pointer ;) i32 (; length ;) i32)))
(export "main" (func $main))
(memory $memory 1)
(export "memory" (memory $memory))
;; n! = n * (n - 1) * (n - 2) * ... * 2 * 1
(func $factorial (param $arg i64) (result i64)
(if (result i64)
(i64.eqz (local.get $arg))
(then (i64.const 1))
(else
(i64.mul
(local.get $arg)
(call $factorial
(i64.sub
(local.get $arg)
(i64.const 1)
))))))
(func $main (result i64)
(call $factorial (i64.const 10))
(call $print (i32.const 0) (i32.const 36))
)
(data (i32.const 0) "Hola From WebAssembly Text Format!!!")
)
]
% cat WATExample/factorial.wat
% cd WATExample
% ls -a
# Build # Cleanup
% rm -rf .build
% ls -a
# Build
% swift build
# Run
% swift run
[
Building for debugging...
[1/1] Write swift-version--58304C5D6DBC2206.txt
Build of product 'WATExample' complete! (0.21s)
Swift Cocoa Date Time Now: 2025-01-08 20:47:07 +0000
Guest module printed: Hola From WebAssembly Text Format!!!
Returned value: [WasmTypes.Value.i64(3628800)]
]
===========================================================================================================================
# Swift # WebAssembly (wasm) # SwiftWasm # Browser App
===========================================================================================================================
# Swift
% swift --version
[
swift-driver version: 1.115.1 Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
Target: arm64-apple-macosx15.0
]
# https://github.com/apple/swift-for-wasm-examples # zip # main
[
% wget --output-document=swift-for-wasm-examples-main.zip https://github.com/apple/swift-for-wasm-examples/archive/main.zip
% tar -xvzf swift-for-wasm-examples-main.zip
]
% unzip swift-for-wasm-examples-main.zip
% cd swift-for-wasm-examples-main
# Remove Toolchains
[
# Swift Xcode Toolchain # Installation Type # "Install for all users of this computer"
% ls /Library/Developer/Toolchains
% sudo rm -rf /Library/Developer/Toolchains
# Swift Xcode Toolchain # Installation Type # "Install for me only"
% ls ~/Library/Developer/Toolchains
% sudo rm -rf ~/Library/Developer/Toolchains
]
# Swift Toolchain # Install # pkg
# Download the appropriate Swift toolchain version from swift.org/install and install the pkg
# swift-6.0.2-RELEASE-osx.pkg
% ls /Library/Developer/Toolchains
[
swift-6.0.2-RELEASE.xctoolchain swift-latest.xctoolchain
]
# No such file or directory
% ls ~/Library/Developer/Toolchains
# export # Swift Toolchai
% export PATH="/Library/Developer/Toolchains/swift-6.0.2-RELEASE.xctoolchain/usr/bin/":$PATH
% swift --version
[
swift-driver version: 1.115.1 Apple Swift version 6.0.3 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
Target: arm64-apple-macosx15.0
]
% export PATH="/Library/Developer/Toolchains/swift-6.0.2-RELEASE.xctoolchain/usr/bin/":$PATH
% swift --version
[
Apple Swift version 6.0.2 (swift-6.0.2-RELEASE)
Target: arm64-apple-macosx15.0
]
% wget https://github.com/swiftwasm/swift/releases/download/swift-wasm-5.10.0-RELEASE/swift-wasm-5.10.0-RELEASE-macos_arm64.artifactbundle.zip
% sudo wget https://github.com/swiftwasm/swift/releases/download/swift-wasm-6.0.2-RELEASE/swift-wasm-6.0.2-RELEASE-macos_arm64.pkg
% sudo installer -pkg swift-wasm-6.0.2-RELEASE-macos_arm64.pkg -target /Library/Developer/Toolchain
% ls /Library/Developer/Toolchains
[
swift-6.0.2-RELEASE.xctoolchain swift-latest.xctoolchain swift-wasm-6.0.2-RELEASE.xctoolchain
]
% cd Guest
% sudo ./build.sh
% cd ../ServerHost
% sudo swift run Server
===========================================================================================================================
# Terminal New Window
===========================================================================================================================
% curl http://127.0.0.1:8080/public/index.html
% wget -S -O - http://127.0.0.1:8080/public/index.html
% open http://127.0.0.1:8080/public/index.html
% curl http://127.0.0.1:8080/public/upload.html
% wget -S -O - http://127.0.0.1:8080/public/upload.html
% open http://127.0.0.1:8080/public/upload.html
===========================================================================================================================
% sudo cat Sources/Server/App.swift
[
//===----------------------------------------------------------------------===//
//
// This source file is part of the Hummingbird open source project
//
// Copyright (c) 2024 Adam Fowler.
// Licensed under Apache License v2.0.
//
// See https://github.com/hummingbird-project/template/blob/main/LICENSE for license information
//
//===----------------------------------------------------------------------===//
import ArgumentParser
import Hummingbird
import Logging
@main
struct App: AsyncParsableCommand, AppArguments {
@Option(name: .shortAndLong)
var hostname: String = "127.0.0.1"
@Option(name: .shortAndLong)
var port: Int = 8080
@Option(name: .shortAndLong)
var logLevel: Logger.Level?
func run() async throws {
let app = try await buildApplication(self)
try await app.runService()
}
}
/// Extend `Logger.Level` so it can be used as an argument
#if hasFeature(RetroactiveAttribute)
extension Logger.Level: @retroactive ExpressibleByArgument {}
#else
extension Logger.Level: ExpressibleByArgument {}
#endif
]
% sudo nano Sources/Server/IndexPage.swift
% sudo cat Sources/Server/IndexPage.swift
[
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import Foundation
import Hummingbird
import _NIOFileSystem
@preconcurrency import SystemPackage
private func serveHTML(_ string: String) -> Response {
.init(
status: .ok,
headers: .init(dictionaryLiteral: (.contentType, "text/html"), (.contentLength, "\(string.utf8.count)")),
body: .init(byteBuffer: .init(string: string))
)
}
struct IndexPage: ResponseGenerator, Sendable {
struct Module: Sendable {
let name: String
let absolutePath: FilePath
let relativePath: FilePath
}
var modules: [Module] = []
var modulesList: String {
if self.modules.isEmpty {
"""
<h1 id="wasm-logger"><a href="/public/upload.html">Rajani Swift SwiftWasm, Upload Wasm plugins</a> to get started</h1>
"""
} else {
"""
\(self.modules.sorted(using: KeyPathComparator(\.name, order: .forward)).map { module in
"""
<h1 class="track-name">\(module.name)</h1>
<div
class="plugin"
data-module-path="\(module.relativePath)"
style="display: flex; flex-direction: column; align-items: flex-start; gap: 1rem;"
>
<canvas class="plotter" width="1000" height="210"></canvas>
<audio class="audio" type="audio.wav" controls></audio>
</div>
"""
}.joined(separator: "\n"))
<h1 class="track-name">Mix</h1>
<div
id="tracks-mix"
style="display: flex; flex-direction: column; align-items: flex-start; gap: 1rem;"
>
<canvas class="plotter" width="1000" height="210"></canvas>
<audio class="audio" type="audio.wav" controls></audio>
</div>
"""
}
}
func response(from request: Request, context: some RequestContext) throws -> Response {
serveHTML(
"""
<html>
<head>
<meta charset="utf-8">
<title>Rajani Swift Audio Workstation</title>
<script type="module" src="/public/Sources/JavaScript/index.js">
</script>
<style>
body {
background-color: black;
padding: 1rem;
}
#wasm-logger, .track-name {
font-family: sans-serif;
color: white;
}
#wasm-logger a, .track-name a {
color: #aabbcc;g
}
</style>
</head>
<body>
\(self.modulesList)
</body>
</html>
"""
)
}
}
func discoverModules(directory: FilePath, root: FilePath) async throws -> [IndexPage.Module] {
try await FileSystem.shared.withDirectoryHandle(atPath: directory) {
var modules = [IndexPage.Module]()
let dirContents = $0.listContents()
for try await module in dirContents where module.type == .regular && module.path.isSynthModule {
let absolutePath = module.path
var relativePath = module.path
_ = relativePath.removePrefix(root)
modules.append(.init(
name: module.path.lastComponent?.stem ?? "Module",
absolutePath: absolutePath,
relativePath: relativePath
))
}
return modules
}
}
extension FilePath {
var isSynthModule: Bool {
self.extension == "wasm" && self.stem != "Plotter"
}
}
]
% cd swift-for-wasm-examples-main/Guest
% sudo ./build.sh
% cd ../ServerHost
% sudo swift run Server
===========================================================================================================================
# Swift # WebAssembly (wasm) # SwiftWasm # Browser App # Docker
===========================================================================================================================
---------------------------------------------------------------------------------------------------------------------------
# Docker # Server
--------------------------------------------------------------------------------------------------------------------------
% mkdir -p Docker
% cd Docker
# https://github.com/apple/swift-for-wasm-examples # zip # main
% wget --output-document=swift-for-wasm-examples-main.zip https://github.com/apple/swift-for-wasm-examples/archive/main.zip
[
% tar -xvzf swift-for-wasm-examples-main.zip
]
% unzip swift-for-wasm-examples-main.zip
% cd swift-for-wasm-examples-main
% nano ServerHost/Sources/Server/IndexPage.swift
[
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import Foundation
import Hummingbird
import _NIOFileSystem
@preconcurrency import SystemPackage
private func serveHTML(_ string: String) -> Response {
.init(
status: .ok,
headers: .init(dictionaryLiteral: (.contentType, "text/html"), (.contentLength, "\(string.utf8.count)")),
body: .init(byteBuffer: .init(string: string))
)
}
struct IndexPage: ResponseGenerator, Sendable {
struct Module: Sendable {
let name: String
let absolutePath: FilePath
let relativePath: FilePath
}
var modules: [Module] = []
var modulesList: String {
if self.modules.isEmpty {
"""
<h1 id="wasm-logger"><a href="/public/upload.html">Rajani Swift SwiftWasm Docker, Upload Wasm plugins</a> to get started</h1>
"""
} else {
"""
\(self.modules.sorted(using: KeyPathComparator(\.name, order: .forward)).map { module in
"""
<h1 class="track-name">\(module.name)</h1>
<div
class="plugin"
data-module-path="\(module.relativePath)"
style="display: flex; flex-direction: column; align-items: flex-start; gap: 1rem;"
>
<canvas class="plotter" width="1000" height="210"></canvas>
<audio class="audio" type="audio.wav" controls></audio>
</div>
"""
}.joined(separator: "\n"))
<h1 class="track-name">Mix</h1>
<div
id="tracks-mix"
style="display: flex; flex-direction: column; align-items: flex-start; gap: 1rem;"
>
<canvas class="plotter" width="1000" height="210"></canvas>
<audio class="audio" type="audio.wav" controls></audio>
</div>
"""
}
}
func response(from request: Request, context: some RequestContext) throws -> Response {
serveHTML(
"""
<html>
<head>
<meta charset="utf-8">
<title>Rajani Swift SwiftWasm Docker Audio Workstation</title>
<script type="module" src="/public/Sources/JavaScript/index.js">
</script>
<style>
body {
background-color: black;
padding: 1rem;
}
#wasm-logger, .track-name {
font-family: sans-serif;
color: white;
}
#wasm-logger a, .track-name a {
color: #aabbcc;g
}
</style>
</head>
<body>
\(self.modulesList)
</body>
</html>
"""
)
}
}
func discoverModules(directory: FilePath, root: FilePath) async throws -> [IndexPage.Module] {
try await FileSystem.shared.withDirectoryHandle(atPath: directory) {
var modules = [IndexPage.Module]()
let dirContents = $0.listContents()
for try await module in dirContents where module.type == .regular && module.path.isSynthModule {
let absolutePath = module.path
var relativePath = module.path
_ = relativePath.removePrefix(root)
modules.append(.init(
name: module.path.lastComponent?.stem ?? "Module",
absolutePath: absolutePath,
relativePath: relativePath
))
}
return modules
}
}
extension FilePath {
var isSynthModule: Bool {
self.extension == "wasm" && self.stem != "Plotter"
}
}
]
% cat ServerHost/Sources/Server/IndexPage.swift
% swift --version
[
% export PATH="/Library/Developer/Toolchains/swift-6.0.2-RELEASE.xctoolchain/usr/bin/":$PATH
% swift --version
]
# Server
# Start docker daemon
% docker --version
% docker info
[
% docker run --rm -it -v "$(pwd)":/root/build swiftlang/swift:nightly-jammy /bin/bash
% docker run --network=swift-network --rm -it -v "$(pwd)":/root/build swiftlang/swift:nightly-jammy
% docker run --network=swift-network -p 8080:8080 --rm -it -v "$(pwd)":/root/build swiftlang/swift:nightly-jammy
% docker run -p 8080:8080 --rm -it -v "$(pwd)":/root/build swiftlang/swift:nightly-jammy
]
% docker run --rm -it -v "$(pwd)":/root/build swiftlang/swift:nightly-jammy /bin/bash
:/# swift --version
[
Swift version 6.2-dev (LLVM 06a77c5cc0ff511, Swift f7fb0991b79fcda)
Target: aarch64-unknown-linux-gnu
]
:/# ls
:/# cd /root/build
:/# ls ServerHost
:/# ls ServerHost/Sources
:/# ls ServerHost/Sources/Server
:/# cat ServerHost/Sources/Server/IndexPage.swift
:/# apt --version
]
:/# apt-get --version
[
:/# apt update
]
:/# apt-get update
[
:/# apt install nano
]
:/# apt-get install nano
:/# nano --version
[
[
:/# apt install sudo
]
:/# apt-get install sudo
]
:/# nano ServerHost/Sources/Server/IndexPage.swift
:/# nano IndexPage.swift
:/# cat ServerHost/Sources/Server/IndexPage.swift
:/# cd Guest
:/# ./build.sh
:/# cd ../ServerHost
:/# swift run Server
# [control + C]
:/# exit
--------------------------------------------------------------------------------------------------------------------------
# Docker # Guest
--------------------------------------------------------------------------------------------------------------------------
% docker --version
% docker ps
[
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e1169e817935 swiftlang/swift:nightly-jammy "/bin/bash" 11 minutes ago Up 11 minutes beautiful_mclaren
]
# docker inspect -f "{{ .NetworkSettings.IPAddress }}" <CONTAINER ID>
% docker inspect -f "{{ .NetworkSettings.IPAddress }}" e1169e817935
[
% docker exec beautiful_mclaren ls -la /usr
% docker exec e1169e817935 ls -la /usr
]
[
% docker exec -i -t e1169e817935 /bin/bash
]
% docker exec -i -t beautiful_mclaren /bin/bash
:/# swift --version
[
Swift version 6.2-dev (LLVM 06a77c5cc0ff511, Swift f7fb0991b79fcda)
Target: aarch64-unknown-linux-gnu
]
[
:/# apt --version
]
:/# apt-get --version
[
:/# apt-get update
]
:/# apt update
[
:/# apt-get install dnsutils
]
:/# apt install dnsutils
:/# nslookup -version
:/# nslookup host.docker.internal
[
Server: 192.168.65.7
Address: 192.168.65.7#53
Non-authoritative answer:
Name: host.docker.internal
Address: 192.168.65.254
Name: host.docker.internal
Address: fdc4:f303:9324::254
]
[
:/# apt-get install curl
]
:/# apt install curl
:/# curl --version
:/# curl http://127.0.0.1:8080/public/index.html
:/# curl http://127.0.0.1:8080/public/upload.html
[
:/# apt-get install wget
]
:/# apt install wget
:/# wget --version
:/# ls
:/# wget -S -o - http://127.0.0.1:8080/public/index.html
:/# ls
:/# cat index.html
:/# wget -S -o - http://127.0.0.1:8080/public/upload.html
:/# ls
:/# cat upload.html
:/# exit
---------------------------------------------------------------------------------------------------------------------------
===========================================================================================================================
***************************************************************************************************************************
***************************************************************************************************************************
# Go # WebAssembly (wasm) # tinygo
***************************************************************************************************************************
% mkdir -p Go
% cd Go
% nano index.go
[
package main
import "fmt"
import "runtime"
// % go run ./index.go % tinygo run ./index.go
func main() {
fmt.Println("Runtime Version: " + runtime.Version());
var x int = 555;
var y int = 777;
var result int = x * y;
fmt.Printf("Math: %d x %d = %d\n", x, y, result);
}
// Comment "export math" to make the func callable from JavaScript
//export math
func math(x int, y int) int {
return x * y;
}
]
% cat index.go
# index.go to wasm
[
% go version
% tinygo version
% go run ./index.go
% tinygo run ./index.go
]
% tinygo build -o index.wasm -target wasm ./index.go
# wasm_exec.js from TinyGo root
% ls
% ls $(tinygo env TINYGOROOT)/targets/wasm_exec.js
% cp $(tinygo env TINYGOROOT)/targets/wasm_exec.js .
% ls
# NB
# wasm_exec.js must match tinygo version
% nano index.js
[
export const wasm = async (source, importObject) => {
let response = undefined;
if (WebAssembly.instantiateStreaming) {
response = await WebAssembly.instantiateStreaming(
fetch(source),
importObject
);
} else {
const fetchThenInstantiate = async () => {
const buffer = await fetch(source).then(response =>
response.arrayBuffer()
);
return WebAssembly.instantiate(buffer, importObject);
};
response = await fetchThenInstantiate();
}
return response;
};
const wasmFunc = async () => {
const go = new Go();
const importObject = go.importObject;
const module = await wasm("./index.wasm", importObject);
go.run(module.instance);
const x = 5;
const y = 7;
const result = module.instance.exports.math(5, 7);
document.body.innerHTML = `Browser: ${navigator.userAgent} <br\><br\> Math: ${x} x ${y} = ${result}`;
};
wasmFunc();
]
% cat index.js
% nano index.html
[
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Go WebAssembly</title>
</head>
<body>
<script src="./wasm_exec.js"></script>
<script type="module" src="./index.js"></script>
</body>
</html>
]
% cat index.html
===========================================================================================================================
# HTTP Server
===========================================================================================================================
[
% npm install http-server --global
]
% npm --version
% http-server -p 8000
[
% python3 --version
% python3 -m http.server 8000
]
[
% export PATH="$HOME/Downloads/Software/OpenJDK/JDK23.0.1/jdk-23.0.1.jdk/Contents/Home/bin/":$PATH
% java --version
% jwebserver --port 8000
]
[
% ruby --version
% gem install webrick
% ruby -run -e httpd . -p 8000
]
[
% php --version
% php -S 127.0.0.1:8000
]
===========================================================================================================================
# Terminal New Window
===========================================================================================================================
% curl http://127.0.0.1:8000
% open http://127.0.0.1:8000
===========================================================================================================================
***************************************************************************************************************************
***************************************************************************************************************************
# Rust # WebAssembly (wasm) # cargo # TOML # wasm-pack
***************************************************************************************************************************
% mkdir -p Rust
% cd Rust
[
% curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
]
% cargo --version
% cargo init
# The name `Rust` is not snake_case or kebab-case which is recommended for package names, consider `rust`
% nano Cargo.toml
[
[package]
name = "rust"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
]
% cat Cargo.toml
# Find library `Rust`, rename file to `src/lib.rs` or specify lib.path
% ls src
% cat src/main.rs
% mv src/main.rs src/lib.rs
% ls src
% cat src/lib.rs
% nano src/lib.rs
[
use wasm_bindgen::prelude::*;
// Comment #[wasm_bindgen] to export the function, callable from JavaScript
#[wasm_bindgen]
pub fn math(x: i32, y: i32) -> i32 {
return x * y;
}
]
% cat src/lib.rs
[
% cargo install wasm-pack
]
% wasm-pack --version
# Rust crate wasm-pack wasm
% wasm-pack build --target web
% nano index.js
[
import init from "./pkg/rust.js";
const wasmFunc = async () => {
const module = await init("./pkg/rust_bg.wasm");
const x = 5;
const y = 7;
const result = module.math(5, 7);
document.body.innerHTML = `Browser: ${navigator.userAgent} <br\><br\> Math: ${x} x ${y} = ${result}`;
};
wasmFunc();
]
% cat index.js
% nano index.html
[
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Rust WebAssembly</title>
<script type="module" src="./index.js"></script>
</head>
<body></body>
</html>
]
% cat index.html
===========================================================================================================================
# HTTP Server
===========================================================================================================================
[
% npm install http-server --global
]
% npm --version
% http-server -p 8000
[
% python3 --version
% python3 -m http.server 8000
]
[
% export PATH="$HOME/Downloads/Software/OpenJDK/JDK23.0.1/jdk-23.0.1.jdk/Contents/Home/bin/":$PATH
% java --version
% jwebserver --port 8000
]
[
% ruby --version
% gem install webrick
% ruby -run -e httpd . -p 8000
]
[
% php --version
% php -S 127.0.0.1:8000
]
===========================================================================================================================
# Terminal New Window
===========================================================================================================================
% curl http://127.0.0.1:8000
% open http://127.0.0.1:8000
===========================================================================================================================
***************************************************************************************************************************
***************************************************************************************************************************
# Python # WebAssembly (wasm) # Pyodide
***************************************************************************************************************************
% mkdir -p Python
% cd Python
% nano complete.html
[
<!doctype html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/pyodide/v0.27.0/full/pyodide.js"></script>
</head>
<body>
Pyodide test page <br>
Open your browser console to see Pyodide output
<script type="text/javascript">
async function main(){
let pyodide = await loadPyodide();
console.log(pyodide.runPython(`
import sys
sys.version
`));
pyodide.runPython("x = 5; y = 7; print(f'Math: {x} x {y} = { x * y }')");
}
main();
</script>
</body>
</html>
]
% cat complete.html
% open -n -a "Google Chrome" --args "--new-window" file:///$HOME/Desktop/GitHub/JavaScript-1/WebAssembly/Python/complete.html
% nano alternative.html
[
<!doctype html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/pyodide/v0.27.0/full/pyodide.js"></script>
</head>
<body>
<p>
You can execute any Python code [Run import statement(s) beforehand just in case]. Just enter something in the box below and
click the button.
</p>
<!-- <input id="code" value="sum([1, 3, 5, 7])" /> -->
<input id="code" value="reduce(mul, [1, 3, 5, 7])" />
<button onclick="evaluatePython()">Run</button>
<br />
<br />
<div>Output:</div>
<textarea id="output" style="width: 100%;" rows="6" disabled></textarea>
<script>
const output = document.getElementById("output");
const code = document.getElementById("code");
function addToOutput(s) {
output.value += ">>> " + code.value + "\n" + s + "\n";
}
output.value = "Initializing...\n";
// init Pyodide
async function main() {
let pyodide = await loadPyodide();
pyodide.runPython(`
# import sys
# sys.version
from functools import reduce
from operator import mul
` );
output.value += "Ready!\n";
return pyodide;
}
let pyodideReadyPromise = main();
async function evaluatePython() {
let pyodide = await pyodideReadyPromise;
try {
let output = pyodide.runPython(code.value);
addToOutput(output);
} catch (err) {
addToOutput(err);
}
}
</script>
</body>
</html>
]
% cat alternative.html
% open -n -a "Google Chrome" --args "--new-window" file:///$HOME/Desktop/GitHub/JavaScript-1/WebAssembly/Python/alternative.html
# CDN
% wget https://cdn.jsdelivr.net/pyodide/v0.27.0/full/pyodide.js --directory-prefix=CDN
===========================================================================================================================
# Pyodide
===========================================================================================================================
% cd Python
% wget https://github.com/pyodide/pyodide/releases/download/0.27.0/pyodide-0.27.0.tar.bz2
% sudo tar -xvzf pyodide-0.27.0.tar.bz2
% cd pyodide
% ./python
[
Python 3.12.7 (main, Dec 31 2024, 17:05:22) [Clang 19.0.0git (https:/github.com/llvm/llvm-project 0a8cd1ed1f4f35905df318015b on emscripten
Type "help", "copyright", "credits" or "license" for more information.
>>> x = 5
>>> y = 7
>>> print( f'Math: {x} x {y} = { x * y }' )
Math: 5 x 7 = 35
>>> print( 'Math: {:} x {:} = {:}'.format(x, y, x * y) )
Math: 5 x 7 = 35
>>> sum([1, 3, 5, 7])
16
>>> from functools import reduce
>>> from operator import mul
>>> reduce(mul, [1, 3, 5, 7])
105
>>> exit()
]
[
% find . -depth -size +50M -print
]
% find . -depth 1 -size +50M -print
% zip "pyodide-0.27.0.tar.bz2.zip" "pyodide-0.27.0.tar.bz2"
% zip "pyodide-0.27.0.tar.bz2.zip" --out "Split pyodide-0.27.0.tar.bz2.zip" -s 45m
[
% find . -depth -size +50M -print
]
% find . -depth 1 -size +50M -print
% find . -depth -size +50M -delete
[
% find . -depth 1 -size +50M -delete
]
% find . -depth -size +50M -print
% 7z x "Split pyodide-0.27.0.tar.bz2.zip"
% rm -rf pyodide-0.27.0.tar.bz2
% sudo rm -rf pyodide
% find . -depth -size +50M -print
===========================================================================================================================
# HTTP Server
===========================================================================================================================
[
% npm install http-server --global
]
% npm --version
% http-server -p 8000
[
% python3 --version
% python3 -m http.server 8000
]
[
% export PATH="$HOME/Downloads/Software/OpenJDK/JDK23.0.1/jdk-23.0.1.jdk/Contents/Home/bin/":$PATH
% java --version
% jwebserver --port 8000
]
[
% ruby --version
% gem install webrick
% ruby -run -e httpd . -p 8000
]
[
% php --version
% php -S 127.0.0.1:8000
]
===========================================================================================================================
# Terminal New Window
===========================================================================================================================
% curl http://127.0.0.1:8000/complete.html
% open http://127.0.0.1:8000/complete.html
% curl http://127.0.0.1:8000/alternative.html
% open http://127.0.0.1:8000/alternative.html
===========================================================================================================================
***************************************************************************************************************************
***************************************************************************************************************************
# Java # WebAssembly (wasm) # GraalVM
***************************************************************************************************************************
===========================================================================================================================
# Java # WebAssembly (wasm) # GraalVM # native-image # Apache Maven
===========================================================================================================================
# GraalVM 23.0.2 # Apache Maven 3.9.9
% export JAVA_HOME="$HOME/Downloads/Software/Oracle/GraalVM/graalvm-jdk-23.0.2+7.1/Contents/Home"
% export M2_HOME="$HOME/Downloads/Software/ApacheMaven/apache-maven-3.9.9"
% export M2="$M2_HOME/bin"
% export PATH=$PATH:"$M2:$JAVA_HOME/bin"
[
% export MAVEN_OPTS="-Xms256m -Xmx512m --enable-preview"
]
% export MAVEN_OPTS="-Xms256m -Xmx512m"
% java --version
[
java 23.0.2 2025-01-21
Java(TM) SE Runtime Environment Oracle GraalVM 23.0.2+7.1 (build 23.0.2+7-jvmci-b01)
Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 23.0.2+7.1 (build 23.0.2+7-jvmci-b01, mixed mode, sharing)
]
% mvn --version
[
Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)
Maven home: /Users/rajaniapple/Downloads/Software/ApacheMaven/apache-maven-3.9.9
Java version: 23.0.2, vendor: Oracle Corporation, runtime: /Users/rajaniapple/Downloads/Software/Oracle/GraalVM/graalvm-jdk-23.0.2+7.1/Contents/Home
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "15.1", arch: "aarch64", family: "mac"
]
% native-image --version
[
native-image 23.0.2 2025-01-21
GraalVM Runtime Environment Oracle GraalVM 23.0.2+7.1 (build 23.0.2+7-jvmci-b01)
Substrate VM Oracle GraalVM 23.0.2+7.1 (build 23.0.2+7, serial gc, compressed references)
]
===========================================================================================================================
# Java # WebAssembly (wasm) # GraalVM # native-image
===========================================================================================================================
# GraalVM 23.0.2 # Gradle 8.12 # Apache Maven 3.9.9
% export PATH="$HOME/Downloads/Software/Oracle/GraalVM/graalvm-jdk-23.0.2+7.1/Contents/Home/bin/:$HOME/Downloads/Software/OpenJDK/JDK23.0.2/jdk-23.0.2.jdk/Contents/Home/bin/:$HOME/Downloads/Software/Gradle/gradle-8.12/bin/:$HOME/Downloads/Software/ApacheMaven/apache-maven-3.9.9/bin/":$PATH
% java --version
[
java 23.0.2 2025-01-21
Java(TM) SE Runtime Environment Oracle GraalVM 23.0.2+7.1 (build 23.0.2+7-jvmci-b01)
Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 23.0.2+7.1 (build 23.0.2+7-jvmci-b01, mixed mode, sharing)
]
% gradle --version
[
Welcome to Gradle 8.12!
Here are the highlights of this release:
- Enhanced error and warning reporting with the Problems API
- File-system watching support on Alpine Linux
- Build and test Swift 6 libraries and apps
For more details see https://docs.gradle.org/8.12/release-notes.html
------------------------------------------------------------
Gradle 8.12
------------------------------------------------------------
Build time: 2024-12-20 15:46:53 UTC
Revision: a3cacb207fec727859be9354c1937da2e59004c1
Kotlin: 2.0.21
Groovy: 3.0.22
Ant: Apache Ant(TM) version 1.10.15 compiled on August 25 2024
Launcher JVM: 23.0.2 (Oracle Corporation 23.0.2+7-jvmci-b01)
Daemon JVM: /Users/rajaniapple/Downloads/Software/Oracle/GraalVM/graalvm-jdk-23.0.2+7.1/Contents/Home (no JDK specified, using current Java home)
OS: Mac OS X 15.1 aarch64
]
% mvn --version
[
Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)
Maven home: /Users/rajaniapple/Downloads/Software/ApacheMaven/apache-maven-3.9.9
Java version: 23.0.2, vendor: Oracle Corporation, runtime: /Users/rajaniapple/Downloads/Software/Oracle/GraalVM/graalvm-jdk-23.0.2+7.1/Contents/Home
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "15.1", arch: "aarch64", family: "mac"
]
% native-image --version
[
native-image 23.0.2 2025-01-21
GraalVM Runtime Environment Oracle GraalVM 23.0.2+7.1 (build 23.0.2+7-jvmci-b01)
Substrate VM Oracle GraalVM 23.0.2+7.1 (build 23.0.2+7, serial gc, compressed references)
]
% mkdir -p Java
% cd Java
# Compile this HelloWorld.java application to bytecode and then build a native executable
% nano HelloWorld.java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
% cat HelloWorld.java
% javac HelloWorld.java
% native-image HelloWorld
% The last command generates an executable file named helloworld in the current working directory. Invoking it runs the natively-compiled code of the HelloWorld class as follows
# ls
% ./helloworld
[
Hello, World!
]
===========================================================================================================================
# Java # WebAssembly (wasm) # GraalVM # SDKMAN! # sdk install java 23-graal # native-image # Apache Maven Wrappper # Gradle Wrappper
===========================================================================================================================
% sdk version
% sdk install java 23-graal
% java --version
[
java 23 2024-09-17
Java(TM) SE Runtime Environment Oracle GraalVM 23+37.1 (build 23+37-jvmci-b01)
Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 23+37.1 (build 23+37-jvmci-b01, mixed mode, sharing)
]
# REPL
% jshell
% jshell --enable-preview
> System.getProperty("java.version")
> System.getProperty("java.vendor.version")
> System.getProperty("java.vm.name")
> /exit
% native-image --version
[
native-image 23 2024-09-17
GraalVM Runtime Environment Oracle GraalVM 23+37.1 (build 23+37-jvmci-b01)
Substrate VM Oracle GraalVM 23+37.1 (build 23+37, serial gc, compressed references)
]
[
% sdk uninstall java 23-graal --force
]
% mkdir -p SDKGraalVM; pushd SDKGraalVM
# https://github.com/graalvm/graal-languages-demos/tree/main # zip # main
[
% wget --output-document=graal-languages-demos-main.zip https://github.com/graalvm/graal-languages-demos/archive/main.zip
% tar -xvzf graal-languages-demos-main.zip
]
% unzip graal-languages-demos-main.zip
% cd graal-languages-demos-main/graalwasm/graalwasm-starter
# Required for Apache Maven Wrapper and Gradle Wrappper # If java 23-graal is not installed
[
# Java 23.0.2
% export PATH="$HOME/Downloads/Software/OpenJDK/JDK23.0.2/jdk-23.0.2.jdk/Contents/Home/bin/":$PATH
# Or
% export JAVA_HOME="$HOME/Downloads/Software/OpenJDK/JDK23.0.2/jdk-23.0.2.jdk/Contents/Home"
]
# Apache Maven
% ./mvnw test
% ./mvnw exec:java
% jar cvf target/demo-1.0-SNAPSHOT.jar com/example/App.class
# Gradle
% ./gradlew test
% ./gradlew run
# Test Results # Chrome
% open -n -a "Google Chrome" --args "--new-window" "file:///$HOME/Desktop/GitHub/WebAssembly-Add/Java/SDKGraalVM/graal-languages-demos-main/graalwasm/graalwasm-starter/build/reports/tests/test/index.html"
% cat target/surefire-reports/com.example.AppTest.txt
[
-------------------------------------------------------------------------------
Test set: com.example.AppTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.330 s -- in com.example.AppTest
]
% sdk uninstall java 23-graal
---------------------------------------------------------------------------------------------------------------------------
# Java # WebAssembly (wasm) # wabt # WebAssembly Text Format
---------------------------------------------------------------------------------------------------------------------------
# Implementation Details
# The WebAssembly is stored in the resource file `add-two.wasm`.
% cat build/resources/main/com/example/add-two.wat
[
(module
(func (export "addTwo") (param i32 i32) (result i32)
local.get 0
local.get 1
i32.add))%
]
# Examine its textual representation in the resource file `add-two.wat`.
# Tweak the WebAssembly module by rebuilding the `add-two.wasm` file from the `add-two.wat` file.
# For that, you can use the `wat2wasm` tool from the [wabt toolkit](https://github.com/WebAssembly/wabt).
# tweak the WebAssembly module
[
% brew install wabt
% brew list wabt
]
% mkdir -p ~/Desktop/GitHub/WebAssembly-Add/Java/SDKGraalVM/TweakWABT
% cp build/resources/main/com/example/add-two.wat ~/Desktop/GitHub/WebAssembly-Add/Java/SDKGraalVM/TweakWABT
% cd ~/Desktop/GitHub/WebAssembly-Add/Java/SDKGraalVM/TweakWABT
% ls
# Parse add-two.wat and write to .wasm binary file with the same name
% wat2wasm add-two.wat
% ls
% cat add-two.wasm
# Parse add-two.wat and write to binary file add-two.wasm
% mkdir -p binary
% wat2wasm add-two.wat -o binary/add-two.wasm
# build/resources/main/com/example/add-two.wat
# WAT # func (export "addTwo")
(module
(func (export "addTwo") (param i32 i32) (result i32)
local.get 0
local.get 1
i32.add))
# JS # WAT # const { addTwo } = wasmInstance.exports
const wasmInstance =
new WebAssembly.Instance(wasmModule, {});
const { addTwo } = wasmInstance.exports;
for (let i = 0; i < 10; i++) {
console.log(addTwo(i, i));
}
# JS LOG
0
2
4
6
8
10
12
14
16
18
# WAT # func $fac (export "fac")
(module
(func $fac (export "fac") (param f64) (result f64)
local.get 0
f64.const 1
f64.lt
if (result f64)
f64.const 1
else
local.get 0
local.get 0
f64.const 1
f64.sub
call $fac
f64.mul
end))
# JS # WAT # const { fac } = wasmInstance.exports
const wasmInstance =
new WebAssembly.Instance(wasmModule, {});
const { fac } = wasmInstance.exports;
for (let i = 1; i <= 15; i++) {
console.log(fac(i));
}
# JS LOG
1
2
6
24
120
720
5040
40320
362880
3628800
39916800
479001600
6227020800
87178291200
1307674368000
# NB # Swift WATExample
# WAT # func $factorial (export "factorial") # i64
(module
;; n! = n * (n - 1) * (n - 2) * ... * 2 * 1
(func $factorial (export "factorial") (param $arg i64) (result i64)
(if (result i64)
(i64.eqz (local.get $arg))
(then (i64.const 1))
(else
(i64.mul
(local.get $arg)
(call $factorial
(i64.sub
(local.get $arg)
(i64.const 1)
))))))
)
# JS # WAT # const { factorial } = wasmInstance.exports # BigInt
const wasmInstance =
new WebAssembly.Instance(wasmModule, {});
const { factorial } = wasmInstance.exports;
for (let i = BigInt(1); i <= 15; i++) {
console.log(factorial(i));
}
# JS LOG
1
2
6
24
120
720
5040
40320
362880
3628800
39916800
479001600
6227020800
87178291200
1307674368000
# WAT # (export "e" (func 1)))
(module
(import "foo" "bar" (func (param f32)))
(memory (data "hi"))
(type (func (param i32) (result i32)))
(start 1)
(table 0 1 funcref)
(func)
(func (type 1)
i32.const 42
drop)
(export "e" (func 1)))
# JS # WAT # const { e } = wasmInstance.exports;
const wasmInstance = new WebAssembly.Instance(wasmModule, {
foo: {
bar() {}
},
});
const { e } = wasmInstance.exports;
console.log(e);
# JS LOG
function 1() { [native code] }
# WAT # (export "e" (func 2)))
(module
(import "foo" "bar" (func (param f32)))
(memory (data "hi"))
(type (func (param i32) (result i32)))
(start 1)
(table 0 1 funcref)
(func)
(func (type 1)
i32.const 42
drop)
(export "e" (func 2)))
# JS # WAT # const { e } = wasmInstance.exports;
const wasmInstance = new WebAssembly.Instance(wasmModule, {
foo: {
bar() {}
},
});
const { e } = wasmInstance.exports;
console.log(e);
# JS LOG
function 2() { [native code] }
# WAT # import "env" "g" (global (mut i32))
(module
(import "env" "g" (global (mut i32)))
(func (export "f")
i32.const 100
global.set 0))
# JS # WAT #
const g = new WebAssembly.Global({value: 'i32', mutable: true});
const wasmInstance = new WebAssembly.Instance(wasmModule, {env: {g}});
console.log('before: ' + g.value);
wasmInstance.exports.f();
console.log('after: ' + g.value);
# JS LOG
before: 0
after: 100
# WAT # f32 To # i32 # Max # 2147483647 # Min # -2147483648
(module
(func (export "f") (param f32) (result i32)
local.get 0
i32.trunc_sat_f32_s))
# JS # WAT # Infinity # -Infinity
const wasmInstance = new WebAssembly.Instance(wasmModule);
const {f} = wasmInstance.exports;
console.log(f(Infinity));
console.log(f(-Infinity));
# JS LOG
2147483647
-2147483648
# WAT i32.extend8 # Int8 # extend # signed
(module
(func (export "f") (param i32) (result i32)
local.get 0
i32.extend8_s))
# JS # WAT # extend # signed
const wasmInstance = new WebAssembly.Instance(wasmModule);
const {f} = wasmInstance.exports;
console.log(f(0));
console.log(f(127));
console.log(f(128));
console.log(f(255));
# JS LOG
0
127
-128
-1
# WAT # Subtraction # Reverse
(module
(func $swap (param i32 i32) (result i32 i32)
local.get 1
local.get 0)
(func (export "reverseSub") (param i32 i32) (result i32)
local.get 0
local.get 1
call $swap
i32.sub))
# JS # WAT # Swap
const wasmInstance = new WebAssembly.Instance(wasmModule);
const {reverseSub} = wasmInstance.exports;
console.log(reverseSub(10, 3));
# JS LOG
-7
# WAT # memory.fill
(module
(memory (export "mem") 1)
(func (export "fill") (param i32 i32 i32)
local.get 0
local.get 1
local.get 2
memory.fill))
# JS # WAT # em.buffer
const wasmInstance = new WebAssembly.Instance(wasmModule);
const {fill, mem} = wasmInstance.exports;
// index // value // count
fill(2, 22, 2);
fill(10, 55, 8);
fill(6, 88, 5);
// overwrite
fill(6, 66, 4);
// Uint8Array buffer, index, count
console.log(new Uint8Array(mem.buffer, 0, 50));
console.log(new Uint8Array(mem.buffer, 0, 25));
# JS LOG
0,0,22,22,0,0,66,66,66,66,88,55,55,55,55,55,55,55,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,0,22,22,0,0,66,66,66,66,88,55,55,55,55,55,55,55,0,0,0,0,0,0,0
===========================================================================================================================
# Java # WebAssembly (wasm) # emcc # em++ # Embed C in Java # Embedding GraalWasm in Java
===========================================================================================================================
# Java 23.0.2 # Gradle 8.12 # Apache Maven 3.9.9
% export PATH="$HOME/Downloads/Software/OpenJDK/JDK23.0.2/jdk-23.0.2.jdk/Contents/Home/bin/:$HOME/Downloads/Software/Gradle/gradle-8.12/bin/:$HOME/Downloads/Software/ApacheMaven/apache-maven-3.9.9/bin/":$PATH
% java --version
[
% gradle --version
]
% mvn --version
# Maven Archetype
% mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.5 -DgroupId=com.example -DartifactId=demo -DinteractiveMode=false
% cd demo
# C Code
% mkdir -p src/main/c
% nano src/main/c/floyd.c
[
#include <stdio.h>
void floyd() {
int number = 1;
int rows = 10;
for (int i = 1; i <= rows; i++) {
for (int j = 1; j <= i; j++) {
printf("%d ", number);
++number;
}
printf(".\n");
}
}
int main() {
floyd();
return 0;
}
]
% cat src/main/c/floyd.c
# C Code to WebAssembly
# Compile the C code using the most recent version of the Emscripten compiler frontend
% mkdir -p target/classes/com/example
[
% brew install emscripten
]
% emcc --version
[
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.74-git
Copyright (C) 2014 the Emscripten authors (see AUTHORS.txt)
This is free and open source software under the MIT license.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
]
% em++ --version
[
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 4.0.1-git
Copyright (C) 2014 the Emscripten authors (see AUTHORS.txt)
This is free and open source software under the MIT license.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
]
# The exported functions must be prefixed by _. If you reference that function in the Java code, the exported name should not contain the underscore.
% emcc --no-entry -s EXPORTED_FUNCTIONS=_floyd -o target/classes/com/example/floyd.wasm src/main/c/floyd.c
# emcc produces a standalone file floyd.wasm in target/classes/com/example/, which enables you to load the file as a resource.
% ls target/classes/com/example/floyd.wasm
# Polyglot API and GraalWasm Dependencies
# pom.xml # dependencies # dependency # Polyglot API # GraalWasm
[
<!-- https://mvnrepository.com/artifact/org.graalvm.polyglot/polyglot -->
<dependency>
<groupId>org.graalvm.polyglot</groupId>
<artifactId>polyglot</artifactId>
<version>24.1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.graalvm.polyglot/wasm -->
<dependency>
<groupId>org.graalvm.polyglot</groupId>
<artifactId>wasm</artifactId>
<version>24.1.1</version>
<type>pom</type>
</dependency>
]
# Maven Compile C Code
# This binds the exec-maven-plugin:exec goal to the generate-resources phase of the build lifecycle
# The exec goal runs mkdir and emcc with the same command line arguments as above, ensuring that the generated WebAssembly module file is included as a resource file in the final JAR file.
# pom.xml # build # plugins
# NB: After </pluginManagement>
[
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>create-output-directory</id>
<phase>generate-resources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>mkdir</executable>
<commandlineArgs>-p ${project.build.outputDirectory}/com/example/</commandlineArgs>
</configuration>
</execution>
<execution>
<id>compile-c-into-wasm</id>
<phase>generate-resources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>emcc</executable>
<commandlineArgs>--no-entry -s EXPORTED_FUNCTIONS=_floyd -o ${project.build.outputDirectory}/com/example/floyd.wasm ${project.basedir}/src/main/c/floyd.c</commandlineArgs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
]
% nano pom.xml
[
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
<name>demo</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>17</maven.compiler.release>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.11.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<!-- Optionally: parameterized tests support -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.graalvm.polyglot/polyglot -->
<dependency>
<groupId>org.graalvm.polyglot</groupId>
<artifactId>polyglot</artifactId>
<version>24.1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.graalvm.polyglot/wasm -->
<dependency>
<groupId>org.graalvm.polyglot</groupId>
<artifactId>wasm</artifactId>
<version>24.1.1</version>
<type>pom</type>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.4.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.3.0</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>3.1.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.1.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.12.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.6.1</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>create-output-directory</id>
<phase>generate-resources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>mkdir</executable>
<commandlineArgs>-p ${project.build.outputDirectory}/com/example/</commandlineArgs>
</configuration>
</execution>
<execution>
<id>compile-c-into-wasm</id>
<phase>generate-resources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>emcc</executable>
<commandlineArgs>--no-entry -s EXPORTED_FUNCTIONS=_floyd -o ${project.build.outputDirectory}/com/example/floyd.wasm ${project.basedir}/src/main/c/floyd.c</commandlineArgs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
]
% cat pom.xml
# Using the WebAssembly Module from Java
# Embed this WebAssembly function in a Java application
% nano src/main/java/com/example/App.java
[
package com.example;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Source;
import org.graalvm.polyglot.Value;
public class App {
public static void main(String[] args) throws IOException {
SystemProperties propertiesSystem = new SystemProperties();
propertiesSystem.print();
System.out.println();
System.out.println("Embed C in Java");
// Find the WebAssembly module resource
URL wasmFile = App.class.getResource("floyd.wasm");
// Setup context
Context.Builder contextBuilder = Context.newBuilder("wasm").option("wasm.Builtins", "wasi_snapshot_preview1");
Source.Builder sourceBuilder = Source.newBuilder("wasm", wasmFile).name("example");
Source source = sourceBuilder.build();
Context context = contextBuilder.build();
// Evaluate the WebAssembly module
context.eval(source);
// Execute the floyd function
context.getBindings("wasm").getMember("example").getMember("_initialize").executeVoid();
Value mainFunction = context.getBindings("wasm").getMember("example").getMember("floyd");
mainFunction.execute();
context.close();
System.out.println();
System.out.println("Embedding GraalWasm in Java");
App instance = new App();
instance.loadWebAssembly();
}
private void loadWebAssembly() throws IOException {
try (Context context = Context.newBuilder("wasm").option("wasm.Builtins", "wasi_snapshot_preview1").build()) {
// Evaluate the WebAssembly module
System.out.println("Using path to floyd.wasm");
String path = System.getProperty("user.dir") + "/target/classes/com/example/";
Source source = Source.newBuilder("wasm", new File(path + "floyd.wasm")).name("example").build();
/*
// Find the WebAssembly module resource
URL wasmFile = App.class.getResource("floyd.wasm");
Source source = Source.newBuilder("wasm", wasmFile).name("example").build();
*/
context.eval(source);
// Initialize the module and execute the floyd function
Value exampleModule = context.getBindings("wasm").getMember("example");
exampleModule.getMember("_initialize").executeVoid();
Value floydFunction = exampleModule.getMember("floyd");
floydFunction.execute();
}
}
}
class SystemProperties {
public void print() {
System.out.println(String.format("OS Name: %s", System.getProperty("os.name")));
System.out.println(String.format("OS Version: %s", System.getProperty("os.version")));
System.out.println(String.format("OS Architecture: %s", System.getProperty("os.arch")));
System.out.println(String.format("Java Version: %s", System.getProperty("java.version")));
System.out.println(String.format("Java Vendor Version: %s", System.getProperty("java.vendor.version")));
System.out.println(String.format("Java VM Name: %s", System.getProperty("java.vm.name")));
// System.getProperties().list(System.out);
}
}
]
% cat src/main/java/com/example/App.java
# Maven Compile
% mvn package
# Run the Java application
% mvn exec:java -Dexec.mainClass=com.example.App
[
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------------< com.example:demo >--------------------------
[INFO] Building demo 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] >>> exec:1.2.1:java (default-cli) > validate @ demo >>>
[INFO]
[INFO] <<< exec:1.2.1:java (default-cli) < validate @ demo <<<
[INFO]
[INFO]
[INFO] --- exec:1.2.1:java (default-cli) @ demo ---
OS Name: Mac OS X
OS Version: 15.1
OS Architecture: aarch64
Java Version: 23.0.1
Java Vendor Version: Oracle GraalVM 23.0.1+11.1
Java VM Name: Java HotSpot(TM) 64-Bit Server VM
Embed C in Java
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 .
Embedding GraalWasm in Java
Using path to floyd.wasm
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 .
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.573 s
[INFO] Finished at: 2025-01-15T00:26:18+05:30
[INFO] ------------------------------------------------------------------------
]
===========================================================================================================================
# Maven Wrapper
===========================================================================================================================
[
% ls -a
]
% mvn wrapper:wrapper
[
% ls -a
% cat mvnw
% cat mvnw.cmd
% ls -a .mvn
% ls -a .mvn/wrapper
% cat .mvn/wrapper/maven-wrapper.properties
]
% ./mvnw clean install
% ./mvnw package
% ./mvnw exec:java -Dexec.mainClass=com.example.App
[
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------------< com.example:demo >--------------------------
[INFO] Building demo 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] >>> exec:1.2.1:java (default-cli) > validate @ demo >>>
[INFO]
[INFO] <<< exec:1.2.1:java (default-cli) < validate @ demo <<<
[INFO]
[INFO]
[INFO] --- exec:1.2.1:java (default-cli) @ demo ---
OS Name: Mac OS X
OS Version: 15.1
OS Architecture: aarch64
Java Version: 23.0.1
Java Vendor Version: Oracle GraalVM 23.0.1+11.1
Java VM Name: Java HotSpot(TM) 64-Bit Server VM
Embed C in Java
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 .
Embedding GraalWasm in Java
Using path to floyd.wasm
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 .
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.566 s
[INFO] Finished at: 2025-01-15T00:30:06+05:30
[INFO] ------------------------------------------------------------------------
]
===========================================================================================================================
# Java # WebAssembly (wasm) # Spring Boot # Native Support # Spring Web # Gradle # Groovy # Kotlin # Apache Maven
===========================================================================================================================
#
.
├── Gradle
│   ├── Groovy
│   └── Kotlin
└── Maven
% mkdir -p "Gradle/Groovy" && mkdir -p "Gradle/Kotlin" && mkdir -p Maven
# Groovy
% cd "Gradle/Groovy"
# Or
# Kotlin
% cd "Gradle/Kotlin"
# Or
# Maven
% cd Maven
]
% mkdir -p sample && cd sample
# Java 23.0.2 # Gradle 8.12 # Apache Maven 3.9.9
% export PATH="$HOME/Downloads/Software/OpenJDK/JDK23.0.2/jdk-23.0.2.jdk/Contents/Home/bin/:$HOME/Downloads/Software/Gradle/gradle-8.12/bin/:$HOME/Downloads/Software/ApacheMaven/apache-maven-3.9.9/bin/":$PATH
% java --version
% gradle --version
% mvn --version
# By default, Maven and Gradle compile sources from src/main/java and src/test/java
# Create # SampleApplication.java # SampleApplicationTests.java with the appropriate directory structure
# Including the path required for the package (if any)
# Example: package com.commons.project;
[
.
└── src
├── main
│   └── java
│   └── com
│   └── commons
│   └── project
│   └── SampleApplication.java
└── test
└── java
└── com
└── commons
└── project
└── SampleApplicationTests.java
]
% mkdir -p src/main/java/com/commons/project
% ls src/main/java/com/commons/project
% mkdir -p src/test/java/com/commons/project
% ls src/test/java/com/commons/project
% nano src/main/java/com/commons/project/SampleApplication.java
[
package com.commons.project;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SampleApplication {
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
}
]
% cat src/main/java/com/commons/project/SampleApplication.java
% nano src/test/java/com/commons/project/SampleApplicationTests.java
[
package com.commons.project;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SampleApplicationTests {
@Test
void contextLoads() {
}
}
]
% cat src/test/java/com/commons/project/SampleApplicationTests.java
% tree
[
.
└── src
├── main
│   └── java
│   └── com
│   └── commons
│   └── project
│   └── SampleApplication.java
└── test
└── java
└── com
└── commons
└── project
└── SampleApplicationTests.java
]
===========================================================================================================================
# Groovy # settings.gradle # build.gradle
===========================================================================================================================
# Settings
# Groovy
% nano settings.gradle
[
rootProject.name = 'sample'
]
% cat settings.gradle
# Build
% nano build.gradle
[
plugins {
id 'java'
id 'org.springframework.boot' version '3.4.1'
id 'io.spring.dependency-management' version '1.1.7'
id 'org.graalvm.buildtools.native' version '0.10.4'
}
group = 'com.commons'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(23)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}
]
% cat build.gradle
===========================================================================================================================
# Kotlin # settings.gradle.kts # build.gradle.kts
===========================================================================================================================
# Settings
% nano settings.gradle.kts
[
rootProject.name = "sample"
]
% cat settings.gradle.kts
# Build
% nano build.gradle.kts
[
plugins {
java
id("org.springframework.boot") version "3.4.1"
id("io.spring.dependency-management") version "1.1.7"
id("org.graalvm.buildtools.native") version "0.10.4"
}
group = "com.commons"
version = "0.0.1-SNAPSHOT"
java {
toolchain {
languageVersion = JavaLanguageVersion.of(23)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}
tasks.withType<Test> {
useJUnitPlatform()
}
]
% cat build.gradle.kts
===========================================================================================================================
# Gradle # Groovy # Kotlin # wrapper
===========================================================================================================================
# Gradle wrapper
% gradle wrapper
===========================================================================================================================
# Maven # xml
===========================================================================================================================
# pom.xml
[
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
]
% nano pom.xml
[
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.commons</groupId>
<artifactId>sample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sample</name>
<description>Spring Boot GraalVM Native Support Spring Web Maven</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>23</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
]
% cat pom.xml
===========================================================================================================================
# @RestController
===========================================================================================================================
% nano src/main/java/com/commons/project/GraalVMController.java
[
package com.commons.project;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GraalVMController {
@GetMapping("/graalvm")
public String graalvm() {
return "GraalVM Java Version: " + System.getProperty("java.version");
}
}
]
% cat src/main/java/com/commons/project/GraalVMController.java
===========================================================================================================================
# Maven wrapper
===========================================================================================================================
% mvn wrapper:wrapper
===========================================================================================================================
# Gradle # Groovy # Kotlin # bootRun
===========================================================================================================================
% ./gradlew bootRun
===========================================================================================================================
# Maven spring-boot:run
===========================================================================================================================
% ./mvnw spring-boot:run
===========================================================================================================================
# Terminal New Window
===========================================================================================================================
% curl http://localhost:8080/graalvm
% open http://localhost:8080/graalvm
===========================================================================================================================
# Copy sample/src
===========================================================================================================================
.
├── Gradle
│   ├── Groovy
│   └── Kotlin
└── Maven
# Groovy
% cp -r ../sample ../../Kotlin/sample
% cp -r ../sample ../../../Maven/sample
# Or
# Kotlin
% cp -r ../sample ../../Groovy/sample
% cp -r ../sample ../../../Maven/sample
# Or
# Maven
% cp -r ../sample ../../Gradle/Groovy/sample
% cp -r ../sample ../../Gradle/Kotlin/sample
===========================================================================================================================
# Spring Initializr # Optional # https://start.spring.io/ # https://start.spring.io/#!dependencies=native,web
===========================================================================================================================
# Optional # Verification # Create Spring Boot sample from Spring Initializr # Dependencies # GraalVM Native Support # Spring Web
[
# Project # Gradle - Groovy # Or # Gradle - Kotlin # Or # Maven
GENERATE
# Language
Java
# Spring Boot
3.4.2
# Project Metadata
# Group
com.commons
# Artifact
sample
# Name
sample
# Description # Gradle Groovy # Gradle Kotlin # Maven
Spring Boot GraalVM Native Support Spring Web
# Package name
com.commons.project
# Packaging
Jar
# Java
23
# Dependencies
# Build web, including RESTful, applications using Spring MVC. Uses Apache Tomcat as the default embedded container.
Spring Web # Web
# Support for compiling Spring applications to native executables using the GraalVM native-image compiler.
GraalVM Native Support # Developer Tools
]
===========================================================================================================================
% mkdir -p SpringInitializr
% cd SpringInitializr
# Download the generated "sample.zip" from # https://start.spring.io/ # https://start.spring.io/#!dependencies=native,web
# tar -xvzf # Or # unzip
% tar -xvzf sample.zip
===========================================================================================================================
# Java # WebAssembly (wasm) # GraalVM Container Image # GraalJS # Docker # Gradle # Kotlin
===========================================================================================================================
# Embed JavaScript code in Java
[
import org.graalvm.polyglot.Context;
try (Context context = Context.create()) {
context.eval("js", "console.log('Hello from GraalJS!')");
}
]
===========================================================================================================================
[
% export PATH="/Applications/Docker.app/Contents/Resources/bin/:/Applications/Docker.app/Contents/Resources/cli-plugins/":$PATH
]
% docker --version
% docker version
% docker info
# Container image for GraalVM JDK for a specific JDK feature version 23
[
% docker pull ghcr.io/graalvm/jdk-community:23
]
% sudo docker pull ghcr.io/graalvm/jdk-community:23
# Or use the container image as the base image in the Dockerfile
[
FROM ghcr.io/graalvm/jdk-community:23
]
# Pull the container image with the native-image utility for a specific JDK feature version 23
% docker pull ghcr.io/graalvm/native-image-community:23
# Pull the container image with the native-image utility with the musl libc toolchain to create fully statically linked executables
% docker pull ghcr.io/graalvm/native-image-community:23-muslib
# Or use the container image as the base image in the Dockerfile
[
FROM ghcr.io/graalvm/native-image-community:23-muslib
]
[
% docker container list --all
]
% docker image list --all
[
REPOSITORY TAG IMAGE ID CREATED SIZE
ghcr.io/graalvm/jdk-community 23 cdcf77f22c9d 8 days ago 718MB
docker/labs-k8s-toolkit-extension 0.0.46 fbbe16ec2589 14 months ago 128MB
]
[
# With the -P or --publish-all flag, you can automatically publish all exposed ports to ephemeral ports. This is quite useful when you’re trying to avoid port conflicts in development or testing environments.
# For example, the following command will publish all of the exposed ports configured by the image
# % docker run -P nginx
]
# --publish-all
# Verify, start the container and enter a Bash session
[
% docker run -it --publish-all --rm --entrypoint /bin/bash ghcr.io/graalvm/jdk-community:23
% docker run -it -p 8000:80 --rm --entrypoint /bin/bash ghcr.io/graalvm/jdk-community:23
]
% docker run -it --rm --entrypoint /bin/bash ghcr.io/graalvm/jdk-community:23
# Terminal New Window
% docker container list --all
[
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dd8b6256e335 ghcr.io/graalvm/jdk-community:23 "/bin/bash" About a minute ago Up About a minute gifted_napier
]
% docker image list --all
[
REPOSITORY TAG IMAGE ID CREATED SIZE
ghcr.io/graalvm/jdk-community 23 cdcf77f22c9d 8 days ago 718MB
docker/labs-k8s-toolkit-extension 0.0.46 fbbe16ec2589 14 months ago 128M
]
# Original Terminal Window
# java --version
# jwebserver --version
[
openjdk 23.0.2 2025-01-21
OpenJDK Runtime Environment GraalVM CE 23.0.2+7.1 (build 23.0.2+7-jvmci-b01)
OpenJDK 64-Bit Server VM GraalVM CE 23.0.2+7.1 (build 23.0.2+7-jvmci-b01, mixed mode, sharing)
]
# cat /etc/os-release
[
NAME="Oracle Linux Server"
VERSION="9.4"
ID="ol"
ID_LIKE="fedora"
VARIANT="Server"
VARIANT_ID="server"
VERSION_ID="9.4"
PLATFORM_ID="platform:el9"
PRETTY_NAME="Oracle Linux Server 9.4"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:oracle:linux:9:4:server"
HOME_URL="https://linux.oracle.com/"
BUG_REPORT_URL="https://github.com/oracle/oracle-linux"
ORACLE_BUGZILLA_PRODUCT="Oracle Linux 9"
ORACLE_BUGZILLA_PRODUCT_VERSION=9.4
ORACLE_SUPPORT_PRODUCT="Oracle Linux"
ORACLE_SUPPORT_PRODUCT_VERSION=9.4
]
# arch
# microdnf --help
[
# microdnf upgrade
# microdnf update
]
# env
[
HOSTNAME=8d82103dc8c3
JAVA_HOME=/usr/lib64/graalvm/graalvm-community-java23
PWD=/app
HOME=/root
LANG=en_US.UTF-8
TERM=xterm
SHLVL=1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
_=/usr/bin/env
]
# ls /etc
# ls /usr/lib64/graalvm
# ls /usr/lib64/graalvm/graalvm-community-java23/bin
# jshell
# > String.format("GraalVM Java Version: %s", System.getProperty("java.version"));
# > /exit
# microdnf install maven
# mvn --version
# microdnf install wget
# wget -V
# wget https://services.gradle.org/distributions/gradle-8.12-all.zip
# mkdir -p /opt/gradle
# ls /opt/gradle
# microdnf install unzip
# unzip --version
# unzip -d /opt/gradle gradle-8.12-all.zip
# ls /opt/gradle/gradle-8.12/bin
# ls /opt/gradle/gradle-8.12/bin/gradle --version
% export PATH="/usr/lib64/graalvm/graalvm-community-java23/bin/:/opt/gradle/gradle-8.12/bin":$PATH
# jwebserver --version
# gradle --version
# microdnf install nano
# nano --version
# microdnf install tree
# tree --version
# mkdir -p GraalJS
# cd GraalJS
[
# ls
# rm -rf *
]
# mkdir -p sample
# cd sample
[
Your Java runtime '23.0.2+7-jvmci-b01' with compiler version '24.1.2' is incompatible with polyglot version '24.1.1'.
Update the org.graalvm.polyglot versions to at least '24.1.2' to resolve this.
Alternatively, it is possible to switch to the fallback runtime with -Dtruffle.UseFallbackRuntime=true.
The fallback runtime is compatible to any Java 17 capable JDK.
]
# 17
# gradle init
[
Select type of build to generate:
1: Application
2: Library
3: Gradle plugin
4: Basic (build structure only)
Enter selection (default: Application) [1..4]
Select implementation language:
1: Java
2: Kotlin
3: Groovy
4: Scala
5: C++
6: Swift
Enter selection (default: Java) [1..6]
Enter target Java version (min: 7, default: 21): 17
Project name (default: sample):
Select application structure:
1: Single application project
2: Application and library project
Enter selection (default: Single application project) [1..2]
Select build script DSL:
1: Kotlin
2: Groovy
Enter selection (default: Kotlin) [1..2]
Select test framework:
1: JUnit 4
2: TestNG
3: Spock
4: JUnit Jupiter
Enter selection (default: JUnit Jupiter) [1..4]
Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no]
> Task :init
Learn more about Gradle by exploring our Samples at https://docs.gradle.org/8.12/samples/sample_building_java_applications.html
BUILD SUCCESSFUL in 12s
1 actionable task: 1 executed
]
# tree
[
.
|-- app
| |-- build.gradle.kts
| `-- src
| |-- main
| | |-- java
| | | `-- org
| | | `-- example
| | | `-- App.java
| | `-- resources
| `-- test
| |-- java
| | `-- org
| | `-- example
| | `-- AppTest.java
| `-- resources
|-- gradle
| |-- libs.versions.toml
| `-- wrapper
| |-- gradle-wrapper.jar
| `-- gradle-wrapper.properties
|-- gradle.properties
|-- gradlew
|-- gradlew.bat
`-- settings.gradle.kts
14 directories, 10 files
]
% cat app/src/main/java/org/example/App.java
[
/*
* This source file was generated by the Gradle 'init' task
*/
package org.example;
public class App {
public String getGreeting() {
return "Hello World!";
}
public static void main(String[] args) {
System.out.println(new App().getGreeting());
}
}
]
% rm -rf app/src/main/java/org/example/App.java
% nano app/src/main/java/org/example/App.java
[
package org.example;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;
public class App {
static String JS_CODE = "(function myFun(param){console.log('Hola ' + param + ' from JS');})";
public String getGreeting() {
return "Hello World!";
}
public static void main(String[] args) {
try (Context context = Context.create()) {
context.eval("js", "console.log('Hello from GraalJS!')");
}
String who = args.length == 0 ? "World" : args[0];
System.out.println("Hello " + who + " from Java");
try (Context context = Context.create()) {
Value value = context.eval("js", JS_CODE);
value.execute(who);
}
System.out.println(new App().getGreeting());
}
}
]
% cat app/src/main/java/org/example/App.java
% cat app/build.gradle.kts
[
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java application project to get you started.
* For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.12/userguide/building_java_projects.html in the Gradle documentation.
*/
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
application
}
repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}
dependencies {
// Use JUnit Jupiter for testing.
testImplementation(libs.junit.jupiter)
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
// This dependency is used by the application.
implementation(libs.guava)
}
// Apply a specific Java toolchain to ease working on different environments.
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
application {
// Define the main class for the application.
mainClass = "org.example.App"
}
tasks.named<Test>("test") {
// Use JUnit Platform for unit tests.
useJUnitPlatform()
}
]
% rm -rf app/build.gradle.kts
% nano app/build.gradle.kts
[
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
application
}
repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}
dependencies {
// This dependency is used by the application.
implementation(libs.guava)
implementation("org.graalvm.polyglot:polyglot:24.1.1")
implementation("org.graalvm.polyglot:js:24.1.1")
}
testing {
suites {
// Configure the built-in test suite
val test by getting(JvmTestSuite::class) {
// Use JUnit Jupiter test framework
useJUnitJupiter("5.11.1")
}
}
}
// Apply a specific Java toolchain to ease working on different environments.
java {
toolchain {
languageVersion = JavaLanguageVersion.of(23)
}
}
application {
// Define the main class for the application.
mainClass = "org.example.App"
}
]
# cat app/build.gradle.kts
# gradle wrapper
# ./gradlew run
[
Calculating task graph as no cached configuration is available for tasks: run
> Task :app:run
Hello World!
BUILD SUCCESSFUL in 488ms
2 actionable tasks: 2 executed
Configuration cache entry stored.
]
[
# ./gradlew clean
]
# ./gradlew build
# yes
# ./gradlew build --scan
# jwebserver
[
Binding to loopback by default. For all interfaces use "-b 0.0.0.0" or "-b ::".
Serving /app/GraalJS/sample/GraalJS/sample/app/build/reports/tests/test and subdirectories on 127.0.0.1 port 8000
URL http://127.0.0.1:8000/
]
# Terminal New Window
% export PATH="/Applications/Docker.app/Contents/Resources/bin/:/Applications/Docker.app/Contents/Resources/cli-plugins/":$PATH
% docker container list --all
[
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dd8b6256e335 ghcr.io/graalvm/jdk-community:23 "/bin/bash" About an hour ago Up About an hour gifted_napie
]
# shell
% docker exec -i -t gifted_napier /bin/bash
# curl http://127.0.0.1:8000/index.html
# curl http://127.0.0.1:8000/packages/org.example.html
# curl http://127.0.0.1:8000/classes/org.example.AppTest.html
# exit
===========================================================================================================================
# Java # WebAssembly (wasm) # GraalVM # GraalPy # Gradle # Kotlin
===========================================================================================================================
# Embed Python code in Java
[
import org.graalvm.polyglot.Context;
try (Context context = Context.create()) {
context.eval("python", "print('Hello from GraalPy!')");
}
]
===========================================================================================================================
% mkdir -p GraalPy
% cd GraalPy
# Java 23.0.2 # Gradle 8.12 # Apache Maven 3.9.9
% export PATH="$HOME/Downloads/Software/OpenJDK/JDK23.0.2/jdk-23.0.2.jdk/Contents/Home/bin/:$HOME/Downloads/Software/Gradle/gradle-8.12/bin/:$HOME/Downloads/Software/ApacheMaven/apache-maven-3.9.9/bin/":$PATH
% java --version
% gradle --version
[
% mvn --version
]
% mkdir -p sample && cd sample
# 23 # yes
# gradle init
[
Starting a Gradle Daemon (subsequent builds will be faster)
Select type of build to generate:
1: Application
2: Library
3: Gradle plugin
4: Basic (build structure only)
Enter selection (default: Application) [1..4]
Select implementation language:
1: Java
2: Kotlin
3: Groovy
4: Scala
5: C++
6: Swift
Enter selection (default: Java) [1..6]
Enter target Java version (min: 7, default: 21): 23
Project name (default: sample):
Select application structure:
1: Single application project
2: Application and library project
Enter selection (default: Single application project) [1..2]
Select build script DSL:
1: Kotlin
2: Groovy
Enter selection (default: Kotlin) [1..2]
Select test framework:
1: JUnit 4
2: TestNG
3: Spock
4: JUnit Jupiter
Enter selection (default: JUnit Jupiter) [1..4]
Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] yes
> Task :init
Learn more about Gradle by exploring our Samples at https://docs.gradle.org/8.12/samples/sample_building_java_applications.html
BUILD SUCCESSFUL in 27s
1 actionable task: 1 executed
]
% tree
[
.
├── app
│   ├── build.gradle.kts
│   └── src
│   ├── main
│   │   ├── java
│   │   │   └── org
│   │   │   └── example
│   │   │   └── App.java
│   │   └── resources
│   └── test
│   ├── java
│   │   └── org
│   │   └── example
│   │   └── AppTest.java
│   └── resources
├── gradle
│   ├── libs.versions.toml
│   └── wrapper
│   ├── gradle-wrapper.jar
│   └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle.kts
15 directories, 10 files
]
% cat app/src/main/java/org/example/App.java
[
/*
* This source file was generated by the Gradle 'init' task
*/
package org.example;
public class App {
public String getGreeting() {
return "Hello World!";
}
public static void main(String[] args) {
System.out.println(new App().getGreeting());
}
}
]
% rm -rf app/src/main/java/org/example/App.java
% cat app/src/test/java/org/example/AppTest.java
[
/*
* This source file was generated by the Gradle 'init' task
*/
package org.example;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class AppTest {
@Test void appHasAGreeting() {
App classUnderTest = new App();
assertNotNull(classUnderTest.getGreeting(), "app should have a greeting");
}
}
]
% rm -rf app/src/test/java/org/example/AppTest.java
% rm -rf app/src/main/java
% rm -rf app/src/test/java
% mkdir -p app/src/main/java/com/commons/project
% ls app/src/main/java/com/commons/project
% mkdir -p app/src/test/java/com/commons/project
% ls app/src/test/java/com/commons/project
% nano app/src/main/java/com/commons/project/App.java
[
package com.commons.project;
import org.graalvm.polyglot.Context;
public class App {
public String getGreeting() {
return "Hello World!";
}
public static void main(String[] args) {
try (Context context = Context.create()) {
context.eval("python", "print('Hola from GraalPy!')");
}
try (var context = Context.create()) {
System.out.println(context.eval("python", "'Hola Python!'").asString());
}
System.out.println(new App().getGreeting());
}
}
]
% cat app/src/main/java/com/commons/project/App.java
% nano app/src/test/java/com/commons/project/AppTest.java
[
package com.commons.project;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class AppTest {
@Test void appHasAGreeting() {
App classUnderTest = new App();
assertNotNull(classUnderTest.getGreeting(), "app should have a greeting");
}
}
]
% cat app/src/test/java/com/commons/project/AppTest.java
% cat app/build.gradle.kts
[
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java application project to get you started.
* For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.12/userguide/building_java_projects.html in the Gradle documentation.
* This project uses @Incubating APIs which are subject to change.
*/
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
application
}
repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}
dependencies {
// This dependency is used by the application.
implementation(libs.guava)
}
testing {
suites {
// Configure the built-in test suite
val test by getting(JvmTestSuite::class) {
// Use JUnit Jupiter test framework
useJUnitJupiter("5.11.1")
}
}
}
// Apply a specific Java toolchain to ease working on different environments.
java {
toolchain {
languageVersion = JavaLanguageVersion.of(23)
}
}
application {
// Define the main class for the application.
mainClass = "org.example.App"
}
]
% rm -rf app/build.gradle.kts
% nano app/build.gradle.kts
[
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
application
}
repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}
dependencies {
// This dependency is used by the application.
implementation(libs.guava)
implementation("org.graalvm.polyglot:polyglot:24.1.1")
implementation("org.graalvm.polyglot:python:24.1.1")
}
testing {
suites {
// Configure the built-in test suite
val test by getting(JvmTestSuite::class) {
// Use JUnit Jupiter test framework
useJUnitJupiter("5.11.1")
}
}
}
// Apply a specific Java toolchain to ease working on different environments.
java {
toolchain {
languageVersion = JavaLanguageVersion.of(23)
}
}
application {
// Define the main class for the application.
mainClass = "com.commons.project.App"
}
]
% cat app/build.gradle.kts
% gradle wrapper
% ./gradlew run
[
% ./gradlew clean
]
% ./gradlew build
# yes
% ./gradlew build --scan
% jwebserver --directory $(pwd)/app/build/reports/tests/test --port 8000
# Terminal New Window
% curl http://127.0.0.1:8000/
% open http://127.0.0.1:8000/
===========================================================================================================================
# Java # WebAssembly (wasm) # GraalVM # TruffleRuby # Gradle # Groovy
===========================================================================================================================
# Embed Ruby code in Java
[
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;
class Embedding {
public static void main(String[] args) {
Context polyglot = Context.newBuilder().allowAllAccess(true).build();
Value array = polyglot.eval("ruby", "[1,2,42,4]");
int result = array.getArrayElement(2).asInt();
System.out.println(result);
}
}
]
===========================================================================================================================
% mkdir -p GraalVMTruffleRuby
% cd GraalVMTruffleRuby
# Java 23.0.2 # Gradle 8.12 # Apache Maven 3.9.9
% export PATH="$HOME/Downloads/Software/OpenJDK/JDK23.0.2/jdk-23.0.2.jdk/Contents/Home/bin/:$HOME/Downloads/Software/Gradle/gradle-8.12/bin/:$HOME/Downloads/Software/ApacheMaven/apache-maven-3.9.9/bin/":$PATH
% java --version
% gradle --version
[
% mvn --version
]
% mkdir -p sample && cd sample
# 23 # 2: Groovy # yes
# gradle init
[
Select type of build to generate:
1: Application
2: Library
3: Gradle plugin
4: Basic (build structure only)
Enter selection (default: Application) [1..4]
Select implementation language:
1: Java
2: Kotlin
3: Groovy
4: Scala
5: C++
6: Swift
Enter selection (default: Java) [1..6]
Enter target Java version (min: 7, default: 21): 23
Project name (default: sample):
Select application structure:
1: Single application project
2: Application and library project
Enter selection (default: Single application project) [1..2]
Select build script DSL:
1: Kotlin
2: Groovy
Enter selection (default: Kotlin) [1..2] 2
Select test framework:
1: JUnit 4
2: TestNG
3: Spock
4: JUnit Jupiter
Enter selection (default: JUnit Jupiter) [1..4]
Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] yes
> Task :init
Learn more about Gradle by exploring our Samples at https://docs.gradle.org/8.12/samples/sample_building_java_applications.html
BUILD SUCCESSFUL in 58s
1 actionable task: 1 executed
]
% tree
[
.
├── app
│   ├── build.gradle
│   └── src
│   ├── main
│   │   ├── java
│   │   │   └── org
│   │   │   └── example
│   │   │   └── App.java
│   │   └── resources
│   └── test
│   ├── java
│   │   └── org
│   │   └── example
│   │   └── AppTest.java
│   └── resources
├── gradle
│   ├── libs.versions.toml
│   └── wrapper
│   ├── gradle-wrapper.jar
│   └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
15 directories, 10 files
]
% cat app/src/main/java/org/example/App.java
[
/*
* This source file was generated by the Gradle 'init' task
*/
package org.example;
public class App {
public String getGreeting() {
return "Hello World!";
}
public static void main(String[] args) {
System.out.println(new App().getGreeting());
}
}
]
% rm -rf app/src/main/java/org/example/App.java
% cat app/src/test/java/org/example/AppTest.java
[
/*
* This source file was generated by the Gradle 'init' task
*/
package org.example;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class AppTest {
@Test void appHasAGreeting() {
App classUnderTest = new App();
assertNotNull(classUnderTest.getGreeting(), "app should have a greeting");
}
}
]
% rm -rf app/src/test/java/org/example/AppTest.java
% rm -rf app/src/main/java
% rm -rf app/src/test/java
% mkdir -p app/src/main/java/com/commons/project
% ls app/src/main/java/com/commons/project
% mkdir -p app/src/test/java/com/commons/project
% ls app/src/test/java/com/commons/project
% nano app/src/main/java/com/commons/project/App.java
[
package com.commons.project;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;
public class App {
public String getGreeting() {
return "Hello World!";
}
public static void main(String[] args) {
Context polyglot = Context.newBuilder().allowAllAccess(true).build();
Value array = polyglot.eval("ruby", "[1,2,42,4]");
int result = array.getArrayElement(2).asInt();
System.out.println(result);
System.out.println(new App().getGreeting());
}
}
]
% cat app/src/main/java/com/commons/project/App.java
% nano app/src/test/java/com/commons/project/AppTest.java
[
package com.commons.project;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class AppTest {
@Test void appHasAGreeting() {
App classUnderTest = new App();
assertNotNull(classUnderTest.getGreeting(), "app should have a greeting");
}
}
]
% cat app/src/test/java/com/commons/project/AppTest.java
% cat app/build.gradle
[
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java application project to get you started.
* For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.12/userguide/building_java_projects.html in the Gradle documentation.
* This project uses @Incubating APIs which are subject to change.
*/
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
id 'application'
}
repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}
dependencies {
// This dependency is used by the application.
implementation libs.guava
}
testing {
suites {
// Configure the built-in test suite
test {
// Use JUnit Jupiter test framework
useJUnitJupiter('5.11.1')
}
}
}
// Apply a specific Java toolchain to ease working on different environments.
java {
toolchain {
languageVersion = JavaLanguageVersion.of(23)
}
}
application {
// Define the main class for the application.
mainClass = 'org.example.App'
}
]
% rm -rf app/build.gradle
% nano app/build.gradle
[
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
id 'application'
}
repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}
dependencies {
// This dependency is used by the application.
implementation libs.guava
implementation 'org.graalvm.polyglot:polyglot:24.1.1'
implementation 'org.graalvm.polyglot:ruby:24.1.1'
}
testing {
suites {
// Configure the built-in test suite
test {
// Use JUnit Jupiter test framework
useJUnitJupiter('5.11.1')
}
}
}
// Apply a specific Java toolchain to ease working on different environments.
java {
toolchain {
languageVersion = JavaLanguageVersion.of(23)
}
}
application {
// Define the main class for the application.
mainClass = 'com.commons.project.App'
}
]
% cat app/build.gradle
% gradle wrapper
% ./gradlew run
[
% ./gradlew clean
]
% ./gradlew build
# yes
% ./gradlew build --scan
% jwebserver --directory $(pwd)/app/build/reports/tests/test --port 8000
# Terminal New Window
% curl http://127.0.0.1:8000/
% open http://127.0.0.1:8000/
===========================================================================================================================
# Java # WebAssembly (wasm) # GraalVM # Truffle # Espresso
===========================================================================================================================
% mkdir -p Espresso
% cd Espresso
% wget https://gds.oracle.com/download/espresso/archive/espresso-java21-24.0.1-macos-aarch64.tar.gz --directory-prefix="$HOME/Downloads/Software/Oracle/GraalVM"
% tar -xzf $HOME/Downloads/Software/Oracle/GraalVM/espresso-java21-24.0.1-macos-aarch64.tar.gz -C $HOME/Downloads/Software/Oracle/GraalVM
% ls $HOME/Downloads/Software/Oracle/GraalVM/graalvm-espresso-jdk-21.0.1+11.1
% ls $HOME/Downloads/Software/Oracle/GraalVM/graalvm-espresso-jdk-21.0.1+11.1/Contents/Home/bin
% export PATH="$HOME/Downloads/Software/Oracle/GraalVM/graalvm-espresso-jdk-21.0.1+11.1/Contents/Home/bin/":$PATH
% java --version
% java -truffle -version
% java -truffle --version
% jshell
[
jshell> System.getProperty("java.version");
System.getProperty("java.version")$1 ==> "21.0.1"
jshell> System.getProperty("java.vendor.version");
System.getProperty("java.vendor.version")$1 ==> "Oracle GraalVM 21.0.1+11.1"
jshell> System.getProperty("java.vm.name");
System.getProperty("java.vm.name")$1 ==> "Espresso 64-Bit VM"
jshell> /exit
]
% mkdir -p JavaEspressoTruffle
% cd JavaEspressoTruffle
% nano App.java
[
class App {
public static void main(String[] args) {
System.out.println("Hola, Java Espresso Truffle!");
System.out.println(String.format("Java Version: %s", System.getProperty("java.version")));
System.out.println(String.format("Java Vendor Version: %s", System.getProperty("java.vendor.version")));
System.out.println(String.format("Java VM Name: %s", System.getProperty("java.vm.name")));
}
}
]
% cat App.java
[
% javac App.java
% java App
% rm -rf *.class
]
% java App.java
***************************************************************************************************************************
***************************************************************************************************************************
# Docker # Docker Desktop.app # Docker cleanup
**************************************************************************************************************************
% docker version
% docker ps --all --quiet
% docker stop $(docker ps -a -q)
% docker rm $(docker ps -a -q) --force
% docker container list --all --quiet
% docker stop $(docker container list -a -q)
% docker rm $(docker container list -a -q) --force
% docker container prune
% docker image list --all --quiet
% docker rmi $(docker image list -a -q) --force
% docker image prune --all
% docker volume list --quiet
% docker volume rm $(docker volume list --quiet) --force
% docker volume prune --all
% docker network list --quiet --filter "type=custom"
% docker network rm $(docker network list --quiet --filter "type=custom")
% docker network prune
% docker system info
% docker system prune --all --volumes
***************************************************************************************************************************
***************************************************************************************************************************
# CS # WebAssembly (wasm) # dotnet # wasmbrowser # Node.js # wasmconsole
***************************************************************************************************************************
% mkdir -p CS
% cd CS
% dotnet --version
% dotnet new console --name Wasm
% cd Wasm
[
% dotnet new sln -n Wasm
% dotnet sln Wasm.sln add Wasm.csproj
]
% dotnet run
% nano Wasm.csproj
[
<Project Sdk="Microsoft.NET.Sdk.WebAssembly">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
</Project>
]
% cat Wasm.csproj
% nano Program.cs
[
using System;
using System.Threading.Tasks;
internal class Program
{
private static async Task Main()
{
int result = await Interop.Run(555, 777);
Console.WriteLine($"CS Task Main() await = {result}");
}
}
]
% cat Program.cs
% nano Interop.cs
[
using System;
using System.Runtime.InteropServices.JavaScript;
using System.Threading.Tasks;
public partial class Interop
{
[JSImport("math", "Shim")]
[return: JSMarshalAs<JSType.Number>]
public static partial int Math([JSMarshalAs<JSType.Number>] int x, [JSMarshalAs<JSType.Number>] int y);
[JSExport]
public static async Task<int> Run(int x, int y)
{
await JSHost.ImportAsync("Shim", "/Shim.js");
int result = Interop.Math(x, y);
Console.WriteLine($"Math from CS loaded JS module: {x} * {y} = {result}");
return result;
}
}
]
% cat Interop.cs
% mkdir -p wwwroot
% ls wwwroot
% nano wwwroot/index.js
[
import { dotnet } from './_framework/dotnet.js'
const { setModuleImports, getAssemblyExports, getConfig, runMain } = await dotnet
.withApplicationArguments("start")
.create();
const config = getConfig();
const exports = await getAssemblyExports(config.mainAssemblyName);
try {
const x = 5;
const y = 7;
const result = JSON.stringify(await exports.Interop.Run(x, y));
document.body.innerHTML = `Browser: ${navigator.userAgent} <br\><br\> Math: ${x} x ${y} = ${result}`;
} catch(error) {
console.error(error);
}
await dotnet.run();
]
% cat wwwroot/index.js
% nano wwwroot/Shim.js
[
export function math(x, y) {
console.log(`Math from JavaScript: ${x} * ${y} = ${x + y}`);
return (x * y);
}
]
% cat wwwroot/Shim.js
% nano wwwroot/index.html
[
<!DOCTYPE html>
<html>
<head>
<title>CS WebAssembly</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>CS WebAssembly</title>
<script type="module" src="./index.js"></script>
</head>
<body></body>
</html>
]
% cat wwwroot/index.html
[
% wget https://www.google.com/favicon.ico --directory-prefix=wwwroot
]
% ls wwwroot
% dotnet build
% dotnet run
===========================================================================================================================
# Terminal New Window
# curl http(s) or open http(s) form dotnet run
===========================================================================================================================
# Manual # Copy # Build # Release
===========================================================================================================================
[
% dotnet restore
% dotnet clean
% dotnet build --configuration Debug
% dotnet build --configuration Release
]
[
% cp -r Wasm/bin/Release/net9.0 WasmRelease
% cp Wasm/wwwroot/* WasmRelease/wwwroot
% cp WasmRelease/wwwroot/_framework/blazor.boot.json WasmRelease/wwwroot
% cd WasmRelease/wwwroot
]
===========================================================================================================================
# Publish # Release # Default
===========================================================================================================================
[
% dotnet restore
% dotnet clean
% dotnet build --configuration Debug
% dotnet build --configuration Release
]
[
% rm -rf bin
% rm -rf obj
]
% dotnet publish
% cd bin/Release/net9.0/publish/wwwroot
===========================================================================================================================
# HTTP Server
===========================================================================================================================
[
% npm install http-server --global
]
% npm --version
% http-server -p 8000
[
% python3 --version
% python3 -m http.server 8000
]
[
% export PATH="$HOME/Downloads/Software/OpenJDK/JDK23.0.1/jdk-23.0.1.jdk/Contents/Home/bin/":$PATH
% java --version
% jwebserver --port 8000
]
[
% ruby --version
% gem install webrick
% ruby -run -e httpd . -p 8000
]
[
% php --version
% php -S 127.0.0.1:8000
]
===========================================================================================================================
# Terminal New Window
% curl http://127.0.0.1:8000
% open http://127.0.0.1:8000
===========================================================================================================================
# CS # WebAssembly (wasm) # dotnet # wasmbrowser
===========================================================================================================================
% dotnet --version
# CS # WebAssembly (wasm) # dotnet # wasmbrowser
[
# Prerequisites # JavaScript interop on WASM
% dotnet workload install wasm-tools
# Experimental workload and project templates
% dotnet workload install wasm-experimental
% dotnet new install Microsoft.NET.Runtime.WebAssembly.Templates
]
# CS # WebAssembly (wasm) # dotnet # wasmbrowser
% dotnet new wasmbrowser --name WasmBrowser
% cd WasmBrowser
% dotnet build
% dotnet run
===========================================================================================================================
# Terminal New Window
# curl http(s) or open http(s) form dotnet run
===========================================================================================================================
# CS # WebAssembly (wasm) # dotnet # wasmconsole # Node.js
===========================================================================================================================
% dotnet --version
# CS # WebAssembly (wasm) # dotnet # wasmconsole # Node.js
% dotnet new wasmconsole --name WasmConsole
% cd WasmConsole
[
% sudo dotnet workload restore
]
[
% dotnet build -c Debug
]
% dotnet build -c Release
[
% dotnet run -c Debug
]
% dotnet run -c Release
[
WasmAppHost --runtime-config /Users/rajaniapple/Desktop/GitHub/JavaScript-1/WebAssembly/CS/WasmConsole/bin/Release/net9.0/browser-wasm/AppBundle/WasmConsole.runtimeconfig.json
MONO_WASM: Error loading symbol file dotnet.native.js.symbols: {}
Hello, World! Greetings from node version: v23.1.0
Hello, Console!
]
[
% node bin/Debug/net9.0/browser-wasm/AppBundle/main.mjs
]
% node bin/Release/net9.0/browser-wasm/AppBundle/main.mjs
[
MONO_WASM: Error loading symbol file dotnet.native.js.symbols: {}
Hello, World! Greetings from node version: v23.1.0
Hello, Console!
]
===========================================================================================================================
# CS # WebAssembly (wasm) # blazorwasm # dotnet # Blazor
===========================================================================================================================
% dotnet new list
[
% dotnet new blazorwasm
]
% dotnet new blazorwasm --output BlazorWasmApp
% cd BlazorWasmApp
% dotnet run
# Terminal New Window # curl # wget # open
% curl http://localhost:5289
% open http://localhost:5289
[
% dotnet new blazorwasm-empty
]
% dotnet new blazorwasm-empty --output BlazorWasmEmptyApp
% cd BlazorWasmEmptyApp
% dotnet run
# Terminal New Window # curl # wget # open
% curl http://localhost:5012
% open http://localhost:5012
===========================================================================================================================
***************************************************************************************************************************
***************************************************************************************************************************
# FS # WebAssembly (wasm) # Bolero
***************************************************************************************************************************
% mkdir -p FS
% cd FS
% dotnet --version
# Creating a project
[
% sudo dotnet new -i Bolero.Templates
]
% sudo dotnet new install Bolero.Templates
[
% sudo dotnet workload update
]
[
% sudo dotnet new bolero-app -o FSWebAssembly
]
% sudo dotnet new bolero-app -o FSWebAssembly --force
% ls
% cd FSWebAssembly
[
% sudo dotnet run --project src/FSWebAssembly.Server
]
# The ASP.NET Core developer certificate is in an invalid state. To fix this issue, run 'dotnet dev-certs https --clean' and 'dotnet dev-certs https' to remove all existing ASP.NET Core development certificates and create a new untrusted developer certificate. On macOS or Windows, use 'dotnet dev-certs https --trust' to trust the new certificate.
[
% sudo dotnet dev-certs https --trust
]
[
% sudo dotnet dev-certs https --clean
% sudo dotnet dev-certs https
% sudo dotnet dev-certs https --trust
]
% sudo dotnet run --project src/FSWebAssembly.Server
===========================================================================================================================
# Terminal New Window # http(s) # curl # wget # open
===========================================================================================================================
---------------------------------------------------------------------------------------------------------------------------
# https
---------------------------------------------------------------------------------------------------------------------------
# curl: (60) SSL certificate problem: unable to get local issuer certificate
# More details here: https://curl.se/docs/sslcerts.html
# -k
% curl -k https://localhost:44303/
# ERROR: cannot verify localhost's certificate, issued by ‘CN=localhost’:
# Self-signed certificate encountered.
# To connect to localhost insecurely, use `--no-check-certificate'.
# --no-check-certificate
% wget -S -O - https://localhost:44303/ --no-check-certificate
% open https://localhost:44303/
---------------------------------------------------------------------------------------------------------------------------
# http
---------------------------------------------------------------------------------------------------------------------------
% curl http://localhost:5015/
% wget -S -O - http://localhost:5015/
% open http://localhost:5015/
---------------------------------------------------------------------------------------------------------------------------
===========================================================================================================================
# Browser
# https://localhost:44303/ # http://localhost:5015/
# Sign in
[
Username: fsharp
Password: password
]
sign in
# Click Reload
# Sign out
***************************************************************************************************************************
***************************************************************************************************************************
# Ruby # WebAssembly (wasm) # WASI # ruby.wasm # wasmtime # Node.js
***************************************************************************************************************************
===========================================================================================================================
# Ruby # WebAssembly (wasm) # Browser
===========================================================================================================================
% mkdir -p Ruby
% cd Ruby
% mkdir -p "Ruby on Browser"
% cd "Ruby on Browser"
% nano index.html
[
<html>
<script src="https://cdn.jsdelivr.net/npm/@ruby/[email protected]/dist/browser.script.iife.js"></script>
<script type="text/ruby">
require "js"
# (Printed to the Web browser console)
# option + command + I
# Safari > Settings > Advanced > Select “Show features for web developers”
puts RUBY_VERSION
x = 5;
y = 7;
puts "Math: #{x} x #{y} = #{x * y}"
JS.global[:document].write "Hola!"
</script>
</html>
]
% cat index.html
% open -n -a "Google Chrome" --args "--new-window" "file:///$HOME/Desktop/GitHub/JavaScript-1/WebAssembly/Ruby/Ruby%20on%20Browser/index.html"
# Run Ruby on browser by using browser.script.iife.js script from CDN
% nano ruby_on_browser.html
[
<html>
<script src="https://cdn.jsdelivr.net/npm/@ruby/[email protected]/dist/browser.script.iife.js"></script>
<script type="text/ruby">
require "js"
JS.global[:document].write "Hola!"
</script>
</html>
]
% cat ruby_on_browser.html
% open -n -a "Google Chrome" --args "--new-window" "file:///$HOME/Desktop/GitHub/JavaScript-1/WebAssembly/Ruby/Ruby%20on%20Browser/ruby_on_browser.html"
# Control Ruby VM from JavaScript by using @ruby/wasm-wasi package API
% nano ruby_wasm_wasi.html
[
<html>
<script type="module">
import { DefaultRubyVM } from "https://cdn.jsdelivr.net/npm/@ruby/[email protected]/dist/browser/+esm";
const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/[email protected]/dist/ruby+stdlib.wasm");
const module = await WebAssembly.compileStreaming(response);
const { vm } = await DefaultRubyVM(module);
vm.eval(`
require "js"
JS.global[:document].write "Hola!"
`);
</script>
</html>
]
% cat ruby_wasm_wasi.html
% open -n -a "Google Chrome" --args "--new-window" "file:///$HOME/Desktop/GitHub/JavaScript-1/WebAssembly/Ruby/Ruby%20on%20Browser/ruby_wasm_wasi.html"
# Alternative Without ES Modules
% nano ruby_wasm_wasi_without_es.html
[
<html>
<script src="https://cdn.jsdelivr.net/npm/@ruby/[email protected]/dist/browser.umd.js"></script>
<script>
const main = async () => {
const { DefaultRubyVM } = window["ruby-wasm-wasi"];
const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/[email protected]/dist/ruby+stdlib.wasm");
const module = await WebAssembly.compileStreaming(response);
const { vm } = await DefaultRubyVM(module);
vm.eval(`
require "js"
JS.global[:document].write "Hola!"
`);
}
main()
</script>
</html>
]
% cat ruby_wasm_wasi_without_es.html
% open -n -a "Google Chrome" --args "--new-window" "file:///$HOME/Desktop/GitHub/JavaScript-1/WebAssembly/Ruby/Ruby%20on%20Browser/ruby_wasm_wasi_without_es.html"
# await JavaScript Promise from Ruby
# data-eval="async" attribute is required to use await in <script> tag
% nano async_await.html
[
<html>
<script src="https://cdn.jsdelivr.net/npm/@ruby/[email protected]/dist/browser.script.iife.js"></script>
<script type="text/ruby" data-eval="async">
require "js"
response = JS.global.fetch("https://www.ruby-lang.org/").await
# (Printed to the Web browser console)
# option + command + I
# Safari > Settings > Advanced > Select “Show features for web developer
puts response[:status]
</script>
</html>
]
% cat async_await.html
% open -n -a "Google Chrome" --args "--new-window" "file:///$HOME/Desktop/GitHub/JavaScript-1/WebAssembly/Ruby/Ruby%20on%20Browser/async_await.html"
# Or using @ruby/wasm-wasi package API RubyVM#evalAsync
% nano async_await_wasm_wasi.html
[
<html>
<script type="module">
import { DefaultRubyVM } from "https://cdn.jsdelivr.net/npm/@ruby/[email protected]/dist/browser/+esm";
const response = await fetch("https://cdn.jsdelivr.net/npm/@ruby/[email protected]/dist/ruby+stdlib.wasm");
const module = await WebAssembly.compileStreaming(response);
const { vm } = await DefaultRubyVM(module);
vm.evalAsync(`
require "js"
response = JS.global.fetch("https://www.ruby-lang.org/").await
# (Printed to the Web browser console)
# option + command + I
# Safari > Settings > Advanced > Select “Show features for web developer
puts response[:status]
`);
</script>
</html>
]
% cat async_await_wasm_wasi.html
% open -n -a "Google Chrome" --args "--new-window" "file:///$HOME/Desktop/GitHub/JavaScript-1/WebAssembly/Ruby/Ruby%20on%20Browser/async_await_wasm_wasi.html"
===========================================================================================================================
# NB
===========================================================================================================================
# Get/set JavaScript variables from Ruby
[
require "js"
document = JS.global[:document]
document[:title] = "Hello, world!"
]
# Call JavaScript methods from Ruby
[
require "js"
JS.global[:document].createElement("div")
JS.global[:document].call(:createElement, "div".to_js) # same as above
]
# Pass Ruby Proc to JavaScript (Callback to Ruby)
[
require "js"
JS.global.setTimeout(proc { puts "Hello, world!" }, 1000)
input = JS.global[:document].querySelector("input")
input.addEventListener("change") do |event|
puts event[:target][:value].to_s
end
]
# new JavaScript instance from Ruby
[
require "js"
JS.global[:Date].new(2000, 9, 13)
]
# Convert returned JavaScript String value to Ruby String
[
require "js"
title = JS.global[:document].title # => JS::Object("Hello, world!")
title.to_s # => "Hello, world!"
]
# Convert JavaScript Boolean value to Ruby true/false
[
require "js"
JS.global[:document].hasFocus? # => true
JS.global[:document].hasFocus # => JS::Object(true)
]
# Convert JavaScript Number value to Ruby Integer/Float
[
require "js"
rand = JS.global[:Math].random # JS::Object(0.123456789)
rand.to_i # => 0
rand.to_f # => 0.123456789
]
===========================================================================================================================
# CDN
===========================================================================================================================
% wget https://cdn.jsdelivr.net/npm/@ruby/[email protected]/dist/browser.script.iife.js --directory-prefix=CDN
% wget https://cdn.jsdelivr.net/npm/@ruby/[email protected]/dist/browser/+esm --directory-prefix=CDN
% wget https://cdn.jsdelivr.net/npm/@ruby/[email protected]/dist/ruby+stdlib.wasm --directory-prefix=CDN
% wget https://cdn.jsdelivr.net/npm/@ruby/[email protected]/dist/browser.umd.js --directory-prefix=CDN
===========================================================================================================================
# HTTP Server
===========================================================================================================================
[
% npm install http-server --global
]
% npm --version
% http-server -p 8000
[
% python3 --version
% python3 -m http.server 8000
]
[
% export PATH="$HOME/Downloads/Software/OpenJDK/JDK23.0.1/jdk-23.0.1.jdk/Contents/Home/bin/":$PATH
% java --version
% jwebserver --port 8000
]
[
% ruby --version
% gem install webrick
% ruby -run -e httpd . -p 8000
]
[
% php --version
% php -S 127.0.0.1:8000
]
===========================================================================================================================
# Terminal New Window
===========================================================================================================================
% curl http://127.0.0.1:8000/index.html
% open http://127.0.0.1:8000/index.html
% curl http://127.0.0.1:8000/ruby_on_browser.html
% open http://127.0.0.1:8000/ruby_on_browser.html
% curl http://127.0.0.1:8000/ruby_wasm_wasi.html
% open http://127.0.0.1:8000/ruby_wasm_wasi.html
% curl http://127.0.0.1:8000/ruby_wasm_wasi_without_es.html
% open http://127.0.0.1:8000/ruby_wasm_wasi_without_es.html
% curl http://127.0.0.1:8000/async_await.html
% open http://127.0.0.1:8000/async_await.html
% curl http://127.0.0.1:8000/async_await_wasm_wasi.html
% open http://127.0.0.1:8000/async_await_wasm_wasi.html
===========================================================================================================================
# Ruby # WebAssembly (wasm) # WASI # ruby.wasm # wasmtime
===========================================================================================================================
# Package Ruby application as a WASI application
% mkdir -p Ruby
% cd Ruby
% ruby --version
% gem --version
% gem install ruby_wasm
# Download a prebuilt Ruby release
% curl -LO https://github.com/ruby/ruby.wasm/releases/latest/download/ruby-3.3-wasm32-unknown-wasip1-full.tar.gz
% sudo tar xfz ruby-3.3-wasm32-unknown-wasip1-full.tar.gz
# Extract ruby binary not to pack itself
% sudo mv ruby-3.3-wasm32-unknown-wasip1-full/usr/local/bin/ruby ruby.wasm
# Put the app code
% mkdir -p src
% echo "puts 'Ruby: ' + RUBY_DESCRIPTION" > src/wasi_app.rb
# Ruby
% ruby src/wasi_app.rb
% tree
# Pack the whole directory under /usr and the app dir # wasi-ruby-app.wasm
% rbwasm pack ruby.wasm --dir ./src::/src --dir ./ruby-3.3-wasm32-unknown-wasip1-full/usr::/usr -o wasi-ruby-app.wasm
% tree
# Dependencies: wasmtime
# Run the packed scripts
# wasmtime installation
[
% wget https://wasmtime.dev/install.sh
]
% curl https://wasmtime.dev/install.sh -sSf | bash
# Terminal New Window
% wasmtime wasi-ruby-app.wasm /src/wasi_app.rb
[
Ruby: ruby 3.3.3 (2024-06-12 revision f1c7b6f435) [wasm32-wasi]
]
===========================================================================================================================
# Ruby # WebAssembly (wasm) # npm install --save @ruby/3.3-wasm-wasi @ruby/wasm-wasi # Node.js
===========================================================================================================================
% mkdir -p NodeJS
% cd NodeJS
% npm --version
# Install @ruby/3.3-wasm-wasi and @ruby/wasm-wasi from npm
% npm install --save @ruby/3.3-wasm-wasi @ruby/wasm-wasi
# Instantiate a Ruby VM
% nano index.mjs
[
import fs from "fs/promises";
import { DefaultRubyVM } from "@ruby/wasm-wasi/dist/node";
const binary = await fs.readFile("./node_modules/@ruby/3.3-wasm-wasi/dist/ruby.wasm");
const module = await WebAssembly.compile(binary);
const { vm } = await DefaultRubyVM(module);
vm.eval(`puts "Ruby Version: " + RUBY_VERSION`);
vm.eval(`puts "Ruby Description: " + RUBY_DESCRIPTION`);
vm.eval(`x = 5; y = 7; puts "Math: #{x} x #{y} = #{x * y}"`);;
]
% cat index.mjs
# Run the code with --experimental-wasi-unstable-preview1 flag to enable WASI support
% node --experimental-wasi-unstable-preview1 index.mjs
[
(node:3010) ExperimentalWarning: WASI is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
`RubyGems' were not loaded.
`error_highlight' was not loaded.
`did_you_mean' was not loaded.
`syntax_suggest' was not loaded.
Ruby Version: 3.3.3
Ruby Description: ruby 3.3.3 (2024-06-12 revision f1c7b6f435) [wasm32-wasi]
Math: 5 x 7 = 35
]
===========================================================================================================================
***************************************************************************************************************************
###########################################################################################################################
// Credits
/*
https://webassembly.org/
https://wasi.dev/
https://wasmtime.dev/
https://w3.org/
https://developer.mozilla.org/
https://emscripten.org/
https://nodejs.org/
https://npmjs.com/
https://typescriptlang.org/
https://assemblyscript.org/
https://swift.org/
https://developer.apple.com/
https://swiftwasm.org/
https://go.dev/
https://tinygo.org/
https://developers.google.com/
https://web.dev/
https://rust-lang.org/
https://python.org/
https://pypi.org/
https://pyodide.org/
https://openjdk.org/
https://oracle.com/java/
https://spring.io/
https://graalvm.org/
https://dotnet.microsoft.com/
https://developer.microsoft.com/
https://fsharp.org/
https://foundation.fsharp.org/
https://fsbolero.io/
https://nuget.org/
https://ruby-lang.org/
https://rubygems.org/
https://php.net/
https://gcc.gnu.org/
https://docker.com/
https://maven.apache.org/
https://gradle.org/
https://gradle.com/
https://groovy-lang.org/
https://kotlinlang.org/
https://toml.io/
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment