Thư viện nbind cung cấp một phương thức tối ưu để expose các thư viện C++11 sang môi trường JavaScript chỉ thông qua việc include các header. Không cần thêm các công cụ tạo mã phức tạp, trình biên dịch C++ sẽ tự động sinh ra các đoạn mã liên kết (binding) cần thiết. Điều này cho phép mã C++ được biên dịch thành Native Addon cho Node.js hoặc biên dịch sang asm.js thông qua Emscripten để chạy trực tiếp trên trình duyệt web.
Các tính năng cốt lõi
Sức mạnh của nbind nằm ở khả năng tương tác hai chiều và xóa nhòa ranh giới giữa hai ngôn ngữ:
- Thực thi mã C++ trực tiếp trong Node.js, Electron và các trình duyệt hiện đại.
- Tự động ánh xạ và chuyển đổi kiểu dữ liệu cho các kiểu cơ bản, chuỗi, mảng và đối tượng phức tạp.
- Hỗ trợ truyền và thực thi các hàm callback từ JavaScript sang C++ và ngược lại.
- Tự động sinh file định nghĩa kiểu (type definitions) cho TypeScript, tối ưu hóa trải nghiệm gợi ý mã nguồn trong IDE.
Quy trình thiết lập cơ bản
1. Chuẩn bị mã nguồn C++
Tạo một lớp C++ chứa các phương thức cần expose. Ví dụ dưới đây minh họa một lớp tiện ích toán học:
#include <numeric>
#include <vector>
class MathUtils {
public:
static int calculateSum(const std::vector<int>& numbers) {
return std::accumulate(numbers.begin(), numbers.end(), 0);
}
};
2. Khai báo binding
Sử dụng macro của nbind để đăng ký lớp và phương thức ở cuối file:
#include "nbind/nbind.h"
NBIND_CLASS(MathUtils) {
method(calculateSum);
}
3. Cấu hình dự án Node.js
Thiết lập file package.json với các script và dependencies cần thiết cho quá trình biên dịch:
{
"scripts": {
"build:native": "node-gyp configure build",
"build:asmjs": "node-gyp configure build --asmjs=1",
"setup": "autogypi --init-gyp -p nbind -s math_utils.cc"
},
"dependencies": {
"nbind": "^0.3.15",
"autogypi": "^0.2.2",
"node-gyp": "^9.0.0"
}
}
4. Biên dịch thư viện
Cài đặt dependencies và khởi tạo cấu hình build:
npm install
npm run setup
Tiến hành biên dịch thành native module:
npm run build:native
Hoặc biên dịch sang định dạng asm.js để sử dụng trên web:
npm run build:asmjs
5. Gọi thư viện từ JavaScript
const nbind = require('nbind');
const module = nbind.init().lib;
const total = module.MathUtils.calculateSum([15, 25, 35]);
console.log(`Tổng kết quả: ${total}`);
Các kỹ thuật nâng cao
Bảng ánh xạ kiểu dữ liệu
nbind tự động xử lý việc chuyển đổi kiểu dữ liệu giữa hai môi trường theo quy tắc sau:
| Kiểu JavaScript | Kiểu C++ tương ứng |
|---|---|
| number | int, float, double, uint32_t |
| boolean | bool |
| string | std::string, const char* |
| Array | std::vector<T>, std::array<T, N> |
| Function | nbind::cbFunction |
| Buffer | nbind::Buffer |
Xử lý hàm callback
Bạn có thể truyền một hàm từ JavaScript vào C++ để thực thi và nhận lại kết quả:
#include "nbind/api.h"
#include <iostream>
void executeCallback(nbind::cbFunction &jsCallback) {
double res = jsCallback.call<double>(5.5, 4.5);
std::cout << "Kết quả trả về từ JS: " << res << std::endl;
}
NBIND_GLOBAL() {
function(executeCallback);
}
Sử dụng trong JavaScript:
module.executeCallback(function(x, y) {
return x * y;
});
Thao tác với dữ liệu nhị phân
Để truyền và xử lý các khối dữ liệu lớn (như ảnh hoặc file âm thanh) mà không tốn chi phí copy bộ nhớ, hãy sử dụng nbind::Buffer:
#include "nbind/api.h"
#include <cstdint>
void invertBytes(nbind::Buffer buffer) {
uint8_t* payload = buffer.data();
size_t size = buffer.length();
for (size_t i = 0; i < size; ++i) {
payload[i] = ~payload[i];
}
buffer.commit();
}