Giới thiệu về WASI-SDK
WASI-SDK là một công cụ hỗ trợ phát triển cho phép lập trình viên viết các thành phần WebAssembly bằng ngôn ngữ C. Khác với Rust với cargo-component
, C/C++ không có công cụ tích hợp để xây dựng các thành phần WebAssembly. WASI SDK cung cấp các công cụ cần thiết để biên dịch mã C thành WebAssembly.
WASI-SDK bao gồm những gì?
WASI SDK bao gồm:
- Trình biên dịch
clang
được cấu hình với một sysroot WASI (bao gồm tập hợp các tiêu đề và thư viện của nền tảng mục tiêu) cho mục tiêuwasm32-wasi
. - Thư viện chuẩn C hỗ trợ WASI (
libc
) triển khai các giao diện WASI. - Hỗ trợ đa nền tảng cho các hệ điều hành và kiến trúc khác nhau.
- Tương thích với Preview 2 để xây dựng các thành phần WebAssembly hiện đại.
Điều này cho phép bạn viết các plugin C có thể truy cập vào hệ thống tệp, mạng và các tài nguyên hệ thống khác thông qua các giao diện WASI, tương tự như các plugin Rust.
Cài đặt WASI-SDK
Dự án sử dụng một tập lệnh tùy chỉnh just dl-wasi-sdk
hoạt động như một trình quản lý gói, tự động tải xuống và giải nén phiên bản chính xác của WASI SDK cho hệ điều hành/kiến trúc của bạn vào thư mục c_deps/
(hoạt động như node_modules
cho các phụ thuộc C).
Cách viết một plugin C
Quy trình xây dựng
Quy trình xây dựng plugin C diễn ra qua hai bước:
- Tạo bindings:
wit-bindgen c ./crates/pluginlab/wit --world plugin-api --out-dir ./c_modules/plugin-name
tạo ra các bindings C từ giao diện WIT của bạn. - Biên dịch và chuyển đổi: Sử dụng
clang
của WASI SDK để biên dịch mã C thành một mô-đun WebAssembly (P1), sau đó chuyển đổi nó thành một thành phần P2.
Quy trình xây dựng:
-
Biên dịch
component.c
,plugin_api.c
, vàplugin_api_component_type.o
thành một mô-đun WebAssembly với-mexec-model=reactor
:./c_deps/wasi-sdk/bin/clang component.c plugin_api.c plugin_api_component_type.o \ -o plugin-name-c.module.p1.wasm -mexec-model=reactor
-
Chuyển đổi mô-đun P1 thành thành phần P2 bằng
wasm-tools component new
:wasm-tools component new plugin-name-c.module.p1.wasm -o plugin-name-c.wasm
Cấu trúc tệp
Cấu trúc của các plugin C trong kho lưu trữ như sau:
c_deps/ # Cài đặt WASI SDK
c_modules/
plugin-echo/ # Thư mục plugin
component.c # Triển khai plugin của bạn
plugin_api.c # Các bindings được tạo ra (từ wit-bindgen)
plugin_api.h # Tệp tiêu đề được tạo ra (từ wit-bindgen)
plugin_api_component_type.o # Tệp đối tượng được tạo ra (từ wit-bindgen)
plugin-echo-c.module.p1.wasm # Mô-đun WebAssembly đã biên dịch (P1)
plugin-echo-c.wasm # Thành phần WebAssembly cuối cùng (P2)
Triển khai Plugin
Plugin C triển khai cùng một giao diện như phiên bản Rust, với các chữ ký hàm được tạo ra từ giao diện WIT bởi wit-bindgen
:
exports_repl_api_plugin_name()
tương ứng vớifn name() -> String
exports_repl_api_plugin_man()
tương ứng vớifn man() -> String
exports_repl_api_plugin_run()
tương ứng vớifn run(payload: String) -> Result<PluginResponse, ()>
Dưới đây là các chi tiết triển khai chính - plugin-echo/component.c
:
c
#include "plugin_api.h"
#include <string.h>
#include <stdlib.h>
void exports_repl_api_plugin_name(plugin_api_string_t *ret)
{
// Điền ret với "echoc" là tên plugin
// plugin_api_string_dup() cấp phát bộ nhớ mới và sao chép chuỗi
plugin_api_string_dup(ret, "echoc");
}
void exports_repl_api_plugin_man(plugin_api_string_t *ret)
{
// Điền ret với văn bản hướng dẫn cho lệnh echo
// plugin_api_string_dup() cấp phát bộ nhớ mới và sao chép chuỗi
const char *man_text = "một số văn bản hướng dẫn ...\n";
plugin_api_string_dup(ret, man_text);
}
bool exports_repl_api_plugin_run(plugin_api_string_t *payload, exports_repl_api_plugin_plugin_response_t *ret)
{
// Đặt trạng thái thành công (0 = thành công, 1 = lỗi)
ret->status = REPL_API_TRANSPORT_REPL_STATUS_SUCCESS;
// Đặt stdout để chứa payload
// is_some = true có nghĩa là chuỗi tùy chọn có giá trị
ret->stdout.is_some = true;
// Tạo một chuỗi được kết thúc bằng null từ payload
// Payload có ptr và len, chúng tôi cần đảm bảo rằng nó được kết thúc bằng null
char *temp_str = malloc(payload->len + 1);
if (temp_str == NULL)
{
// Xử lý lỗi cấp phát
ret->stdout.is_some = false;
ret->stderr.is_some = false;
return false;
}
// Sao chép dữ liệu payload và kết thúc bằng null
memcpy(temp_str, payload->ptr, payload->len);
temp_str[payload->len] = '\0';
// Sử dụng plugin_api_string_dup để tạo chuỗi đầu ra
plugin_api_string_dup(&ret->stdout.val, temp_str);
// Giải phóng chuỗi tạm thời
free(temp_str);
// Đặt stderr thành none (không có đầu ra lỗi)
ret->stderr.is_some = false;
// Trả về true để thành công (false sẽ chỉ ra lỗi)
// Điều này tương ứng với Ok(response) trong mô hình Rust Result<T, ()>
return true;
}
Lưu ý về quản lý bộ nhớ
- Các tham số đầu vào (như
payload
) do runtime sở hữu - chúng KHÔNG ĐƯỢC giải phóng bởi plugin. - Các tham số đầu ra (như
ret
) được điền bởi plugin, được giải phóng bởi runtime. plugin_api_string_dup()
cấp phát bộ nhớ mới cho các bản sao chuỗi.- Các hàm
_free
được tạo ra tự động xử lý việc dọn dẹp.
Sự khác biệt chính so với Rust
- Quản lý bộ nhớ thủ công cho các chuỗi tạm thời.
- Xử lý rõ ràng độ dài chuỗi so với kết thúc null.
- Giá trị trả về boolean thay vì mô hình
Result<T, ()>
của Rust. - Quản lý trực tiếp các cấu trúc C được tạo ra.
Thực hành tốt nhất và mẹo hiệu suất
- Sử dụng các công cụ tự động hóa: Sử dụng các công cụ như
just
để tự động hóa quy trình xây dựng giúp tăng tốc độ phát triển. - Quản lý Bộ nhớ Cẩn thận: Hãy thận trọng với việc cấp phát và giải phóng bộ nhớ để tránh rò rỉ bộ nhớ.
- Kiểm tra và Gỡ lỗi: Sử dụng các công cụ gỡ lỗi để theo dõi và kiểm tra mã của bạn trong môi trường WebAssembly.
Các cạm bẫy thường gặp
- Cố gắng giải phóng bộ nhớ không thuộc sở hữu: Tránh giải phóng bộ nhớ cho các tham số do runtime cung cấp.
- Không xử lý lỗi đầy đủ: Đảm bảo rằng bạn xử lý tất cả các trường hợp ngoại lệ và lỗi có thể xảy ra trong mã của bạn.
Kết luận
Việc phát triển các thành phần C với WASI SDK mở ra nhiều cơ hội cho lập trình viên. Bằng cách tuân theo các hướng dẫn và thực hành tốt nhất, bạn có thể tạo ra các plugin mạnh mẽ mà có thể hoạt động trên nhiều nền tảng. Hãy bắt đầu khám phá WASI SDK và phát triển các ứng dụng WebAssembly của riêng bạn ngay hôm nay!
Câu hỏi thường gặp (FAQ)
1. WASI SDK có hỗ trợ những hệ điều hành nào?
WASI SDK hỗ trợ nhiều hệ điều hành khác nhau, bao gồm cả Linux và macOS.
2. Tôi có thể sử dụng WASI SDK với ngôn ngữ khác không?
WASI SDK chủ yếu được thiết kế cho C/C++, nhưng cũng có thể sử dụng với các ngôn ngữ khác thông qua các bindings tương ứng.
3. Làm thế nào để gỡ lỗi mã WebAssembly?
Bạn có thể sử dụng các công cụ gỡ lỗi như Chrome DevTools để gỡ lỗi mã WebAssembly.
Hãy bắt đầu hành trình phát triển WebAssembly của bạn với WASI SDK ngay hôm nay!