1彤守、注:此教程默認(rèn)你具備一定的 C/C++ 基礎(chǔ)語(yǔ)法知識(shí)
2、如:指針、結(jié)構(gòu)體等
3舍扰、本教程以 windows 操作系統(tǒng)為例,假設(shè)你會(huì)簡(jiǎn)單的使用 Visual Studio
系列文章
- C/C++ Addons 入門(mén) Hello world!
- C/C++ Addons 對(duì)象參數(shù)及回調(diào)函數(shù)
- C/C++ Addons 非阻塞多線程回調(diào)
- C/C++ Addons windows 下 .dll 動(dòng)態(tài)鏈接庫(kù) 實(shí)用篇
前置準(zhǔn)備
工具
-
node-gyp
- Google 出品的跨平臺(tái)構(gòu)建工具希坚,初衷是用來(lái)打包 chromium 的
-
gyp
即generate your package
边苹,將你的C/++
代碼編譯成node.js
可識(shí)別的文件 - 類(lèi)似
webpack
將vue、jsx
等方言編譯成為瀏覽器可識(shí)別文件 - 也可以用 cMake.js 做同樣的事情
-
.node
文件在 windows 平臺(tái)下既.dll
在 *nix 平臺(tái)下.so
文件裁僧,.node
的尾綴只是看起來(lái)自然些
(20.0404 - 深入淺出node.js)
-
python
- 因?yàn)?
node-gyp
是用python
寫(xiě)的 - 不止一個(gè)博客中說(shuō)只能用
python2.7
- 騙人的?? - 官方的說(shuō)明 Python v2.7, v3.5, v3.6, v3.7, or v3.8
- 因?yàn)?
-
Visual Studio2017
- C/C++ 在
windows
下依賴 VS - 個(gè)人推薦 - 官方給出了木有 VS 的方案个束,windows-build-tools 但這沒(méi)法用最重要語(yǔ)法提示、報(bào)錯(cuò)功能 - 不推薦
- C/C++ 在
姿勢(shì)
目前一共有三種方式可以編寫(xiě) node.js 擴(kuò)展聊疲,本文以官方推薦的
N-API
為例
-
N-API
- node.js 由官方維護(hù)的
node.js
擴(kuò)展 api - 純 C 語(yǔ)法不依賴
node.js
版本茬底,node.js
更新后基于N-API
寫(xiě)的插件照樣用,官方的解釋是底層調(diào)用的node.js
穩(wěn)定版的二進(jìn)制接口
- node.js 由官方維護(hù)的
-
node-addon-api
-
N-API
的 C++ 包裝版本(有對(duì)象获洲,更美好??)阱表,目前 (Release 2.0.0) 并未完全的包裝N-API
的所有 api
-
-
nan
-
N-API
沒(méi)出來(lái)之前主要的插件開(kāi)發(fā)方式 - “雖然”依賴
node.js
版本,但是維護(hù)團(tuán)隊(duì)很賣(mài)力贡珊,幫忙做好了每個(gè)版本的編譯所以就 不依賴node.js
版本了 ??
-
-
原生 C/C++
- 極度復(fù)雜最爬,需要用一些
v8
api、源碼 - 依賴
node.js
版本门岔,所以很難用 ??
- 極度復(fù)雜最爬,需要用一些
起步
- 安裝依賴
$ yarn add -D node-gyp # 就這一個(gè)依賴就夠了
- 個(gè)人很喜歡安裝到項(xiàng)目里面爱致,而不是
yarn add -g node-gyp
- package.js 配置
scripts
{
"scripts": {
"configure": "node-gyp configure",
"build": "node-gyp build",
"clean": "node-gyp clean",
"rebuild": "node-gyp rebuild"
}
}
-
configure
會(huì)根據(jù)binding.gyp
在build
文件夾下生成當(dāng)前平臺(tái)的 C/C++ 工程 - 第一步執(zhí)行這個(gè)
ps: 下面的命令干的活都交給 VS 咯,不要去折騰命令咯(除非你沒(méi)有VS)
-
build
(可選) 如果你不想用 VS寒随,只是編譯已有的 C/C++ 程序糠悯,那么這條命令可以代替 VS 幫你構(gòu)建 - 需要 windows-build-tools -
clean
(可選) 把build
目錄清除 -
rebuild
(可選) 依次執(zhí)行clean胯努、configure、build
三條命令
- 新建 binding.gyp
{
"targets": [
{
"target_name": "hello",
"sources": [ "src/hello.c" ],
}
]
}
- 構(gòu)建配置文件逢防,語(yǔ)法同 js 版本的 json叶沛。等價(jià)于 webpack.config.js
-
targets
下面的每一項(xiàng)都可以理解為一個(gè)node插件
,等價(jià)于webpack
打包bundle.js
-
target_name
即require([target_name])
-
sources
C/C++ 源碼目錄 - 更多配置參考
- 生成目標(biāo)平臺(tái)項(xiàng)目
$ yarn configure
- 啟動(dòng)
Visual Studio
編寫(xiě)擴(kuò)展
- 一些 API 說(shuō)明
napi_status 枚舉
· 調(diào)用任意 N-API 后返回值類(lèi)型
napi_extended_error_info 結(jié)構(gòu)體
· 表示調(diào)用 N-API 后發(fā)生的錯(cuò)誤對(duì)象
napi_env 結(jié)構(gòu)體
· 告訴 N-API 當(dāng)前執(zhí)行上下文忘朝,在調(diào)用 Addons 時(shí)自動(dòng)(Init)傳入
· 調(diào)用任意多個(gè)灰署、或嵌套 N-API 時(shí)候需要一直傳遞下去,不允許重用
napi_callback_info
· 用于 Addons 獲取 js 調(diào)用時(shí)候傳入的上下文信息局嘁,如參數(shù)
napi_value 不透明指針
· N-API 提供的在 C溉箕、js 中間的一種數(shù)據(jù)類(lèi)型
· 任意的 js 數(shù)據(jù)類(lèi)型都可以賦值給 napi_value,然后通過(guò) N-API 提供的方法再把 napi_value 轉(zhuǎn)成 C 語(yǔ)言的類(lèi)型悦昵,反之亦然
napi_threadsafe_function 不透明指針
· 代表一個(gè) js 的 function肴茄,在多線程模式下通過(guò) napi_call_threadsafe_function 調(diào)用實(shí)現(xiàn)異步 ??
# 函數(shù)
napi_create_string_utf8
· 創(chuàng)建 napi 類(lèi)型的 string
· 相當(dāng)于 const str = 'Hello world!'
napi_get_property
· 從 napi 類(lèi)型的對(duì)象中取值
· 相當(dāng)于對(duì) json = { name: 'anan', age: 29 } 取值: console.log(json.name, json.age)
napi_get_cb_info
· **** 這個(gè)可以說(shuō)是最重要的 API 了,再怎么強(qiáng)調(diào)也不為過(guò) ****
· 用于獲取 js 的入?yún)⒌福蝗缭贾殿?lèi)型寡痰、對(duì)象類(lèi)型,甚至拿到 function 類(lèi)型的指針地址
· 可以說(shuō)是 js 和 N-NAP 之前的橋梁
napi_call_function
· Addons 調(diào)用 js 回調(diào)
napi_create_function
· 創(chuàng)建 js 函數(shù)
napi_get_global
· 在 Addons 中獲取 js 的 global 對(duì)象
- C/C++
src/hello.c
#include <stdio.h>
#include <node_api.h>
#include <string.h>
napi_value Hello(napi_env env, napi_callback_info info) {
size_t argc = 1; // 只接受一個(gè)參數(shù)
napi_value argv; // 接收到的參數(shù)
char n[40];
char hello[90] = "Hello ";
napi_value result;
napi_get_cb_info(env, info, &argc, &argv, NULL, NULL); // 獲取接收參數(shù)
napi_get_value_string_utf8(env, argv, n, sizeof(n), NULL); // 將接收到的參數(shù)轉(zhuǎn)換為 C 語(yǔ)言類(lèi)型
napi_create_string_utf8(env, strcat(hello, n), NAPI_AUTO_LENGTH, &result); // 拼接字符串
return result;
}
napi_value Init(napi_env env, napi_value exports) {
// 描述 hello 屬性
napi_property_descriptor desc = {
"hello",
NULL,
Hello,
NULL,
NULL,
NULL,
napi_default,
NULL };
// 將 hello 掛載到 exports 上面 === require('hello.node').hello;
napi_define_properties(env, exports, 1, &desc);
return exports;
}
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
ps: 編寫(xiě)好C代碼后棋凳,Ctrl+Shift+b (VS編譯快捷鍵)
- javascript
test/hello.js
// const addon = require('./build/Debug/hello.node'); // 如果 VS 編譯模式是 Debug
const addon = require('./build/Release/hello.node'); // 如果 VS 編譯模式是 Release
console.log(addon.hello('world!'));
- 運(yùn)行
$ node test/hello.js
Hello world!
Boom Shakalaka