1. QuickJS 快速入門 (QuickJS QuickStart)
<span id='11-簡介'></span>html
1.1. 簡介
QuickJS是一個小型的可嵌入Javascript引擎。它支持ES2020規範,包括模塊、異步生成器和代理。它還支持數學擴展,好比大整數(BigInt)、大浮點數(BigFloat)和操做符重載。
<span id='12-安裝'></span>git
1.2. 安裝
- Linux 直接下載 源碼
make && make install
- MacOS X 下 makefile 有 Bug ,能夠直接使用 homebrew 安裝
brew install quickjs
- 執行
qjs
驗證安裝成功
<span id='13-簡單使用'></span>github
1.3. 簡單使用
<span id='131-控制檯執行'></span>bash
1.3.1. 控制檯執行
qjs
進入quickjs環境,-h
獲取幫助,-q
退出環境。
直接執行js:異步
console.log(new Date())
輸出:Wed Aug 14 2019 23:51:43 GMT+0800
undefined </br>函數
(function(){ return 1+1;})()
輸出:2 </br>測試
<span id='132-js腳本執行'></span>ui
1.3.2. js腳本執行
新建一個js腳本,名爲hello.js
,內容爲console.log('hello world !')
, 在js目錄下執行this
qjs hello.js
輸出:hello world ! </br>spa
<span id='133-編譯二進制文件'></span>
1.3.3. 編譯二進制文件
將 quickjs.h
、quickjs-libc.h
、libquickjs.a
拷貝到js文件同目錄下。
qjsc -o hello hello.js ls ./hello
輸出:hello world !
編譯出來的可執行文件的大小隻有569K(2019-9-18版本爲900K),沒有任何外部依賴,很是適合嵌入式設備使用。
<span id='14-全局對象'></span>
1.4. 全局對象
scriptArgs
輸入的命令行參數,第一個參數爲腳本的名稱。print(...args)
、console.log(...args)
打印由空格和尾隨換行符分隔的參數。
新建js腳本globle_obj.js
(function(){ if(typeof scriptArgs != 'undefined'){ print(scriptArgs); console.log(scriptArgs[1]); } })()
qjs globle_obj.js -a 123 1234
輸出:
globle_obj.js,-a,123,1234
-a
<span id='15-std-模塊'></span>
1.5. std 模塊
std
模塊爲quickjs-libc
提供包裝器stdlib.h
和stdio.h
和其餘一些實用程序。
std代碼示例:
建立文件std_m.js
import * as std from 'std'; var file = std.open('std_open_file.js','w'); file.puts('var file = std.open(\"std_open_file.txt\",\"w\");\n'); file.puts('file.puts(\'std_open_file line1\\n\');\n'); file.puts('file.puts(\'std_open_file line2\\n\');\n'); file.puts('file.close();\n'); file.close(); std.loadScript('std_open_file.js'); var rdfile = std.open("std_open_file.txt","r"); do{ console.log(rdfile.getline()); }while(!rdfile.eof()); rdfile.close();
執行qjs std_m.js
,目錄下會生成2個新文件std_open_file.js
std_open_file.txt
。
控制檯輸出:
std_open_file line1
std_open_file line2
null
<span id='16-os-模塊'></span>
1.6. os 模塊
os
模塊提供操做系統特定功能:底層文件訪問、信號、計時器、異步 I/O。
代碼示例:
import * as os from 'os'; os.remove('hello'); os.remove('std_open_file.js'); os.remove('std_open_file.txt');
刪除生成的測試文件
<span id='17-自定義C模塊' ></span>
1.7. 自定義C模塊
ES6模塊徹底支持。默認名稱解析規則以下:
- 模塊名稱帶有前導.或..是相對於當前模塊的路徑
- 模塊名稱沒有前導.或..是系統模塊,例如std或os
- 模塊名稱以.so結尾,是使用QuickJS C API的原生模塊
使用js文件模塊和系統模塊,參照引用原生js模塊和上面的例子便可,這裏就很少贅述。 這裏着重講解如何編寫本身的原生C模塊,而且以導入so文件的方式在js代碼中使用。
<span id='171-js數據類型在C中的定義' ></span>
1.7.1. js數據類型在C中的定義
typedef union JSValueUnion { int32_t int32; //整數值 double float64; //double值 void *ptr; //QuickJS引用類型的指針 } JSValueUnion; //存放於同一地址,且互斥 typedef struct JSValue { JSValueUnion u; //存放真實數值或着其指針 int64_t tag; //JSValue類型的標示符(如 undefined 其 tag == JS_TAG_UNDEFINED) } JSValue;
此結構定義在 quickjs.h 中。
<span id='172-c模塊編寫' ></span>
1.7.2. c模塊編寫
流程以下:
- 自定義原生C函數
- 定義 QuickJS C 函數
- 定義API的函數入口名稱及列表
- 定義初始化回調方法,將函數入口列表在模塊中暴露
- 定義初始化模塊方法,由系統自動調用,且函數名稱不可更改
建立編寫c_test_m.c文件:
#include "quickjs.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #define JS_INIT_MODULE js_init_module #define countof(x) (sizeof(x) / sizeof((x)[0])) /* 自定義原生C函數 */ static double test_add(int a, double b) { return a + b; } static char *test_add_str(const char *a, double b) { /* 要有足夠的空間來容納要拼接的字符串,不然可能會形成緩衝溢出的錯誤狀況 */ char instr[64]; sprintf(instr, "%.2f", b); char *dest = malloc(128); memset(dest, 0, 128); strcpy(dest, a); char *retdest = strcat(dest, instr); return dest; } /* 定義 QuickJS C 函數 *ctx : 運行時上下文 this_val : this對象 argc : 入參個數 *argv : 入參列表 */ static JSValue js_test_add(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { int a; double b; if (JS_ToInt32(ctx, &a, argv[0])) return JS_EXCEPTION; if (JS_ToFloat64(ctx, &b, argv[1])) return JS_EXCEPTION; printf("argc = %d \n", argc); printf("a = %d \n", a); printf("b = %lf \n", b); printf("argv[1].u.float64 = %lf \n", argv[1].u.float64); return JS_NewFloat64(ctx, test_add(a, b)); } static JSValue js_test_add_str(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { if (!JS_IsString(argv[0])) { return JS_EXCEPTION; } double d; if (JS_ToFloat64(ctx, &d, argv[1])) return JS_EXCEPTION; const char *jscstr = JS_ToCString(ctx, argv[0]); printf("JS_ToCString(ctx, argv[0]) = %s \n", jscstr); printf("argv[1].u.float64 = %lf \n", argv[1].u.float64); char *jsret = test_add_str(jscstr, d); return JS_NewString(ctx, jsret); } /* 定義API的函數入口名稱及列表 */ static const JSCFunctionListEntry js_test_funcs[] = { /* JS_CFUNC_DEF(函數入口名稱,入參個數,QuickJS C 函數) */ JS_CFUNC_DEF("testAdd", 2, js_test_add), JS_CFUNC_DEF("testAddStr", 2, js_test_add_str), }; /* 定義初始化回調方法(由系統調用,入參格式固定),將函數入口列表 在模塊中暴露 */ static int js_test_init(JSContext *ctx, JSModuleDef *m) { return JS_SetModuleExportList(ctx, m, js_test_funcs, countof(js_test_funcs)); } /* 定義初始化模塊方法,由系統自動調用,且函數名稱不可更改 */ JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name) { JSModuleDef *m; m = JS_NewCModule(ctx, module_name, js_test_init); if (!m) return NULL; JS_AddModuleExportList(ctx, m, js_test_funcs, countof(js_test_funcs)); return m; }
將 quickjs.h
、quickjs-libc.h
、libquickjs.a
拷貝到當前工程目錄下。
執行命令
gcc c_test_m.c libquickjs.a -fPIC -shared -o libtest.so
生成libtest.so
文件。
<span id='173-使用.so模塊' ></span>
1.7.3. 使用.so模塊
建立js文件 c_test_m.js
import { testAdd , testAddStr} from 'libtest.so' console.log('\n') console.log(`testAdd: ${testAdd(1, 0.5)}`) console.log('\n') console.log(`testAddStr: ${testAddStr('Pi equal to about ', 3.14159)}`) console.log('\n')
qjs c_test_m.js
輸出:
argc = 2
a = 1
b = 0.500000
argv[1].u.float64 = 0.500000
testAdd: 1.5
JS_ToCString(ctx, argv[0]) = Pi equal to about
argv[1].u.float64 = 3.141590
testAddStr: Pi equal to about 3.14
<br> <br> 項目地址
原文出處:https://www.cnblogs.com/gaobw/p/11693876.html