forked from wasmerio/wasmer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
engine_cross_compilation.rs
108 lines (95 loc) · 3.28 KB
/
engine_cross_compilation.rs
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
//! Defining an engine in Wasmer is one of the fundamental steps.
//!
//! As a reminder, an engine applies roughly 2 steps:
//!
//! 1. It compiles the Wasm module bytes to executable code, through
//! the intervention of a compiler,
//! 2. It stores the executable code somewhere.
//!
//! This example focuses on the first step: the compiler. It
//! illustrates how the abstraction over the compiler is so powerful
//! that it is possible to cross-compile a Wasm module.
//!
//! You can run the example directly by executing in Wasmer root:
//!
//! ```shell
//! cargo run --example cross-compilation --release --features "cranelift"
//! ```
//!
//! Ready?
use std::str::FromStr;
use wasmer::{wat2wasm, Module, RuntimeError, Store};
use wasmer_compiler::Universal;
use wasmer_compiler::{CpuFeature, Target, Triple};
use wasmer_compiler_cranelift::Cranelift;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Let's declare the Wasm module with the text representation.
let wasm_bytes = wat2wasm(
br#"
(module
(type $sum_t (func (param i32 i32) (result i32)))
(func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
i32.add)
(export "sum" (func $sum_f)))
"#,
)?;
// Define a compiler configuration.
//
// In this situation, the compiler is
// `wasmer_compiler_cranelift`. The compiler is responsible to
// compile the Wasm module into executable code.
let compiler_config = Cranelift::default();
// Here we go.
//
// Let's define the target “triple”. Historically, such things had
// three fields, though additional fields have been added over
// time.
let triple = Triple::from_str("x86_64-linux-musl")
.map_err(|error| RuntimeError::new(error.to_string()))?;
// Here we go again.
//
// Let's define a CPU feature.
let mut cpu_feature = CpuFeature::set();
cpu_feature.insert(CpuFeature::from_str("sse2")?);
// Here we go finally.
//
// Let's build the target.
let target = Target::new(triple, cpu_feature);
println!("Chosen target: {:?}", target);
// Define the engine that will drive everything.
//
// That's where we specify the target for the compiler.
//
// Use the Universal engine.
let engine = Universal::new(compiler_config)
// Here we go.
// Pass the target to the engine! The engine will share
// this information with the compiler.
.target(target)
// Get the engine.
.engine();
// Create a store, that holds the engine.
let store = Store::new_with_engine(&engine);
println!("Compiling module...");
// Let's compile the Wasm module.
let _module = Module::new(&store, wasm_bytes)?;
println!("Module compiled successfully.");
// Congrats, the Wasm module is cross-compiled!
//
// What to do with that? It is possible to use an engine (probably
// a headless engine) to execute the cross-compiled Wasm module an
// the targeted platform.
Ok(())
}
#[test]
#[cfg(not(any(
windows,
// We don't support yet crosscompilation in macOS with Apple Silicon
all(target_os = "macos", target_arch = "aarch64"),
target_env = "musl",
)))]
fn test_cross_compilation() -> Result<(), Box<dyn std::error::Error>> {
main()
}