mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-12 18:41:02 +00:00
Add support for esm and cjs modules
This commit is contained in:
@@ -8,7 +8,7 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
REVIVE_WASM_INSTALL_DIR: ${{ github.workspace }}/target/wasm32-unknown-emscripten/release
|
REVIVE_WASM_INSTALL_DIR: ${{ github.workspace }}/js/dist/revive-cjs
|
||||||
EMSCRIPTEN_VERSION: 3.1.64
|
EMSCRIPTEN_VERSION: 3.1.64
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -75,5 +75,6 @@ jobs:
|
|||||||
name: revive-wasm
|
name: revive-wasm
|
||||||
path: |
|
path: |
|
||||||
${{ env.REVIVE_WASM_INSTALL_DIR }}/resolc.js
|
${{ env.REVIVE_WASM_INSTALL_DIR }}/resolc.js
|
||||||
|
${{ env.REVIVE_WASM_INSTALL_DIR }}/worker.js
|
||||||
${{ env.REVIVE_WASM_INSTALL_DIR }}/resolc.wasm
|
${{ env.REVIVE_WASM_INSTALL_DIR }}/resolc.wasm
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|||||||
+2
-1
@@ -14,5 +14,6 @@ artifacts
|
|||||||
tmp
|
tmp
|
||||||
package-lock.json
|
package-lock.json
|
||||||
/*.html
|
/*.html
|
||||||
/js/resolc.*
|
/js/src/resolc.*
|
||||||
|
/js/dist/
|
||||||
/build
|
/build
|
||||||
|
|||||||
@@ -11,20 +11,22 @@ RUSTFLAGS_EMSCRIPTEN := \
|
|||||||
-Clink-arg=-sMODULARIZE \
|
-Clink-arg=-sMODULARIZE \
|
||||||
-Clink-arg=-sEXPORT_ES6 \
|
-Clink-arg=-sEXPORT_ES6 \
|
||||||
-Clink-arg=-sEXPORT_NAME=createRevive \
|
-Clink-arg=-sEXPORT_NAME=createRevive \
|
||||||
-Clink-arg=--js-library=js/soljson_interface.js \
|
-Clink-arg=--js-library=js/embed/soljson_interface.js \
|
||||||
-Clink-arg=--pre-js=js/pre.js
|
-Clink-arg=--pre-js=js/embed/pre.js
|
||||||
|
|
||||||
install: install-bin install-npm
|
install: install-bin install-npm
|
||||||
|
|
||||||
install-bin:
|
install-bin:
|
||||||
cargo install --path crates/solidity
|
cargo install --path crates/solidity
|
||||||
|
|
||||||
install-wasm:
|
|
||||||
RUSTFLAGS='$(RUSTFLAGS_EMSCRIPTEN)' cargo install --target wasm32-unknown-emscripten --path crates/solidity
|
|
||||||
|
|
||||||
install-npm:
|
install-npm:
|
||||||
npm install && npm fund
|
npm install && npm fund
|
||||||
|
|
||||||
|
install-wasm:
|
||||||
|
RUSTFLAGS='$(RUSTFLAGS_EMSCRIPTEN)' cargo build --target wasm32-unknown-emscripten -p revive-solidity --release --no-default-features
|
||||||
|
npm install
|
||||||
|
npm run build:revive
|
||||||
|
|
||||||
# install-revive: Build and install to the directory specified in REVIVE_INSTALL_DIR
|
# install-revive: Build and install to the directory specified in REVIVE_INSTALL_DIR
|
||||||
ifeq ($(origin REVIVE_INSTALL_DIR), undefined)
|
ifeq ($(origin REVIVE_INSTALL_DIR), undefined)
|
||||||
REVIVE_INSTALL_DIR=`pwd`/release/revive-debian
|
REVIVE_INSTALL_DIR=`pwd`/release/revive-debian
|
||||||
@@ -75,4 +77,6 @@ clean:
|
|||||||
rm -rf node_modules ; \
|
rm -rf node_modules ; \
|
||||||
rm -rf crates/solidity/src/tests/cli-tests/artifacts ; \
|
rm -rf crates/solidity/src/tests/cli-tests/artifacts ; \
|
||||||
cargo uninstall revive-solidity ; \
|
cargo uninstall revive-solidity ; \
|
||||||
rm -f package-lock.json
|
rm -f package-lock.json ; \
|
||||||
|
rm -rf js/dist ; \
|
||||||
|
rm -f js/src/resolc.{wasm,js}
|
||||||
|
|||||||
@@ -49,9 +49,5 @@ libc = { workspace = true }
|
|||||||
inkwell = { workspace = true, features = ["target-riscv", "llvm18-0-no-llvm-linking"]}
|
inkwell = { workspace = true, features = ["target-riscv", "llvm18-0-no-llvm-linking"]}
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
|
||||||
parallel = ["rayon"]
|
parallel = ["rayon"]
|
||||||
|
|
||||||
# Enable parallel by default only for non-emscripten targets
|
|
||||||
[target.'cfg(not(target_os = "emscripten"))'.features]
|
|
||||||
default = ["parallel"]
|
default = ["parallel"]
|
||||||
|
|||||||
@@ -7,10 +7,62 @@ pub mod output;
|
|||||||
#[cfg(target_os = "emscripten")]
|
#[cfg(target_os = "emscripten")]
|
||||||
pub mod worker_process;
|
pub mod worker_process;
|
||||||
|
|
||||||
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
use self::input::Input;
|
use self::input::Input;
|
||||||
use self::output::Output;
|
use self::output::Output;
|
||||||
|
|
||||||
pub trait Process {
|
pub trait Process {
|
||||||
fn run(input_file: Option<&mut std::fs::File>) -> anyhow::Result<()>;
|
/// Read input from `stdin`, compile a contract, and write the output to `stdout`.
|
||||||
|
fn run(input_file: Option<&mut std::fs::File>) -> anyhow::Result<()> {
|
||||||
|
let mut stdin = std::io::stdin();
|
||||||
|
let mut stdout = std::io::stdout();
|
||||||
|
let mut stderr = std::io::stderr();
|
||||||
|
|
||||||
|
let mut buffer = Vec::with_capacity(16384);
|
||||||
|
match input_file {
|
||||||
|
Some(ins) => {
|
||||||
|
if let Err(error) = ins.read_to_end(&mut buffer) {
|
||||||
|
anyhow::bail!("Failed to read recursive process input file: {:?}", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
if let Err(error) = stdin.read_to_end(&mut buffer) {
|
||||||
|
anyhow::bail!(
|
||||||
|
"Failed to read recursive process input from stdin: {:?}",
|
||||||
|
error
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let input: Input = revive_common::deserialize_from_slice(buffer.as_slice())?;
|
||||||
|
let result = input.contract.compile(
|
||||||
|
input.project,
|
||||||
|
input.optimizer_settings,
|
||||||
|
input.include_metadata_hash,
|
||||||
|
input.debug_config,
|
||||||
|
);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(build) => {
|
||||||
|
let output = Output::new(build);
|
||||||
|
let json = serde_json::to_vec(&output).expect("Always valid");
|
||||||
|
stdout
|
||||||
|
.write_all(json.as_slice())
|
||||||
|
.expect("Stdout writing error");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
let message = error.to_string();
|
||||||
|
stderr
|
||||||
|
.write_all(message.as_bytes())
|
||||||
|
.expect("Stderr writing error");
|
||||||
|
Err(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs this process recursively to compile a single contract.
|
||||||
fn call(input: Input) -> anyhow::Result<Output>;
|
fn call(input: Input) -> anyhow::Result<Output>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
//! Process for compiling a single compilation unit.
|
//! Process for compiling a single compilation unit.
|
||||||
|
|
||||||
use std::io::Read;
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
@@ -17,57 +16,6 @@ pub static EXECUTABLE: OnceCell<PathBuf> = OnceCell::new();
|
|||||||
pub struct NativeProcess;
|
pub struct NativeProcess;
|
||||||
|
|
||||||
impl Process for NativeProcess {
|
impl Process for NativeProcess {
|
||||||
/// Read input from `stdin`, compile a contract, and write the output to `stdout`.
|
|
||||||
fn run(input_file: Option<&mut std::fs::File>) -> anyhow::Result<()> {
|
|
||||||
let mut stdin = std::io::stdin();
|
|
||||||
let mut stdout = std::io::stdout();
|
|
||||||
let mut stderr = std::io::stderr();
|
|
||||||
|
|
||||||
let mut buffer = Vec::with_capacity(16384);
|
|
||||||
match input_file {
|
|
||||||
Some(ins) => {
|
|
||||||
if let Err(error) = ins.read_to_end(&mut buffer) {
|
|
||||||
anyhow::bail!("Failed to read recursive process input file: {:?}", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
if let Err(error) = stdin.read_to_end(&mut buffer) {
|
|
||||||
anyhow::bail!(
|
|
||||||
"Failed to read recursive process input from stdin: {:?}",
|
|
||||||
error
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let input: Input = revive_common::deserialize_from_slice(buffer.as_slice())?;
|
|
||||||
let result = input.contract.compile(
|
|
||||||
input.project,
|
|
||||||
input.optimizer_settings,
|
|
||||||
input.include_metadata_hash,
|
|
||||||
input.debug_config,
|
|
||||||
);
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(build) => {
|
|
||||||
let output = Output::new(build);
|
|
||||||
let json = serde_json::to_vec(&output).expect("Always valid");
|
|
||||||
stdout
|
|
||||||
.write_all(json.as_slice())
|
|
||||||
.expect("Stdout writing error");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(error) => {
|
|
||||||
let message = error.to_string();
|
|
||||||
stderr
|
|
||||||
.write_all(message.as_bytes())
|
|
||||||
.expect("Stderr writing error");
|
|
||||||
Err(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Runs this process recursively to compile a single contract.
|
|
||||||
fn call(input: Input) -> anyhow::Result<Output> {
|
fn call(input: Input) -> anyhow::Result<Output> {
|
||||||
let input_json = serde_json::to_vec(&input).expect("Always valid");
|
let input_json = serde_json::to_vec(&input).expect("Always valid");
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
//! Process for compiling a single compilation unit using Web Workers.
|
//! Process for compiling a single compilation unit using Web Workers.
|
||||||
|
|
||||||
use std::ffi::{c_char, c_void, CStr, CString};
|
use std::ffi::{c_char, c_void, CStr, CString};
|
||||||
use std::fs::File;
|
|
||||||
use std::io::Read;
|
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
use super::Input;
|
use super::Input;
|
||||||
use super::Output;
|
use super::Output;
|
||||||
@@ -32,61 +29,6 @@ enum Response {
|
|||||||
pub struct WorkerProcess;
|
pub struct WorkerProcess;
|
||||||
|
|
||||||
impl Process for WorkerProcess {
|
impl Process for WorkerProcess {
|
||||||
/// Read input from `stdin`, compile a contract, and write the output to `stdout`.
|
|
||||||
fn run(input_file: Option<&mut std::fs::File>) -> anyhow::Result<()> {
|
|
||||||
let mut buffer = Vec::with_capacity(16384);
|
|
||||||
// TODO: Init correctly stdin in emscripten - preload FS conf before module init
|
|
||||||
let mut stdin = File::open("/in")
|
|
||||||
.map_err(|error| anyhow::anyhow!("File /in openning error: {}", error))?;
|
|
||||||
let mut stdout = File::create("/out")
|
|
||||||
.map_err(|error| anyhow::anyhow!("File /out creating error: {}", error))?;
|
|
||||||
let mut stderr = File::create("/err")
|
|
||||||
.map_err(|error| anyhow::anyhow!("File /err creating error: {}", error))?;
|
|
||||||
|
|
||||||
match input_file {
|
|
||||||
Some(ins) => {
|
|
||||||
if let Err(error) = ins.read_to_end(&mut buffer) {
|
|
||||||
anyhow::bail!("Failed to read recursive process input file: {:?}", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
if let Err(error) = stdin.read_to_end(&mut buffer) {
|
|
||||||
anyhow::bail!(
|
|
||||||
"Failed to read recursive process input from stdin: {:?}",
|
|
||||||
error
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let input: Input = revive_common::deserialize_from_slice(buffer.as_slice())?;
|
|
||||||
let result = input.contract.compile(
|
|
||||||
input.project,
|
|
||||||
input.optimizer_settings,
|
|
||||||
input.include_metadata_hash,
|
|
||||||
input.debug_config,
|
|
||||||
);
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(build) => {
|
|
||||||
let output = Output::new(build);
|
|
||||||
let json = serde_json::to_vec(&output).expect("Always valid");
|
|
||||||
stdout
|
|
||||||
.write_all(json.as_slice())
|
|
||||||
.expect("Stdout writing error");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(error) => {
|
|
||||||
let message = error.to_string();
|
|
||||||
stderr
|
|
||||||
.write_all(message.as_bytes())
|
|
||||||
.expect("Stderr writing error");
|
|
||||||
Err(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Runs this process recursively to compile a single contract.
|
|
||||||
fn call(input: Input) -> anyhow::Result<Output> {
|
fn call(input: Input) -> anyhow::Result<Output> {
|
||||||
let input_json = serde_json::to_vec(&input).expect("Always valid");
|
let input_json = serde_json::to_vec(&input).expect("Always valid");
|
||||||
let input_str = String::from_utf8(input_json).expect("Input shall be valid");
|
let input_str = String::from_utf8(input_json).expect("Input shall be valid");
|
||||||
|
|||||||
@@ -14,39 +14,11 @@ mergeInto(LibraryManager.library, {
|
|||||||
|
|
||||||
var inputJson = UTF8ToString(inputPtr, inputLen);
|
var inputJson = UTF8ToString(inputPtr, inputLen);
|
||||||
|
|
||||||
// Inline worker code
|
|
||||||
const workerCode = `
|
|
||||||
// worker.js
|
|
||||||
// nodejs version
|
|
||||||
const { parentPort } = require('worker_threads');
|
|
||||||
|
|
||||||
parentPort.on('message', async (inputJson) => {
|
|
||||||
const { default: ModuleFactory } = await import('./resolc.js');
|
|
||||||
const newModule = await ModuleFactory();
|
|
||||||
|
|
||||||
// Create a virtual file for stdin
|
|
||||||
newModule.FS.writeFile('/in', inputJson);
|
|
||||||
|
|
||||||
// Call main on the new instance
|
|
||||||
const output = newModule.callMain(['--recursive-process']);
|
|
||||||
|
|
||||||
// Check the /err file content
|
|
||||||
const errorMessage = newModule.FS.readFile('/err', { encoding: 'utf8' });
|
|
||||||
|
|
||||||
if (errorMessage.length > 0) {
|
|
||||||
// If /err is not empty, throw an error with its content
|
|
||||||
throw new Error(errorMessage);
|
|
||||||
} else {
|
|
||||||
// If no error, read the output file
|
|
||||||
let outputFile = newModule.FS.readFile('/out', { encoding: 'utf8' });
|
|
||||||
parentPort.postMessage({ output: outputFile });
|
|
||||||
}
|
|
||||||
});`;
|
|
||||||
|
|
||||||
function compileWithWorker(inputJson, callback) {
|
function compileWithWorker(inputJson, callback) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// Create a new Worker
|
const worker = new Worker(new URL('./worker.js', import.meta.url), {
|
||||||
const worker = new Worker(workerCode, { eval: true });
|
type: 'module',
|
||||||
|
});
|
||||||
|
|
||||||
// Listen for messages from the worker
|
// Listen for messages from the worker
|
||||||
worker.on('message', (message) => {
|
worker.on('message', (message) => {
|
||||||
+10
-2
@@ -9,7 +9,15 @@
|
|||||||
"solc": "^0.8.28"
|
"solc": "^0.8.28"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"init": "cp -r ../target/wasm32-unknown-emscripten/release/resolc.{js,wasm} .",
|
"build": "cp -r ../target/wasm32-unknown-emscripten/release/resolc.{js,wasm} ./src && npx rollup -c",
|
||||||
"test": "npm run init && node run_revive.js"
|
"test": "npm run build && node run_revive.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.26.0",
|
||||||
|
"@babel/preset-env": "^7.26.0",
|
||||||
|
"@rollup/plugin-babel": "^6.0.4",
|
||||||
|
"@rollup/plugin-node-resolve": "^15.3.0",
|
||||||
|
"rollup": "^4.27.3",
|
||||||
|
"rollup-plugin-copy": "^3.5.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import babel from '@rollup/plugin-babel';
|
||||||
|
import copy from 'rollup-plugin-copy';
|
||||||
|
import resolve from '@rollup/plugin-node-resolve';
|
||||||
|
|
||||||
|
const outputDirCJS = 'dist/revive-cjs';
|
||||||
|
const outputDirESM = 'dist/revive-esm';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
input: ['src/resolc.js', 'src/worker.js'], // Adjust this to your main entry file
|
||||||
|
output: [
|
||||||
|
{
|
||||||
|
dir: outputDirCJS,
|
||||||
|
format: 'cjs',
|
||||||
|
exports: 'auto',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dir: outputDirESM,
|
||||||
|
format: 'esm',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
babel({
|
||||||
|
exclude: 'node_modules/**',
|
||||||
|
presets: ['@babel/preset-env'],
|
||||||
|
babelHelpers: 'inline',
|
||||||
|
}),
|
||||||
|
resolve(),
|
||||||
|
copy({
|
||||||
|
targets: [
|
||||||
|
{ src: 'src/resolc.wasm', dest: outputDirCJS },
|
||||||
|
{ src: 'src/resolc.wasm', dest: outputDirESM },
|
||||||
|
],
|
||||||
|
})
|
||||||
|
],
|
||||||
|
};
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
import solc from 'solc';
|
import solc from 'solc';
|
||||||
// Import the Emscripten module
|
// Import the Emscripten module
|
||||||
import createRevive from './resolc.js';
|
import createRevive from './dist/revive-esm/resolc.js';
|
||||||
|
|
||||||
const compilerStandardJsonInput = {
|
const compilerStandardJsonInput = {
|
||||||
language: 'Solidity',
|
language: 'Solidity',
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { parentPort } from 'worker_threads';
|
||||||
|
|
||||||
|
parentPort.on('message', async (inputJson) => {
|
||||||
|
const { default: createRevive } = await import(new URL('./resolc.js', import.meta.url));
|
||||||
|
const revive = await createRevive();
|
||||||
|
|
||||||
|
revive.setStdinData(inputJson);
|
||||||
|
|
||||||
|
let stdoutString = "";
|
||||||
|
revive.setStdoutCallback(function(char) {
|
||||||
|
if (char.charCodeAt(0) === '\n') {
|
||||||
|
console.log("new line")
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
stdoutString += char;
|
||||||
|
});
|
||||||
|
|
||||||
|
let stderrString = "";
|
||||||
|
revive.setStderrCallback(function(char) {
|
||||||
|
stderrString += char;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Call main on the new instance
|
||||||
|
const output = revive.callMain(['--recursive-process']);
|
||||||
|
|
||||||
|
if (stderrString.length > 0) {
|
||||||
|
// If /err is not empty, throw an error with its content
|
||||||
|
throw new Error(stderrString);
|
||||||
|
} else {
|
||||||
|
parentPort.postMessage({ output: stdoutString });
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test:cli": "npm run test -w crates/solidity/src/tests/cli-tests",
|
"test:cli": "npm run test -w crates/solidity/src/tests/cli-tests",
|
||||||
|
"build:revive": "npm run build -w js",
|
||||||
"test:revive": "npm run test -w js"
|
"test:revive": "npm run test -w js"
|
||||||
},
|
},
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
|
|||||||
Reference in New Issue
Block a user