0%

前言

已经有很久没有写过博客了,或者是有很久没有写过东西了。

翻看上一篇博客,已经是七月份的事情了,当时是毕业正式上班前,将博客迁移至Github时的一篇技术博客。

当时还在想着,要继续坚持写东西,结果就到现在。

阅读全文 »

问题描述

一直以来使用python项目的时候,都是选择Anaconda下的python.exe作为解释器。

今天在项目中创建了venv并使用该目录下python时,使用pip时报错显示

WARNING: pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available

问题本质

Python的ssl模块不可用,导致pip无法正常工作。

ssl模块不可用的原因是ssl.pyd没有位于环境变量中

阅读全文 »

在使用rustc --target wasm32-unknown-unknown —O src/lib.rs cargo build wasm32-unknown-unknown 生成的wasm文件大小为1.6Mb

添加-C lto 参数后大小仅为232kb

阅读全文 »

前言

wasmer-java导入函数中提到wasm操作限制较大。我们需要通过导入外部函数去解决一些问题。

截至写文章时,已用wasmer-java中他人维护的分支解决导入函数问题

问题

但是导入的外部函数与wasm(实际上为rust程序)之间参数传递只能使用intlongfloatdouble 四种,这是远远不够的。

解决方法

对于一些复杂对象的传递,我们可以考虑使用字符串。但是字符串类型也是不能作为参数直接在Java与wasm中直接传递的,我们需要借助wasmer-java中的Memory类,将字符串直接写入虚拟机内存中,并传递一个 int 类型的指针。

传入字符串

Java
参数初始化
1
2
3
4
5
6
7
8
9
10
11
//获取memory对象
Memory memory = instance.exports.getMemory("memory");
String str = "要传递的参数";
//获取字符串对应的字节数组
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
//调用rust中写的申请内存区域的方法,记录这块内存地址的指针
Integer strPtr = (Integer) instance.exports.getFunction("allocate").apply(bytes.length)[0];
//写入内存
ByteBuffer mbf = memory.buffer();
mbf.position(strPtr);
mbf.put(bytes);
参数传递
1
Object[] results = instance.exports.getFunction("函数名").apply(strPtr);
Rust
直接解析

通过CStrCString两个库操作

1
2
3
4
5
6
7
8
9
10
#[no_mangle]
pub extern fn func(param_ptr: *mut c_char){
let result;
unsafe {
result = CStr::from_ptr(str_ptr).to_str().unwrap();
}

let string = CString::new(format!("wallet:{}", result)).unwrap();
//其他操作
}

传出字符串

Rust

返回 *mut c_char 类型即可

1
2
3
4
5
6
7
8
#[no_mangle]
pub extern fn func() -> *mut c_char{
let result = ...;

let string = CString::new(format!("wallet:{}", result)).unwrap();

string.into_raw()
}
Java
1
2
3
4
5
6
7
//获取指针
Integer resultPtr = (Integer) instance.exports.getFunction("func").apply()[0];
//获取内存
Memory memory = instance.exports.getMemory("memory");
ByteBuffer mbf = memory.buffer();
//解析
String res = getString(resultPtr,mbf);
1
2
3
4
5
6
7
8
9
10
11
12
13
public static String getString(Integer ptr, ByteBuffer mbf) {
StringBuilder sb = new StringBuilder();
for(int i = ptr, max = mbf.limit(); i < max; i++) {
mbf.position(i);
byte b = mbf.get();
if (b == 0) {
break;
}
sb.appendCodePoint(b);
}
String result = sb.toString();
return result;
}

前言

由于wasm暂时无法支持文件读写、网络通信等系统操作。

所以现需要在Java运行wasm,同时将数据库的读写作为外部函数供给wasm调用。

问题

wasmer-java调用wasmer部分由rust编写,部分代码较老。

在wasmer仓库中,官方给出的示例为:

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
let wasm_bytes = wat2wasm("bytes")?;
let store = Store::new(&JIT::new(Cranelift::default()).engine());

println!("Compiling module...");
let module = Module::new(&store, wasm_bytes)?;


fn multiply(a: i32) -> i32 {
println!("Calling `multiply_native`...");
let result = a * 3;

println!("Result of `multiply_native`: {:?}", result);

result
}

let multiply_native = Function::new_native(&store, multiply);

// Create an import object.
let import_object = imports! {
"env" => {
"multiply_native" => multiply_native,
}
};

println!("Instantiating module...");
let instance = Instance::new(&module, &import_object)?;

而对于仍在使用较老版本的wasmer-java中,此方法无法奏效。

解决

通过查阅源码,发现在老版本中并没有使用 Function::new_native(&store, multiply);

而是使用位于runtime-core 中的func!

注:runtime-core被标记为已弃用

1
2
3
4
5
6
7
8
9
fn func(_: &mut vm::Ctx, arg: i32) -> i32 {
arg + 1
}

let _ = imports! {
"env" => {
"func" => func!(func),
},
};

使用emsdk的emcc可以将c代码编译成.wasm文件。

但是要将rust代码编译成.wasm文件,按照官网文档,需要使用wasm-pack进行build(安装wasm-pack时又有各种问题)。

但是最后生成的wasm有1900kb,也无法运行于Java(wasmer-java)中。

最后使用rustc --target wasm32-unknown-unknown -O <src.rs>生成wasm,大小1600kb,可以于Java中运行,但是官方GitHub下载的用rust编译的示例wasm只有1kb,跟c生成wasm文件一样

补充:cargo build --target wasm32-unknown-unknown,也行,关键参数为--target wasm32-unknown-unknown