Skip to main content

wasmedge_sdk/
compiler.rs

1//! Defines WasmEdge ahead-of-time compiler.
2
3use crate::{config::Config, WasmEdgeResult};
4use std::path::{Path, PathBuf};
5use wasmedge_sys as sys;
6
7/// Defines WasmEdge ahead-of-time(AOT) compiler and the relevant APIs.
8#[derive(Debug)]
9pub struct Compiler {
10    pub(crate) inner: sys::Compiler,
11}
12impl Compiler {
13    /// Creates a new AOT compiler.
14    ///
15    /// # Error
16    ///
17    /// If fail to create a AOT compiler, then an error is returned.
18    pub fn new(config: Option<&Config>) -> WasmEdgeResult<Self> {
19        let inner = match config {
20            Some(cfg) => sys::Compiler::create(Some(&cfg.inner))?,
21            None => sys::Compiler::create(None)?,
22        };
23
24        Ok(Self { inner })
25    }
26
27    /// Compiles the given wasm file into a shared library file (*.so in Linux, *.dylib in macOS, or *.dll in Windows). The file path of the generated shared library file will be returned if the method works successfully.
28    ///
29    /// # Arguments
30    ///
31    /// * `wasm_file` - The target wasm file.
32    ///
33    /// * `filename` - The filename of the generated shared library file.
34    ///
35    /// * `out_dir` - The target directory to save the generated shared library file.
36    ///
37    /// # Error
38    ///
39    /// If fail to compile, then an error is returned.
40    pub fn compile_from_file(
41        &self,
42        wasm_file: impl AsRef<Path>,
43        filename: impl AsRef<str>,
44        out_dir: impl AsRef<Path>,
45    ) -> WasmEdgeResult<PathBuf> {
46        #[cfg(target_os = "linux")]
47        let extension = "so";
48        #[cfg(target_os = "macos")]
49        let extension = "dylib";
50        #[cfg(target_os = "windows")]
51        let extension = "dll";
52        let aot_file = out_dir
53            .as_ref()
54            .join(format!("{}.{}", filename.as_ref(), extension));
55        self.inner.compile_from_file(wasm_file, &aot_file)?;
56
57        Ok(aot_file)
58    }
59
60    /// Compiles the given wasm bytes into a shared library file (*.so in Linux, *.dylib in macOS, or *.dll in Windows). The file path of the generated shared library file will be returned if the method works successfully.
61    ///
62    /// # Argument
63    ///
64    /// * `bytes` - A in-memory WASM bytes.
65    ///
66    /// * `filename` - The filename of the generated shared library file.
67    ///
68    /// * `out_dir` - The target directory to save the generated shared library file.
69    ///
70    /// # Error
71    ///
72    /// If fail to compile, then an error is returned.
73    pub fn compile_from_bytes(
74        &self,
75        bytes: impl AsRef<[u8]>,
76        filename: impl AsRef<str>,
77        out_dir: impl AsRef<Path>,
78    ) -> WasmEdgeResult<PathBuf> {
79        #[cfg(target_os = "linux")]
80        let extension = "so";
81        #[cfg(target_os = "macos")]
82        let extension = "dylib";
83        #[cfg(target_os = "windows")]
84        let extension = "dll";
85        let aot_file = out_dir
86            .as_ref()
87            .join(format!("{}.{}", filename.as_ref(), extension));
88        self.inner.compile_from_bytes(bytes, &aot_file)?;
89
90        Ok(aot_file)
91    }
92}
93
94#[cfg(not(feature = "async"))]
95#[cfg(test)]
96mod tests {
97    use super::*;
98    use crate::{
99        config::{CompilerConfigOptions, ConfigBuilder},
100        params, wat2wasm, CompilerOutputFormat, VmBuilder, WasmVal,
101    };
102    use std::io::Read;
103
104    #[test]
105    fn test_compiler_compile_from_file() -> Result<(), Box<dyn std::error::Error>> {
106        // compile from file
107        {
108            let config = ConfigBuilder::default()
109                .with_compiler_config(
110                    CompilerConfigOptions::new().out_format(CompilerOutputFormat::Native),
111                )
112                .build()?;
113
114            let compiler = Compiler::new(Some(&config))?;
115            let wasm_file = std::env::current_dir()
116                .unwrap()
117                .join("examples/wasmedge-sys/data/fibonacci.wat");
118            let out_dir = std::env::current_dir()?;
119            let aot_filename = "aot_fibonacci_1";
120            let aot_file_path = compiler.compile_from_file(wasm_file, aot_filename, out_dir)?;
121            assert!(aot_file_path.exists());
122            #[cfg(target_os = "macos")]
123            assert!(aot_file_path.ends_with("aot_fibonacci_1.dylib"));
124            #[cfg(target_os = "linux")]
125            assert!(aot_file_path.ends_with("aot_fibonacci_1.so"));
126            #[cfg(target_os = "windows")]
127            assert!(aot_file_path.ends_with("aot_fibonacci_1.dll"));
128
129            // read buffer
130            let mut aot_file = std::fs::File::open(&aot_file_path)?;
131            let mut buffer = [0u8; 4];
132            aot_file.read_exact(&mut buffer)?;
133            let wasm_magic: [u8; 4] = [0x00, 0x61, 0x73, 0x6D];
134            assert_ne!(buffer, wasm_magic);
135
136            let res =
137                VmBuilder::new()
138                    .build()?
139                    .run_func_from_file(&aot_file_path, "fib", params!(5))?;
140            assert_eq!(res[0].to_i32(), 8);
141
142            // cleanup
143            assert!(std::fs::remove_file(aot_file_path).is_ok());
144        }
145
146        // compile from bytes
147        {
148            let wasm_bytes = wat2wasm(
149                br#"(module
150                    (export "fib" (func $fib))
151                    (func $fib (param $n i32) (result i32)
152                     (if
153                      (i32.lt_s
154                       (local.get $n)
155                       (i32.const 2)
156                      )
157                      (then
158                        (return (i32.const 1))
159                      )
160                     )
161                     (return
162                      (i32.add
163                       (call $fib
164                        (i32.sub
165                         (local.get $n)
166                         (i32.const 2)
167                        )
168                       )
169                       (call $fib
170                        (i32.sub
171                         (local.get $n)
172                         (i32.const 1)
173                        )
174                       )
175                      )
176                     )
177                    )
178                   )
179              "#,
180            )?;
181
182            // create a aot compiler
183            let config = ConfigBuilder::default()
184                .with_compiler_config(
185                    CompilerConfigOptions::new().out_format(CompilerOutputFormat::Native),
186                )
187                .build()?;
188            let compiler = Compiler::new(Some(&config))?;
189
190            // compile wasm bytes into a shared library file
191            let out_dir = std::env::current_dir()?;
192            let aot_filename = "aot_fibonacci_2";
193            let aot_file_path = compiler.compile_from_bytes(wasm_bytes, aot_filename, out_dir)?;
194            assert!(aot_file_path.exists());
195            #[cfg(target_os = "macos")]
196            assert!(aot_file_path.ends_with("aot_fibonacci_2.dylib"));
197            #[cfg(target_os = "linux")]
198            assert!(aot_file_path.ends_with("aot_fibonacci_2.so"));
199            #[cfg(target_os = "windows")]
200            assert!(aot_file_path.ends_with("aot_fibonacci_2.dll"));
201
202            // read buffer
203            let mut aot_file = std::fs::File::open(&aot_file_path)?;
204            let mut buffer = [0u8; 4];
205            aot_file.read_exact(&mut buffer)?;
206            let wasm_magic: [u8; 4] = [0x00, 0x61, 0x73, 0x6D];
207            assert_ne!(buffer, wasm_magic);
208
209            let res =
210                VmBuilder::new()
211                    .build()?
212                    .run_func_from_file(&aot_file_path, "fib", params!(5))?;
213            assert_eq!(res[0].to_i32(), 8);
214
215            // cleanup
216            assert!(std::fs::remove_file(aot_file_path).is_ok());
217        }
218
219        Ok(())
220    }
221}