在Node.js下编写ObjC及汇编函数与JavaScript交
当前稳定版本的Node.js v8.9.1已经引入了实验性的N-API,我们可以通过这组API来写本地C/C++代码以及与之相兼容的其他编程语言的代码与JavaScript层进行交互。本文将介绍我们如何用自己编写的一套包含Objective-C和汇编语言的本地代码与JavaScript进行交互的。在本文中,我们主要介绍在JavaScript层调用本地代码实现的函数。
在开始之前,我们需要做一些准备工作,包括安装至少版本为8.9.1的Node.js运行时环境,还有node-gyp编译工具,这些可以在这篇博文中找到(看中间段的文字部分)。这篇博文中还包含了如何编译gyp工程的步序,因此这些基本的东西在本文中不详细展开了。下面我们就先列出gyp文件内容:
{
"targets": [
{
"target_name": "test",
"sources": [ "native.m", "test.s" ]
}
]
}
在上述配置文件中,我们可以看到,这里面的目标模块名为test,源文件有Objective-C语言的native.m,以及汇编语言的test.s。
下面给出最主要的native.m的内容,该源文件列出了暴露给JavaScript端的所有外部函数:
#include <node_api.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#import <Foundation/Foundation.h>
#define var __auto_type
extern int ASMSub(int a, int b);
static napi_value MyStringMethod(napi_env env, napi_callback_info info)
{
napi_value world;
var str = @"Hello, world!".UTF8String;
var str_len = strlen(str);
printf("The length is: %zu\n", str_len);
napi_create_string_utf8(env, str, str_len, &world);
return world;
}
static napi_value MyIntMethod(napi_env env, napi_callback_info info)
{
@autoreleasepool {
size_t nArgs = 32;
napi_value inputArgs[32];
napi_value thisObj;
napi_get_cb_info(env, info, &nArgs, inputArgs, &thisObj, NULL);
napi_value result;
int32_t argValue = 0;
napi_get_value_int32(env, inputArgs[0], &argValue);
var array = @[@"abc", @"def", @"xyz"];
napi_create_int32(env, ASMSub(100, argValue) + array.count, &result);
return result;
}
}
napi_value Init(napi_env env, napi_value exports)
{
napi_property_descriptor stringDesc = { "stringMethod", 0, MyStringMethod, 0, 0, 0, napi_default, 0 };
napi_property_descriptor intDesc = { "intMethod", 0, MyIntMethod, 0, 0, 0, napi_default, 0 };
napi_define_properties(env, exports, 2, (napi_property_descriptor[]){stringDesc, intDesc});
return exports;
}
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
当前,node-gyp编译工具链还不是非常成熟,因此Objective-C中还有不少东西无法使用,比如NSNumber类型就不支持,还有NSLog也不支持,这些对于Clang前端而言都能解析得过,但是后端库没有包含,所以我们用node-gyp命令去构建是没问题的,但在运行时就会发生符号找不到的异常。不过我们用用NSString、NSArray这些还是没有问题的。这个源文件中还引入了一个全局函数——ASMSub
,这个函数将在下面的汇编文件中实现。
.text
.align 4
.intel_syntax
.globl _ASMSub
_ASMSub:
sub edi, esi
mov eax, edi
ret
以上三个文件都准备好之后,我们就可以在命令行用cd
命令进入到此目录中,然后使用node-gyp configure &&node-gyp build
命令进行构建。成功的话最后会显示ok。
最后,我们创建一个名为hello.js的JavaScript源文件:
const test = require('./build/Release/test.node');
const str = test.stringMethod();
const value = test.intMethod(30);
console.log("String is: " + str);
console.log("Value is: " + value);
然后我们可以用node hello.js
运行来查看结果了。