`
haoningabc
  • 浏览: 1465673 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

用WebAssembly与rust和c交互的demo

阅读更多
32,263.98

入门教程
https://learnku.com/docs/rust-lang/2018/ch01-01-installation/4494

安装:
curl https://sh.rustup.rs -sSf | sh
source $HOME/.cargo/env


linux 和mac 基本一样
rustup toolchain install nightly-x86_64-unknown-linux-gnu
rustup target add wasm32-unknown-unknown --toolchain nightly
rustc +nightly --target=wasm32-unknown-unknown -O --crate-type=cdylib src/lib.rs -o build/hello.wasm

hello rust:
语法:https://learnku.com/docs/rust-lang/2018

https://www.hellorust.com/news/native-wasm-target.html

hexdump hello.wasm



###############
webassembly:

############
helloword1:

https://blog.csdn.net/weixin_34208283/article/details/88005347

cargo new hello_world --lib


main.js
//! hello world with WebAssembly
const imports = {
  env: {
    hello_insert_dom: () => {
      const h1 = document.createElement('h1');
      h1.innerHTML = 'Hello, world';
      const body = document.querySelector('body');
      body.appendChild(h1);
    }
  }
};

fetch('build/hello.wasm')
  .then(response => response.arrayBuffer())
  .then(bytes => WebAssembly.instantiate(bytes, imports))
  .then(results => {
    console.log(results);
    const exports = results.instance.exports;
    exports.hello_call_js();
    // exports.hello_call_js_pass_data();
  });


vim src/lib.rs
//! a WebAssembly module with Rust
extern {
  fn hello_insert_dom();
}

#[no_mangle]
pub extern fn hello_call_js() { // equal pub extern "C" fn ...
    unsafe {
        hello_insert_dom();
    }
}

index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebAssembly</title>
</head>
<body>
<script src="main.js"></script>
</body>


mkdir build
rustc +nightly --target=wasm32-unknown-unknown -O --crate-type=cdylib src/lib.rs -o build/hello.wasm

生成hello.wasm
python2 -m SimpleHTTPServer 8000
localhost:8000
index.html--->main.js:WebAssembly---->hello.asm--->main.js:import


####################
helloworld2:

https://blog.csdn.net/teajs/article/details/78937865
部分代码比较老,修改如下
helloworld.c
#include "helloworld.h"

void sayHi() {
    alert("hello,world!");
}

helloworld.h
extern void alert(char* str);


emcc helloworld.c -s BINARYEN=1 -s SIDE_MODULE=1 -O3 -s 
"EXPORTED_FUNCTIONS=['_sayHi']"  -o helloworld.wasm


生成helloworld.wasm
index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebAssembly</title>
</head>
<body>
<script src="main.js"></script>
</body>


main.js 中使用helloworld.wasm
//! hello world with WebAssembly
let imports = {
  env: {
       // 'memoryBase':0,
        '__memory_base': 0,
        'tableBase': 0,
        'memory': new WebAssembly.Memory({initial: 256 }),
        'table': new WebAssembly.Table({initial: 256, element: "anyfunc" }),
        _alert: function (p) {
            // 这一块说明请看文章
            alert(utf8ToString(p));
        }
  }
};
function utf8ToString(p) {
    let h = new Uint8Array(imports.env.memory.buffer);
    let s = "";
    for (let i = p; h[i]; i++) {
        s += String.fromCharCode(h[i]);
    }
    return s;
}

fetch('helloworld.wasm').
       then(response => response.arrayBuffer()).
       then(bytes => WebAssembly.instantiate(bytes, imports)).
       then(mod => mod.instance).
       then(instance => {
           let exports = instance.exports;
           exports._sayHi();
       });


说明:
1.c通过 extern void alert定义接口,对应js的env里定义的_alert 用emcc生成helloworld.wasm
2.main.js 加载 helloworld.wasm,调用 c里定义的sayHi ,加个下划线_sayHi()


几张图让你看懂WebAssembly
https://www.jianshu.com/p/bff8aa23fe4d

############

demo:
https://yksoft1.github.io/dosboxxem-demo/



######################
emscripten调用文件系统:
mem,nodefs,idbfs
https://wasm.comptechs.cn/cppwasm/ch3-03-fs.html
memfile:
emcc packfile.cc -o packfile.js --preload-file hello.txt
#include <stdio.h>
int main() {
    FILE* fp = fopen("hello.txt", "rt");
    if (fp) {
        while (!feof(fp)) {
            char c = fgetc(fp);
            if (c != EOF) {
                putchar(c);
            }
        }
        fclose(fp);
    }
    return 0;
}

index.html
<html>
<head></head>
<body>
<script >
    Module={};
    Module.onRuntimeInitialized = function(){

    }
</script>

<script src="packfile.js"></script>
</body>
</html



packdir.cc
读写的例子
#include <stdio.h>

void read_fs(const char* fname) {
    FILE* fp = fopen(fname, "rt");
    if (fp) {
        while (!feof(fp)) {
            char c = fgetc(fp);
            if (c != EOF) {
                putchar(c);
            }
        }
        fclose(fp);
    }
}

void write_fs() {
    FILE* fp = fopen("t3.txt", "wt");
    if (fp) {
        fprintf(fp, "This is t3.txt.wo ca...\n");
        fclose(fp);
    }
}

int main() {
    read_fs("dat_dir/t1.txt");
    read_fs("dat_dir/t2.txt");
    read_fs("dat_dir/sub_dir/t3.txt");

    write_fs();
    read_fs("t3.txt");
    return 0;
}



相同的c文件 ,file和执行js分开:
先给files打包
python /opt/mt/emsdk/emscripten/incoming/tools/file_packager.py fp.data --preload dat_dir --js-output=fp.js
再给
packdir.cc打包:注意参数FORCE_FILESYSTEM
emcc packdir.cc -o packdir_sep.js -s FORCE_FILESYSTEM=1

执行的html
<html>
<head></head>
<body>
<script >
    Module={};
    Module.onRuntimeInitialized = function(){
    }
</script>
<script src="fp.js"></script>
<script src="packdir_sep.js"></script>
</body>
</html


使用nodefs,在node的环境下使用
#include <stdio.h>
#include <emscripten.h>
//nodefs.cc
void setup_nodefs() {
    EM_ASM(
        FS.mkdir('/data');
        FS.mount(NODEFS, {root:'.'}, '/data');
    );
}

int main() {
    setup_nodefs();

    FILE* fp = fopen("/data/nodefs_data.txt", "r+t");
    if (fp == NULL) fp = fopen("/data/nodefs_data.txt", "w+t");
    int count = 0;
    if (fp) {
        fscanf(fp, "%d", &count);
        count++;
        fseek(fp, 0, SEEK_SET);
        fprintf(fp, "%d", count);
        fclose(fp);
        printf("count:%d\n", count);
    }
    else {
        printf("fopen failed.\n");
    }

    return 0;
}

注意需要加#include <emscripten.h> 这个头
emcc nodefs.cc -lnodefs.js -o nodefs.js

node nodefs.js多运行几次,发现写入的数字在自增


https://www.cntofu.com/book/150/zh/ch2-c-js/ch2-01-js-call-c.md
需要定义EM_PORT_API

#include <stdio.h>
#include <emscripten.h>
#ifndef EM_PORT_API
#   if defined(__EMSCRIPTEN__)
#       include <emscripten.h>
#       if defined(__cplusplus)
#           define EM_PORT_API(rettype) extern "C" rettype EMSCRIPTEN_KEEPALIVE
#       else
#           define EM_PORT_API(rettype) rettype EMSCRIPTEN_KEEPALIVE
#       endif
#   else
#       if defined(__cplusplus)
#           define EM_PORT_API(rettype) extern "C" rettype
#       else
#           define EM_PORT_API(rettype) rettype
#       endif
#   endif
#endif
void sync_idbfs() {
    EM_ASM(
        FS.syncfs(function (err) {});
    );
}

EM_PORT_API(void) test() {
    FILE* fp = fopen("/data/nodefs_data.txt", "r+t");
    if (fp == NULL) fp = fopen("/data/nodefs_data.txt", "w+t");
    int count = 0;
    if (fp) {
        fscanf(fp, "%d", &count);
        count++;
        fseek(fp, 0, SEEK_SET);
        fprintf(fp, "%d", count);
        fclose(fp);
        printf("count:%d\n", count);

        sync_idbfs();
    }
    else {
        printf("fopen failed.\n");
    }
}

int main() {
    EM_ASM(
        FS.mkdir('/data');
        FS.mount(IDBFS, {}, '/data');
        FS.syncfs(true, function (err) {
            assert(!err);
            ccall('test', 'v');
        });
    );

    return 0;
}

emcc idbfs.cc -lidbfs.js -o idbfs.js

idbfs.html
<html>
<head></head>
<body>
<script >
    Module={};
    Module.onRuntimeInitialized = function(){
    }
</script>
<script src="idbfs.js"></script>
</body>
</html



indexedDB的基本使用:
http://www.ruanyifeng.com/blog/2018/07/indexeddb.html
indexeddb.html

<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<input type="button" value="add" onclick="add()" />
<input type="button" value="read" onclick="read()" />
<input type="button" value="readAll" onclick="readAll()" />
<input type="button" value="update" onclick="update()" />
<input type="button" value="remove" onclick="remove()" />
<script >
var db;
    var request = window.indexedDB.open("test", 2);
    request.onerror = function (event) {
      console.log('数据库打开报错');
    };
    request.onsuccess = function (event) {
      db = request.result;
      console.log('数据库打开成功');
    };
    request.onupgradeneeded = function (event) {
        console.log("upgrade begin");
        db = event.target.result;
        var objectStore;
        if (!db.objectStoreNames.contains('person')) {
            objectStore = db.createObjectStore('person', { keyPath: 'id' });
            objectStore.createIndex('name', 'name', { unique: false });
            objectStore.createIndex('email', 'email', { unique: true })
        }
    }
//----------add-------
    function add() {
        console.log(JSON.stringify(db));
      var request = db.transaction(['person'], 'readwrite')
        .objectStore('person')
        .add({ id: 1, name: '张三', age: 24, email: 'zhangsan@example.com' });

      request.onsuccess = function (event) {
        console.log('数据写入成功');
      };

      request.onerror = function (event) {
        console.log('数据写入失败');
      }
    }

    //add();
   // console.log("----add end");
//-------read--------
    function read() {
       var transaction = db.transaction(['person']);
       var objectStore = transaction.objectStore('person');
       var request = objectStore.get(1);

       request.onerror = function(event) {
         console.log('事务失败');
       };

       request.onsuccess = function( event) {
          if (request.result) {
            console.log('Name: ' + request.result.name);
            console.log('Age: ' + request.result.age);
            console.log('Email: ' + request.result.email);
          } else {
            console.log('未获得数据记录');
          }
       };
    }
//-------readAll----
function readAll() {
  var objectStore = db.transaction('person').objectStore('person');
   objectStore.openCursor().onsuccess = function (event) {
     var cursor = event.target.result;

     if (cursor) {
       console.log('Id: ' + cursor.key);
       console.log('Name: ' + cursor.value.name);
       console.log('Age: ' + cursor.value.age);
       console.log('Email: ' + cursor.value.email);
       cursor.continue();
    } else {
      console.log('没有更多数据了!');
    }
  };
}
//--update-----
function update() {
  var request = db.transaction(['person'], 'readwrite')
    .objectStore('person')
    .put({ id: 1, name: '李四', age: 35, email: 'lisi@example.com' });

  request.onsuccess = function (event) {
    console.log('数据更新成功');
  };

  request.onerror = function (event) {
    console.log('数据更新失败');
  }
}
//----remove-----
function remove() {
  var request = db.transaction(['person'], 'readwrite')
    .objectStore('person')
    .delete(1);

  request.onsuccess = function (event) {
    console.log('数据删除成功');
  };
}

console.log("---end");
//});
</script>
</body>
</html>




##########调试:
https://blog.csdn.net/VhWfR2u02Q/article/details/80148319

vim nginx/conf/mime.types
增加
application/wasm                                 wasm;



##########debug:https://blog.csdn.net/VhWfR2u02Q/article/details/80148319

debug.c
int sumOfSquare(int a,int b){
    int t1=a*a;
    int t2=b*b;
    return t1+t2;
}

debug.html
<html>
<head>
<meta charset="UTF-8">
  <script>
    const importObj = {
        env: {
            memory: new WebAssembly.Memory({initial: 256, maximum: 256}),
            __memory_base: 0,
            tableBase: 0,
            table: new WebAssembly.Table({initial: 10, element: 'anyfunc'}),
            abort:function(){}
        }
    };


  fetch('./debug.wasm').then(response =>
    response.arrayBuffer()
  ).then(bytes => WebAssembly.instantiate(bytes,importObj)).then(results => {
    instance = results.instance;
    var sumOfSquare= instance.exports._sumOfSquare;

     var button = document.getElementById('run');
     button.addEventListener('click', function() {
          var input1 = 3;
          var input2 = 4;
          alert('sumOfSquare('+input1+','+input2+')='+sumOfSquare(input1,input2));
     }, false);
  });

  </script>
</head>
<body>
  <input type="button" id="run" value="click"/>
</body>
</html>


编译:
如果试试运行
emcc debug.c -O1 -s WASM=1 -s SIDE_MODULE=1 -s "EXPORTED_FUNCTIONS=['_sumOfSquare']" -o debug.wasm

如果要debug:
emcc debug.c -O1 -s WASM=1 -s SIDE_MODULE=1 -s "EXPORTED_FUNCTIONS=['_sumOfSquare']" -o debug.wasm -g4 --source-map-base http://212.129.249.212/rusttest/debug/
注意是能打开debug.html的路径
在firefox上的调试器上能看到debug.c











分享到:
评论

相关推荐

    Programming WebAssembly with Rust by Kevin Hoffman (z-lib.org).pdf

    由于给出的文件内容中包含大量的重复信息和不完整片段,并且内容主要是关于书籍的出版状态和版权声明,并未详细提及WebAssembly或Rust的具体知识点,因此我将基于文件标题“Programming WebAssembly with Rust by ...

    Rust语言和C语言的相互调用

    文件里面有两个资源包,一个是Rust调用C语言的,另一个是C语言调用Rust语言的,写的比较详细,各个文件写的比较清晰,可以直接使用,观察如何调用和参数编写。

    Rust与Java进行交互实例代码

    Rust与Java进行交互实例代码,使用JNI技术,实现Rust与JAVA的相互调用,从而提高执行效率,本资源是文章《【一起学Rust | 进阶篇 | jni库】JNI实现Java与Rust进行交互》的配套案例代码,供读者进行学习,查看,以...

    带您浏览WebAssembly-Rust开发

    我们已经将其记录为思维导图,以便它可以帮助像我这样的人节省时间在Internet上搜索,以找到有用的文档和工具,以开始在Rust上使用WebAssembly。 给个星星! :star:如果您喜欢或正在使用此项目进行学习,请给个星号...

    wasm-and-rust:WebAssembly和Rust:网络爱情故事

    它允许开发者使用C、C++、Rust等系统编程语言编写代码,然后在浏览器中运行。WASM的主要优点包括: 1. **高性能**:由于其二进制格式,WASM代码加载和执行速度快,接近原生性能。 2. **安全性**:WASM运行在沙盒...

    rust-conf-demo.zip

    rust配置文件读取器,实现通用快捷的调用方式,符合开发项目时所需,以及其精简的方式实现于调用,非常方便用户自定义拓展,适用于web框架的配置读取,或者桌面引用配置读取,目前只实现conf的读取可在文档中写注释...

    demo-rust:带wasm-pack的Rust WebAssembly Hello World演示

    "demo-rust:带wasm-pack的Rust WebAssembly Hello World演示"揭示了这是一个使用Rust语言和WebAssembly技术实现的简单示例项目,重点在于展示如何将Rust代码编译为WebAssembly(WASM)模块,并通过wasm-pack工具与...

    基于Rust实现EBpf的采集Demo,使用aya-rs.zip

    基于Rust实现EBpf的采集Demo,使用aya-rs.zip基于Rust实现EBpf的采集Demo,使用aya-rs.zip基于Rust实现EBpf的采集Demo,使用aya-rs.zip基于Rust实现EBpf的采集Demo,使用aya-rs.zip基于Rust实现EBpf的采集Demo,使用...

    web assembly-002 安装Rust和WebAssembly工具链和helloworld.avi

    rust学习爱好者

    rust终端显示库demo

    rust终端显示库demo

    wasm-rust:使用WebAssembly + Rust进行试验

    # It will contain the `.wasm` compiled from the Rust code (in `src`) and the JS glue to make it work wasm-pack build # In `site` directory # Install JS dependencies npm install :rocket: 跑 # in `site...

    Rust学习书籍整理2022-07-06.zip

    Game Development with Rust and WebAssembly Learn How to Run Rust on the Web while Building a Game (Eric Smith) (z-lib.org).pdf Hands-on Rust Effective Learning through 2D Game Development and Play ...

    用于在MacOS或Linux上轻松将Rust编译成WebAssembly

    标题和描述中提到的知识点是使用Rust编程语言在MacOS或Linux操作系统上编译成WebAssembly(简称WASM)的技术。WebAssembly是一种低级的虚拟指令格式,它被设计为一种安全、快速且可移植的目标语言,可以被用作多种...

    Rust-wasm-nodejs.pdf Rust ➡ WebAssembly Node.js

    它允许代码直接与JavaScript交互,同时也成为了Rust程序的理想编译目标,因为Rust和Cargo工具链都支持WASM。 使用WASM,我们可以享受到以下几点好处: 1. 安全性:对于执行不可信代码的环境,WASM提供了一层额外的...

    rust-heroku-slug:WebAssembly Studio Rustc服务的源

    WebAssembly Studio的Rustc服务 这是用于WebAssembly Studio的heroku rustc编译器微服务。 这也是一个sl子建设者。 在本地运行服务 可以从“ app”文件夹中运行该应用程序/服务器: cd app node . 默认情况下,它...

    Rust内置的跨平台(目前为Linux和WebAssembly)网络引擎。-Rust开发

    Rust内置的跨平台(目前为Linux和WebAssembly)网络引擎。 Naia旨在使多人游戏开发变得简捷而快如闪电般的Naia成为交互式应用程序的网络体系结构,Naia打算使Rust Dead中的跨平台(目前为Linux和WebAssemby)多人...

    rust代码与c代码相互调用,rust调用c动态库静态库,以及rust代码之间的相互引用

    这种互操作性使得开发者可以充分利用 Rust 的内存安全特性与 C 语言的广泛库支持,创造出高效且可靠的系统级软件。在实际项目中,合理地利用这些工具和方法,可以帮助我们构建出既安全又高效的代码。

    react-使用React和基于Rust编译的WebAssembly样板应用程序

    本项目"react-使用React和基于Rust编译的WebAssembly样板应用程序"是一个示例,展示了如何将Rust编写的代码通过WebAssembly引入到React应用中。这个模板可以帮助开发者快速开始实践这一技术栈。 首先,你需要理解...

    一个简单的样板可以获取由Rust生成的WebAssembly代码并捆绑Webpack

    1. **Rust与WebAssembly**:Rust提供了`wasm-bindgen`工具,它可以将Rust代码转换为WASM模块,同时处理与JavaScript交互的绑定。这使得Rust编写的代码能够在Web环境中无缝运行。 2. **Cargo.toml配置**:Rust项目的...

    用JavaScriptWebAssembly实现的Conway游戏呈现到画布上

    JavaScript WebAssembly是现代Web开发中的一个强大工具,它允许开发者将用C++、Rust等高性能语言编写的代码引入到JavaScript环境中,以提高Web应用的性能。本项目以"用JavaScript WebAssembly实现的Conway游戏呈现到...

Global site tag (gtag.js) - Google Analytics