mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Merge pull request #182 from rmliddle/wasm-steps
Exposes API for running Python via JS
This commit is contained in:
60
README.md
60
README.md
@@ -98,9 +98,14 @@ $ cargo run -- -c 'import statistics'
|
||||
|
||||
# Compiling to WebAssembly
|
||||
|
||||
At this stage RustPython only has preliminary support for web assembly. The instructions here are intended for developers or those wishing to run a toy example.
|
||||
|
||||
## Setup
|
||||
|
||||
Using `rustup` add the compile target `wasm32-unknown-emscripten`. To do so you will need to have [rustup](https://rustup.rs/) installed.
|
||||
To get started, install [wasm-bingden](https://rustwasm.github.io/wasm-bindgen/whirlwind-tour/basic-usage.html)
|
||||
and [wasm-webpack](https://rustwasm.github.io/wasm-pack/installer/). You will also need to have `npm` installed.
|
||||
|
||||
<!-- Using `rustup` add the compile target `wasm32-unknown-emscripten`. To do so you will need to have [rustup](https://rustup.rs/) installed.
|
||||
|
||||
```bash
|
||||
rustup target add wasm32-unknown-emscripten
|
||||
@@ -114,41 +119,58 @@ cd emsdk-portable/
|
||||
./emsdk update
|
||||
./emsdk install sdk-incoming-64bit
|
||||
./emsdk activate sdk-incoming-64bit
|
||||
source ./emsdk_env.sh
|
||||
```
|
||||
``` -->
|
||||
|
||||
|
||||
|
||||
## Build
|
||||
|
||||
Move into the `wasm` directory. This contains a custom binary crate optimized for a web assembly build.
|
||||
Move into the `wasm` directory. This contains a custom library crate optimized for wasm build of RustPython.
|
||||
|
||||
```bash
|
||||
cd wasm
|
||||
```
|
||||
|
||||
From here run the build. This can take several minutes depending on the machine.
|
||||
```
|
||||
cargo build --target=wasm32-unknown-emscripten --release
|
||||
```
|
||||
|
||||
Upon successful build, the following files will be available:
|
||||
|
||||
|
||||
```
|
||||
target/wasm32-unknown-emscripten/release/rustpython_wasm.wasm
|
||||
target/wasm32-unknown-emscripten/release/rustpython_wasm.js
|
||||
wasm-pack build
|
||||
```
|
||||
|
||||
- `rustpython_wasm.wasm`: the wasm build for rustpython. It includes both an parser and virtual machine.
|
||||
- `rustpython_wasm.js`: the loading scripts for the above wasm file.
|
||||
|
||||
You will also find `index.html` in the `wasm` directory.
|
||||
From here, you can copy these 3 files into the static assets directory of your web server and you should be
|
||||
able to see the ouput in the web console of your browser.
|
||||
Upon successful build, cd in the the `/pkg` directory and run:
|
||||
|
||||
```
|
||||
Hello RustPython!
|
||||
npm link
|
||||
```
|
||||
|
||||
Now move back out into the `/app` directory. The files here have been adapted from [wasm-pack-template](https://github.com/rustwasm/wasm-pack-template).
|
||||
|
||||
Finally, run:
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
and you will be able to run the files with:
|
||||
|
||||
```
|
||||
webpack-dev-server
|
||||
```
|
||||
|
||||
Open a browser console and see the output of rustpython_wasm. To verify this, modify the line in `app/index.js`
|
||||
|
||||
```js
|
||||
rp.run_code("print('Hello Python!')\n");
|
||||
```
|
||||
|
||||
To the following:
|
||||
|
||||
```js
|
||||
rp.run_code("assert(False)\n");
|
||||
```
|
||||
|
||||
and you should observe: `Execution failed` in your console output, indicating that the execution of RustPython has failed.
|
||||
|
||||
# Code style
|
||||
|
||||
The code style used is the default rustfmt codestyle. Please format your code accordingly.
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
[package]
|
||||
name = "rustpython_wasm"
|
||||
version = "0.1.0"
|
||||
authors = ["rmliddle <ryan@rmliddle.com>"]
|
||||
authors = ["Ryan Liddle <ryan@rmliddle.com>"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[workspace]
|
||||
members = []
|
||||
@@ -9,6 +12,9 @@ members = []
|
||||
[dependencies]
|
||||
rustpython_parser = {path = "../parser"}
|
||||
rustpython_vm = {path = "../vm"}
|
||||
cfg-if = "0.1.2"
|
||||
wasm-bindgen = "0.2"
|
||||
|
||||
|
||||
[profile.release]
|
||||
opt-level = 's'
|
||||
opt-level = "s"
|
||||
|
||||
5
wasm/app/bootstrap.js
vendored
Normal file
5
wasm/app/bootstrap.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
// A dependency graph that contains any wasm must all be imported
|
||||
// asynchronously. This `bootstrap.js` file does the single async import, so
|
||||
// that no one else needs to worry about it again.
|
||||
import("./index.js")
|
||||
.catch(e => console.error("Error importing `index.js`:", e));
|
||||
10
wasm/app/index.html
Normal file
10
wasm/app/index.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>RustPython Starter Application</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="./bootstrap.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
3
wasm/app/index.js
Normal file
3
wasm/app/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import * as rp from "rustpython_wasm";
|
||||
|
||||
rp.run_code("print('Hello Python!')\n");
|
||||
27
wasm/app/package.json
Normal file
27
wasm/app/package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "app",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"hello-wasm-pack": "^0.1.0",
|
||||
"webpack": "^4.16.3",
|
||||
"webpack-cli": "^3.1.0",
|
||||
"webpack-dev-server": "^3.1.5",
|
||||
"copy-webpack-plugin": "^4.5.2"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/RustPython/RustPython.git"
|
||||
},
|
||||
"author": "Ryan Liddle",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/RustPython/RustPython/issues"
|
||||
},
|
||||
"homepage": "https://github.com/RustPython/RustPython#readme"
|
||||
}
|
||||
14
wasm/app/webpack.config.js
Normal file
14
wasm/app/webpack.config.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
entry: "./bootstrap.js",
|
||||
output: {
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
filename: "bootstrap.js",
|
||||
},
|
||||
mode: "development",
|
||||
plugins: [
|
||||
new CopyWebpackPlugin(['index.html'])
|
||||
],
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>RustPython/Wasm</title>
|
||||
<script>
|
||||
var Module = {
|
||||
wasmBinaryFile: "rustpython_wasm.wasm"
|
||||
}
|
||||
</script>
|
||||
<script src="rustpython_wasm.js"></script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
28
wasm/src/lib.rs
Normal file
28
wasm/src/lib.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
extern crate rustpython_vm;
|
||||
extern crate wasm_bindgen;
|
||||
use rustpython_vm::compile;
|
||||
use rustpython_vm::VirtualMachine;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
// Use `js_namespace` here to bind `console.log(..)` instead of just
|
||||
// `log(..)`
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn log(s: &str);
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn run_code(source: &str) -> () {
|
||||
//add hash in here
|
||||
log("Running RustPython");
|
||||
log(&source.to_string());
|
||||
let mut vm = VirtualMachine::new();
|
||||
let code_obj = compile::compile(&mut vm, &source.to_string(), compile::Mode::Exec, None);
|
||||
let builtins = vm.get_builtin_scope();
|
||||
let vars = vm.context().new_scope(Some(builtins));
|
||||
match vm.run_code_obj(code_obj.unwrap(), vars) {
|
||||
Ok(_value) => log("Execution successful"),
|
||||
Err(_) => log("Execution failed"),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user